Fix bug where prior LSP completions can be displayed after trigger char (cherry-pick #32927) (#32931)
gcp-cherry-pick-bot[bot]
and
Michael Sloan
created 6 months ago
Cherry-picked Fix bug where prior LSP completions can be displayed after
trigger char (#32927)
Bug in #31872
Closes #32774
Release Notes:
- Fixed a bug in LSP completions caching where prior completions may be
used when they should not, after typing a trigger char like `.`
Co-authored-by: Michael Sloan <michael@zed.dev>
Change summary
crates/editor/src/editor.rs | 48 +++++++++++++++++++++++++-------------
1 file changed, 31 insertions(+), 17 deletions(-)
Detailed changes
@@ -5139,6 +5139,37 @@ impl Editor {
.as_ref()
.map_or(true, |provider| provider.filter_completions());
+ let trigger_kind = match trigger {
+ Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
+ CompletionTriggerKind::TRIGGER_CHARACTER
+ }
+ _ => CompletionTriggerKind::INVOKED,
+ };
+ let completion_context = CompletionContext {
+ trigger_character: trigger.and_then(|trigger| {
+ if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
+ Some(String::from(trigger))
+ } else {
+ None
+ }
+ }),
+ trigger_kind,
+ };
+
+ // Hide the current completions menu when a trigger char is typed. Without this, cached
+ // completions from before the trigger char may be reused (#32774). Snippet choices could
+ // involve trigger chars, so this is skipped in that case.
+ if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER && self.snippet_stack.is_empty()
+ {
+ let menu_is_open = matches!(
+ self.context_menu.borrow().as_ref(),
+ Some(CodeContextMenu::Completions(_))
+ );
+ if menu_is_open {
+ self.hide_context_menu(window, cx);
+ }
+ }
+
if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
if filter_completions {
menu.filter(query.clone(), provider.clone(), window, cx);
@@ -5169,23 +5200,6 @@ impl Editor {
}
};
- let trigger_kind = match trigger {
- Some(trigger) if buffer.read(cx).completion_triggers().contains(trigger) => {
- CompletionTriggerKind::TRIGGER_CHARACTER
- }
- _ => CompletionTriggerKind::INVOKED,
- };
- let completion_context = CompletionContext {
- trigger_character: trigger.and_then(|trigger| {
- if trigger_kind == CompletionTriggerKind::TRIGGER_CHARACTER {
- Some(String::from(trigger))
- } else {
- None
- }
- }),
- trigger_kind,
- };
-
let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
buffer_snapshot.surrounding_word(buffer_position)
{