@@ -169,7 +169,6 @@ pub struct CompletionsMenu {
resolve_completions: bool,
show_completion_documentation: bool,
last_rendered_range: Rc<RefCell<Option<Range<usize>>>>,
- pub previewing_inline_completion: bool,
}
impl CompletionsMenu {
@@ -200,7 +199,6 @@ impl CompletionsMenu {
scroll_handle: UniformListScrollHandle::new(),
resolve_completions: true,
last_rendered_range: RefCell::new(None).into(),
- previewing_inline_completion: false,
}
}
@@ -257,7 +255,6 @@ impl CompletionsMenu {
resolve_completions: false,
show_completion_documentation: false,
last_rendered_range: RefCell::new(None).into(),
- previewing_inline_completion: false,
}
}
@@ -410,12 +407,8 @@ impl CompletionsMenu {
.detach();
}
- pub fn is_empty(&self) -> bool {
- self.entries.borrow().is_empty()
- }
-
pub fn visible(&self) -> bool {
- !self.is_empty() && !self.previewing_inline_completion
+ !self.entries.borrow().is_empty()
}
fn origin(&self) -> ContextMenuOrigin {
@@ -709,10 +702,6 @@ impl CompletionsMenu {
// This keeps the display consistent when y_flipped.
self.scroll_handle.scroll_to_item(0, ScrollStrategy::Top);
}
-
- pub fn set_previewing_inline_completion(&mut self, value: bool) {
- self.previewing_inline_completion = value;
- }
}
#[derive(Clone)]
@@ -97,8 +97,8 @@ use language::{
language_settings::{self, all_language_settings, language_settings, InlayHintSettings},
markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CharKind, CodeLabel,
CompletionDocumentation, CursorShape, Diagnostic, EditPreview, HighlightedText, IndentKind,
- IndentSize, Language, OffsetRangeExt, Point, Selection, SelectionGoal, TextObject,
- TransactionId, TreeSitterOptions,
+ IndentSize, InlineCompletionPreviewMode, Language, OffsetRangeExt, Point, Selection,
+ SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
};
use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange};
use linked_editing_ranges::refresh_linked_ranges;
@@ -693,6 +693,7 @@ pub struct Editor {
show_inline_completions: bool,
show_inline_completions_override: Option<bool>,
menu_inline_completions_policy: MenuInlineCompletionsPolicy,
+ previewing_inline_completion: bool,
inlay_hint_cache: InlayHintCache,
next_inlay_id: usize,
_subscriptions: Vec<Subscription>,
@@ -1384,6 +1385,7 @@ impl Editor {
inline_completion_provider: None,
active_inline_completion: None,
stale_inline_completion_in_menu: None,
+ previewing_inline_completion: false,
inlay_hint_cache: InlayHintCache::new(inlay_hint_settings),
gutter_hovered: false,
@@ -4662,6 +4664,18 @@ impl Editor {
}
}
+ fn inline_completion_preview_mode(&self, cx: &App) -> language::InlineCompletionPreviewMode {
+ let cursor = self.selections.newest_anchor().head();
+
+ self.buffer
+ .read(cx)
+ .text_anchor_for_position(cursor, cx)
+ .map(|(buffer, _)| {
+ all_language_settings(buffer.read(cx).file(), cx).inline_completions_preview_mode()
+ })
+ .unwrap_or_default()
+ }
+
fn should_show_inline_completions_in_buffer(
&self,
buffer: &Entity<Buffer>,
@@ -5009,11 +5023,28 @@ impl Editor {
true
}
- pub fn is_previewing_inline_completion(&self) -> bool {
- matches!(
- self.context_menu.borrow().as_ref(),
- Some(CodeContextMenu::Completions(menu)) if !menu.is_empty() && menu.previewing_inline_completion
- )
+ /// Returns true when we're displaying the inline completion popover below the cursor
+ /// like we are not previewing and the LSP autocomplete menu is visible
+ /// or we are in `when_holding_modifier` mode.
+ pub fn inline_completion_visible_in_cursor_popover(
+ &self,
+ has_completion: bool,
+ cx: &App,
+ ) -> bool {
+ if self.previewing_inline_completion
+ || !self.show_inline_completions_in_menu(cx)
+ || !self.should_show_inline_completions(cx)
+ {
+ return false;
+ }
+
+ if self.has_visible_completions_menu() {
+ return true;
+ }
+
+ has_completion
+ && self.inline_completion_preview_mode(cx)
+ == InlineCompletionPreviewMode::WhenHoldingModifier
}
fn update_inline_completion_preview(
@@ -5022,13 +5053,13 @@ impl Editor {
window: &mut Window,
cx: &mut Context<Self>,
) {
- // Moves jump directly with a preview step
-
+ // Moves jump directly without a preview step
if self
.active_inline_completion
.as_ref()
.map_or(true, |c| c.is_move())
{
+ self.previewing_inline_completion = false;
cx.notify();
return;
}
@@ -5037,20 +5068,7 @@ impl Editor {
return;
}
- let mut menu_borrow = self.context_menu.borrow_mut();
-
- let Some(CodeContextMenu::Completions(completions_menu)) = menu_borrow.as_mut() else {
- return;
- };
-
- if completions_menu.is_empty()
- || completions_menu.previewing_inline_completion == modifiers.alt
- {
- return;
- }
-
- completions_menu.set_previewing_inline_completion(modifiers.alt);
- drop(menu_borrow);
+ self.previewing_inline_completion = modifiers.alt;
self.update_visible_inline_completion(window, cx);
}
@@ -5146,7 +5164,7 @@ impl Editor {
snapshot,
}
} else {
- if !show_in_menu || !self.has_active_completions_menu() {
+ if !self.inline_completion_visible_in_cursor_popover(true, cx) {
if edits
.iter()
.all(|(range, _)| range.to_offset(&multibuffer).is_empty())
@@ -5180,7 +5198,7 @@ impl Editor {
let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
if provider.show_tab_accept_marker() {
- EditDisplayMode::TabAccept(self.is_previewing_inline_completion())
+ EditDisplayMode::TabAccept(self.previewing_inline_completion)
} else {
EditDisplayMode::Inline
}
@@ -5443,10 +5461,12 @@ impl Editor {
}
pub fn context_menu_visible(&self) -> bool {
- self.context_menu
- .borrow()
- .as_ref()
- .map_or(false, |menu| menu.visible())
+ !self.previewing_inline_completion
+ && self
+ .context_menu
+ .borrow()
+ .as_ref()
+ .map_or(false, |menu| menu.visible())
}
fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
@@ -5848,9 +5868,7 @@ impl Editor {
self.completion_tasks.clear();
let context_menu = self.context_menu.borrow_mut().take();
self.stale_inline_completion_in_menu.take();
- if context_menu.is_some() {
- self.update_visible_inline_completion(window, cx);
- }
+ self.update_visible_inline_completion(window, cx);
context_menu
}
@@ -14438,10 +14456,11 @@ impl Editor {
Some(gpui::Point::new(source_x, source_y))
}
- pub fn has_active_completions_menu(&self) -> bool {
- self.context_menu.borrow().as_ref().map_or(false, |menu| {
- menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
- })
+ pub fn has_visible_completions_menu(&self) -> bool {
+ !self.previewing_inline_completion
+ && self.context_menu.borrow().as_ref().map_or(false, |menu| {
+ menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
+ })
}
pub fn register_addon<T: Addon>(&mut self, instance: T) {
@@ -214,6 +214,19 @@ pub struct InlineCompletionSettings {
pub provider: InlineCompletionProvider,
/// A list of globs representing files that edit predictions should be disabled for.
pub disabled_globs: Vec<GlobMatcher>,
+ /// When to show edit predictions previews in buffer.
+ pub inline_preview: InlineCompletionPreviewMode,
+}
+
+/// The mode in which edit predictions should be displayed.
+#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum InlineCompletionPreviewMode {
+ /// Display inline when there are no language server completions available.
+ #[default]
+ Auto,
+ /// Display inline when holding modifier key (alt by default).
+ WhenHoldingModifier,
}
/// The settings for all languages.
@@ -406,6 +419,9 @@ pub struct InlineCompletionSettingsContent {
/// A list of globs representing files that edit predictions should be disabled for.
#[serde(default)]
pub disabled_globs: Option<Vec<String>>,
+ /// When to show edit predictions previews in buffer.
+ #[serde(default)]
+ pub inline_preview: InlineCompletionPreviewMode,
}
/// The settings for enabling/disabling features.
@@ -890,6 +906,11 @@ impl AllLanguageSettings {
self.language(None, language.map(|l| l.name()).as_ref(), cx)
.show_inline_completions
}
+
+ /// Returns the edit predictions preview mode for the given language and path.
+ pub fn inline_completions_preview_mode(&self) -> InlineCompletionPreviewMode {
+ self.inline_completions.inline_preview
+ }
}
fn merge_with_editorconfig(settings: &mut LanguageSettings, cfg: &EditorconfigProperties) {
@@ -987,6 +1008,12 @@ impl settings::Settings for AllLanguageSettings {
.features
.as_ref()
.and_then(|f| f.inline_completion_provider);
+ let mut inline_completions_preview = default_value
+ .inline_completions
+ .as_ref()
+ .map(|inline_completions| inline_completions.inline_preview)
+ .ok_or_else(Self::missing_default)?;
+
let mut completion_globs: HashSet<&String> = default_value
.inline_completions
.as_ref()
@@ -1017,12 +1044,13 @@ impl settings::Settings for AllLanguageSettings {
{
inline_completion_provider = Some(provider);
}
- if let Some(globs) = user_settings
- .inline_completions
- .as_ref()
- .and_then(|f| f.disabled_globs.as_ref())
- {
- completion_globs.extend(globs.iter());
+
+ if let Some(inline_completions) = user_settings.inline_completions.as_ref() {
+ inline_completions_preview = inline_completions.inline_preview;
+
+ if let Some(disabled_globs) = inline_completions.disabled_globs.as_ref() {
+ completion_globs.extend(disabled_globs.iter());
+ }
}
// A user's global settings override the default global settings and
@@ -1075,6 +1103,7 @@ impl settings::Settings for AllLanguageSettings {
.iter()
.filter_map(|g| Some(globset::Glob::new(g).ok()?.compile_matcher()))
.collect(),
+ inline_preview: inline_completions_preview,
},
defaults,
languages,