Fix relative indentation when pasting content copied from outside Zed (#25300)

Max Brunsfeld created

Closes https://github.com/zed-industries/zed/issues/24914

Release Notes:

- Fixed incorrect indentation when pasting multi-line content that was
copied from another app.

Change summary

crates/assistant_context_editor/src/patch.rs |   2 
crates/editor/src/editor.rs                  |  33 +-
crates/editor/src/editor_tests.rs            | 278 ++++++++++++---------
crates/language/src/buffer.rs                |  26 +
crates/language/src/buffer_tests.rs          |  10 
crates/multi_buffer/src/multi_buffer.rs      |  28 +-
crates/vim/src/normal/paste.rs               |  18 
crates/vim/src/normal/yank.rs                |   2 
8 files changed, 220 insertions(+), 177 deletions(-)

Detailed changes

crates/editor/src/editor.rs πŸ”—

@@ -976,9 +976,12 @@ struct ActiveDiagnosticGroup {
 
 #[derive(Serialize, Deserialize, Clone, Debug)]
 pub struct ClipboardSelection {
+    /// The number of bytes in this selection.
     pub len: usize,
+    /// Whether this was a full-line selection.
     pub is_entire_line: bool,
-    pub first_line_indent: u32,
+    /// The column where this selection originally started.
+    pub start_column: u32,
 }
 
 #[derive(Debug)]
@@ -2273,7 +2276,7 @@ impl Editor {
     pub fn edit_with_block_indent<I, S, T>(
         &mut self,
         edits: I,
-        original_indent_columns: Vec<u32>,
+        original_start_columns: Vec<u32>,
         cx: &mut Context<Self>,
     ) where
         I: IntoIterator<Item = (Range<S>, T)>,
@@ -2288,7 +2291,7 @@ impl Editor {
             buffer.edit(
                 edits,
                 Some(AutoindentMode::Block {
-                    original_indent_columns,
+                    original_start_columns,
                 }),
                 cx,
             )
@@ -3397,7 +3400,7 @@ impl Editor {
 
     pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
         let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
-            original_indent_columns: Vec::new(),
+            original_start_columns: Vec::new(),
         });
         self.insert_with_autoindent_mode(text, autoindent, window, cx);
     }
@@ -7943,9 +7946,7 @@ impl Editor {
                 clipboard_selections.push(ClipboardSelection {
                     len,
                     is_entire_line,
-                    first_line_indent: buffer
-                        .indent_size_for_line(MultiBufferRow(selection.start.row))
-                        .len,
+                    start_column: selection.start.column,
                 });
             }
         }
@@ -8024,7 +8025,7 @@ impl Editor {
                 clipboard_selections.push(ClipboardSelection {
                     len,
                     is_entire_line,
-                    first_line_indent: buffer.indent_size_for_line(MultiBufferRow(start.row)).len,
+                    start_column: start.column,
                 });
             }
         }
@@ -8054,8 +8055,8 @@ impl Editor {
                 let old_selections = this.selections.all::<usize>(cx);
                 let all_selections_were_entire_line =
                     clipboard_selections.iter().all(|s| s.is_entire_line);
-                let first_selection_indent_column =
-                    clipboard_selections.first().map(|s| s.first_line_indent);
+                let first_selection_start_column =
+                    clipboard_selections.first().map(|s| s.start_column);
                 if clipboard_selections.len() != old_selections.len() {
                     clipboard_selections.drain(..);
                 }
@@ -8069,21 +8070,21 @@ impl Editor {
 
                     let mut start_offset = 0;
                     let mut edits = Vec::new();
-                    let mut original_indent_columns = Vec::new();
+                    let mut original_start_columns = Vec::new();
                     for (ix, selection) in old_selections.iter().enumerate() {
                         let to_insert;
                         let entire_line;
-                        let original_indent_column;
+                        let original_start_column;
                         if let Some(clipboard_selection) = clipboard_selections.get(ix) {
                             let end_offset = start_offset + clipboard_selection.len;
                             to_insert = &clipboard_text[start_offset..end_offset];
                             entire_line = clipboard_selection.is_entire_line;
                             start_offset = end_offset + 1;
-                            original_indent_column = Some(clipboard_selection.first_line_indent);
+                            original_start_column = Some(clipboard_selection.start_column);
                         } else {
                             to_insert = clipboard_text.as_str();
                             entire_line = all_selections_were_entire_line;
-                            original_indent_column = first_selection_indent_column
+                            original_start_column = first_selection_start_column
                         }
 
                         // If the corresponding selection was empty when this slice of the
@@ -8099,7 +8100,7 @@ impl Editor {
                         };
 
                         edits.push((range, to_insert));
-                        original_indent_columns.extend(original_indent_column);
+                        original_start_columns.extend(original_start_column);
                     }
                     drop(snapshot);
 
@@ -8107,7 +8108,7 @@ impl Editor {
                         edits,
                         if auto_indent_on_paste {
                             Some(AutoindentMode::Block {
-                                original_indent_columns,
+                                original_start_columns,
                             })
                         } else {
                             None

crates/editor/src/editor_tests.rs πŸ”—

@@ -1897,7 +1897,7 @@ fn test_prev_next_word_bounds_with_soft_wrap(cx: &mut TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppContext) {
+async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorTestContext::new(cx).await;
 
@@ -2014,7 +2014,7 @@ async fn test_move_start_of_paragraph_end_of_paragraph(cx: &mut gpui::TestAppCon
 }
 
 #[gpui::test]
-async fn test_scroll_page_up_page_down(cx: &mut gpui::TestAppContext) {
+async fn test_scroll_page_up_page_down(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorTestContext::new(cx).await;
     let line_height = cx.editor(|editor, window, _| {
@@ -2076,7 +2076,7 @@ async fn test_scroll_page_up_page_down(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_autoscroll(cx: &mut gpui::TestAppContext) {
+async fn test_autoscroll(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorTestContext::new(cx).await;
 
@@ -2159,7 +2159,7 @@ async fn test_autoscroll(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) {
+async fn test_move_page_up_page_down(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorTestContext::new(cx).await;
 
@@ -2284,7 +2284,7 @@ async fn test_move_page_up_page_down(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_delete_to_beginning_of_line(cx: &mut gpui::TestAppContext) {
+async fn test_delete_to_beginning_of_line(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorTestContext::new(cx).await;
     cx.set_state("one «two threeˇ» four");
@@ -2529,7 +2529,7 @@ fn test_newline_with_old_selections(cx: &mut TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_newline_above(cx: &mut gpui::TestAppContext) {
+async fn test_newline_above(cx: &mut TestAppContext) {
     init_test(cx, |settings| {
         settings.defaults.tab_size = NonZeroU32::new(4)
     });
@@ -2577,7 +2577,7 @@ async fn test_newline_above(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_newline_below(cx: &mut gpui::TestAppContext) {
+async fn test_newline_below(cx: &mut TestAppContext) {
     init_test(cx, |settings| {
         settings.defaults.tab_size = NonZeroU32::new(4)
     });
@@ -2625,7 +2625,7 @@ async fn test_newline_below(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_newline_comments(cx: &mut gpui::TestAppContext) {
+async fn test_newline_comments(cx: &mut TestAppContext) {
     init_test(cx, |settings| {
         settings.defaults.tab_size = NonZeroU32::new(4)
     });
@@ -2704,7 +2704,7 @@ fn test_insert_with_old_selections(cx: &mut TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_tab(cx: &mut gpui::TestAppContext) {
+async fn test_tab(cx: &mut TestAppContext) {
     init_test(cx, |settings| {
         settings.defaults.tab_size = NonZeroU32::new(3)
     });
@@ -2734,7 +2734,7 @@ async fn test_tab(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_tab_in_leading_whitespace_auto_indents_lines(cx: &mut gpui::TestAppContext) {
+async fn test_tab_in_leading_whitespace_auto_indents_lines(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -2794,7 +2794,7 @@ async fn test_tab_in_leading_whitespace_auto_indents_lines(cx: &mut gpui::TestAp
 }
 
 #[gpui::test]
-async fn test_tab_with_mixed_whitespace(cx: &mut gpui::TestAppContext) {
+async fn test_tab_with_mixed_whitespace(cx: &mut TestAppContext) {
     init_test(cx, |settings| {
         settings.defaults.tab_size = NonZeroU32::new(4)
     });
@@ -2829,7 +2829,7 @@ async fn test_tab_with_mixed_whitespace(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_indent_outdent(cx: &mut gpui::TestAppContext) {
+async fn test_indent_outdent(cx: &mut TestAppContext) {
     init_test(cx, |settings| {
         settings.defaults.tab_size = NonZeroU32::new(4);
     });
@@ -2902,7 +2902,7 @@ async fn test_indent_outdent(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_indent_outdent_with_hard_tabs(cx: &mut gpui::TestAppContext) {
+async fn test_indent_outdent_with_hard_tabs(cx: &mut TestAppContext) {
     init_test(cx, |settings| {
         settings.defaults.hard_tabs = Some(true);
     });
@@ -3111,7 +3111,7 @@ fn test_indent_outdent_with_excerpts(cx: &mut TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_backspace(cx: &mut gpui::TestAppContext) {
+async fn test_backspace(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -3160,7 +3160,7 @@ async fn test_backspace(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_delete(cx: &mut gpui::TestAppContext) {
+async fn test_delete(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -3366,10 +3366,7 @@ fn test_join_lines_with_multi_selection(cx: &mut TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_join_lines_with_git_diff_base(
-    executor: BackgroundExecutor,
-    cx: &mut gpui::TestAppContext,
-) {
+async fn test_join_lines_with_git_diff_base(executor: BackgroundExecutor, cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -3427,7 +3424,7 @@ async fn test_join_lines_with_git_diff_base(
 #[gpui::test]
 async fn test_custom_newlines_cause_no_false_positive_diffs(
     executor: BackgroundExecutor,
-    cx: &mut gpui::TestAppContext,
+    cx: &mut TestAppContext,
 ) {
     init_test(cx, |_| {});
     let mut cx = EditorTestContext::new(cx).await;
@@ -4624,7 +4621,7 @@ async fn test_rewrap(cx: &mut TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_clipboard(cx: &mut gpui::TestAppContext) {
+async fn test_clipboard(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -4710,15 +4707,11 @@ async fn test_clipboard(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_paste_multiline(cx: &mut gpui::TestAppContext) {
+async fn test_paste_multiline(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
-    let language = Arc::new(Language::new(
-        LanguageConfig::default(),
-        Some(tree_sitter_rust::LANGUAGE.into()),
-    ));
-    cx.update_buffer(|buffer, cx| buffer.set_language(Some(language), cx));
+    cx.update_buffer(|buffer, cx| buffer.set_language(Some(rust_lang()), cx));
 
     // Cut an indented block, without the leading whitespace.
     cx.set_state(indoc! {"
@@ -4823,6 +4816,58 @@ async fn test_paste_multiline(cx: &mut gpui::TestAppContext) {
     "});
 }
 
+#[gpui::test]
+async fn test_paste_content_from_other_app(cx: &mut TestAppContext) {
+    init_test(cx, |_| {});
+
+    cx.write_to_clipboard(ClipboardItem::new_string(
+        "    d(\n        e\n    );\n".into(),
+    ));
+
+    let mut cx = EditorTestContext::new(cx).await;
+    cx.update_buffer(|buffer, cx| buffer.set_language(Some(rust_lang()), cx));
+
+    cx.set_state(indoc! {"
+        fn a() {
+            b();
+            if c() {
+                Λ‡
+            }
+        }
+    "});
+
+    cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx));
+    cx.assert_editor_state(indoc! {"
+        fn a() {
+            b();
+            if c() {
+                d(
+                    e
+                );
+        Λ‡
+            }
+        }
+    "});
+
+    cx.set_state(indoc! {"
+        fn a() {
+            b();
+            Λ‡
+        }
+    "});
+
+    cx.update_editor(|e, window, cx| e.paste(&Paste, window, cx));
+    cx.assert_editor_state(indoc! {"
+        fn a() {
+            b();
+            d(
+                e
+            );
+        Λ‡
+        }
+    "});
+}
+
 #[gpui::test]
 fn test_select_all(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
@@ -5278,7 +5323,7 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_select_next(cx: &mut gpui::TestAppContext) {
+async fn test_select_next(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -5308,7 +5353,7 @@ async fn test_select_next(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_select_all_matches(cx: &mut gpui::TestAppContext) {
+async fn test_select_all_matches(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -5351,7 +5396,7 @@ async fn test_select_all_matches(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_select_next_with_multiple_carets(cx: &mut gpui::TestAppContext) {
+async fn test_select_next_with_multiple_carets(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -5386,7 +5431,7 @@ let foo = Β«2Λ‡Β»;"#,
 }
 
 #[gpui::test]
-async fn test_select_previous_multibuffer(cx: &mut gpui::TestAppContext) {
+async fn test_select_previous_multibuffer(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx =
@@ -5418,7 +5463,7 @@ async fn test_select_previous_multibuffer(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_select_previous_with_single_caret(cx: &mut gpui::TestAppContext) {
+async fn test_select_previous_with_single_caret(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -5452,7 +5497,7 @@ async fn test_select_previous_with_single_caret(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_select_previous_empty_buffer(cx: &mut gpui::TestAppContext) {
+async fn test_select_previous_empty_buffer(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -5467,7 +5512,7 @@ async fn test_select_previous_empty_buffer(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_select_previous_with_multiple_carets(cx: &mut gpui::TestAppContext) {
+async fn test_select_previous_with_multiple_carets(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -5502,7 +5547,7 @@ let foo = Β«2Λ‡Β»;"#,
 }
 
 #[gpui::test]
-async fn test_select_previous_with_single_selection(cx: &mut gpui::TestAppContext) {
+async fn test_select_previous_with_single_selection(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -5532,7 +5577,7 @@ async fn test_select_previous_with_single_selection(cx: &mut gpui::TestAppContex
 }
 
 #[gpui::test]
-async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) {
+async fn test_select_larger_smaller_syntax_node(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let language = Arc::new(Language::new(
@@ -5720,7 +5765,7 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_fold_function_bodies(cx: &mut gpui::TestAppContext) {
+async fn test_fold_function_bodies(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let base_text = r#"
@@ -5823,7 +5868,7 @@ async fn test_fold_function_bodies(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_autoindent(cx: &mut gpui::TestAppContext) {
+async fn test_autoindent(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let language = Arc::new(
@@ -5886,7 +5931,7 @@ async fn test_autoindent(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) {
+async fn test_autoindent_selections(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     {
@@ -5969,7 +6014,7 @@ async fn test_autoindent_selections(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_autoclose_and_auto_surround_pairs(cx: &mut gpui::TestAppContext) {
+async fn test_autoclose_and_auto_surround_pairs(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -6160,7 +6205,7 @@ async fn test_autoclose_and_auto_surround_pairs(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_always_treat_brackets_as_autoclosed_skip_over(cx: &mut gpui::TestAppContext) {
+async fn test_always_treat_brackets_as_autoclosed_skip_over(cx: &mut TestAppContext) {
     init_test(cx, |settings| {
         settings.defaults.always_treat_brackets_as_autoclosed = Some(true);
     });
@@ -6262,7 +6307,7 @@ async fn test_always_treat_brackets_as_autoclosed_skip_over(cx: &mut gpui::TestA
 }
 
 #[gpui::test]
-async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) {
+async fn test_autoclose_with_embedded_language(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -6496,7 +6541,7 @@ async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_autoclose_with_overrides(cx: &mut gpui::TestAppContext) {
+async fn test_autoclose_with_overrides(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -6592,7 +6637,7 @@ async fn test_autoclose_with_overrides(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) {
+async fn test_surround_with_pair(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let language = Arc::new(Language::new(
@@ -6750,7 +6795,7 @@ async fn test_surround_with_pair(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_delete_autoclose_pair(cx: &mut gpui::TestAppContext) {
+async fn test_delete_autoclose_pair(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let language = Arc::new(Language::new(
@@ -6857,7 +6902,7 @@ async fn test_delete_autoclose_pair(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_always_treat_brackets_as_autoclosed_delete(cx: &mut gpui::TestAppContext) {
+async fn test_always_treat_brackets_as_autoclosed_delete(cx: &mut TestAppContext) {
     init_test(cx, |settings| {
         settings.defaults.always_treat_brackets_as_autoclosed = Some(true);
     });
@@ -6960,7 +7005,7 @@ async fn test_always_treat_brackets_as_autoclosed_delete(cx: &mut gpui::TestAppC
 }
 
 #[gpui::test]
-async fn test_auto_replace_emoji_shortcode(cx: &mut gpui::TestAppContext) {
+async fn test_auto_replace_emoji_shortcode(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let language = Arc::new(Language::new(
@@ -7029,7 +7074,7 @@ async fn test_auto_replace_emoji_shortcode(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_snippet_placeholder_choices(cx: &mut gpui::TestAppContext) {
+async fn test_snippet_placeholder_choices(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let (text, insertion_ranges) = marked_text_ranges(
@@ -7068,7 +7113,7 @@ async fn test_snippet_placeholder_choices(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_snippets(cx: &mut gpui::TestAppContext) {
+async fn test_snippets(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let (text, insertion_ranges) = marked_text_ranges(
@@ -7176,7 +7221,7 @@ async fn test_snippets(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) {
+async fn test_document_format_during_save(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let fs = FakeFs::new(cx.executor());
@@ -7322,7 +7367,7 @@ async fn test_document_format_during_save(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_multibuffer_format_during_save(cx: &mut gpui::TestAppContext) {
+async fn test_multibuffer_format_during_save(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let cols = 4;
@@ -7552,7 +7597,7 @@ async fn test_multibuffer_format_during_save(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) {
+async fn test_range_format_during_save(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let fs = FakeFs::new(cx.executor());
@@ -7699,7 +7744,7 @@ async fn test_range_format_during_save(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) {
+async fn test_document_format_manual_trigger(cx: &mut TestAppContext) {
     init_test(cx, |settings| {
         settings.defaults.formatter = Some(language_settings::SelectedFormatter::List(
             FormatterList(vec![Formatter::LanguageServer { name: None }].into()),
@@ -7825,7 +7870,7 @@ async fn test_document_format_manual_trigger(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_concurrent_format_requests(cx: &mut gpui::TestAppContext) {
+async fn test_concurrent_format_requests(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorLspTestContext::new_rust(
@@ -7882,7 +7927,7 @@ async fn test_concurrent_format_requests(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_strip_whitespace_and_format_via_lsp(cx: &mut gpui::TestAppContext) {
+async fn test_strip_whitespace_and_format_via_lsp(cx: &mut TestAppContext) {
     init_test(cx, |settings| {
         settings.defaults.formatter = Some(language_settings::SelectedFormatter::Auto)
     });
@@ -8000,7 +8045,7 @@ async fn test_strip_whitespace_and_format_via_lsp(cx: &mut gpui::TestAppContext)
 
 #[gpui::test]
 async fn test_handle_input_for_show_signature_help_auto_signature_help_true(
-    cx: &mut gpui::TestAppContext,
+    cx: &mut TestAppContext,
 ) {
     init_test(cx, |_| {});
 
@@ -8140,7 +8185,7 @@ async fn test_handle_input_for_show_signature_help_auto_signature_help_true(
 }
 
 #[gpui::test]
-async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui::TestAppContext) {
+async fn test_handle_input_with_different_show_signature_settings(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     cx.update(|cx| {
@@ -8352,7 +8397,7 @@ async fn test_handle_input_with_different_show_signature_settings(cx: &mut gpui:
 }
 
 #[gpui::test]
-async fn test_signature_help(cx: &mut gpui::TestAppContext) {
+async fn test_signature_help(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     cx.update(|cx| {
         cx.update_global::<SettingsStore, _>(|settings, cx| {
@@ -8614,7 +8659,7 @@ async fn test_signature_help(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_completion(cx: &mut gpui::TestAppContext) {
+async fn test_completion(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorLspTestContext::new_rust(
@@ -8829,7 +8874,7 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_multiline_completion(cx: &mut gpui::TestAppContext) {
+async fn test_multiline_completion(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let fs = FakeFs::new(cx.executor());
@@ -9070,7 +9115,7 @@ async fn test_multiline_completion(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_completion_page_up_down_keys(cx: &mut gpui::TestAppContext) {
+async fn test_completion_page_up_down_keys(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorLspTestContext::new_rust(
         lsp::ServerCapabilities {
@@ -9137,7 +9182,7 @@ async fn test_completion_page_up_down_keys(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_completion_sort(cx: &mut gpui::TestAppContext) {
+async fn test_completion_sort(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorLspTestContext::new_rust(
         lsp::ServerCapabilities {
@@ -9207,7 +9252,7 @@ async fn test_completion_sort(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_no_duplicated_completion_requests(cx: &mut gpui::TestAppContext) {
+async fn test_no_duplicated_completion_requests(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorLspTestContext::new_rust(
@@ -9304,7 +9349,7 @@ async fn test_no_duplicated_completion_requests(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_toggle_comment(cx: &mut gpui::TestAppContext) {
+async fn test_toggle_comment(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorTestContext::new(cx).await;
     let language = Arc::new(Language::new(
@@ -9425,7 +9470,7 @@ async fn test_toggle_comment(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_toggle_comment_ignore_indent(cx: &mut gpui::TestAppContext) {
+async fn test_toggle_comment_ignore_indent(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorTestContext::new(cx).await;
     let language = Arc::new(Language::new(
@@ -9550,7 +9595,7 @@ async fn test_toggle_comment_ignore_indent(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext) {
+async fn test_advance_downward_on_toggle_comment(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let language = Arc::new(Language::new(
@@ -9682,7 +9727,7 @@ async fn test_advance_downward_on_toggle_comment(cx: &mut gpui::TestAppContext)
 }
 
 #[gpui::test]
-async fn test_toggle_block_comment(cx: &mut gpui::TestAppContext) {
+async fn test_toggle_block_comment(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -10115,7 +10160,7 @@ fn test_refresh_selections_while_selecting_with_mouse(cx: &mut TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_extra_newline_insertion(cx: &mut gpui::TestAppContext) {
+async fn test_extra_newline_insertion(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let language = Arc::new(
@@ -10275,7 +10320,7 @@ fn test_highlighted_ranges(cx: &mut TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_following(cx: &mut gpui::TestAppContext) {
+async fn test_following(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let fs = FakeFs::new(cx.executor());
@@ -10471,7 +10516,7 @@ async fn test_following(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) {
+async fn test_following_with_multiple_excerpts(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let fs = FakeFs::new(cx.executor());
@@ -10656,10 +10701,7 @@ async fn test_following_with_multiple_excerpts(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn go_to_prev_overlapping_diagnostic(
-    executor: BackgroundExecutor,
-    cx: &mut gpui::TestAppContext,
-) {
+async fn go_to_prev_overlapping_diagnostic(executor: BackgroundExecutor, cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -10755,7 +10797,7 @@ async fn go_to_prev_overlapping_diagnostic(
 #[gpui::test]
 async fn cycle_through_same_place_diagnostics(
     executor: BackgroundExecutor,
-    cx: &mut gpui::TestAppContext,
+    cx: &mut TestAppContext,
 ) {
     init_test(cx, |_| {});
 
@@ -10963,7 +11005,7 @@ async fn test_diagnostics_with_links(cx: &mut TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut gpui::TestAppContext) {
+async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -11144,7 +11186,7 @@ fn test_split_words() {
 }
 
 #[gpui::test]
-async fn test_move_to_enclosing_bracket(cx: &mut gpui::TestAppContext) {
+async fn test_move_to_enclosing_bracket(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorLspTestContext::new_typescript(Default::default(), cx).await;
@@ -11195,7 +11237,7 @@ async fn test_move_to_enclosing_bracket(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_on_type_formatting_not_triggered(cx: &mut gpui::TestAppContext) {
+async fn test_on_type_formatting_not_triggered(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let fs = FakeFs::new(cx.executor());
@@ -11312,7 +11354,7 @@ async fn test_on_type_formatting_not_triggered(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_language_server_restart_due_to_settings_change(cx: &mut gpui::TestAppContext) {
+async fn test_language_server_restart_due_to_settings_change(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let fs = FakeFs::new(cx.executor());
@@ -11462,7 +11504,7 @@ async fn test_language_server_restart_due_to_settings_change(cx: &mut gpui::Test
 }
 
 #[gpui::test]
-async fn test_completions_with_additional_edits(cx: &mut gpui::TestAppContext) {
+async fn test_completions_with_additional_edits(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorLspTestContext::new_rust(
@@ -11554,9 +11596,7 @@ async fn test_completions_with_additional_edits(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_completions_resolve_updates_labels_if_filter_text_matches(
-    cx: &mut gpui::TestAppContext,
-) {
+async fn test_completions_resolve_updates_labels_if_filter_text_matches(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorLspTestContext::new_rust(
@@ -11691,7 +11731,7 @@ async fn test_completions_resolve_updates_labels_if_filter_text_matches(
 }
 
 #[gpui::test]
-async fn test_completions_resolve_happens_once(cx: &mut gpui::TestAppContext) {
+async fn test_completions_resolve_happens_once(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorLspTestContext::new_rust(
@@ -11857,7 +11897,7 @@ async fn test_completions_resolve_happens_once(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_completions_default_resolve_data_handling(cx: &mut gpui::TestAppContext) {
+async fn test_completions_default_resolve_data_handling(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let item_0 = lsp::CompletionItem {
@@ -12026,7 +12066,7 @@ async fn test_completions_default_resolve_data_handling(cx: &mut gpui::TestAppCo
 }
 
 #[gpui::test]
-async fn test_completions_in_languages_with_extra_word_characters(cx: &mut gpui::TestAppContext) {
+async fn test_completions_in_languages_with_extra_word_characters(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorLspTestContext::new(
@@ -12130,7 +12170,7 @@ fn completion_menu_entries(menu: &CompletionsMenu) -> Vec<String> {
 }
 
 #[gpui::test]
-async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
+async fn test_document_format_with_prettier(cx: &mut TestAppContext) {
     init_test(cx, |settings| {
         settings.defaults.formatter = Some(language_settings::SelectedFormatter::List(
             FormatterList(vec![Formatter::Prettier].into()),
@@ -12224,7 +12264,7 @@ async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_addition_reverts(cx: &mut gpui::TestAppContext) {
+async fn test_addition_reverts(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorLspTestContext::new_rust(lsp::ServerCapabilities::default(), cx).await;
     let base_text = indoc! {r#"
@@ -12366,7 +12406,7 @@ async fn test_addition_reverts(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_modification_reverts(cx: &mut gpui::TestAppContext) {
+async fn test_modification_reverts(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorLspTestContext::new_rust(lsp::ServerCapabilities::default(), cx).await;
     let base_text = indoc! {r#"
@@ -12481,7 +12521,7 @@ async fn test_modification_reverts(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_deleting_over_diff_hunk(cx: &mut gpui::TestAppContext) {
+async fn test_deleting_over_diff_hunk(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorLspTestContext::new_rust(lsp::ServerCapabilities::default(), cx).await;
     let base_text = indoc! {r#"
@@ -12514,7 +12554,7 @@ async fn test_deleting_over_diff_hunk(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_deletion_reverts(cx: &mut gpui::TestAppContext) {
+async fn test_deletion_reverts(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
     let mut cx = EditorLspTestContext::new_rust(lsp::ServerCapabilities::default(), cx).await;
     let base_text = indoc! {r#"struct Row;
@@ -12643,7 +12683,7 @@ struct Row10;"#};
 }
 
 #[gpui::test]
-async fn test_multibuffer_reverts(cx: &mut gpui::TestAppContext) {
+async fn test_multibuffer_reverts(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let base_text_1 = "aaaa\nbbbb\ncccc\ndddd\neeee\nffff\ngggg\nhhhh\niiii\njjjj";
@@ -12801,7 +12841,7 @@ async fn test_multibuffer_reverts(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_mutlibuffer_in_navigation_history(cx: &mut gpui::TestAppContext) {
+async fn test_mutlibuffer_in_navigation_history(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let cols = 4;
@@ -13095,10 +13135,7 @@ async fn test_mutlibuffer_in_navigation_history(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_toggle_selected_diff_hunks(
-    executor: BackgroundExecutor,
-    cx: &mut gpui::TestAppContext,
-) {
+async fn test_toggle_selected_diff_hunks(executor: BackgroundExecutor, cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -13225,7 +13262,7 @@ async fn test_toggle_selected_diff_hunks(
 #[gpui::test]
 async fn test_diff_base_change_with_expanded_diff_hunks(
     executor: BackgroundExecutor,
-    cx: &mut gpui::TestAppContext,
+    cx: &mut TestAppContext,
 ) {
     init_test(cx, |_| {});
 
@@ -13316,7 +13353,7 @@ async fn test_diff_base_change_with_expanded_diff_hunks(
 }
 
 #[gpui::test]
-async fn test_toggle_diff_expand_in_multi_buffer(cx: &mut gpui::TestAppContext) {
+async fn test_toggle_diff_expand_in_multi_buffer(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let file_1_old = "aaa\nbbb\nccc\nddd\neee\nfff\nggg\nhhh\niii\njjj";
@@ -13480,7 +13517,7 @@ async fn test_toggle_diff_expand_in_multi_buffer(cx: &mut gpui::TestAppContext)
 }
 
 #[gpui::test]
-async fn test_expand_diff_hunk_at_excerpt_boundary(cx: &mut gpui::TestAppContext) {
+async fn test_expand_diff_hunk_at_excerpt_boundary(cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let base = "aaa\nbbb\nccc\nddd\neee\nfff\nggg\n";
@@ -13554,7 +13591,7 @@ async fn test_expand_diff_hunk_at_excerpt_boundary(cx: &mut gpui::TestAppContext
 #[gpui::test]
 async fn test_edits_around_expanded_insertion_hunks(
     executor: BackgroundExecutor,
-    cx: &mut gpui::TestAppContext,
+    cx: &mut TestAppContext,
 ) {
     init_test(cx, |_| {});
 
@@ -13823,7 +13860,7 @@ async fn test_toggling_adjacent_diff_hunks(cx: &mut TestAppContext) {
 #[gpui::test]
 async fn test_edits_around_expanded_deletion_hunks(
     executor: BackgroundExecutor,
-    cx: &mut gpui::TestAppContext,
+    cx: &mut TestAppContext,
 ) {
     init_test(cx, |_| {});
 
@@ -13963,10 +14000,7 @@ async fn test_edits_around_expanded_deletion_hunks(
 }
 
 #[gpui::test]
-async fn test_backspace_after_deletion_hunk(
-    executor: BackgroundExecutor,
-    cx: &mut gpui::TestAppContext,
-) {
+async fn test_backspace_after_deletion_hunk(executor: BackgroundExecutor, cx: &mut TestAppContext) {
     init_test(cx, |_| {});
 
     let mut cx = EditorTestContext::new(cx).await;
@@ -14030,7 +14064,7 @@ async fn test_backspace_after_deletion_hunk(
 #[gpui::test]
 async fn test_edit_after_expanded_modification_hunk(
     executor: BackgroundExecutor,
-    cx: &mut gpui::TestAppContext,
+    cx: &mut TestAppContext,
 ) {
     init_test(cx, |_| {});
 
@@ -14130,7 +14164,7 @@ async fn test_edit_after_expanded_modification_hunk(
 #[gpui::test]
 async fn test_stage_and_unstage_added_file_hunk(
     executor: BackgroundExecutor,
-    cx: &mut gpui::TestAppContext,
+    cx: &mut TestAppContext,
 ) {
     init_test(cx, |_| {});
 
@@ -14182,7 +14216,7 @@ async fn test_stage_and_unstage_added_file_hunk(
 
 async fn setup_indent_guides_editor(
     text: &str,
-    cx: &mut gpui::TestAppContext,
+    cx: &mut TestAppContext,
 ) -> (BufferId, EditorTestContext) {
     init_test(cx, |_| {});
 
@@ -14257,7 +14291,7 @@ fn indent_guide(buffer_id: BufferId, start_row: u32, end_row: u32, depth: u32) -
 }
 
 #[gpui::test]
-async fn test_indent_guide_single_line(cx: &mut gpui::TestAppContext) {
+async fn test_indent_guide_single_line(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
     fn main() {
@@ -14272,7 +14306,7 @@ async fn test_indent_guide_single_line(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_indent_guide_simple_block(cx: &mut gpui::TestAppContext) {
+async fn test_indent_guide_simple_block(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
     fn main() {
@@ -14288,7 +14322,7 @@ async fn test_indent_guide_simple_block(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_indent_guide_nested(cx: &mut gpui::TestAppContext) {
+async fn test_indent_guide_nested(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
     fn main() {
@@ -14317,7 +14351,7 @@ async fn test_indent_guide_nested(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_indent_guide_tab(cx: &mut gpui::TestAppContext) {
+async fn test_indent_guide_tab(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
     fn main() {
@@ -14342,7 +14376,7 @@ async fn test_indent_guide_tab(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_indent_guide_continues_on_empty_line(cx: &mut gpui::TestAppContext) {
+async fn test_indent_guide_continues_on_empty_line(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
         fn main() {
@@ -14359,7 +14393,7 @@ async fn test_indent_guide_continues_on_empty_line(cx: &mut gpui::TestAppContext
 }
 
 #[gpui::test]
-async fn test_indent_guide_complex(cx: &mut gpui::TestAppContext) {
+async fn test_indent_guide_complex(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
         fn main() {
@@ -14391,7 +14425,7 @@ async fn test_indent_guide_complex(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_indent_guide_starts_off_screen(cx: &mut gpui::TestAppContext) {
+async fn test_indent_guide_starts_off_screen(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
         fn main() {
@@ -14423,7 +14457,7 @@ async fn test_indent_guide_starts_off_screen(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_indent_guide_ends_off_screen(cx: &mut gpui::TestAppContext) {
+async fn test_indent_guide_ends_off_screen(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
         fn main() {
@@ -14455,7 +14489,7 @@ async fn test_indent_guide_ends_off_screen(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_indent_guide_without_brackets(cx: &mut gpui::TestAppContext) {
+async fn test_indent_guide_without_brackets(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
         block1
@@ -14483,7 +14517,7 @@ async fn test_indent_guide_without_brackets(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_indent_guide_ends_before_empty_line(cx: &mut gpui::TestAppContext) {
+async fn test_indent_guide_ends_before_empty_line(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
         block1
@@ -14509,7 +14543,7 @@ async fn test_indent_guide_ends_before_empty_line(cx: &mut gpui::TestAppContext)
 }
 
 #[gpui::test]
-async fn test_indent_guide_continuing_off_screen(cx: &mut gpui::TestAppContext) {
+async fn test_indent_guide_continuing_off_screen(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
         block1
@@ -14527,7 +14561,7 @@ async fn test_indent_guide_continuing_off_screen(cx: &mut gpui::TestAppContext)
 }
 
 #[gpui::test]
-async fn test_indent_guide_tabs(cx: &mut gpui::TestAppContext) {
+async fn test_indent_guide_tabs(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
         def a:
@@ -14554,7 +14588,7 @@ async fn test_indent_guide_tabs(cx: &mut gpui::TestAppContext) {
 }
 
 #[gpui::test]
-async fn test_active_indent_guide_single_line(cx: &mut gpui::TestAppContext) {
+async fn test_active_indent_guide_single_line(cx: &mut TestAppContext) {
     let (buffer_id, mut cx) = setup_indent_guides_editor(
         &"
     fn main() {

crates/language/src/buffer.rs πŸ”—

@@ -393,9 +393,17 @@ pub enum AutoindentMode {
     /// Apply the same indentation adjustment to all of the lines
     /// in a given insertion.
     Block {
-        /// The original indentation level of the first line of each
-        /// insertion, if it has been copied.
-        original_indent_columns: Vec<u32>,
+        /// The original start column of each insertion, if it was
+        /// copied from elsewhere.
+        ///
+        /// Knowing this start column makes it possible to preserve the
+        /// relative indentation of every line in the insertion from
+        /// when it was copied.
+        ///
+        /// If the start column is `a`, and the first line of insertion
+        /// is then auto-indented to column `b`, then every other line of
+        /// the insertion will be auto-indented to column `b - a`
+        original_start_columns: Vec<u32>,
     },
 }
 
@@ -2191,16 +2199,16 @@ impl Buffer {
 
                     let mut original_indent_column = None;
                     if let AutoindentMode::Block {
-                        original_indent_columns,
+                        original_start_columns,
                     } = &mode
                     {
-                        original_indent_column =
-                            Some(original_indent_columns.get(ix).copied().unwrap_or_else(|| {
-                                indent_size_for_text(
+                        original_indent_column = Some(
+                            original_start_columns.get(ix).copied().unwrap_or(0)
+                                + indent_size_for_text(
                                     new_text[range_of_insertion_to_indent.clone()].chars(),
                                 )
-                                .len
-                            }));
+                                .len,
+                        );
 
                         // Avoid auto-indenting the line after the edit.
                         if new_text[range_of_insertion_to_indent.clone()].ends_with('\n') {

crates/language/src/buffer_tests.rs πŸ”—

@@ -1657,7 +1657,7 @@ fn test_autoindent_block_mode(cx: &mut App) {
         buffer.edit(
             [(Point::new(2, 0)..Point::new(2, 0), inserted_text.clone())],
             Some(AutoindentMode::Block {
-                original_indent_columns: original_indent_columns.clone(),
+                original_start_columns: original_indent_columns.clone(),
             }),
             cx,
         );
@@ -1685,7 +1685,7 @@ fn test_autoindent_block_mode(cx: &mut App) {
         buffer.edit(
             [(Point::new(2, 8)..Point::new(2, 8), inserted_text)],
             Some(AutoindentMode::Block {
-                original_indent_columns: original_indent_columns.clone(),
+                original_start_columns: original_indent_columns.clone(),
             }),
             cx,
         );
@@ -1734,7 +1734,7 @@ fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut App) {
         buffer.edit(
             [(Point::new(2, 0)..Point::new(2, 0), inserted_text)],
             Some(AutoindentMode::Block {
-                original_indent_columns: original_indent_columns.clone(),
+                original_start_columns: original_indent_columns.clone(),
             }),
             cx,
         );
@@ -1765,7 +1765,7 @@ fn test_autoindent_block_mode_without_original_indent_columns(cx: &mut App) {
         buffer.edit(
             [(Point::new(2, 12)..Point::new(2, 12), inserted_text)],
             Some(AutoindentMode::Block {
-                original_indent_columns: Vec::new(),
+                original_start_columns: Vec::new(),
             }),
             cx,
         );
@@ -1821,7 +1821,7 @@ fn test_autoindent_block_mode_multiple_adjacent_ranges(cx: &mut App) {
                 (ranges_to_replace[2].clone(), "fn three() {\n    103\n}\n"),
             ],
             Some(AutoindentMode::Block {
-                original_indent_columns: vec![0, 0, 0],
+                original_start_columns: vec![0, 0, 0],
             }),
             cx,
         );

crates/multi_buffer/src/multi_buffer.rs πŸ”—

@@ -488,7 +488,7 @@ struct BufferEdit {
     range: Range<usize>,
     new_text: Arc<str>,
     is_insertion: bool,
-    original_indent_column: u32,
+    original_start_column: u32,
     excerpt_id: ExcerptId,
 }
 
@@ -747,15 +747,15 @@ impl MultiBuffer {
                 return;
             }
 
-            let original_indent_columns = match &mut autoindent_mode {
+            let original_start_columns = match &mut autoindent_mode {
                 Some(AutoindentMode::Block {
-                    original_indent_columns,
-                }) => mem::take(original_indent_columns),
+                    original_start_columns,
+                }) => mem::take(original_start_columns),
                 _ => Default::default(),
             };
 
             let (buffer_edits, edited_excerpt_ids) =
-                this.convert_edits_to_buffer_edits(edits, &snapshot, &original_indent_columns);
+                this.convert_edits_to_buffer_edits(edits, &snapshot, &original_start_columns);
             drop(snapshot);
 
             for (buffer_id, mut edits) in buffer_edits {
@@ -772,7 +772,7 @@ impl MultiBuffer {
                             mut range,
                             mut new_text,
                             mut is_insertion,
-                            original_indent_column,
+                            original_start_column: original_indent_column,
                             excerpt_id,
                         }) = edits.next()
                         {
@@ -815,7 +815,7 @@ impl MultiBuffer {
                         let deletion_autoindent_mode =
                             if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
                                 Some(AutoindentMode::Block {
-                                    original_indent_columns: Default::default(),
+                                    original_start_columns: Default::default(),
                                 })
                             } else {
                                 autoindent_mode.clone()
@@ -823,7 +823,7 @@ impl MultiBuffer {
                         let insertion_autoindent_mode =
                             if let Some(AutoindentMode::Block { .. }) = autoindent_mode {
                                 Some(AutoindentMode::Block {
-                                    original_indent_columns,
+                                    original_start_columns: original_indent_columns,
                                 })
                             } else {
                                 autoindent_mode.clone()
@@ -844,13 +844,13 @@ impl MultiBuffer {
         &self,
         edits: Vec<(Range<usize>, Arc<str>)>,
         snapshot: &MultiBufferSnapshot,
-        original_indent_columns: &[u32],
+        original_start_columns: &[u32],
     ) -> (HashMap<BufferId, Vec<BufferEdit>>, Vec<ExcerptId>) {
         let mut buffer_edits: HashMap<BufferId, Vec<BufferEdit>> = Default::default();
         let mut edited_excerpt_ids = Vec::new();
         let mut cursor = snapshot.cursor::<usize>();
         for (ix, (range, new_text)) in edits.into_iter().enumerate() {
-            let original_indent_column = original_indent_columns.get(ix).copied().unwrap_or(0);
+            let original_start_column = original_start_columns.get(ix).copied().unwrap_or(0);
 
             cursor.seek(&range.start);
             let mut start_region = cursor.region().expect("start offset out of bounds");
@@ -901,7 +901,7 @@ impl MultiBuffer {
                             range: buffer_start..buffer_end,
                             new_text,
                             is_insertion: true,
-                            original_indent_column,
+                            original_start_column,
                             excerpt_id: start_region.excerpt.id,
                         });
                 }
@@ -917,7 +917,7 @@ impl MultiBuffer {
                             range: start_excerpt_range,
                             new_text: new_text.clone(),
                             is_insertion: true,
-                            original_indent_column,
+                            original_start_column,
                             excerpt_id: start_region.excerpt.id,
                         });
                 }
@@ -930,7 +930,7 @@ impl MultiBuffer {
                             range: end_excerpt_range,
                             new_text: new_text.clone(),
                             is_insertion: false,
-                            original_indent_column,
+                            original_start_column,
                             excerpt_id: end_region.excerpt.id,
                         });
                 }
@@ -950,7 +950,7 @@ impl MultiBuffer {
                                 range: region.buffer_range,
                                 new_text: new_text.clone(),
                                 is_insertion: false,
-                                original_indent_column,
+                                original_start_column,
                                 excerpt_id: region.excerpt.id,
                             });
                     }

crates/vim/src/normal/paste.rs πŸ”—

@@ -81,32 +81,32 @@ impl Vim {
                     }
                 }
 
-                let first_selection_indent_column =
+                let first_selection_start_column =
                     clipboard_selections.as_ref().and_then(|zed_selections| {
                         zed_selections
                             .first()
-                            .map(|selection| selection.first_line_indent)
+                            .map(|selection| selection.start_column)
                     });
                 let before = action.before || vim.mode == Mode::VisualLine;
 
                 let mut edits = Vec::new();
                 let mut new_selections = Vec::new();
-                let mut original_indent_columns = Vec::new();
+                let mut original_start_columns = Vec::new();
                 let mut start_offset = 0;
 
                 for (ix, (selection, preserve)) in selections_to_process.iter().enumerate() {
-                    let (mut to_insert, original_indent_column) =
+                    let (mut to_insert, original_start_column) =
                         if let Some(clipboard_selections) = &clipboard_selections {
                             if let Some(clipboard_selection) = clipboard_selections.get(ix) {
                                 let end_offset = start_offset + clipboard_selection.len;
                                 let text = text[start_offset..end_offset].to_string();
                                 start_offset = end_offset + 1;
-                                (text, Some(clipboard_selection.first_line_indent))
+                                (text, Some(clipboard_selection.start_column))
                             } else {
-                                ("".to_string(), first_selection_indent_column)
+                                ("".to_string(), first_selection_start_column)
                             }
                         } else {
-                            (text.to_string(), first_selection_indent_column)
+                            (text.to_string(), first_selection_start_column)
                         };
                     let line_mode = to_insert.ends_with('\n');
                     let is_multiline = to_insert.contains('\n');
@@ -152,10 +152,10 @@ impl Vim {
                         new_selections.push((anchor, line_mode, is_multiline));
                     }
                     edits.push((point_range, to_insert.repeat(count)));
-                    original_indent_columns.extend(original_indent_column);
+                    original_start_columns.extend(original_start_column);
                 }
 
-                editor.edit_with_block_indent(edits, original_indent_columns, cx);
+                editor.edit_with_block_indent(edits, original_start_columns, cx);
 
                 // in line_mode vim will insert the new text on the next (or previous if before) line
                 // and put the cursor on the first non-blank character of the first inserted line (or at the end if the first line is blank).

crates/vim/src/normal/yank.rs πŸ”—

@@ -188,7 +188,7 @@ impl Vim {
                 clipboard_selections.push(ClipboardSelection {
                     len: text.len() - initial_len,
                     is_entire_line: linewise,
-                    first_line_indent: buffer.indent_size_for_line(MultiBufferRow(start.row)).len,
+                    start_column: start.column,
                 });
             }
         }