From 95cde129af4bb4789ca317529e7016ac5b022536 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Wed, 22 Jan 2025 13:19:18 -0300 Subject: [PATCH] Show "tab Accept" only for zeta (#23463) #23460 brought up we are showing the new "tab Accept" marker for single line suggestions for non-zeta providers. We think this might be valid for any provider, but we only want to enable it for zeta initially so it doesn't affect an existing user base. Release Notes: - N/A --- crates/editor/src/editor.rs | 61 ++++++++++++++++--- crates/editor/src/element.rs | 59 ++++++------------ crates/editor/src/inline_completion_tests.rs | 6 +- .../src/inline_completion.rs | 8 +++ crates/zeta/src/zeta.rs | 4 ++ 5 files changed, 85 insertions(+), 53 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index db4a4cba01ea228c4a65dbd392f34f45455e6e75..9efc74c787cfd60c28a03bd7bbe05cdb8d103dcf 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -485,10 +485,16 @@ enum InlineCompletionText { }, } +pub(crate) enum EditDisplayMode { + TabAccept, + DiffPopover, + Inline, +} + enum InlineCompletion { Edit { edits: Vec<(Range, String)>, - single_line: bool, + display_mode: EditDisplayMode, }, Move(Anchor), } @@ -4691,7 +4697,7 @@ impl Editor { } InlineCompletion::Edit { edits, - single_line: _, + display_mode: _, } => { if let Some(provider) = self.inline_completion_provider() { provider.accept(cx); @@ -4741,7 +4747,7 @@ impl Editor { } InlineCompletion::Edit { edits, - single_line: _, + display_mode: _, } => { // Find an insertion that starts at the cursor position. let snapshot = self.buffer.read(cx).snapshot(cx); @@ -4941,10 +4947,23 @@ impl Editor { invalidation_row_range = edit_start_row..edit_end_row; - let single_line = first_edit_start_point.row == last_edit_end_point.row - && !edits.iter().any(|(_, edit)| edit.contains('\n')); + let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) { + if provider.show_tab_accept_marker() + && first_edit_start_point.row == last_edit_end_point.row + && !edits.iter().any(|(_, edit)| edit.contains('\n')) + { + EditDisplayMode::TabAccept + } else { + EditDisplayMode::Inline + } + } else { + EditDisplayMode::DiffPopover + }; - completion = InlineCompletion::Edit { edits, single_line }; + completion = InlineCompletion::Edit { + edits, + display_mode, + }; }; let invalidation_range = multibuffer @@ -4987,7 +5006,7 @@ impl Editor { let text = match &self.active_inline_completion.as_ref()?.completion { InlineCompletion::Edit { edits, - single_line: _, + display_mode: _, } => inline_completion_edit_text(&editor_snapshot, edits, true, cx), InlineCompletion::Move(target) => { let target_point = @@ -15275,3 +15294,31 @@ pub struct KillRing(ClipboardItem); impl Global for KillRing {} const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50); + +fn all_edits_insertions_or_deletions( + edits: &Vec<(Range, String)>, + snapshot: &MultiBufferSnapshot, +) -> bool { + let mut all_insertions = true; + let mut all_deletions = true; + + for (range, new_text) in edits.iter() { + let range_is_empty = range.to_offset(&snapshot).is_empty(); + let text_is_empty = new_text.is_empty(); + + if range_is_empty != text_is_empty { + if range_is_empty { + all_deletions = false; + } else { + all_insertions = false; + } + } else { + return false; + } + + if !all_insertions && !all_deletions { + return false; + } + } + all_insertions || all_deletions +} diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index 504790f30d7633e921d09652893e4ecdcc16086e..6bde90e622bf41034c7d74c4f3dd533e71243a0a 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -18,12 +18,13 @@ use crate::{ mouse_context_menu::{self, MenuPosition, MouseContextMenu}, scroll::{axis_pair, scroll_amount::ScrollAmount, AxisPair}, BlockId, ChunkReplacement, CursorShape, CustomBlockId, DisplayPoint, DisplayRow, - DocumentHighlightRead, DocumentHighlightWrite, Editor, EditorMode, EditorSettings, - EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GutterDimensions, HalfPageDown, - HalfPageUp, HandleInput, HoveredCursor, HoveredHunk, InlineCompletion, JumpData, LineDown, - LineUp, OpenExcerpts, PageDown, PageUp, Point, RowExt, RowRangeExt, SelectPhase, Selection, - SoftWrap, StickyHeaderExcerpt, ToPoint, ToggleFold, CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT, - GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN, MULTI_BUFFER_EXCERPT_HEADER_HEIGHT, + DocumentHighlightRead, DocumentHighlightWrite, EditDisplayMode, Editor, EditorMode, + EditorSettings, EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GutterDimensions, + HalfPageDown, HalfPageUp, HandleInput, HoveredCursor, HoveredHunk, InlineCompletion, JumpData, + LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, RowExt, RowRangeExt, SelectPhase, + Selection, SoftWrap, StickyHeaderExcerpt, ToPoint, ToggleFold, CURSORS_VISIBLE_FOR, + FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN, + MULTI_BUFFER_EXCERPT_HEADER_HEIGHT, }; use client::ParticipantIndex; use collections::{BTreeMap, HashMap, HashSet}; @@ -50,7 +51,7 @@ use language::{ use lsp::DiagnosticSeverity; use multi_buffer::{ Anchor, AnchorRangeExt, ExcerptId, ExcerptInfo, ExpandExcerptDirection, MultiBufferPoint, - MultiBufferRow, MultiBufferSnapshot, ToOffset, + MultiBufferRow, ToOffset, }; use project::project_settings::{GitGutterSetting, ProjectSettings}; use settings::Settings; @@ -1628,7 +1629,8 @@ impl EditorElement { if let Some(inline_completion) = editor.active_inline_completion.as_ref() { match &inline_completion.completion { InlineCompletion::Edit { - single_line: true, .. + display_mode: EditDisplayMode::TabAccept, + .. } => padding += INLINE_ACCEPT_SUGGESTION_EM_WIDTHS, _ => {} } @@ -3386,7 +3388,10 @@ impl EditorElement { Some(element) } } - InlineCompletion::Edit { edits, single_line } => { + InlineCompletion::Edit { + edits, + display_mode, + } => { if self.editor.read(cx).has_active_completions_menu() { return None; } @@ -3410,8 +3415,8 @@ impl EditorElement { return None; } - if all_edits_insertions_or_deletions(edits, &editor_snapshot.buffer_snapshot) { - if *single_line { + match display_mode { + EditDisplayMode::TabAccept => { let range = &edits.first()?.0; let target_display_point = range.end.to_display_point(editor_snapshot); @@ -3433,8 +3438,8 @@ impl EditorElement { return Some(element); } - - return None; + EditDisplayMode::Inline => return None, + EditDisplayMode::DiffPopover => {} } let crate::InlineCompletionText::Edit { text, highlights } = @@ -5249,34 +5254,6 @@ fn inline_completion_tab_indicator( .into_any() } -fn all_edits_insertions_or_deletions( - edits: &Vec<(Range, String)>, - snapshot: &MultiBufferSnapshot, -) -> bool { - let mut all_insertions = true; - let mut all_deletions = true; - - for (range, new_text) in edits.iter() { - let range_is_empty = range.to_offset(&snapshot).is_empty(); - let text_is_empty = new_text.is_empty(); - - if range_is_empty != text_is_empty { - if range_is_empty { - all_deletions = false; - } else { - all_insertions = false; - } - } else { - return false; - } - - if !all_insertions && !all_deletions { - return false; - } - } - all_insertions || all_deletions -} - #[allow(clippy::too_many_arguments)] fn prepaint_gutter_button( button: IconButton, diff --git a/crates/editor/src/inline_completion_tests.rs b/crates/editor/src/inline_completion_tests.rs index 92944ae57a3e3dabfb8da61ca611ccc42a74280a..676b154aedf81d601fe6885fd6fced51b752f629 100644 --- a/crates/editor/src/inline_completion_tests.rs +++ b/crates/editor/src/inline_completion_tests.rs @@ -286,11 +286,7 @@ fn assert_editor_active_edit_completion( .as_ref() .expect("editor has no active completion"); - if let InlineCompletion::Edit { - edits, - single_line: _, - } = &completion_state.completion - { + if let InlineCompletion::Edit { edits, .. } = &completion_state.completion { assert(editor.buffer().read(cx).snapshot(cx), edits); } else { panic!("expected edit completion"); diff --git a/crates/inline_completion/src/inline_completion.rs b/crates/inline_completion/src/inline_completion.rs index 4b467906bbf2aa06badc23d22fa85277bacbac55..0ff4a593efc1bf96c209351392633eee01d14ced 100644 --- a/crates/inline_completion/src/inline_completion.rs +++ b/crates/inline_completion/src/inline_completion.rs @@ -22,6 +22,9 @@ pub trait InlineCompletionProvider: 'static + Sized { fn display_name() -> &'static str; fn show_completions_in_menu() -> bool; fn show_completions_in_normal_mode() -> bool; + fn show_tab_accept_marker() -> bool { + false + } fn is_enabled( &self, buffer: &Model, @@ -67,6 +70,7 @@ pub trait InlineCompletionProviderHandle { ) -> bool; fn show_completions_in_menu(&self) -> bool; fn show_completions_in_normal_mode(&self) -> bool; + fn show_tab_accept_marker(&self) -> bool; fn needs_terms_acceptance(&self, cx: &AppContext) -> bool; fn is_refreshing(&self, cx: &AppContext) -> bool; fn refresh( @@ -113,6 +117,10 @@ where T::show_completions_in_normal_mode() } + fn show_tab_accept_marker(&self) -> bool { + T::show_tab_accept_marker() + } + fn is_enabled( &self, buffer: &Model, diff --git a/crates/zeta/src/zeta.rs b/crates/zeta/src/zeta.rs index 9a12ce42597db0a63d4060d3b38e7133cd2704f8..32dec5d6f023f501392aa1b4c509a26ecc9e20af 100644 --- a/crates/zeta/src/zeta.rs +++ b/crates/zeta/src/zeta.rs @@ -1024,6 +1024,10 @@ impl inline_completion::InlineCompletionProvider for ZetaInlineCompletionProvide true } + fn show_tab_accept_marker() -> bool { + true + } + fn is_enabled( &self, buffer: &Model,