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,