diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index 486292f20e..9929c6f907 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -364,12 +364,14 @@ "b": "vim::Parentheses", "[": "vim::SquareBrackets", "]": "vim::SquareBrackets", + "r": "vim::SquareBrackets", "{": "vim::CurlyBrackets", "}": "vim::CurlyBrackets", "shift-b": "vim::CurlyBrackets", "<": "vim::AngleBrackets", ">": "vim::AngleBrackets", - "a": "vim::Argument" + "a": "vim::AngleBrackets", + "g": "vim::Argument" } }, { diff --git a/crates/vim/src/object.rs b/crates/vim/src/object.rs index 9f8e8366a7..c73cee836e 100644 --- a/crates/vim/src/object.rs +++ b/crates/vim/src/object.rs @@ -1402,7 +1402,7 @@ mod test { // Generic arguments cx.set_state("fn boop() {}", Mode::Normal); - cx.simulate_keystrokes("v i a"); + cx.simulate_keystrokes("v i g"); cx.assert_state("fn boop<«A: Debugˇ», B>() {}", Mode::Visual); // Function arguments @@ -1410,11 +1410,11 @@ mod test { "fn boop(ˇarg_a: (Tuple, Of, Types), arg_b: String) {}", Mode::Normal, ); - cx.simulate_keystrokes("d a a"); + cx.simulate_keystrokes("d a g"); cx.assert_state("fn boop(ˇarg_b: String) {}", Mode::Normal); cx.set_state("std::namespace::test(\"strinˇg\", a.b.c())", Mode::Normal); - cx.simulate_keystrokes("v a a"); + cx.simulate_keystrokes("v a g"); cx.assert_state("std::namespace::test(«\"string\", ˇ»a.b.c())", Mode::Visual); // Tuple, vec, and array arguments @@ -1422,34 +1422,34 @@ mod test { "fn boop(arg_a: (Tuple, Ofˇ, Types), arg_b: String) {}", Mode::Normal, ); - cx.simulate_keystrokes("c i a"); + cx.simulate_keystrokes("c i g"); cx.assert_state( "fn boop(arg_a: (Tuple, ˇ, Types), arg_b: String) {}", Mode::Insert, ); cx.set_state("let a = (test::call(), 'p', my_macro!{ˇ});", Mode::Normal); - cx.simulate_keystrokes("c a a"); + cx.simulate_keystrokes("c a g"); cx.assert_state("let a = (test::call(), 'p'ˇ);", Mode::Insert); cx.set_state("let a = [test::call(ˇ), 300];", Mode::Normal); - cx.simulate_keystrokes("c i a"); + cx.simulate_keystrokes("c i g"); cx.assert_state("let a = [ˇ, 300];", Mode::Insert); cx.set_state( "let a = vec![Vec::new(), vecˇ![test::call(), 300]];", Mode::Normal, ); - cx.simulate_keystrokes("c a a"); + cx.simulate_keystrokes("c a g"); cx.assert_state("let a = vec![Vec::new()ˇ];", Mode::Insert); // Cursor immediately before / after brackets cx.set_state("let a = [test::call(first_arg)ˇ]", Mode::Normal); - cx.simulate_keystrokes("v i a"); + cx.simulate_keystrokes("v i g"); cx.assert_state("let a = [«test::call(first_arg)ˇ»]", Mode::Visual); cx.set_state("let a = [test::callˇ(first_arg)]", Mode::Normal); - cx.simulate_keystrokes("v i a"); + cx.simulate_keystrokes("v i g"); cx.assert_state("let a = [«test::call(first_arg)ˇ»]", Mode::Visual); } diff --git a/crates/vim/src/surrounds.rs b/crates/vim/src/surrounds.rs index 81025103fb..781485e4cc 100644 --- a/crates/vim/src/surrounds.rs +++ b/crates/vim/src/surrounds.rs @@ -52,7 +52,7 @@ impl Vim { newline: false, }, }; - let surround = pair.end != *text; + let surround = pair.end != surround_alias((*text).as_ref()); let (display_map, display_selections) = editor.selections.all_adjusted_display(cx); let mut edits = Vec::new(); let mut anchors = Vec::new(); @@ -245,7 +245,7 @@ impl Vim { newline: false, }, }; - let surround = pair.end != *text; + let surround = pair.end != surround_alias((*text).as_ref()); let (display_map, selections) = editor.selections.all_adjusted_display(cx); let mut edits = Vec::new(); let mut anchors = Vec::new(); @@ -393,7 +393,19 @@ impl Vim { } fn find_surround_pair<'a>(pairs: &'a [BracketPair], ch: &str) -> Option<&'a BracketPair> { - pairs.iter().find(|pair| pair.start == ch || pair.end == ch) + pairs + .iter() + .find(|pair| pair.start == surround_alias(ch) || pair.end == surround_alias(ch)) +} + +fn surround_alias(ch: &str) -> &str { + match ch { + "b" => ")", + "B" => "}", + "a" => ">", + "r" => "]", + _ => ch, + } } fn all_support_surround_pair() -> Vec { @@ -1171,4 +1183,236 @@ mod test { Mode::Normal, ); } + + #[gpui::test] + async fn test_surround_aliases(cx: &mut gpui::TestAppContext) { + let mut cx = VimTestContext::new(cx, true).await; + + // add aliases + cx.set_state( + indoc! {" + The quˇick brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("y s i w b"); + cx.assert_state( + indoc! {" + The ˇ(quick) brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + cx.set_state( + indoc! {" + The quˇick brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("y s i w B"); + cx.assert_state( + indoc! {" + The ˇ{quick} brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + cx.set_state( + indoc! {" + The quˇick brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("y s i w a"); + cx.assert_state( + indoc! {" + The ˇ brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + cx.set_state( + indoc! {" + The quˇick brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("y s i w r"); + cx.assert_state( + indoc! {" + The ˇ[quick] brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + // change aliases + cx.set_state( + indoc! {" + The {quˇick} brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("c s { b"); + cx.assert_state( + indoc! {" + The ˇ(quick) brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + cx.set_state( + indoc! {" + The (quˇick) brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("c s ( B"); + cx.assert_state( + indoc! {" + The ˇ{quick} brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + cx.set_state( + indoc! {" + The (quˇick) brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("c s ( a"); + cx.assert_state( + indoc! {" + The ˇ brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + cx.set_state( + indoc! {" + The brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("c s < b"); + cx.assert_state( + indoc! {" + The ˇ(quick) brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + cx.set_state( + indoc! {" + The (quˇick) brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("c s ( r"); + cx.assert_state( + indoc! {" + The ˇ[quick] brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + cx.set_state( + indoc! {" + The [quˇick] brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("c s [ b"); + cx.assert_state( + indoc! {" + The ˇ(quick) brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + // delete alias + cx.set_state( + indoc! {" + The {quˇick} brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("d s B"); + cx.assert_state( + indoc! {" + The ˇquick brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + cx.set_state( + indoc! {" + The (quˇick) brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("d s b"); + cx.assert_state( + indoc! {" + The ˇquick brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + cx.set_state( + indoc! {" + The [quˇick] brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("d s r"); + cx.assert_state( + indoc! {" + The ˇquick brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + + cx.set_state( + indoc! {" + The brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + cx.simulate_keystrokes("d s a"); + cx.assert_state( + indoc! {" + The ˇquick brown + fox jumps over + the lazy dog."}, + Mode::Normal, + ); + } }