diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index ea8ec7096f..8d94aec8e6 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -8929,7 +8929,10 @@ impl Editor { .iter() .cloned() .map(|range| (range, snippet_text.clone())); - buffer.edit(edits, Some(AutoindentMode::EachLine), cx); + let autoindent_mode = AutoindentMode::Block { + original_indent_columns: Vec::new(), + }; + buffer.edit(edits, Some(autoindent_mode), cx); let snapshot = &*buffer.read(cx); let snippet = &snippet; diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index af62a8af72..43cb9617d9 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -8513,108 +8513,123 @@ async fn test_snippet_placeholder_choices(cx: &mut TestAppContext) { async fn test_snippets(cx: &mut TestAppContext) { init_test(cx, |_| {}); - let (text, insertion_ranges) = marked_text_ranges( - indoc! {" - a.ˇ b - a.ˇ b - a.ˇ b - "}, - false, - ); + let mut cx = EditorTestContext::new(cx).await; - let buffer = cx.update(|cx| MultiBuffer::build_simple(&text, cx)); - let (editor, cx) = cx.add_window_view(|window, cx| build_editor(buffer, window, cx)); + cx.set_state(indoc! {" + a.ˇ b + a.ˇ b + a.ˇ b + "}); - editor.update_in(cx, |editor, window, cx| { + cx.update_editor(|editor, window, cx| { let snippet = Snippet::parse("f(${1:one}, ${2:two}, ${1:three})$0").unwrap(); - + let insertion_ranges = editor + .selections + .all(cx) + .iter() + .map(|s| s.range().clone()) + .collect::>(); editor .insert_snippet(&insertion_ranges, snippet, window, cx) .unwrap(); - - fn assert(editor: &mut Editor, cx: &mut Context, marked_text: &str) { - let (expected_text, selection_ranges) = marked_text_ranges(marked_text, false); - assert_eq!(editor.text(cx), expected_text); - assert_eq!(editor.selections.ranges::(cx), selection_ranges); - } - - assert( - editor, - cx, - indoc! {" - a.f(«one», two, «three») b - a.f(«one», two, «three») b - a.f(«one», two, «three») b - "}, - ); - - // Can't move earlier than the first tab stop - assert!(!editor.move_to_prev_snippet_tabstop(window, cx)); - assert( - editor, - cx, - indoc! {" - a.f(«one», two, «three») b - a.f(«one», two, «three») b - a.f(«one», two, «three») b - "}, - ); - - assert!(editor.move_to_next_snippet_tabstop(window, cx)); - assert( - editor, - cx, - indoc! {" - a.f(one, «two», three) b - a.f(one, «two», three) b - a.f(one, «two», three) b - "}, - ); - - editor.move_to_prev_snippet_tabstop(window, cx); - assert( - editor, - cx, - indoc! {" - a.f(«one», two, «three») b - a.f(«one», two, «three») b - a.f(«one», two, «three») b - "}, - ); - - assert!(editor.move_to_next_snippet_tabstop(window, cx)); - assert( - editor, - cx, - indoc! {" - a.f(one, «two», three) b - a.f(one, «two», three) b - a.f(one, «two», three) b - "}, - ); - assert!(editor.move_to_next_snippet_tabstop(window, cx)); - assert( - editor, - cx, - indoc! {" - a.f(one, two, three)ˇ b - a.f(one, two, three)ˇ b - a.f(one, two, three)ˇ b - "}, - ); - - // As soon as the last tab stop is reached, snippet state is gone - editor.move_to_prev_snippet_tabstop(window, cx); - assert( - editor, - cx, - indoc! {" - a.f(one, two, three)ˇ b - a.f(one, two, three)ˇ b - a.f(one, two, three)ˇ b - "}, - ); }); + + cx.assert_editor_state(indoc! {" + a.f(«oneˇ», two, «threeˇ») b + a.f(«oneˇ», two, «threeˇ») b + a.f(«oneˇ», two, «threeˇ») b + "}); + + // Can't move earlier than the first tab stop + cx.update_editor(|editor, window, cx| { + assert!(!editor.move_to_prev_snippet_tabstop(window, cx)) + }); + cx.assert_editor_state(indoc! {" + a.f(«oneˇ», two, «threeˇ») b + a.f(«oneˇ», two, «threeˇ») b + a.f(«oneˇ», two, «threeˇ») b + "}); + + cx.update_editor(|editor, window, cx| assert!(editor.move_to_next_snippet_tabstop(window, cx))); + cx.assert_editor_state(indoc! {" + a.f(one, «twoˇ», three) b + a.f(one, «twoˇ», three) b + a.f(one, «twoˇ», three) b + "}); + + cx.update_editor(|editor, window, cx| assert!(editor.move_to_prev_snippet_tabstop(window, cx))); + cx.assert_editor_state(indoc! {" + a.f(«oneˇ», two, «threeˇ») b + a.f(«oneˇ», two, «threeˇ») b + a.f(«oneˇ», two, «threeˇ») b + "}); + + cx.update_editor(|editor, window, cx| assert!(editor.move_to_next_snippet_tabstop(window, cx))); + cx.assert_editor_state(indoc! {" + a.f(one, «twoˇ», three) b + a.f(one, «twoˇ», three) b + a.f(one, «twoˇ», three) b + "}); + cx.update_editor(|editor, window, cx| assert!(editor.move_to_next_snippet_tabstop(window, cx))); + cx.assert_editor_state(indoc! {" + a.f(one, two, three)ˇ b + a.f(one, two, three)ˇ b + a.f(one, two, three)ˇ b + "}); + + // As soon as the last tab stop is reached, snippet state is gone + cx.update_editor(|editor, window, cx| { + assert!(!editor.move_to_prev_snippet_tabstop(window, cx)) + }); + cx.assert_editor_state(indoc! {" + a.f(one, two, three)ˇ b + a.f(one, two, three)ˇ b + a.f(one, two, three)ˇ b + "}); +} + +#[gpui::test] +async fn test_snippet_indentation(cx: &mut TestAppContext) { + init_test(cx, |_| {}); + + let mut cx = EditorTestContext::new(cx).await; + + cx.update_editor(|editor, window, cx| { + let snippet = Snippet::parse(indoc! {" + /* + * Multiline comment with leading indentation + * + * $1 + */ + $0"}) + .unwrap(); + let insertion_ranges = editor + .selections + .all(cx) + .iter() + .map(|s| s.range().clone()) + .collect::>(); + editor + .insert_snippet(&insertion_ranges, snippet, window, cx) + .unwrap(); + }); + + cx.assert_editor_state(indoc! {" + /* + * Multiline comment with leading indentation + * + * ˇ + */ + "}); + + cx.update_editor(|editor, window, cx| assert!(editor.move_to_next_snippet_tabstop(window, cx))); + cx.assert_editor_state(indoc! {" + /* + * Multiline comment with leading indentation + * + *• + */ + ˇ"}); } #[gpui::test] diff --git a/crates/editor/src/test/editor_test_context.rs b/crates/editor/src/test/editor_test_context.rs index e8165e9c65..b3de321a1f 100644 --- a/crates/editor/src/test/editor_test_context.rs +++ b/crates/editor/src/test/editor_test_context.rs @@ -532,7 +532,9 @@ impl EditorTestContext { #[track_caller] pub fn assert_editor_selections(&mut self, expected_selections: Vec>) { let expected_marked_text = - generate_marked_text(&self.buffer_text(), &expected_selections, true); + generate_marked_text(&self.buffer_text(), &expected_selections, true) + .replace(" \n", "•\n"); + self.assert_selections(expected_selections, expected_marked_text) } @@ -561,7 +563,8 @@ impl EditorTestContext { ) { let actual_selections = self.editor_selections(); let actual_marked_text = - generate_marked_text(&self.buffer_text(), &actual_selections, true); + generate_marked_text(&self.buffer_text(), &actual_selections, true) + .replace(" \n", "•\n"); if expected_selections != actual_selections { pretty_assertions::assert_eq!( actual_marked_text,