@@ -7294,6 +7294,92 @@ async fn test_completions_with_extra_edits(cx: &mut gpui::TestAppContext) {
request.next().await;
+ cx.condition(|editor, _| editor.context_menu_visible())
+ .await;
+ let apply_additional_edits = cx.update_editor(|editor, cx| {
+ editor
+ .confirm_completion(&ConfirmCompletion::default(), cx)
+ .unwrap()
+ });
+ cx.assert_editor_state(indoc! {"fn main() { let a = 2.Some(2)ˇ; }"});
+ apply_additional_edits.await.unwrap();
+ cx.assert_editor_state(indoc! {"fn main() { let a = Some(2)ˇ; }"});
+}
+
+#[gpui::test]
+async fn test_completions_with_extra_resolved_edits(cx: &mut gpui::TestAppContext) {
+ init_test(cx, |_| {});
+
+ let mut cx = EditorLspTestContext::new_rust(
+ lsp::ServerCapabilities {
+ completion_provider: Some(lsp::CompletionOptions {
+ trigger_characters: Some(vec![".".to_string()]),
+ ..Default::default()
+ }),
+ ..Default::default()
+ },
+ cx,
+ )
+ .await;
+
+ cx.set_state(indoc! {"fn main() { let a = 2ˇ; }"});
+ cx.simulate_keystroke(".");
+ let completion_item = lsp::CompletionItem {
+ label: "some".into(),
+ kind: Some(lsp::CompletionItemKind::SNIPPET),
+ detail: Some("Wrap the expression in an `Option::Some`".to_string()),
+ documentation: Some(lsp::Documentation::MarkupContent(lsp::MarkupContent {
+ kind: lsp::MarkupKind::Markdown,
+ value: "```rust\nSome(2)\n```".to_string(),
+ })),
+ deprecated: Some(false),
+ sort_text: Some("fffffff2".to_string()),
+ filter_text: Some("some".to_string()),
+ insert_text_format: Some(lsp::InsertTextFormat::SNIPPET),
+ text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
+ range: lsp::Range {
+ start: lsp::Position {
+ line: 0,
+ character: 22,
+ },
+ end: lsp::Position {
+ line: 0,
+ character: 22,
+ },
+ },
+ new_text: "Some(2)".to_string(),
+ })),
+ additional_text_edits: Some(vec![lsp::TextEdit {
+ range: lsp::Range {
+ start: lsp::Position {
+ line: 0,
+ character: 20,
+ },
+ end: lsp::Position {
+ line: 0,
+ character: 22,
+ },
+ },
+ new_text: "".to_string(),
+ }]),
+ ..Default::default()
+ };
+
+ let closure_completion_item = completion_item.clone();
+ let mut request = cx.handle_request::<lsp::request::Completion, _, _>(move |_, _, _| {
+ let task_completion_item = closure_completion_item.clone();
+ async move {
+ Ok(Some(lsp::CompletionResponse::Array(vec![
+ lsp::CompletionItem {
+ additional_text_edits: None,
+ ..task_completion_item
+ },
+ ])))
+ }
+ });
+
+ request.next().await;
+
cx.condition(|editor, _| editor.context_menu_visible())
.await;
let apply_additional_edits = cx.update_editor(|editor, cx| {
@@ -1349,6 +1349,7 @@ impl LspCommand for GetCompletions {
} else {
Default::default()
};
+
let completions = buffer.read_with(&cx, |buffer, _| {
let language = buffer.language().cloned();
let snapshot = buffer.snapshot();
@@ -1357,17 +1358,6 @@ impl LspCommand for GetCompletions {
completions
.into_iter()
.filter_map(move |mut lsp_completion| {
- // TODO kb store these? at least, should only allow this when we have resolve
- // // For now, we can only handle additional edits if they are returned
- // // when resolving the completion, not if they are present initially.
- // if lsp_completion
- // .additional_text_edits
- // .as_ref()
- // .map_or(false, |edits| !edits.is_empty())
- // {
- // return None;
- // }
-
let (old_range, mut new_text) = match lsp_completion.text_edit.as_ref() {
// If the language server provides a range to overwrite, then
// check that the range is valid.
@@ -4446,11 +4446,18 @@ impl Project {
};
cx.spawn(|this, mut cx| async move {
- let resolved_completion = lang_server
- .request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
- .await?;
+ let additional_text_edits = if let Some(edits) =
+ completion.lsp_completion.additional_text_edits.as_ref()
+ {
+ Some(edits.clone())
+ } else {
+ lang_server
+ .request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
+ .await?
+ .additional_text_edits
+ };
- if let Some(edits) = resolved_completion.additional_text_edits {
+ if let Some(edits) = additional_text_edits {
let edits = this
.update(&mut cx, |this, cx| {
this.edits_from_lsp(