Detailed changes
@@ -160,6 +160,9 @@
/// Whether to show the signature help after completion or a bracket pair inserted.
/// If `auto_signature_help` is enabled, this setting will be treated as enabled also.
"show_signature_help_after_edits": false,
+ /// Whether to show the inline completions next to the completions provided by a language server.
+ /// Only has an effect if inline completion provider supports it.
+ "show_inline_completions_in_menu": true,
// Whether to show wrap guides (vertical rulers) in the editor.
// Setting this to true will show a guide at the 'preferred_line_length' value
// if 'soft_wrap' is set to 'preferred_line_length', and will show any
@@ -59,6 +59,10 @@ impl InlineCompletionProvider for CopilotCompletionProvider {
"Copilot"
}
+ fn show_completions_in_menu() -> bool {
+ false
+ }
+
fn is_enabled(
&self,
buffer: &Model<Buffer>,
@@ -326,17 +330,15 @@ mod tests {
);
executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT);
cx.update_editor(|editor, cx| {
- // We want to show both: the inline completion and the completion menu
assert!(editor.context_menu_visible());
- assert!(editor.context_menu_contains_inline_completion());
- assert!(editor.has_active_inline_completion());
+ assert!(!editor.context_menu_contains_inline_completion());
+ assert!(!editor.has_active_inline_completion());
// Since we have both, the copilot suggestion is not shown inline
assert_eq!(editor.text(cx), "one.\ntwo\nthree\n");
assert_eq!(editor.display_text(cx), "one.\ntwo\nthree\n");
// Confirming a non-copilot completion inserts it and hides the context menu, without showing
// the copilot suggestion afterwards.
- editor.context_menu_next(&Default::default(), cx);
editor
.confirm_completion(&Default::default(), cx)
.unwrap()
@@ -384,23 +386,12 @@ mod tests {
// Ensure existing inline completion is interpolated when inserting again.
cx.simulate_keystroke("c");
- drop(handle_completion_request(
- &mut cx,
- indoc! {"
- one.c|<>
- two
- three
- "},
- vec!["completion_a", "completion_b"],
- ));
executor.run_until_parked();
cx.update_editor(|editor, cx| {
- // Since we have an LSP completion too, the inline completion is
- // shown in the menu now
- assert!(editor.context_menu_visible());
- assert!(editor.context_menu_contains_inline_completion());
+ assert!(!editor.context_menu_visible());
+ assert!(!editor.context_menu_contains_inline_completion());
assert!(editor.has_active_inline_completion());
- assert_eq!(editor.display_text(cx), "one.c\ntwo\nthree\n");
+ assert_eq!(editor.display_text(cx), "one.copilot1\ntwo\nthree\n");
assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n");
});
@@ -416,16 +407,9 @@ mod tests {
);
executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT);
cx.update_editor(|editor, cx| {
- assert!(editor.context_menu_visible());
- assert!(editor.has_active_inline_completion());
- assert!(editor.context_menu_contains_inline_completion());
- assert_eq!(editor.display_text(cx), "one.c\ntwo\nthree\n");
- assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n");
-
- // Canceling should first hide the menu and make Copilot suggestion visible.
- editor.cancel(&Default::default(), cx);
assert!(!editor.context_menu_visible());
assert!(editor.has_active_inline_completion());
+ assert!(!editor.context_menu_contains_inline_completion());
assert_eq!(editor.display_text(cx), "one.copilot2\ntwo\nthree\n");
assert_eq!(editor.text(cx), "one.c\ntwo\nthree\n");
@@ -928,8 +912,8 @@ mod tests {
executor.advance_clock(COPILOT_DEBOUNCE_TIMEOUT);
cx.update_editor(|editor, cx| {
assert!(editor.context_menu_visible());
- assert!(editor.context_menu_contains_inline_completion());
- assert!(editor.has_active_inline_completion(),);
+ assert!(!editor.context_menu_contains_inline_completion());
+ assert!(!editor.has_active_inline_completion(),);
assert_eq!(editor.text(cx), "one\ntwo.\nthree\n");
});
}
@@ -2473,7 +2473,7 @@ impl Editor {
}
if self.hide_context_menu(cx).is_some() {
- if self.has_active_inline_completion() {
+ if self.show_inline_completions_in_menu(cx) && self.has_active_inline_completion() {
self.update_visible_inline_completion(cx);
}
return true;
@@ -2856,6 +2856,7 @@ impl Editor {
);
}
+ let had_active_inline_completion = this.has_active_inline_completion();
this.change_selections_inner(Some(Autoscroll::fit()), false, cx, |s| {
s.select(new_selections)
});
@@ -2876,7 +2877,9 @@ impl Editor {
this.show_signature_help(&ShowSignatureHelp, cx);
}
- this.trigger_completion_on_input(&text, true, cx);
+ let trigger_in_words =
+ this.show_inline_completions_in_menu(cx) || !had_active_inline_completion;
+ this.trigger_completion_on_input(&text, trigger_in_words, cx);
linked_editing_ranges::refresh_linked_ranges(this, cx);
this.refresh_inline_completion(true, false, cx);
});
@@ -3741,9 +3744,13 @@ impl Editor {
let mut menu = menu.unwrap();
menu.resolve_selected_completion(editor.completion_provider.as_deref(), cx);
- if let Some(hint) = editor.inline_completion_menu_hint(cx) {
- editor.hide_active_inline_completion(cx);
- menu.show_inline_completion_hint(hint);
+ if editor.show_inline_completions_in_menu(cx) {
+ if let Some(hint) = editor.inline_completion_menu_hint(cx) {
+ editor.hide_active_inline_completion(cx);
+ menu.show_inline_completion_hint(hint);
+ }
+ } else {
+ editor.discard_inline_completion(false, cx);
}
*editor.context_menu.borrow_mut() =
@@ -3752,9 +3759,14 @@ impl Editor {
cx.notify();
} else if editor.completion_tasks.len() <= 1 {
// If there are no more completion tasks and the last menu was
- // empty, we should hide it. If it was already hidden, we should
- // also show the copilot completion when available.
- editor.hide_context_menu(cx);
+ // empty, we should hide it.
+ let was_hidden = editor.hide_context_menu(cx).is_none();
+ // If it was already hidden and we don't show inline
+ // completions in the menu, we should also show the
+ // inline-completion when available.
+ if was_hidden && editor.show_inline_completions_in_menu(cx) {
+ editor.update_visible_inline_completion(cx);
+ }
}
})?;
@@ -3808,7 +3820,9 @@ impl Editor {
return Some(Task::ready(Ok(())));
}
CompletionEntry::Match(mat) => {
- self.discard_inline_completion(true, cx);
+ if self.show_inline_completions_in_menu(cx) {
+ self.discard_inline_completion(true, cx);
+ }
mat
}
};
@@ -4546,7 +4560,9 @@ impl Editor {
_: &AcceptInlineCompletion,
cx: &mut ViewContext<Self>,
) {
- self.hide_context_menu(cx);
+ if self.show_inline_completions_in_menu(cx) {
+ self.hide_context_menu(cx);
+ }
let Some(active_inline_completion) = self.active_inline_completion.as_ref() else {
return;
@@ -4713,7 +4729,11 @@ impl Editor {
let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
let excerpt_id = cursor.excerpt_id;
- if !offset_selection.is_empty()
+ let completions_menu_has_precedence = !self.show_inline_completions_in_menu(cx)
+ && (self.context_menu.borrow().is_some()
+ || (!self.completion_tasks.is_empty() && !self.has_active_inline_completion()));
+ if completions_menu_has_precedence
+ || !offset_selection.is_empty()
|| self
.active_inline_completion
.as_ref()
@@ -4771,7 +4791,7 @@ impl Editor {
invalidation_row_range = edit_start_row..cursor_row;
completion = InlineCompletion::Move(first_edit_start);
} else {
- if !self.has_active_completions_menu() {
+ if !self.show_inline_completions_in_menu(cx) || !self.has_active_completions_menu() {
if edits
.iter()
.all(|(range, _)| range.to_offset(&multibuffer).is_empty())
@@ -4818,7 +4838,7 @@ impl Editor {
invalidation_range,
});
- if self.has_active_completions_menu() {
+ if self.show_inline_completions_in_menu(cx) && self.has_active_completions_menu() {
if let Some(hint) = self.inline_completion_menu_hint(cx) {
match self.context_menu.borrow_mut().as_mut() {
Some(CodeContextMenu::Completions(menu)) => {
@@ -4869,6 +4889,13 @@ impl Editor {
Some(self.inline_completion_provider.as_ref()?.provider.clone())
}
+ fn show_inline_completions_in_menu(&self, cx: &AppContext) -> bool {
+ EditorSettings::get_global(cx).show_inline_completions_in_menu
+ && self
+ .inline_completion_provider()
+ .map_or(false, |provider| provider.show_completions_in_menu())
+ }
+
fn render_code_actions_indicator(
&self,
_style: &EditorStyle,
@@ -5137,7 +5164,11 @@ impl Editor {
fn hide_context_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<CodeContextMenu> {
cx.notify();
self.completion_tasks.clear();
- self.context_menu.borrow_mut().take()
+ let context_menu = self.context_menu.borrow_mut().take();
+ if context_menu.is_some() && !self.show_inline_completions_in_menu(cx) {
+ self.update_visible_inline_completion(cx);
+ }
+ context_menu
}
fn show_snippet_choices(
@@ -35,6 +35,7 @@ pub struct EditorSettings {
pub auto_signature_help: bool,
pub show_signature_help_after_edits: bool,
pub jupyter: Jupyter,
+ pub show_inline_completions_in_menu: bool,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
@@ -300,6 +301,12 @@ pub struct EditorSettingsContent {
/// Default: false
pub show_signature_help_after_edits: Option<bool>,
+ /// Whether to show the inline completions next to the completions provided by a language server.
+ /// Only has an effect if inline completion provider supports it.
+ ///
+ /// Default: true
+ pub show_inline_completions_in_menu: Option<bool>,
+
/// Jupyter REPL settings.
pub jupyter: Option<JupyterContent>,
}
@@ -321,6 +321,10 @@ impl InlineCompletionProvider for FakeInlineCompletionProvider {
"Fake Completion Provider"
}
+ fn show_completions_in_menu() -> bool {
+ false
+ }
+
fn is_enabled(
&self,
_buffer: &gpui::Model<language::Buffer>,
@@ -20,6 +20,7 @@ pub struct InlineCompletion {
pub trait InlineCompletionProvider: 'static + Sized {
fn name() -> &'static str;
fn display_name() -> &'static str;
+ fn show_completions_in_menu() -> bool;
fn is_enabled(
&self,
buffer: &Model<Buffer>,
@@ -59,6 +60,7 @@ pub trait InlineCompletionProviderHandle {
cursor_position: language::Anchor,
cx: &AppContext,
) -> bool;
+ fn show_completions_in_menu(&self) -> bool;
fn refresh(
&self,
buffer: Model<Buffer>,
@@ -95,6 +97,10 @@ where
T::display_name()
}
+ fn show_completions_in_menu(&self) -> bool {
+ T::show_completions_in_menu()
+ }
+
fn is_enabled(
&self,
buffer: &Model<Buffer>,
@@ -102,6 +102,10 @@ impl InlineCompletionProvider for SupermavenCompletionProvider {
"Supermaven"
}
+ fn show_completions_in_menu() -> bool {
+ false
+ }
+
fn is_enabled(&self, buffer: &Model<Buffer>, cursor_position: Anchor, cx: &AppContext) -> bool {
if !self.supermaven.read(cx).is_enabled() {
return false;
@@ -932,6 +932,10 @@ impl inline_completion::InlineCompletionProvider for ZetaInlineCompletionProvide
"Zeta"
}
+ fn show_completions_in_menu() -> bool {
+ true
+ }
+
fn is_enabled(
&self,
buffer: &Model<Buffer>,