diff --git a/crates/copilot/src/copilot.rs b/crates/copilot/src/copilot.rs index d27332cbde..1fb7ee0b5b 100644 --- a/crates/copilot/src/copilot.rs +++ b/crates/copilot/src/copilot.rs @@ -522,6 +522,9 @@ impl Copilot { let language = snapshot.language_at(position); let language_name = language.map(|language| language.name()); let language_name = language_name.as_deref(); + let tab_size = settings.tab_size(language_name); + let hard_tabs = settings.hard_tabs(language_name); + let language_id = id_for_language(language); let path; let relative_path; @@ -537,22 +540,23 @@ impl Copilot { relative_path = PathBuf::new(); } - let params = request::GetCompletionsParams { - doc: request::GetCompletionsDocument { - source: snapshot.text(), - tab_size: settings.tab_size(language_name).into(), - indent_size: 1, - insert_spaces: !settings.hard_tabs(language_name), - uri, - path: path.to_string_lossy().into(), - relative_path: relative_path.to_string_lossy().into(), - language_id: id_for_language(language), - position: point_to_lsp(position), - version: 0, - }, - }; cx.background().spawn(async move { - let result = server.request::(params).await?; + let result = server + .request::(request::GetCompletionsParams { + doc: request::GetCompletionsDocument { + source: snapshot.text(), + tab_size: tab_size.into(), + indent_size: 1, + insert_spaces: !hard_tabs, + uri, + path: path.to_string_lossy().into(), + relative_path: relative_path.to_string_lossy().into(), + language_id, + position: point_to_lsp(position), + version: 0, + }, + }) + .await?; let completions = result .completions .into_iter() diff --git a/crates/editor/src/display_map.rs b/crates/editor/src/display_map.rs index c9869e7a9c..c5e6b371ed 100644 --- a/crates/editor/src/display_map.rs +++ b/crates/editor/src/display_map.rs @@ -230,6 +230,10 @@ impl DisplayMap { self.text_highlights.remove(&Some(type_id)) } + pub fn has_suggestion(&self) -> bool { + self.suggestion_map.has_suggestion() + } + pub fn replace_suggestion( &self, new_suggestion: Option>, diff --git a/crates/editor/src/display_map/suggestion_map.rs b/crates/editor/src/display_map/suggestion_map.rs index 0fc2a025fe..ccc07bf591 100644 --- a/crates/editor/src/display_map/suggestion_map.rs +++ b/crates/editor/src/display_map/suggestion_map.rs @@ -171,6 +171,11 @@ impl SuggestionMap { (snapshot.clone(), suggestion_edits) } + + pub fn has_suggestion(&self) -> bool { + let snapshot = self.0.lock(); + snapshot.suggestion.is_some() + } } #[derive(Clone)] diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 5c6470fe90..7a8293e195 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -2188,7 +2188,9 @@ impl Editor { } fn trigger_completion_on_input(&mut self, text: &str, cx: &mut ViewContext) { - if !cx.global::().show_completions_on_input { + if !cx.global::().show_completions_on_input + || self.has_active_copilot_suggestion(cx) + { return; } @@ -2373,11 +2375,11 @@ impl Editor { } this.completion_tasks.retain(|(id, _)| *id > menu.id); - if this.focused { + if this.focused && !menu.matches.is_empty() { this.show_context_menu(ContextMenu::Completions(menu), cx); + } else { + this.hide_context_menu(cx); } - - cx.notify(); }); } Ok::<_, anyhow::Error>(()) @@ -2806,33 +2808,9 @@ impl Editor { let cursor = if selection.start == selection.end { selection.start.bias_left(&snapshot) } else { - self.clear_copilot_suggestions(cx); return None; }; - - if let Some(new_text) = self - .copilot_state - .text_for_active_completion(cursor, &snapshot) - { - self.display_map.update(cx, |map, cx| { - map.replace_suggestion( - Some(Suggestion { - position: cursor, - text: new_text.into(), - }), - cx, - ) - }); - self.copilot_state - .completions - .swap(0, self.copilot_state.active_completion_index); - self.copilot_state.completions.truncate(1); - self.copilot_state.active_completion_index = 0; - cx.notify(); - } else { - self.display_map - .update(cx, |map, cx| map.replace_suggestion::(None, cx)); - } + self.refresh_active_copilot_suggestion(cx); if !copilot.read(cx).status().is_authorized() { return None; @@ -2860,23 +2838,7 @@ impl Editor { for completion in completions { this.copilot_state.push_completion(completion); } - - let buffer = this.buffer.read(cx).snapshot(cx); - if let Some(text) = this - .copilot_state - .text_for_active_completion(cursor, &buffer) - { - this.display_map.update(cx, |map, cx| { - map.replace_suggestion( - Some(Suggestion { - position: cursor, - text: text.into(), - }), - cx, - ) - }); - } - cx.notify(); + this.refresh_active_copilot_suggestion(cx); } }); @@ -2901,7 +2863,7 @@ impl Editor { self.copilot_state.active_completion_index = (self.copilot_state.active_completion_index + 1) % self.copilot_state.completions.len(); - self.sync_suggestion(cx); + self.refresh_active_copilot_suggestion(cx); } fn previous_copilot_suggestion( @@ -2927,7 +2889,7 @@ impl Editor { self.copilot_state.active_completion_index - 1 }; - self.sync_suggestion(cx); + self.refresh_active_copilot_suggestion(cx); } fn toggle_copilot_suggestions(&mut self, _: &copilot::Toggle, cx: &mut ViewContext) { @@ -2957,11 +2919,15 @@ impl Editor { cx.notify(); } - fn sync_suggestion(&mut self, cx: &mut ViewContext) { + fn refresh_active_copilot_suggestion(&mut self, cx: &mut ViewContext) { let snapshot = self.buffer.read(cx).snapshot(cx); let cursor = self.selections.newest_anchor().head(); - if let Some(text) = self + if self.context_menu.is_some() { + self.display_map + .update(cx, |map, cx| map.replace_suggestion::(None, cx)); + cx.notify(); + } else if let Some(text) = self .copilot_state .text_for_active_completion(cursor, &snapshot) { @@ -2975,6 +2941,10 @@ impl Editor { ) }); cx.notify(); + } else if self.has_active_copilot_suggestion(cx) { + self.display_map + .update(cx, |map, cx| map.replace_suggestion::(None, cx)); + cx.notify(); } } @@ -3005,6 +2975,10 @@ impl Editor { !was_empty } + fn has_active_copilot_suggestion(&self, cx: &AppContext) -> bool { + self.display_map.read(cx).has_suggestion() + } + pub fn render_code_actions_indicator( &self, style: &EditorStyle, @@ -3120,13 +3094,16 @@ impl Editor { self.completion_tasks.clear(); } self.context_menu = Some(menu); + self.refresh_active_copilot_suggestion(cx); cx.notify(); } fn hide_context_menu(&mut self, cx: &mut ViewContext) -> Option { cx.notify(); self.completion_tasks.clear(); - self.context_menu.take() + let context_menu = self.context_menu.take(); + self.refresh_active_copilot_suggestion(cx); + context_menu } pub fn insert_snippet(