Skip to content

Commit

Permalink
Resolve completion items once exactly (zed-industries#22448)
Browse files Browse the repository at this point in the history
Closes zed-industries#19214
Closes zed-industries#22443

Adds `resolved` property into Zed completion item data, to ensure we
resolve every completion item exactly once.

There are 2 paths for singplayer Zed, and corresponding 2 analogues for
multi player code, where resolve may happen:
* completions menu display & selection, that ends up using
`resolve_completions` in `lsp_store.rs`
* applying a completion menu entry, that ends up using
`apply_additional_edits_for_completion` in `lsp_store.rs`

Now, all local counterparts check `enabled` field before resolving and
set it to true afterwards, and reuse the same `resolve_completion_local`
method for resolving the items.

A logic for re-generating docs and item labels was moved out from the
`resolve_completion_local` method into a separate method, as
`apply_additional_edits_for_completion` does not need that, but needs
the rest of the logic for resolving.
During the extraction, I've noted that multiplayer clients are not
getting the item labels, regenerated after the resolve — as the Zed
protocol-based flow is not the exact copy of the local resolving.
To improve that, `resolve_completion_remote` needs to be adjusted, but
this change is omitted to avoid bloating the PR.

Release Notes:

- Fixed autocomplete inserting multiple imports
  • Loading branch information
SomeoneToIgnore authored Dec 27, 2024
1 parent d71180a commit ed61abb
Show file tree
Hide file tree
Showing 9 changed files with 369 additions and 199 deletions.
12 changes: 2 additions & 10 deletions crates/assistant/src/slash_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ impl SlashCommandCompletionProvider {
server_id: LanguageServerId(0),
lsp_completion: Default::default(),
confirm,
resolved: true,
})
})
.collect()
Expand Down Expand Up @@ -242,6 +243,7 @@ impl SlashCommandCompletionProvider {
server_id: LanguageServerId(0),
lsp_completion: Default::default(),
confirm,
resolved: true,
}
})
.collect())
Expand Down Expand Up @@ -330,16 +332,6 @@ impl CompletionProvider for SlashCommandCompletionProvider {
Task::ready(Ok(true))
}

fn apply_additional_edits_for_completion(
&self,
_: Model<Buffer>,
_: project::Completion,
_: bool,
_: &mut ViewContext<Editor>,
) -> Task<Result<Option<language::Transaction>>> {
Task::ready(Ok(None))
}

fn is_completion_trigger(
&self,
buffer: &Model<Buffer>,
Expand Down
11 changes: 1 addition & 10 deletions crates/collab_ui/src/chat_panel/message_editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,6 @@ impl CompletionProvider for MessageEditorCompletionProvider {
Task::ready(Ok(false))
}

fn apply_additional_edits_for_completion(
&self,
_buffer: Model<Buffer>,
_completion: Completion,
_push_to_history: bool,
_cx: &mut ViewContext<Editor>,
) -> Task<Result<Option<language::Transaction>>> {
Task::ready(Ok(None))
}

fn is_completion_trigger(
&self,
_buffer: &Model<Buffer>,
Expand Down Expand Up @@ -319,6 +309,7 @@ impl MessageEditor {
server_id: LanguageServerId(0), // TODO: Make this optional or something?
lsp_completion: Default::default(), // TODO: Make this optional or something?
confirm: None,
resolved: true,
}
})
.collect()
Expand Down
1 change: 1 addition & 0 deletions crates/editor/src/code_context_menus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ impl CompletionsMenu {
documentation: None,
lsp_completion: Default::default(),
confirm: None,
resolved: true,
})
.collect();

Expand Down
44 changes: 32 additions & 12 deletions crates/editor/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3830,8 +3830,11 @@ impl Editor {
};

let buffer_handle = completions_menu.buffer;
let completions = completions_menu.completions.borrow_mut();
let completion = completions.get(mat.candidate_id)?;
let completion = completions_menu
.completions
.borrow()
.get(mat.candidate_id)?
.clone();
cx.stop_propagation();

let snippet;
Expand Down Expand Up @@ -3975,9 +3978,11 @@ impl Editor {
}

let provider = self.completion_provider.as_ref()?;
drop(completion);
let apply_edits = provider.apply_additional_edits_for_completion(
buffer_handle,
completion.clone(),
completions_menu.completions.clone(),
mat.candidate_id,
true,
cx,
);
Expand Down Expand Up @@ -5087,7 +5092,7 @@ impl Editor {
}))
}

#[cfg(feature = "test-support")]
#[cfg(any(feature = "test-support", test))]
pub fn context_menu_visible(&self) -> bool {
self.context_menu
.borrow()
Expand Down Expand Up @@ -13447,11 +13452,14 @@ pub trait CompletionProvider {

fn apply_additional_edits_for_completion(
&self,
buffer: Model<Buffer>,
completion: Completion,
push_to_history: bool,
cx: &mut ViewContext<Editor>,
) -> Task<Result<Option<language::Transaction>>>;
_buffer: Model<Buffer>,
_completions: Rc<RefCell<Box<[Completion]>>>,
_completion_index: usize,
_push_to_history: bool,
_cx: &mut ViewContext<Editor>,
) -> Task<Result<Option<language::Transaction>>> {
Task::ready(Ok(None))
}

fn is_completion_trigger(
&self,
Expand Down Expand Up @@ -13610,6 +13618,7 @@ fn snippet_completions(
Some(Completion {
old_range: range,
new_text: snippet.body.clone(),
resolved: false,
label: CodeLabel {
text: matching_prefix.clone(),
runs: vec![],
Expand Down Expand Up @@ -13675,19 +13684,30 @@ impl CompletionProvider for Model<Project> {
cx: &mut ViewContext<Editor>,
) -> Task<Result<bool>> {
self.update(cx, |project, cx| {
project.resolve_completions(buffer, completion_indices, completions, cx)
project.lsp_store().update(cx, |lsp_store, cx| {
lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
})
})
}

fn apply_additional_edits_for_completion(
&self,
buffer: Model<Buffer>,
completion: Completion,
completions: Rc<RefCell<Box<[Completion]>>>,
completion_index: usize,
push_to_history: bool,
cx: &mut ViewContext<Editor>,
) -> Task<Result<Option<language::Transaction>>> {
self.update(cx, |project, cx| {
project.apply_additional_edits_for_completion(buffer, completion, push_to_history, cx)
project.lsp_store().update(cx, |lsp_store, cx| {
lsp_store.apply_additional_edits_for_completion(
buffer,
completions,
completion_index,
push_to_history,
cx,
)
})
})
}

Expand Down
Loading

0 comments on commit ed61abb

Please sign in to comment.