@@ -709,6 +709,7 @@ pub struct Editor {
/// Used to prevent flickering as the user types while the menu is open
stale_inline_completion_in_menu: Option<InlineCompletionState>,
edit_prediction_settings: EditPredictionSettings,
+ edit_prediction_cursor_on_leading_whitespace: bool,
inline_completions_hidden_for_vim_mode: bool,
show_inline_completions_override: Option<bool>,
menu_inline_completions_policy: MenuInlineCompletionsPolicy,
@@ -1423,6 +1424,7 @@ 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,
custom_context_menu: None,
show_git_blame_gutter: false,
show_git_blame_inline: false,
@@ -1567,8 +1569,12 @@ impl Editor {
if has_active_edit_prediction {
key_context.add("copilot_suggestion");
key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
-
- if showing_completions || self.edit_prediction_requires_modifier() {
+ if showing_completions
+ || 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_cursor_on_leading_whitespace
+ {
key_context.add(EDIT_PREDICTION_REQUIRES_MODIFIER_KEY_CONTEXT);
}
}
@@ -4931,23 +4937,6 @@ impl Editor {
window: &mut Window,
cx: &mut Context<Self>,
) {
- let buffer = self.buffer.read(cx);
- let snapshot = buffer.snapshot(cx);
- let selection = self.selections.newest_adjusted(cx);
- let cursor = selection.head();
- let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
- let suggested_indents = snapshot.suggested_indents([cursor.row], cx);
- if let Some(suggested_indent) = suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
- {
- if cursor.column < suggested_indent.len
- && cursor.column <= current_indent.len
- && current_indent.len <= suggested_indent.len
- {
- self.tab(&Default::default(), window, cx);
- return;
- }
- }
-
if self.show_edit_predictions_in_menu() {
self.hide_context_menu(window, cx);
}
@@ -5298,6 +5287,9 @@ impl Editor {
return None;
}
+ self.edit_prediction_cursor_on_leading_whitespace =
+ multibuffer.is_line_whitespace_upto(cursor);
+
let inline_completion = provider.suggest(&buffer, cursor_buffer_position, cx)?;
let edits = inline_completion
.edits
@@ -1,10 +1,9 @@
use gpui::{prelude::*, Entity};
use indoc::indoc;
use inline_completion::EditPredictionProvider;
-use language::{Language, LanguageConfig};
use multi_buffer::{Anchor, MultiBufferSnapshot, ToPoint};
use project::Project;
-use std::{num::NonZeroU32, ops::Range, sync::Arc};
+use std::ops::Range;
use text::{Point, ToOffset};
use crate::{
@@ -124,54 +123,6 @@ async fn test_inline_completion_jump_button(cx: &mut gpui::TestAppContext) {
"});
}
-#[gpui::test]
-async fn test_indentation(cx: &mut gpui::TestAppContext) {
- init_test(cx, |settings| {
- settings.defaults.tab_size = NonZeroU32::new(4)
- });
-
- let language = Arc::new(
- Language::new(
- LanguageConfig::default(),
- Some(tree_sitter_rust::LANGUAGE.into()),
- )
- .with_indents_query(r#"(_ "(" ")" @end) @indent"#)
- .unwrap(),
- );
-
- let mut cx = EditorTestContext::new(cx).await;
- cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
- let provider = cx.new(|_| FakeInlineCompletionProvider::default());
- assign_editor_completion_provider(provider.clone(), &mut cx);
-
- cx.set_state(indoc! {"
- const a: A = (
- ˇ
- );
- "});
-
- propose_edits(
- &provider,
- vec![(Point::new(1, 0)..Point::new(1, 0), " const function()")],
- &mut cx,
- );
- cx.update_editor(|editor, window, cx| editor.update_visible_inline_completion(window, cx));
-
- assert_editor_active_edit_completion(&mut cx, |_, edits| {
- assert_eq!(edits.len(), 1);
- assert_eq!(edits[0].1.as_str(), " const function()");
- });
-
- // When the cursor is before the suggested indentation level, accepting a
- // completion should just indent.
- accept_completion(&mut cx);
- cx.assert_editor_state(indoc! {"
- const a: A = (
- ˇ
- );
- "});
-}
-
#[gpui::test]
async fn test_inline_completion_invalidation_range(cx: &mut gpui::TestAppContext) {
init_test(cx, |_| {});
@@ -4236,6 +4236,21 @@ impl MultiBufferSnapshot {
indent
}
+ pub fn is_line_whitespace_upto<T>(&self, position: T) -> bool
+ where
+ T: ToOffset,
+ {
+ for char in self.reversed_chars_at(position) {
+ if !char.is_whitespace() {
+ return false;
+ }
+ if char == '\n' {
+ return true;
+ }
+ }
+ return true;
+ }
+
pub fn prev_non_blank_row(&self, mut row: MultiBufferRow) -> Option<MultiBufferRow> {
while row.0 > 0 {
row.0 -= 1;