From 2f7a62780ad865b3c36cb4b9ff9a4bbf8bbeb3e2 Mon Sep 17 00:00:00 2001 From: Agus Zubiaga Date: Mon, 24 Feb 2025 18:37:18 -0300 Subject: [PATCH] edit predictions: Refine leading whitespace behavior (#25491) Closes https://github.com/zed-industries/zed/issues/25406 ### Problem Users have been confused about requiring `alt-tab` instead of just `tab` in cases where they don't have a completions menu open (see issue above). When they insert a newline and are in leading whitespace, they expect to be able to accept a prediction with just `tab`, but doing so increasing the indentation instead. This PR changes the behavior in so a modifier is only required if the cursor isn't already at the right indentation level based on the surrounding block. In this case, `tab` would increase the indentation and the prediction would get interpolated, allowing the user to press `tab` again to accept it. We also updated the docs to break down this behavior: https://github.com/zed-industries/zed/pull/25493 ### Before https://github.com/user-attachments/assets/91fe6193-dddd-43c1-8c26-0f4648bdc3fa ### After https://github.com/user-attachments/assets/671041bf-bf22-46a3-8466-b19b3e7dd6a0 Release Notes: - edit predictions: Do not require a modifier key when indentation is correct according to its surrounding block Co-authored-by: Danilo Leal --- crates/editor/src/editor.rs | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 4862f8cf8b11a9a68815c69af95aee6465da3dfe..eb83b8b5a0c6adb340ef747d37d86afd815231ac 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -677,8 +677,8 @@ pub struct Editor { show_inline_completions_override: Option, menu_inline_completions_policy: MenuInlineCompletionsPolicy, edit_prediction_preview: EditPredictionPreview, - edit_prediction_cursor_on_leading_whitespace: bool, - edit_prediction_requires_modifier_in_leading_space: bool, + edit_prediction_indent_conflict: bool, + edit_prediction_requires_modifier_in_indent_conflict: bool, inlay_hint_cache: InlayHintCache, next_inlay_id: usize, _subscriptions: Vec, @@ -1403,8 +1403,8 @@ impl Editor { show_inline_completions_override: None, menu_inline_completions_policy: MenuInlineCompletionsPolicy::ByProvider, edit_prediction_settings: EditPredictionSettings::Disabled, - edit_prediction_cursor_on_leading_whitespace: false, - edit_prediction_requires_modifier_in_leading_space: true, + edit_prediction_indent_conflict: false, + edit_prediction_requires_modifier_in_indent_conflict: true, custom_context_menu: None, show_git_blame_gutter: false, show_git_blame_inline: false, @@ -1578,7 +1578,7 @@ impl Editor { || self.edit_prediction_requires_modifier() // Require modifier key when the cursor is on leading whitespace, to allow `tab` // bindings to insert tab characters. - || (self.edit_prediction_requires_modifier_in_leading_space && self.edit_prediction_cursor_on_leading_whitespace) + || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict) } pub fn accept_edit_prediction_keybind( @@ -2150,7 +2150,7 @@ impl Editor { self.refresh_selected_text_highlights(window, cx); refresh_matching_bracket_highlights(self, window, cx); self.update_visible_inline_completion(window, cx); - self.edit_prediction_requires_modifier_in_leading_space = true; + self.edit_prediction_requires_modifier_in_indent_conflict = true; linked_editing_ranges::refresh_linked_ranges(self, window, cx); if self.git_blame_inline_enabled { self.start_inline_blame_timer(window, cx); @@ -5136,7 +5136,7 @@ impl Editor { } } - self.edit_prediction_requires_modifier_in_leading_space = false; + self.edit_prediction_requires_modifier_in_indent_conflict = false; } pub fn accept_partial_inline_completion( @@ -5434,8 +5434,19 @@ impl Editor { self.edit_prediction_settings = self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx); - self.edit_prediction_cursor_on_leading_whitespace = - multibuffer.is_line_whitespace_upto(cursor); + self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor); + + if self.edit_prediction_indent_conflict { + let cursor_point = cursor.to_point(&multibuffer); + + let indents = multibuffer.suggested_indents(cursor_point.row..cursor_point.row + 1, cx); + + if let Some((_, indent)) = indents.iter().next() { + if indent.len == cursor_point.column { + self.edit_prediction_indent_conflict = false; + } + } + } let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?; let edits = inline_completion