vim test redux (#11709)

This cleans up the neovim-backed vim tests:
- removed exempted tests (we'll rely on bug reports to find missing edge
cases)
- moved all assertions into non-async fn's so that failures are
reporting on the right file/line
- removed the NeovimBackedBindingTestContext
- renamed a few things to make them clearer
- reduced the number of permutations tested in some cases to reduce
slowest test from 60s to 5s

Release Notes:

- N/A
This commit is contained in:
Conrad Irwin 2024-05-11 12:04:05 -06:00 committed by GitHub
parent 48cba328f2
commit f550f23b97
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 2311 additions and 6505 deletions

View File

@ -193,32 +193,11 @@ impl EditorTestContext {
self.assertion_cx.context() self.assertion_cx.context()
} }
pub fn simulate_keystroke(&mut self, keystroke_text: &str) -> ContextHandle { // unlike cx.simulate_keystrokes(), this does not run_until_parked
let keystroke_under_test_handle = // so you can use it to test detailed timing
self.add_assertion_context(format!("Simulated Keystroke: {:?}", keystroke_text)); pub fn simulate_keystroke(&mut self, keystroke_text: &str) {
let keystroke = Keystroke::parse(keystroke_text).unwrap(); let keystroke = Keystroke::parse(keystroke_text).unwrap();
self.cx.dispatch_keystroke(self.window, keystroke); self.cx.dispatch_keystroke(self.window, keystroke);
keystroke_under_test_handle
}
pub fn simulate_keystrokes<const COUNT: usize>(
&mut self,
keystroke_texts: [&str; COUNT],
) -> ContextHandle {
let keystrokes_under_test_handle =
self.add_assertion_context(format!("Simulated Keystrokes: {:?}", keystroke_texts));
for keystroke_text in keystroke_texts.into_iter() {
self.simulate_keystroke(keystroke_text);
}
// it is common for keyboard shortcuts to kick off async actions, so this ensures that they are complete
// before returning.
// NOTE: we don't do this in simulate_keystroke() because a possible cause of bugs is that typing too
// quickly races with async actions.
self.cx.background_executor.run_until_parked();
keystrokes_under_test_handle
} }
pub fn run_until_parked(&mut self) { pub fn run_until_parked(&mut self) {

View File

@ -102,20 +102,16 @@ mod test {
cx.set_shared_state("ˇ").await; cx.set_shared_state("ˇ").await;
cx.simulate_shared_keystrokes([ cx.simulate_shared_keystrokes("i 1 1 escape shift-o 2 2 escape shift-g o 3 3 escape")
"i", "1", "1", "escape", "shift-o", "2", "2", "escape", "shift-g", "o", "3", "3", .await;
"escape",
])
.await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"22 "22
11 11
3ˇ3" 3ˇ3"
}) });
.await;
cx.simulate_shared_keystrokes(["g", ";"]).await; cx.simulate_shared_keystrokes("g ;").await;
// NOTE: this matches nvim when I type it into it // NOTE: this matches nvim when I type it into it
// but in tests, nvim always reports the column as 0... // but in tests, nvim always reports the column as 0...
cx.assert_state( cx.assert_state(
@ -126,7 +122,7 @@ mod test {
}, },
Mode::Normal, Mode::Normal,
); );
cx.simulate_shared_keystrokes(["g", ";"]).await; cx.simulate_shared_keystrokes("g ;").await;
cx.assert_state( cx.assert_state(
indoc! { indoc! {
"2ˇ2 "2ˇ2
@ -135,7 +131,7 @@ mod test {
}, },
Mode::Normal, Mode::Normal,
); );
cx.simulate_shared_keystrokes(["g", ";"]).await; cx.simulate_shared_keystrokes("g ;").await;
cx.assert_state( cx.assert_state(
indoc! { indoc! {
"22 "22
@ -144,7 +140,7 @@ mod test {
}, },
Mode::Normal, Mode::Normal,
); );
cx.simulate_shared_keystrokes(["g", ","]).await; cx.simulate_shared_keystrokes("g ,").await;
cx.assert_state( cx.assert_state(
indoc! { indoc! {
"2ˇ2 "2ˇ2
@ -153,9 +149,8 @@ mod test {
}, },
Mode::Normal, Mode::Normal,
); );
cx.simulate_shared_keystrokes(["shift-g", "i", "4", "4", "escape"]) cx.simulate_shared_keystrokes("shift-g i 4 4 escape").await;
.await; cx.simulate_shared_keystrokes("g ;").await;
cx.simulate_shared_keystrokes(["g", ";"]).await;
cx.assert_state( cx.assert_state(
indoc! { indoc! {
"22 "22
@ -164,7 +159,7 @@ mod test {
}, },
Mode::Normal, Mode::Normal,
); );
cx.simulate_shared_keystrokes(["g", ";"]).await; cx.simulate_shared_keystrokes("g ;").await;
cx.assert_state( cx.assert_state(
indoc! { indoc! {
"2ˇ2 "2ˇ2
@ -182,22 +177,18 @@ mod test {
"one two "one two
three fˇour"}) three fˇour"})
.await; .await;
cx.simulate_shared_keystrokes(["x", "k", "d", "i", "w", "^", "x"]) cx.simulate_shared_keystrokes("x k d i w ^ x").await;
.await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"ˇne• "ˇne•
three fur"}) three fur"});
.await; cx.simulate_shared_keystrokes("2 g ;").await;
cx.simulate_shared_keystrokes(["2", "g", ";"]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"ne• "ne•
three fˇur"}) three fˇur"});
.await; cx.simulate_shared_keystrokes("g ,").await;
cx.simulate_shared_keystrokes(["g", ","]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"ˇne• "ˇne•
three fur"}) three fur"});
.await;
} }
#[gpui::test] #[gpui::test]
@ -207,13 +198,11 @@ mod test {
"one two "one two
three fˇr"}) three fˇr"})
.await; .await;
cx.simulate_shared_keystrokes(["i", "o", "escape", "k", "g", "i"]) cx.simulate_shared_keystrokes("i o escape k g i").await;
.await; cx.simulate_shared_keystrokes("u escape").await;
cx.simulate_shared_keystrokes(["u", "escape"]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"one two "one two
three foˇur"}) three foˇur"});
.await;
} }
#[gpui::test] #[gpui::test]
@ -223,11 +212,9 @@ mod test {
"one two "one two
three fˇr"}) three fˇr"})
.await; .await;
cx.simulate_shared_keystrokes(["i", "o", "escape", "k", "`", "."]) cx.simulate_shared_keystrokes("i o escape k ` .").await;
.await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"one two "one two
three fˇor"}) three fˇor"});
.await;
} }
} }

View File

@ -404,15 +404,14 @@ mod test {
c"}) c"})
.await; .await;
cx.simulate_shared_keystrokes([":", "j", "enter"]).await; cx.simulate_shared_keystrokes(": j enter").await;
// hack: our cursor positionining after a join command is wrong // hack: our cursor positionining after a join command is wrong
cx.simulate_shared_keystrokes(["^"]).await; cx.simulate_shared_keystrokes("^").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"ˇa b "ˇa b
c" c"
}) });
.await;
} }
#[gpui::test] #[gpui::test]
@ -424,12 +423,11 @@ mod test {
b b
c"}) c"})
.await; .await;
cx.simulate_shared_keystrokes([":", "3", "enter"]).await; cx.simulate_shared_keystrokes(": 3 enter").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
a a
b b
ˇc"}) ˇc"});
.await;
} }
#[gpui::test] #[gpui::test]
@ -441,22 +439,17 @@ mod test {
b b
c"}) c"})
.await; .await;
cx.simulate_shared_keystrokes([":", "%", "s", "/", "b", "/", "d", "enter"]) cx.simulate_shared_keystrokes(": % s / b / d enter").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
a a
ˇd ˇd
c"}) c"});
cx.simulate_shared_keystrokes(": % s : . : \\ 0 \\ 0 enter")
.await; .await;
cx.simulate_shared_keystrokes([ cx.shared_state().await.assert_eq(indoc! {"
":", "%", "s", ":", ".", ":", "\\", "0", "\\", "0", "enter",
])
.await;
cx.assert_shared_state(indoc! {"
aa aa
dd dd
ˇcc"}) ˇcc"});
.await;
} }
#[gpui::test] #[gpui::test]
@ -469,22 +462,18 @@ mod test {
a a
c"}) c"})
.await; .await;
cx.simulate_shared_keystrokes([":", "/", "b", "enter"]) cx.simulate_shared_keystrokes(": / b enter").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
a a
ˇb ˇb
a a
c"}) c"});
.await; cx.simulate_shared_keystrokes(": ? a enter").await;
cx.simulate_shared_keystrokes([":", "?", "a", "enter"]) cx.shared_state().await.assert_eq(indoc! {"
.await;
cx.assert_shared_state(indoc! {"
ˇa ˇa
b b
a a
c"}) c"});
.await;
} }
#[gpui::test] #[gpui::test]
@ -493,23 +482,23 @@ mod test {
let path = Path::new("/root/dir/file.rs"); let path = Path::new("/root/dir/file.rs");
let fs = cx.workspace(|workspace, cx| workspace.project().read(cx).fs().clone()); let fs = cx.workspace(|workspace, cx| workspace.project().read(cx).fs().clone());
cx.simulate_keystrokes(["i", "@", "escape"]); cx.simulate_keystrokes("i @ escape");
cx.simulate_keystrokes([":", "w", "enter"]); cx.simulate_keystrokes(": w enter");
assert_eq!(fs.load(&path).await.unwrap(), "@\n"); assert_eq!(fs.load(&path).await.unwrap(), "@\n");
fs.as_fake().insert_file(path, b"oops\n".to_vec()).await; fs.as_fake().insert_file(path, b"oops\n".to_vec()).await;
// conflict! // conflict!
cx.simulate_keystrokes(["i", "@", "escape"]); cx.simulate_keystrokes("i @ escape");
cx.simulate_keystrokes([":", "w", "enter"]); cx.simulate_keystrokes(": w enter");
assert!(cx.has_pending_prompt()); assert!(cx.has_pending_prompt());
// "Cancel" // "Cancel"
cx.simulate_prompt_answer(0); cx.simulate_prompt_answer(0);
assert_eq!(fs.load(&path).await.unwrap(), "oops\n"); assert_eq!(fs.load(&path).await.unwrap(), "oops\n");
assert!(!cx.has_pending_prompt()); assert!(!cx.has_pending_prompt());
// force overwrite // force overwrite
cx.simulate_keystrokes([":", "w", "!", "enter"]); cx.simulate_keystrokes(": w ! enter");
assert!(!cx.has_pending_prompt()); assert!(!cx.has_pending_prompt());
assert_eq!(fs.load(&path).await.unwrap(), "@@\n"); assert_eq!(fs.load(&path).await.unwrap(), "@@\n");
} }
@ -518,13 +507,13 @@ mod test {
async fn test_command_quit(cx: &mut TestAppContext) { async fn test_command_quit(cx: &mut TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await; let mut cx = VimTestContext::new(cx, true).await;
cx.simulate_keystrokes([":", "n", "e", "w", "enter"]); cx.simulate_keystrokes(": n e w enter");
cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 2)); cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 2));
cx.simulate_keystrokes([":", "q", "enter"]); cx.simulate_keystrokes(": q enter");
cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 1)); cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 1));
cx.simulate_keystrokes([":", "n", "e", "w", "enter"]); cx.simulate_keystrokes(": n e w enter");
cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 2)); cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 2));
cx.simulate_keystrokes([":", "q", "a", "enter"]); cx.simulate_keystrokes(": q a enter");
cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 0)); cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 0));
} }
} }

View File

@ -46,11 +46,11 @@ mod test {
#[gpui::test] #[gpui::test]
async fn test_enter_and_exit_insert_mode(cx: &mut gpui::TestAppContext) { async fn test_enter_and_exit_insert_mode(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await; let mut cx = VimTestContext::new(cx, true).await;
cx.simulate_keystroke("i"); cx.simulate_keystrokes("i");
assert_eq!(cx.mode(), Mode::Insert); assert_eq!(cx.mode(), Mode::Insert);
cx.simulate_keystrokes(["T", "e", "s", "t"]); cx.simulate_keystrokes("T e s t");
cx.assert_editor_state("Testˇ"); cx.assert_editor_state("Testˇ");
cx.simulate_keystroke("escape"); cx.simulate_keystrokes("escape");
assert_eq!(cx.mode(), Mode::Normal); assert_eq!(cx.mode(), Mode::Normal);
cx.assert_editor_state("Tesˇt"); cx.assert_editor_state("Tesˇt");
} }
@ -60,38 +60,32 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("ˇhello\n").await; cx.set_shared_state("ˇhello\n").await;
cx.simulate_shared_keystrokes(["5", "i", "-", "escape"]) cx.simulate_shared_keystrokes("5 i - escape").await;
.await;
cx.run_until_parked(); cx.run_until_parked();
cx.assert_shared_state("----ˇ-hello\n").await; cx.shared_state().await.assert_eq("----ˇ-hello\n");
cx.set_shared_state("ˇhello\n").await; cx.set_shared_state("ˇhello\n").await;
cx.simulate_shared_keystrokes(["5", "a", "-", "escape"]) cx.simulate_shared_keystrokes("5 a - escape").await;
.await;
cx.run_until_parked(); cx.run_until_parked();
cx.assert_shared_state("h----ˇ-ello\n").await; cx.shared_state().await.assert_eq("h----ˇ-ello\n");
cx.simulate_shared_keystrokes(["4", "shift-i", "-", "escape"]) cx.simulate_shared_keystrokes("4 shift-i - escape").await;
.await;
cx.run_until_parked(); cx.run_until_parked();
cx.assert_shared_state("---ˇ-h-----ello\n").await; cx.shared_state().await.assert_eq("---ˇ-h-----ello\n");
cx.simulate_shared_keystrokes(["3", "shift-a", "-", "escape"]) cx.simulate_shared_keystrokes("3 shift-a - escape").await;
.await;
cx.run_until_parked(); cx.run_until_parked();
cx.assert_shared_state("----h-----ello--ˇ-\n").await; cx.shared_state().await.assert_eq("----h-----ello--ˇ-\n");
cx.set_shared_state("ˇhello\n").await; cx.set_shared_state("ˇhello\n").await;
cx.simulate_shared_keystrokes(["3", "o", "o", "i", "escape"]) cx.simulate_shared_keystrokes("3 o o i escape").await;
.await;
cx.run_until_parked(); cx.run_until_parked();
cx.assert_shared_state("hello\noi\noi\noˇi\n").await; cx.shared_state().await.assert_eq("hello\noi\noi\noˇi\n");
cx.set_shared_state("ˇhello\n").await; cx.set_shared_state("ˇhello\n").await;
cx.simulate_shared_keystrokes(["3", "shift-o", "o", "i", "escape"]) cx.simulate_shared_keystrokes("3 shift-o o i escape").await;
.await;
cx.run_until_parked(); cx.run_until_parked();
cx.assert_shared_state("oi\noi\noˇi\nhello\n").await; cx.shared_state().await.assert_eq("oi\noi\noˇi\nhello\n");
} }
#[gpui::test] #[gpui::test]
@ -99,27 +93,29 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("ˇhello\n").await; cx.set_shared_state("ˇhello\n").await;
cx.simulate_shared_keystrokes(["3", "i", "-", "escape"]) cx.simulate_shared_keystrokes("3 i - escape").await;
.await;
cx.run_until_parked(); cx.run_until_parked();
cx.assert_shared_state("--ˇ-hello\n").await; cx.shared_state().await.assert_eq("--ˇ-hello\n");
cx.simulate_shared_keystrokes(["."]).await; cx.simulate_shared_keystrokes(".").await;
cx.run_until_parked(); cx.run_until_parked();
cx.assert_shared_state("----ˇ--hello\n").await; cx.shared_state().await.assert_eq("----ˇ--hello\n");
cx.simulate_shared_keystrokes(["2", "."]).await; cx.simulate_shared_keystrokes("2 .").await;
cx.run_until_parked(); cx.run_until_parked();
cx.assert_shared_state("-----ˇ---hello\n").await; cx.shared_state().await.assert_eq("-----ˇ---hello\n");
cx.set_shared_state("ˇhello\n").await; cx.set_shared_state("ˇhello\n").await;
cx.simulate_shared_keystrokes(["2", "o", "k", "k", "escape"]) cx.simulate_shared_keystrokes("2 o k k escape").await;
.await;
cx.run_until_parked(); cx.run_until_parked();
cx.assert_shared_state("hello\nkk\nkˇk\n").await; cx.shared_state().await.assert_eq("hello\nkk\nkˇk\n");
cx.simulate_shared_keystrokes(["."]).await; cx.simulate_shared_keystrokes(".").await;
cx.run_until_parked(); cx.run_until_parked();
cx.assert_shared_state("hello\nkk\nkk\nkk\nkˇk\n").await; cx.shared_state()
cx.simulate_shared_keystrokes(["1", "."]).await; .await
.assert_eq("hello\nkk\nkk\nkk\nkˇk\n");
cx.simulate_shared_keystrokes("1 .").await;
cx.run_until_parked(); cx.run_until_parked();
cx.assert_shared_state("hello\nkk\nkk\nkk\nkk\nkˇk\n").await; cx.shared_state()
.await
.assert_eq("hello\nkk\nkk\nkk\nkk\nkˇk\n");
} }
} }

View File

@ -1779,8 +1779,8 @@ mod test {
// goes down once // goes down once
cx.set_shared_state(initial_state).await; cx.set_shared_state(initial_state).await;
cx.simulate_shared_keystrokes(["}"]).await; cx.simulate_shared_keystrokes("}").await;
cx.assert_shared_state(indoc! {r"abc cx.shared_state().await.assert_eq(indoc! {r"abc
def def
ˇ ˇ
paragraph paragraph
@ -1789,16 +1789,15 @@ mod test {
third and third and
final"}) final"});
.await;
// goes up once // goes up once
cx.simulate_shared_keystrokes(["{"]).await; cx.simulate_shared_keystrokes("{").await;
cx.assert_shared_state(initial_state).await; cx.shared_state().await.assert_eq(initial_state);
// goes down twice // goes down twice
cx.simulate_shared_keystrokes(["2", "}"]).await; cx.simulate_shared_keystrokes("2 }").await;
cx.assert_shared_state(indoc! {r"abc cx.shared_state().await.assert_eq(indoc! {r"abc
def def
paragraph paragraph
@ -1807,12 +1806,11 @@ mod test {
third and third and
final"}) final"});
.await;
// goes down over multiple blanks // goes down over multiple blanks
cx.simulate_shared_keystrokes(["}"]).await; cx.simulate_shared_keystrokes("}").await;
cx.assert_shared_state(indoc! {r"abc cx.shared_state().await.assert_eq(indoc! {r"abc
def def
paragraph paragraph
@ -1821,12 +1819,11 @@ mod test {
third and third and
finaˇl"}) finaˇl"});
.await;
// goes up twice // goes up twice
cx.simulate_shared_keystrokes(["2", "{"]).await; cx.simulate_shared_keystrokes("2 {").await;
cx.assert_shared_state(indoc! {r"abc cx.shared_state().await.assert_eq(indoc! {r"abc
def def
ˇ ˇ
paragraph paragraph
@ -1835,8 +1832,7 @@ mod test {
third and third and
final"}) final"});
.await
} }
#[gpui::test] #[gpui::test]
@ -1847,39 +1843,41 @@ mod test {
do(something(with<Types>.and_arrays[0, 2])) do(something(with<Types>.and_arrays[0, 2]))
}"}) }"})
.await; .await;
cx.simulate_shared_keystrokes(["%"]).await; cx.simulate_shared_keystrokes("%").await;
cx.assert_shared_state(indoc! {r"func (a stringˇ) { cx.shared_state()
.await
.assert_eq(indoc! {r"func (a stringˇ) {
do(something(with<Types>.and_arrays[0, 2])) do(something(with<Types>.and_arrays[0, 2]))
}"}) }"});
.await;
// test it works on the last character of the line // test it works on the last character of the line
cx.set_shared_state(indoc! {r"func (a string) ˇ{ cx.set_shared_state(indoc! {r"func (a string) ˇ{
do(something(with<Types>.and_arrays[0, 2])) do(something(with<Types>.and_arrays[0, 2]))
}"}) }"})
.await; .await;
cx.simulate_shared_keystrokes(["%"]).await; cx.simulate_shared_keystrokes("%").await;
cx.assert_shared_state(indoc! {r"func (a string) { cx.shared_state()
.await
.assert_eq(indoc! {r"func (a string) {
do(something(with<Types>.and_arrays[0, 2])) do(something(with<Types>.and_arrays[0, 2]))
ˇ}"}) ˇ}"});
.await;
// test it works on immediate nesting // test it works on immediate nesting
cx.set_shared_state("ˇ{()}").await; cx.set_shared_state("ˇ{()}").await;
cx.simulate_shared_keystrokes(["%"]).await; cx.simulate_shared_keystrokes("%").await;
cx.assert_shared_state("{()ˇ}").await; cx.shared_state().await.assert_eq("{()ˇ}");
cx.simulate_shared_keystrokes(["%"]).await; cx.simulate_shared_keystrokes("%").await;
cx.assert_shared_state("ˇ{()}").await; cx.shared_state().await.assert_eq("ˇ{()}");
// test it works on immediate nesting inside braces // test it works on immediate nesting inside braces
cx.set_shared_state("{\n ˇ{()}\n}").await; cx.set_shared_state("{\n ˇ{()}\n}").await;
cx.simulate_shared_keystrokes(["%"]).await; cx.simulate_shared_keystrokes("%").await;
cx.assert_shared_state("{\n {()ˇ}\n}").await; cx.shared_state().await.assert_eq("{\n {()ˇ}\n}");
// test it jumps to the next paren on a line // test it jumps to the next paren on a line
cx.set_shared_state("func ˇboop() {\n}").await; cx.set_shared_state("func ˇboop() {\n}").await;
cx.simulate_shared_keystrokes(["%"]).await; cx.simulate_shared_keystrokes("%").await;
cx.assert_shared_state("func boop(ˇ) {\n}").await; cx.shared_state().await.assert_eq("func boop(ˇ) {\n}");
} }
#[gpui::test] #[gpui::test]
@ -1888,33 +1886,33 @@ mod test {
// f and F // f and F
cx.set_shared_state("ˇone two three four").await; cx.set_shared_state("ˇone two three four").await;
cx.simulate_shared_keystrokes(["f", "o"]).await; cx.simulate_shared_keystrokes("f o").await;
cx.assert_shared_state("one twˇo three four").await; cx.shared_state().await.assert_eq("one twˇo three four");
cx.simulate_shared_keystrokes([","]).await; cx.simulate_shared_keystrokes(",").await;
cx.assert_shared_state("ˇone two three four").await; cx.shared_state().await.assert_eq("ˇone two three four");
cx.simulate_shared_keystrokes(["2", ";"]).await; cx.simulate_shared_keystrokes("2 ;").await;
cx.assert_shared_state("one two three fˇour").await; cx.shared_state().await.assert_eq("one two three fˇour");
cx.simulate_shared_keystrokes(["shift-f", "e"]).await; cx.simulate_shared_keystrokes("shift-f e").await;
cx.assert_shared_state("one two threˇe four").await; cx.shared_state().await.assert_eq("one two threˇe four");
cx.simulate_shared_keystrokes(["2", ";"]).await; cx.simulate_shared_keystrokes("2 ;").await;
cx.assert_shared_state("onˇe two three four").await; cx.shared_state().await.assert_eq("onˇe two three four");
cx.simulate_shared_keystrokes([","]).await; cx.simulate_shared_keystrokes(",").await;
cx.assert_shared_state("one two thrˇee four").await; cx.shared_state().await.assert_eq("one two thrˇee four");
// t and T // t and T
cx.set_shared_state("ˇone two three four").await; cx.set_shared_state("ˇone two three four").await;
cx.simulate_shared_keystrokes(["t", "o"]).await; cx.simulate_shared_keystrokes("t o").await;
cx.assert_shared_state("one tˇwo three four").await; cx.shared_state().await.assert_eq("one tˇwo three four");
cx.simulate_shared_keystrokes([","]).await; cx.simulate_shared_keystrokes(",").await;
cx.assert_shared_state("oˇne two three four").await; cx.shared_state().await.assert_eq("oˇne two three four");
cx.simulate_shared_keystrokes(["2", ";"]).await; cx.simulate_shared_keystrokes("2 ;").await;
cx.assert_shared_state("one two three ˇfour").await; cx.shared_state().await.assert_eq("one two three ˇfour");
cx.simulate_shared_keystrokes(["shift-t", "e"]).await; cx.simulate_shared_keystrokes("shift-t e").await;
cx.assert_shared_state("one two threeˇ four").await; cx.shared_state().await.assert_eq("one two threeˇ four");
cx.simulate_shared_keystrokes(["3", ";"]).await; cx.simulate_shared_keystrokes("3 ;").await;
cx.assert_shared_state("oneˇ two three four").await; cx.shared_state().await.assert_eq("oneˇ two three four");
cx.simulate_shared_keystrokes([","]).await; cx.simulate_shared_keystrokes(",").await;
cx.assert_shared_state("one two thˇree four").await; cx.shared_state().await.assert_eq("one two thˇree four");
} }
#[gpui::test] #[gpui::test]
@ -1922,26 +1920,26 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
let initial_state = indoc! {r"something(ˇfoo)"}; let initial_state = indoc! {r"something(ˇfoo)"};
cx.set_shared_state(initial_state).await; cx.set_shared_state(initial_state).await;
cx.simulate_shared_keystrokes(["}"]).await; cx.simulate_shared_keystrokes("}").await;
cx.assert_shared_state(indoc! {r"something(fooˇ)"}).await; cx.shared_state().await.assert_eq("something(fooˇ)");
} }
#[gpui::test] #[gpui::test]
async fn test_next_line_start(cx: &mut gpui::TestAppContext) { async fn test_next_line_start(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("ˇone\n two\nthree").await; cx.set_shared_state("ˇone\n two\nthree").await;
cx.simulate_shared_keystrokes(["enter"]).await; cx.simulate_shared_keystrokes("enter").await;
cx.assert_shared_state("one\n ˇtwo\nthree").await; cx.shared_state().await.assert_eq("one\n ˇtwo\nthree");
} }
#[gpui::test] #[gpui::test]
async fn test_end_of_line_downward(cx: &mut gpui::TestAppContext) { async fn test_end_of_line_downward(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("ˇ one \n two \nthree").await; cx.set_shared_state("ˇ one \n two \nthree").await;
cx.simulate_shared_keystrokes(["g", "_"]).await; cx.simulate_shared_keystrokes("g _").await;
cx.assert_shared_state(" onˇe \n two \nthree").await; cx.shared_state().await.assert_eq(" onˇe \n two \nthree");
cx.simulate_shared_keystrokes(["2", "g", "_"]).await; cx.simulate_shared_keystrokes("2 g _").await;
cx.assert_shared_state(" one \n twˇo \nthree").await; cx.shared_state().await.assert_eq(" one \n twˇo \nthree");
} }
#[gpui::test] #[gpui::test]
@ -1955,14 +1953,13 @@ mod test {
final"}; final"};
cx.set_shared_state(initial_state).await; cx.set_shared_state(initial_state).await;
cx.simulate_shared_keystrokes(["shift-h"]).await; cx.simulate_shared_keystrokes("shift-h").await;
cx.assert_shared_state(indoc! {r"abˇc cx.shared_state().await.assert_eq(indoc! {r"abˇc
def def
paragraph paragraph
the second the second
third and third and
final"}) final"});
.await;
// clip point // clip point
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
@ -1971,13 +1968,12 @@ mod test {
7 8 ˇ9 7 8 ˇ9
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["shift-h"]).await; cx.simulate_shared_keystrokes("shift-h").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
1 2 ˇ3 1 2 ˇ3
4 5 6 4 5 6
7 8 9 7 8 9
"}) "});
.await;
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
1 2 3 1 2 3
@ -1985,25 +1981,23 @@ mod test {
ˇ7 8 9 ˇ7 8 9
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["shift-h"]).await; cx.simulate_shared_keystrokes("shift-h").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
ˇ1 2 3 ˇ1 2 3
4 5 6 4 5 6
7 8 9 7 8 9
"}) "});
.await;
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
1 2 3 1 2 3
4 5 ˇ6 4 5 ˇ6
7 8 9"}) 7 8 9"})
.await; .await;
cx.simulate_shared_keystrokes(["9", "shift-h"]).await; cx.simulate_shared_keystrokes("9 shift-h").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
1 2 3 1 2 3
4 5 6 4 5 6
7 8 ˇ9"}) 7 8 ˇ9"});
.await;
} }
#[gpui::test] #[gpui::test]
@ -2017,14 +2011,13 @@ mod test {
final"}; final"};
cx.set_shared_state(initial_state).await; cx.set_shared_state(initial_state).await;
cx.simulate_shared_keystrokes(["shift-m"]).await; cx.simulate_shared_keystrokes("shift-m").await;
cx.assert_shared_state(indoc! {r"abc cx.shared_state().await.assert_eq(indoc! {r"abc
def def
paˇragraph paˇragraph
the second the second
third and third and
final"}) final"});
.await;
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
1 2 3 1 2 3
@ -2032,65 +2025,60 @@ mod test {
7 8 ˇ9 7 8 ˇ9
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["shift-m"]).await; cx.simulate_shared_keystrokes("shift-m").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
1 2 3 1 2 3
4 5 ˇ6 4 5 ˇ6
7 8 9 7 8 9
"}) "});
.await;
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
1 2 3 1 2 3
4 5 6 4 5 6
ˇ7 8 9 ˇ7 8 9
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["shift-m"]).await; cx.simulate_shared_keystrokes("shift-m").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
1 2 3 1 2 3
ˇ4 5 6 ˇ4 5 6
7 8 9 7 8 9
"}) "});
.await;
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
ˇ1 2 3 ˇ1 2 3
4 5 6 4 5 6
7 8 9 7 8 9
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["shift-m"]).await; cx.simulate_shared_keystrokes("shift-m").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
1 2 3 1 2 3
ˇ4 5 6 ˇ4 5 6
7 8 9 7 8 9
"}) "});
.await;
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
1 2 3 1 2 3
ˇ4 5 6 ˇ4 5 6
7 8 9 7 8 9
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["shift-m"]).await; cx.simulate_shared_keystrokes("shift-m").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
1 2 3 1 2 3
ˇ4 5 6 ˇ4 5 6
7 8 9 7 8 9
"}) "});
.await;
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
1 2 3 1 2 3
4 5 ˇ6 4 5 ˇ6
7 8 9 7 8 9
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["shift-m"]).await; cx.simulate_shared_keystrokes("shift-m").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
1 2 3 1 2 3
4 5 ˇ6 4 5 ˇ6
7 8 9 7 8 9
"}) "});
.await;
} }
#[gpui::test] #[gpui::test]
@ -2104,14 +2092,13 @@ mod test {
final"}; final"};
cx.set_shared_state(initial_state).await; cx.set_shared_state(initial_state).await;
cx.simulate_shared_keystrokes(["shift-l"]).await; cx.simulate_shared_keystrokes("shift-l").await;
cx.assert_shared_state(indoc! {r"abc cx.shared_state().await.assert_eq(indoc! {r"abc
def def
paragraph paragraph
the second the second
third and third and
fiˇnal"}) fiˇnal"});
.await;
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
1 2 3 1 2 3
@ -2119,13 +2106,12 @@ mod test {
7 8 9 7 8 9
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["shift-l"]).await; cx.simulate_shared_keystrokes("shift-l").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
1 2 3 1 2 3
4 5 6 4 5 6
7 8 9 7 8 9
ˇ"}) ˇ"});
.await;
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
1 2 3 1 2 3
@ -2133,13 +2119,12 @@ mod test {
7 8 9 7 8 9
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["shift-l"]).await; cx.simulate_shared_keystrokes("shift-l").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
1 2 3 1 2 3
4 5 6 4 5 6
7 8 9 7 8 9
ˇ"}) ˇ"});
.await;
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
1 2 ˇ3 1 2 ˇ3
@ -2147,13 +2132,12 @@ mod test {
7 8 9 7 8 9
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["shift-l"]).await; cx.simulate_shared_keystrokes("shift-l").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
1 2 3 1 2 3
4 5 6 4 5 6
7 8 9 7 8 9
ˇ"}) ˇ"});
.await;
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
ˇ1 2 3 ˇ1 2 3
@ -2161,13 +2145,12 @@ mod test {
7 8 9 7 8 9
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["shift-l"]).await; cx.simulate_shared_keystrokes("shift-l").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
1 2 3 1 2 3
4 5 6 4 5 6
7 8 9 7 8 9
ˇ"}) ˇ"});
.await;
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
1 2 3 1 2 3
@ -2175,13 +2158,12 @@ mod test {
7 8 9 7 8 9
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["9", "shift-l"]).await; cx.simulate_shared_keystrokes("9 shift-l").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
1 2 ˇ3 1 2 ˇ3
4 5 6 4 5 6
7 8 9 7 8 9
"}) "});
.await;
} }
#[gpui::test] #[gpui::test]
@ -2191,11 +2173,10 @@ mod test {
456 5ˇ67 678 456 5ˇ67 678
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["g", "e"]).await; cx.simulate_shared_keystrokes("g e").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
45ˇ6 567 678 45ˇ6 567 678
"}) "});
.await;
// Test times // Test times
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
@ -2203,12 +2184,11 @@ mod test {
456 5ˇ67 678 456 5ˇ67 678
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["4", "g", "e"]).await; cx.simulate_shared_keystrokes("4 g e").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
12ˇ3 234 345 12ˇ3 234 345
456 567 678 456 567 678
"}) "});
.await;
// With punctuation // With punctuation
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
@ -2217,13 +2197,12 @@ mod test {
789 890 901 789 890 901
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["g", "e"]).await; cx.simulate_shared_keystrokes("g e").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
123 234 345 123 234 345
4;5.ˇ6 567 678 4;5.ˇ6 567 678
789 890 901 789 890 901
"}) "});
.await;
// With punctuation and count // With punctuation and count
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
@ -2232,13 +2211,12 @@ mod test {
789 890 901 789 890 901
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["5", "g", "e"]).await; cx.simulate_shared_keystrokes("5 g e").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
123 234 345 123 234 345
ˇ4;5.6 567 678 ˇ4;5.6 567 678
789 890 901 789 890 901
"}) "});
.await;
// newlines // newlines
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
@ -2247,20 +2225,18 @@ mod test {
78ˇ9 890 901 78ˇ9 890 901
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["g", "e"]).await; cx.simulate_shared_keystrokes("g e").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
123 234 345 123 234 345
ˇ ˇ
789 890 901 789 890 901
"}) "});
.await; cx.simulate_shared_keystrokes("g e").await;
cx.simulate_shared_keystrokes(["g", "e"]).await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {r"
123 234 34ˇ5 123 234 34ˇ5
789 890 901 789 890 901
"}) "});
.await;
// With punctuation // With punctuation
cx.set_shared_state(indoc! {r" cx.set_shared_state(indoc! {r"
@ -2269,13 +2245,12 @@ mod test {
789 890 901 789 890 901
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["g", "shift-e"]).await; cx.simulate_shared_keystrokes("g shift-e").await;
cx.assert_shared_state(indoc! {r" cx.shared_state().await.assert_eq(indoc! {"
123 234 34ˇ5 123 234 34ˇ5
4;5.6 567 678 4;5.6 567 678
789 890 901 789 890 901
"}) "});
.await;
} }
#[gpui::test] #[gpui::test]
@ -2288,12 +2263,11 @@ mod test {
} }
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["v", "$", "%"]).await; cx.simulate_shared_keystrokes("v $ %").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
fn a«() { fn a«() {
return return
}ˇ» }ˇ»
"}) "});
.await;
} }
} }

View File

@ -443,24 +443,30 @@ mod test {
#[gpui::test] #[gpui::test]
async fn test_h(cx: &mut gpui::TestAppContext) { async fn test_h(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["h"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"h",
indoc! {"
ˇThe qˇuick ˇThe qˇuick
ˇbrown" ˇbrown"
}) },
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_backspace(cx: &mut gpui::TestAppContext) { async fn test_backspace(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx) let mut cx = NeovimBackedTestContext::new(cx).await;
.await cx.simulate_at_each_offset(
.binding(["backspace"]); "backspace",
cx.assert_all(indoc! {" indoc! {"
ˇThe qˇuick ˇThe qˇuick
ˇbrown" ˇbrown"
}) },
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
@ -468,320 +474,426 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
aaˇaa aaˇaa
😃😃" 😃😃"
})
.await;
cx.simulate_shared_keystrokes(["j"]).await;
cx.assert_shared_state(indoc! {"
aaaa
😃ˇ😃"
}) })
.await; .await;
cx.simulate_shared_keystrokes("j").await;
cx.shared_state().await.assert_eq(indoc! {"
aaaa
😃ˇ😃"
});
for marked_position in cx.each_marked_position(indoc! {" cx.simulate_at_each_offset(
ˇThe qˇuick broˇwn "j",
ˇfox jumps" indoc! {"
}) { ˇThe qˇuick broˇwn
cx.assert_neovim_compatible(&marked_position, ["j"]).await; ˇfox jumps"
} },
)
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_enter(cx: &mut gpui::TestAppContext) { async fn test_enter(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["enter"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"enter",
indoc! {"
ˇThe qˇuick broˇwn ˇThe qˇuick broˇwn
ˇfox jumps" ˇfox jumps"
}) },
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_k(cx: &mut gpui::TestAppContext) { async fn test_k(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["k"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"k",
indoc! {"
ˇThe qˇuick ˇThe qˇuick
ˇbrown fˇox jumˇps" ˇbrown fˇox jumˇps"
}) },
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_l(cx: &mut gpui::TestAppContext) { async fn test_l(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["l"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"l",
indoc! {"
ˇThe qˇuicˇk ˇThe qˇuicˇk
ˇbrowˇn"}) ˇbrowˇn"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_jump_to_line_boundaries(cx: &mut gpui::TestAppContext) { async fn test_jump_to_line_boundaries(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_binding_matches_all( cx.simulate_at_each_offset(
["$"], "$",
indoc! {" indoc! {"
ˇThe qˇuicˇk ˇThe qˇuicˇk
ˇbrowˇn"}, ˇbrowˇn"},
) )
.await; .await
cx.assert_binding_matches_all( .assert_matches();
["0"], cx.simulate_at_each_offset(
"0",
indoc! {" indoc! {"
ˇThe qˇuicˇk ˇThe qˇuicˇk
ˇbrowˇn"}, ˇbrowˇn"},
) )
.await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_jump_to_end(cx: &mut gpui::TestAppContext) { async fn test_jump_to_end(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["shift-g"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"shift-g",
indoc! {"
The ˇquick The ˇquick
brown fox jumps brown fox jumps
overˇ the lazy doˇg"}) overˇ the lazy doˇg"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"shift-g",
indoc! {"
The quiˇck The quiˇck
brown"}) brown"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"shift-g",
indoc! {"
The quiˇck The quiˇck
"}) "},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_w(cx: &mut gpui::TestAppContext) { async fn test_w(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["w"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"w",
indoc! {"
The ˇquickˇ-ˇbrown The ˇquickˇ-ˇbrown
ˇ ˇ
ˇ ˇ
ˇfox_jumps ˇover ˇfox_jumps ˇover
ˇthˇe"}) ˇthˇe"},
.await; )
let mut cx = cx.binding(["shift-w"]); .await
cx.assert_all(indoc! {" .assert_matches();
cx.simulate_at_each_offset(
"shift-w",
indoc! {"
The ˇquickˇ-ˇbrown The ˇquickˇ-ˇbrown
ˇ ˇ
ˇ ˇ
ˇfox_jumps ˇover ˇfox_jumps ˇover
ˇthˇe"}) ˇthˇe"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_end_of_word(cx: &mut gpui::TestAppContext) { async fn test_end_of_word(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["e"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"e",
indoc! {"
Thˇe quicˇkˇ-browˇn Thˇe quicˇkˇ-browˇn
fox_jumpˇs oveˇr fox_jumpˇs oveˇr
thˇe"}) thˇe"},
.await; )
let mut cx = cx.binding(["shift-e"]); .await
cx.assert_all(indoc! {" .assert_matches();
cx.simulate_at_each_offset(
"shift-e",
indoc! {"
Thˇe quicˇkˇ-browˇn Thˇe quicˇkˇ-browˇn
fox_jumpˇs oveˇr fox_jumpˇs oveˇr
thˇe"}) thˇe"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_b(cx: &mut gpui::TestAppContext) { async fn test_b(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["b"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"b",
indoc! {"
ˇThe ˇquickˇ-ˇbrown ˇThe ˇquickˇ-ˇbrown
ˇ ˇ
ˇ ˇ
ˇfox_jumps ˇover ˇfox_jumps ˇover
ˇthe"}) ˇthe"},
.await; )
let mut cx = cx.binding(["shift-b"]); .await
cx.assert_all(indoc! {" .assert_matches();
cx.simulate_at_each_offset(
"shift-b",
indoc! {"
ˇThe ˇquickˇ-ˇbrown ˇThe ˇquickˇ-ˇbrown
ˇ ˇ
ˇ ˇ
ˇfox_jumps ˇover ˇfox_jumps ˇover
ˇthe"}) ˇthe"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_gg(cx: &mut gpui::TestAppContext) { async fn test_gg(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_binding_matches_all( cx.simulate_at_each_offset(
["g", "g"], "g g",
indoc! {" indoc! {"
The qˇuick The qˇuick
brown fox jumps brown fox jumps
over ˇthe laˇzy dog"}, over ˇthe laˇzy dog"},
) )
.await; .await
cx.assert_binding_matches( .assert_matches();
["g", "g"], cx.simulate(
"g g",
indoc! {" indoc! {"
brown fox jumps brown fox jumps
over the laˇzy dog"}, over the laˇzy dog"},
) )
.await; .await
cx.assert_binding_matches( .assert_matches();
["2", "g", "g"], cx.simulate(
"2 g g",
indoc! {" indoc! {"
ˇ ˇ
brown fox jumps brown fox jumps
over the lazydog"}, over the lazydog"},
) )
.await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_end_of_document(cx: &mut gpui::TestAppContext) { async fn test_end_of_document(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_binding_matches_all( cx.simulate_at_each_offset(
["shift-g"], "shift-g",
indoc! {" indoc! {"
The qˇuick The qˇuick
brown fox jumps brown fox jumps
over ˇthe laˇzy dog"}, over ˇthe laˇzy dog"},
) )
.await; .await
cx.assert_binding_matches( .assert_matches();
["shift-g"], cx.simulate(
"shift-g",
indoc! {" indoc! {"
brown fox jumps brown fox jumps
over the laˇzy dog"}, over the laˇzy dog"},
) )
.await; .await
cx.assert_binding_matches( .assert_matches();
["2", "shift-g"], cx.simulate(
"2 shift-g",
indoc! {" indoc! {"
ˇ ˇ
brown fox jumps brown fox jumps
over the lazydog"}, over the lazydog"},
) )
.await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_a(cx: &mut gpui::TestAppContext) { async fn test_a(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["a"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all("The qˇuicˇk").await; cx.simulate_at_each_offset("a", "The qˇuicˇk")
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_insert_end_of_line(cx: &mut gpui::TestAppContext) { async fn test_insert_end_of_line(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["shift-a"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"shift-a",
indoc! {"
ˇ ˇ
The qˇuick The qˇuick
brown ˇfox "}) brown ˇfox "},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_jump_to_first_non_whitespace(cx: &mut gpui::TestAppContext) { async fn test_jump_to_first_non_whitespace(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["^"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert("The qˇuick").await; cx.simulate("^", "The qˇuick").await.assert_matches();
cx.assert(" The qˇuick").await; cx.simulate("^", " The qˇuick").await.assert_matches();
cx.assert("ˇ").await; cx.simulate("^", "ˇ").await.assert_matches();
cx.assert(indoc! {" cx.simulate(
"^",
indoc! {"
The qˇuick The qˇuick
brown fox"}) brown fox"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"^",
indoc! {"
ˇ ˇ
The quick"}) The quick"},
.await; )
.await
.assert_matches();
// Indoc disallows trailing whitespace. // Indoc disallows trailing whitespace.
cx.assert(" ˇ \nThe quick").await; cx.simulate("^", " ˇ \nThe quick").await.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_insert_first_non_whitespace(cx: &mut gpui::TestAppContext) { async fn test_insert_first_non_whitespace(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["shift-i"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert("The qˇuick").await; cx.simulate("shift-i", "The qˇuick").await.assert_matches();
cx.assert(" The qˇuick").await; cx.simulate("shift-i", " The qˇuick").await.assert_matches();
cx.assert("ˇ").await; cx.simulate("shift-i", "ˇ").await.assert_matches();
cx.assert(indoc! {" cx.simulate(
"shift-i",
indoc! {"
The qˇuick The qˇuick
brown fox"}) brown fox"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"shift-i",
indoc! {"
ˇ ˇ
The quick"}) The quick"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_to_end_of_line(cx: &mut gpui::TestAppContext) { async fn test_delete_to_end_of_line(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["shift-d"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert(indoc! {" cx.simulate(
"shift-d",
indoc! {"
The qˇuick The qˇuick
brown fox"}) brown fox"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"shift-d",
indoc! {"
The quick The quick
ˇ ˇ
brown fox"}) brown fox"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_x(cx: &mut gpui::TestAppContext) { async fn test_x(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["x"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all("ˇTeˇsˇt").await; cx.simulate_at_each_offset("x", "ˇTeˇsˇt")
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"x",
indoc! {"
Tesˇt Tesˇt
test"}) test"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_left(cx: &mut gpui::TestAppContext) { async fn test_delete_left(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["shift-x"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all("ˇTˇeˇsˇt").await; cx.simulate_at_each_offset("shift-x", "ˇTˇeˇsˇt")
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"shift-x",
indoc! {"
Test Test
ˇtest"}) ˇtest"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_o(cx: &mut gpui::TestAppContext) { async fn test_o(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["o"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert("ˇ").await; cx.simulate("o", "ˇ").await.assert_matches();
cx.assert("The ˇquick").await; cx.simulate("o", "The ˇquick").await.assert_matches();
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"o",
indoc! {"
The qˇuick The qˇuick
brown ˇfox brown ˇfox
jumps ˇover"}) jumps ˇover"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"o",
indoc! {"
The quick The quick
ˇ ˇ
brown fox"}) brown fox"},
.await; )
.await
.assert_matches();
cx.assert_manual( cx.assert_binding(
"o",
indoc! {" indoc! {"
fn test() { fn test() {
println!(ˇ); println!(ˇ);
@ -795,7 +907,8 @@ mod test {
Mode::Insert, Mode::Insert,
); );
cx.assert_manual( cx.assert_binding(
"o",
indoc! {" indoc! {"
fn test(ˇ) { fn test(ˇ) {
println!(); println!();
@ -812,23 +925,31 @@ mod test {
#[gpui::test] #[gpui::test]
async fn test_insert_line_above(cx: &mut gpui::TestAppContext) { async fn test_insert_line_above(cx: &mut gpui::TestAppContext) {
let cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
let mut cx = cx.binding(["shift-o"]); cx.simulate("shift-o", "ˇ").await.assert_matches();
cx.assert("ˇ").await; cx.simulate("shift-o", "The ˇquick").await.assert_matches();
cx.assert("The ˇquick").await; cx.simulate_at_each_offset(
cx.assert_all(indoc! {" "shift-o",
indoc! {"
The qˇuick The qˇuick
brown ˇfox brown ˇfox
jumps ˇover"}) jumps ˇover"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"shift-o",
indoc! {"
The quick The quick
ˇ ˇ
brown fox"}) brown fox"},
.await; )
.await
.assert_matches();
// Our indentation is smarter than vims. So we don't match here // Our indentation is smarter than vims. So we don't match here
cx.assert_manual( cx.assert_binding(
"shift-o",
indoc! {" indoc! {"
fn test() { fn test() {
println!(ˇ); println!(ˇ);
@ -841,7 +962,8 @@ mod test {
}"}, }"},
Mode::Insert, Mode::Insert,
); );
cx.assert_manual( cx.assert_binding(
"shift-o",
indoc! {" indoc! {"
fn test(ˇ) { fn test(ˇ) {
println!(); println!();
@ -859,40 +981,51 @@ mod test {
#[gpui::test] #[gpui::test]
async fn test_dd(cx: &mut gpui::TestAppContext) { async fn test_dd(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_neovim_compatible("ˇ", ["d", "d"]).await; cx.simulate("d d", "ˇ").await.assert_matches();
cx.assert_neovim_compatible("The ˇquick", ["d", "d"]).await; cx.simulate("d d", "The ˇquick").await.assert_matches();
for marked_text in cx.each_marked_position(indoc! {" cx.simulate_at_each_offset(
"d d",
indoc! {"
The qˇuick The qˇuick
brown ˇfox brown ˇfox
jumps ˇover"}) jumps ˇover"},
{ )
cx.assert_neovim_compatible(&marked_text, ["d", "d"]).await; .await
} .assert_matches();
cx.assert_neovim_compatible( cx.simulate(
"d d",
indoc! {" indoc! {"
The quick The quick
ˇ ˇ
brown fox"}, brown fox"},
["d", "d"],
) )
.await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_cc(cx: &mut gpui::TestAppContext) { async fn test_cc(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "c"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert("ˇ").await; cx.simulate("c c", "ˇ").await.assert_matches();
cx.assert("The ˇquick").await; cx.simulate("c c", "The ˇquick").await.assert_matches();
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"c c",
indoc! {"
The quˇick The quˇick
brown ˇfox brown ˇfox
jumps ˇover"}) jumps ˇover"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"c c",
indoc! {"
The quick The quick
ˇ ˇ
brown fox"}) brown fox"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
@ -900,8 +1033,8 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
for count in 1..=5 { for count in 1..=5 {
cx.assert_binding_matches_all( cx.simulate_at_each_offset(
[&count.to_string(), "w"], &format!("{count} w"),
indoc! {" indoc! {"
ˇThe quˇickˇ browˇn ˇThe quˇickˇ browˇn
ˇ ˇ
@ -909,14 +1042,17 @@ mod test {
ˇthe lazy dog ˇthe lazy dog
"}, "},
) )
.await; .await
.assert_matches();
} }
} }
#[gpui::test] #[gpui::test]
async fn test_h_through_unicode(cx: &mut gpui::TestAppContext) { async fn test_h_through_unicode(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["h"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all("Testˇ├ˇ──ˇ┐ˇTest").await; cx.simulate_at_each_offset("h", "Testˇ├ˇ──ˇ┐ˇTest")
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
@ -931,11 +1067,13 @@ mod test {
ˇb ˇb
"}; "};
cx.assert_binding_matches_all([&count.to_string(), "f", "b"], test_case) cx.simulate_at_each_offset(&format!("{count} f b"), test_case)
.await; .await
.assert_matches();
cx.assert_binding_matches_all([&count.to_string(), "t", "b"], test_case) cx.simulate_at_each_offset(&format!("{count} t b"), test_case)
.await; .await
.assert_matches();
} }
} }
@ -951,11 +1089,13 @@ mod test {
}; };
for count in 1..=3 { for count in 1..=3 {
cx.assert_binding_matches_all([&count.to_string(), "shift-f", "b"], test_case) cx.simulate_at_each_offset(&format!("{count} shift-f b"), test_case)
.await; .await
.assert_matches();
cx.assert_binding_matches_all([&count.to_string(), "shift-t", "b"], test_case) cx.simulate_at_each_offset(&format!("{count} shift-t b"), test_case)
.await; .await
.assert_matches();
} }
} }
@ -969,7 +1109,7 @@ mod test {
}); });
cx.assert_binding( cx.assert_binding(
["f", "l"], "f l",
indoc! {" indoc! {"
ˇfunction print() { ˇfunction print() {
console.log('ok') console.log('ok')
@ -985,7 +1125,7 @@ mod test {
); );
cx.assert_binding( cx.assert_binding(
["t", "l"], "t l",
indoc! {" indoc! {"
ˇfunction print() { ˇfunction print() {
console.log('ok') console.log('ok')
@ -1011,7 +1151,7 @@ mod test {
}); });
cx.assert_binding( cx.assert_binding(
["shift-f", "p"], "shift-f p",
indoc! {" indoc! {"
function print() { function print() {
console.ˇlog('ok') console.ˇlog('ok')
@ -1027,7 +1167,7 @@ mod test {
); );
cx.assert_binding( cx.assert_binding(
["shift-t", "p"], "shift-t p",
indoc! {" indoc! {"
function print() { function print() {
console.ˇlog('ok') console.ˇlog('ok')
@ -1053,7 +1193,7 @@ mod test {
}); });
cx.assert_binding( cx.assert_binding(
["f", "p"], "f p",
indoc! {"ˇfmt.Println(\"Hello, World!\")"}, indoc! {"ˇfmt.Println(\"Hello, World!\")"},
Mode::Normal, Mode::Normal,
indoc! {"fmt.ˇPrintln(\"Hello, World!\")"}, indoc! {"fmt.ˇPrintln(\"Hello, World!\")"},
@ -1061,7 +1201,7 @@ mod test {
); );
cx.assert_binding( cx.assert_binding(
["shift-f", "p"], "shift-f p",
indoc! {"fmt.Printlnˇ(\"Hello, World!\")"}, indoc! {"fmt.Printlnˇ(\"Hello, World!\")"},
Mode::Normal, Mode::Normal,
indoc! {"fmt.ˇPrintln(\"Hello, World!\")"}, indoc! {"fmt.ˇPrintln(\"Hello, World!\")"},
@ -1069,7 +1209,7 @@ mod test {
); );
cx.assert_binding( cx.assert_binding(
["t", "p"], "t p",
indoc! {"ˇfmt.Println(\"Hello, World!\")"}, indoc! {"ˇfmt.Println(\"Hello, World!\")"},
Mode::Normal, Mode::Normal,
indoc! {"fmtˇ.Println(\"Hello, World!\")"}, indoc! {"fmtˇ.Println(\"Hello, World!\")"},
@ -1077,7 +1217,7 @@ mod test {
); );
cx.assert_binding( cx.assert_binding(
["shift-t", "p"], "shift-t p",
indoc! {"fmt.Printlnˇ(\"Hello, World!\")"}, indoc! {"fmt.Printlnˇ(\"Hello, World!\")"},
Mode::Normal, Mode::Normal,
indoc! {"fmt.Pˇrintln(\"Hello, World!\")"}, indoc! {"fmt.Pˇrintln(\"Hello, World!\")"},
@ -1087,11 +1227,16 @@ mod test {
#[gpui::test] #[gpui::test]
async fn test_percent(cx: &mut TestAppContext) { async fn test_percent(cx: &mut TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["%"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_all("ˇconsole.logˇ(ˇvaˇrˇ)ˇ;").await; cx.simulate_at_each_offset("%", "ˇconsole.logˇ(ˇvaˇrˇ)ˇ;")
cx.assert_all("ˇconsole.logˇ(ˇ'var', ˇ[ˇ1, ˇ2, 3ˇ]ˇ)ˇ;") .await
.await; .assert_matches();
cx.assert_all("let result = curried_funˇ(ˇ)ˇ(ˇ)ˇ;").await; cx.simulate_at_each_offset("%", "ˇconsole.logˇ(ˇ'var', ˇ[ˇ1, ˇ2, 3ˇ]ˇ)ˇ;")
.await
.assert_matches();
cx.simulate_at_each_offset("%", "let result = curried_funˇ(ˇ)ˇ(ˇ)ˇ;")
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
@ -1100,16 +1245,16 @@ mod test {
// goes to current line end // goes to current line end
cx.set_shared_state(indoc! {"ˇaa\nbb\ncc"}).await; cx.set_shared_state(indoc! {"ˇaa\nbb\ncc"}).await;
cx.simulate_shared_keystrokes(["$"]).await; cx.simulate_shared_keystrokes("$").await;
cx.assert_shared_state(indoc! {"aˇa\nbb\ncc"}).await; cx.shared_state().await.assert_eq("aˇa\nbb\ncc");
// goes to next line end // goes to next line end
cx.simulate_shared_keystrokes(["2", "$"]).await; cx.simulate_shared_keystrokes("2 $").await;
cx.assert_shared_state("aa\nbˇb\ncc").await; cx.shared_state().await.assert_eq("aa\nbˇb\ncc");
// try to exceed the final line. // try to exceed the final line.
cx.simulate_shared_keystrokes(["4", "$"]).await; cx.simulate_shared_keystrokes("4 $").await;
cx.assert_shared_state("aa\nbb\ncˇc").await; cx.shared_state().await.assert_eq("aa\nbb\ncˇc");
} }
#[gpui::test] #[gpui::test]
@ -1148,34 +1293,22 @@ mod test {
]); ]);
}); });
cx.assert_binding_normal( cx.assert_binding_normal("w", indoc! {"ˇassert_binding"}, indoc! {"assert_ˇbinding"});
["w"],
indoc! {"ˇassert_binding"},
indoc! {"assert_ˇbinding"},
);
// Special case: In 'cw', 'w' acts like 'e' // Special case: In 'cw', 'w' acts like 'e'
cx.assert_binding( cx.assert_binding(
["c", "w"], "c w",
indoc! {"ˇassert_binding"}, indoc! {"ˇassert_binding"},
Mode::Normal, Mode::Normal,
indoc! {"ˇ_binding"}, indoc! {"ˇ_binding"},
Mode::Insert, Mode::Insert,
); );
cx.assert_binding_normal( cx.assert_binding_normal("e", indoc! {"ˇassert_binding"}, indoc! {"asserˇt_binding"});
["e"],
indoc! {"ˇassert_binding"}, cx.assert_binding_normal("b", indoc! {"assert_ˇbinding"}, indoc! {"ˇassert_binding"});
indoc! {"asserˇt_binding"},
);
cx.assert_binding_normal( cx.assert_binding_normal(
["b"], "g e",
indoc! {"assert_ˇbinding"},
indoc! {"ˇassert_binding"},
);
cx.assert_binding_normal(
["g", "e"],
indoc! {"assert_bindinˇg"}, indoc! {"assert_bindinˇg"},
indoc! {"asserˇt_binding"}, indoc! {"asserˇt_binding"},
); );

View File

@ -111,35 +111,35 @@ mod test {
async fn test_change_case(cx: &mut gpui::TestAppContext) { async fn test_change_case(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("ˇabC\n").await; cx.set_shared_state("ˇabC\n").await;
cx.simulate_shared_keystrokes(["~"]).await; cx.simulate_shared_keystrokes("~").await;
cx.assert_shared_state("AˇbC\n").await; cx.shared_state().await.assert_eq("AˇbC\n");
cx.simulate_shared_keystrokes(["2", "~"]).await; cx.simulate_shared_keystrokes("2 ~").await;
cx.assert_shared_state("ABˇc\n").await; cx.shared_state().await.assert_eq("ABˇc\n");
// works in visual mode // works in visual mode
cx.set_shared_state("a😀C«dÉ1*fˇ»\n").await; cx.set_shared_state("a😀C«dÉ1*fˇ»\n").await;
cx.simulate_shared_keystrokes(["~"]).await; cx.simulate_shared_keystrokes("~").await;
cx.assert_shared_state("a😀CˇDé1*F\n").await; cx.shared_state().await.assert_eq("a😀CˇDé1*F\n");
// works with multibyte characters // works with multibyte characters
cx.simulate_shared_keystrokes(["~"]).await; cx.simulate_shared_keystrokes("~").await;
cx.set_shared_state("aˇC😀é1*F\n").await; cx.set_shared_state("aˇC😀é1*F\n").await;
cx.simulate_shared_keystrokes(["4", "~"]).await; cx.simulate_shared_keystrokes("4 ~").await;
cx.assert_shared_state("ac😀É1ˇ*F\n").await; cx.shared_state().await.assert_eq("ac😀É1ˇ*F\n");
// works with line selections // works with line selections
cx.set_shared_state("abˇC\n").await; cx.set_shared_state("abˇC\n").await;
cx.simulate_shared_keystrokes(["shift-v", "~"]).await; cx.simulate_shared_keystrokes("shift-v ~").await;
cx.assert_shared_state("ˇABc\n").await; cx.shared_state().await.assert_eq("ˇABc\n");
// works in visual block mode // works in visual block mode
cx.set_shared_state("ˇaa\nbb\ncc").await; cx.set_shared_state("ˇaa\nbb\ncc").await;
cx.simulate_shared_keystrokes(["ctrl-v", "j", "~"]).await; cx.simulate_shared_keystrokes("ctrl-v j ~").await;
cx.assert_shared_state("ˇAa\nBb\ncc").await; cx.shared_state().await.assert_eq("ˇAa\nBb\ncc");
// works with multiple cursors (zed only) // works with multiple cursors (zed only)
cx.set_state("aˇßcdˇe\n", Mode::Normal); cx.set_state("aˇßcdˇe\n", Mode::Normal);
cx.simulate_keystroke("~"); cx.simulate_keystrokes("~");
cx.assert_state("aSSˇcdˇE\n", Mode::Normal); cx.assert_state("aSSˇcdˇE\n", Mode::Normal);
} }
@ -148,18 +148,18 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
// works in visual mode // works in visual mode
cx.set_shared_state("a😀C«dÉ1*fˇ»\n").await; cx.set_shared_state("a😀C«dÉ1*fˇ»\n").await;
cx.simulate_shared_keystrokes(["U"]).await; cx.simulate_shared_keystrokes("U").await;
cx.assert_shared_state("a😀CˇDÉ1*F\n").await; cx.shared_state().await.assert_eq("a😀CˇDÉ1*F\n");
// works with line selections // works with line selections
cx.set_shared_state("abˇC\n").await; cx.set_shared_state("abˇC\n").await;
cx.simulate_shared_keystrokes(["shift-v", "U"]).await; cx.simulate_shared_keystrokes("shift-v U").await;
cx.assert_shared_state("ˇABC\n").await; cx.shared_state().await.assert_eq("ˇABC\n");
// works in visual block mode // works in visual block mode
cx.set_shared_state("ˇaa\nbb\ncc").await; cx.set_shared_state("ˇaa\nbb\ncc").await;
cx.simulate_shared_keystrokes(["ctrl-v", "j", "U"]).await; cx.simulate_shared_keystrokes("ctrl-v j U").await;
cx.assert_shared_state("ˇAa\nBb\ncc").await; cx.shared_state().await.assert_eq("ˇAa\nBb\ncc");
} }
#[gpui::test] #[gpui::test]
@ -167,17 +167,17 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
// works in visual mode // works in visual mode
cx.set_shared_state("A😀c«DÉ1*fˇ»\n").await; cx.set_shared_state("A😀c«DÉ1*fˇ»\n").await;
cx.simulate_shared_keystrokes(["u"]).await; cx.simulate_shared_keystrokes("u").await;
cx.assert_shared_state("A😀cˇdé1*f\n").await; cx.shared_state().await.assert_eq("A😀cˇdé1*f\n");
// works with line selections // works with line selections
cx.set_shared_state("ABˇc\n").await; cx.set_shared_state("ABˇc\n").await;
cx.simulate_shared_keystrokes(["shift-v", "u"]).await; cx.simulate_shared_keystrokes("shift-v u").await;
cx.assert_shared_state("ˇabc\n").await; cx.shared_state().await.assert_eq("ˇabc\n");
// works in visual block mode // works in visual block mode
cx.set_shared_state("ˇAa\nBb\nCc").await; cx.set_shared_state("ˇAa\nBb\nCc").await;
cx.simulate_shared_keystrokes(["ctrl-v", "j", "u"]).await; cx.simulate_shared_keystrokes("ctrl-v j u").await;
cx.assert_shared_state("ˇaa\nbb\nCc").await; cx.shared_state().await.assert_eq("ˇaa\nbb\nCc");
} }
} }

View File

@ -169,329 +169,401 @@ mod test {
#[gpui::test] #[gpui::test]
async fn test_change_h(cx: &mut gpui::TestAppContext) { async fn test_change_h(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "h"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert("Teˇst").await; cx.simulate("c h", "Teˇst").await.assert_matches();
cx.assert("Tˇest").await; cx.simulate("c h", "Tˇest").await.assert_matches();
cx.assert("ˇTest").await; cx.simulate("c h", "ˇTest").await.assert_matches();
cx.assert(indoc! {" cx.simulate(
"c h",
indoc! {"
Test Test
ˇtest"}) ˇtest"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_change_backspace(cx: &mut gpui::TestAppContext) { async fn test_change_backspace(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx) let mut cx = NeovimBackedTestContext::new(cx).await;
.await cx.simulate("c backspace", "Teˇst").await.assert_matches();
.binding(["c", "backspace"]); cx.simulate("c backspace", "Tˇest").await.assert_matches();
cx.assert("Teˇst").await; cx.simulate("c backspace", "ˇTest").await.assert_matches();
cx.assert("Tˇest").await; cx.simulate(
cx.assert("ˇTest").await; "c backspace",
cx.assert(indoc! {" indoc! {"
Test Test
ˇtest"}) ˇtest"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_change_l(cx: &mut gpui::TestAppContext) { async fn test_change_l(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "l"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert("Teˇst").await; cx.simulate("c l", "Teˇst").await.assert_matches();
cx.assert("Tesˇt").await; cx.simulate("c l", "Tesˇt").await.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_change_w(cx: &mut gpui::TestAppContext) { async fn test_change_w(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "w"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert("Teˇst").await; cx.simulate("c w", "Teˇst").await.assert_matches();
cx.assert("Tˇest test").await; cx.simulate("c w", "Tˇest test").await.assert_matches();
cx.assert("Testˇ test").await; cx.simulate("c w", "Testˇ test").await.assert_matches();
cx.assert("Tesˇt test").await; cx.simulate("c w", "Tesˇt test").await.assert_matches();
cx.assert(indoc! {" cx.simulate(
"c w",
indoc! {"
Test teˇst Test teˇst
test"}) test"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"c w",
indoc! {"
Test tesˇt Test tesˇt
test"}) test"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"c w",
indoc! {"
Test test Test test
ˇ ˇ
test"}) test"},
.await; )
.await
.assert_matches();
let mut cx = cx.binding(["c", "shift-w"]); cx.simulate("c shift-w", "Test teˇst-test test")
cx.assert("Test teˇst-test test").await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_change_e(cx: &mut gpui::TestAppContext) { async fn test_change_e(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "e"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert("Teˇst Test").await; cx.simulate("c e", "Teˇst Test").await.assert_matches();
cx.assert("Tˇest test").await; cx.simulate("c e", "Tˇest test").await.assert_matches();
cx.assert(indoc! {" cx.simulate(
"c e",
indoc! {"
Test teˇst Test teˇst
test"}) test"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"c e",
indoc! {"
Test tesˇt Test tesˇt
test"}) test"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"c e",
indoc! {"
Test test Test test
ˇ ˇ
test"}) test"},
.await; )
.await
.assert_matches();
let mut cx = cx.binding(["c", "shift-e"]); cx.simulate("c shift-e", "Test teˇst-test test")
cx.assert("Test teˇst-test test").await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_change_b(cx: &mut gpui::TestAppContext) { async fn test_change_b(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "b"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert("Teˇst Test").await; cx.simulate("c b", "Teˇst Test").await.assert_matches();
cx.assert("Test ˇtest").await; cx.simulate("c b", "Test ˇtest").await.assert_matches();
cx.assert("Test1 test2 ˇtest3").await; cx.simulate("c b", "Test1 test2 ˇtest3")
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"c b",
indoc! {"
Test test Test test
ˇtest"}) ˇtest"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"c b",
indoc! {"
Test test Test test
ˇ ˇ
test"}) test"},
.await; )
.await
.assert_matches();
let mut cx = cx.binding(["c", "shift-b"]); cx.simulate("c shift-b", "Test test-test ˇtest")
cx.assert("Test test-test ˇtest").await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_change_end_of_line(cx: &mut gpui::TestAppContext) { async fn test_change_end_of_line(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "$"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert(indoc! {" cx.simulate(
"c $",
indoc! {"
The qˇuick The qˇuick
brown fox"}) brown fox"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"c $",
indoc! {"
The quick The quick
ˇ ˇ
brown fox"}) brown fox"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_change_0(cx: &mut gpui::TestAppContext) { async fn test_change_0(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_neovim_compatible( cx.simulate(
"c 0",
indoc! {" indoc! {"
The qˇuick The qˇuick
brown fox"}, brown fox"},
["c", "0"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c 0",
indoc! {" indoc! {"
The quick The quick
ˇ ˇ
brown fox"}, brown fox"},
["c", "0"],
) )
.await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_change_k(cx: &mut gpui::TestAppContext) { async fn test_change_k(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_neovim_compatible( cx.simulate(
"c k",
indoc! {" indoc! {"
The quick The quick
brown ˇfox brown ˇfox
jumps over"}, jumps over"},
["c", "k"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c k",
indoc! {" indoc! {"
The quick The quick
brown fox brown fox
jumps ˇover"}, jumps ˇover"},
["c", "k"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c k",
indoc! {" indoc! {"
The qˇuick The qˇuick
brown fox brown fox
jumps over"}, jumps over"},
["c", "k"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c k",
indoc! {" indoc! {"
ˇ ˇ
brown fox brown fox
jumps over"}, jumps over"},
["c", "k"],
) )
.await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_change_j(cx: &mut gpui::TestAppContext) { async fn test_change_j(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_neovim_compatible( cx.simulate(
"c j",
indoc! {" indoc! {"
The quick The quick
brown ˇfox brown ˇfox
jumps over"}, jumps over"},
["c", "j"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c j",
indoc! {" indoc! {"
The quick The quick
brown fox brown fox
jumps ˇover"}, jumps ˇover"},
["c", "j"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c j",
indoc! {" indoc! {"
The qˇuick The qˇuick
brown fox brown fox
jumps over"}, jumps over"},
["c", "j"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c j",
indoc! {" indoc! {"
The quick The quick
brown fox brown fox
ˇ"}, ˇ"},
["c", "j"],
) )
.await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_change_end_of_document(cx: &mut gpui::TestAppContext) { async fn test_change_end_of_document(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_neovim_compatible( cx.simulate(
"c shift-g",
indoc! {" indoc! {"
The quick The quick
brownˇ fox brownˇ fox
jumps over jumps over
the lazy"}, the lazy"},
["c", "shift-g"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c shift-g",
indoc! {" indoc! {"
The quick The quick
brownˇ fox brownˇ fox
jumps over jumps over
the lazy"}, the lazy"},
["c", "shift-g"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c shift-g",
indoc! {" indoc! {"
The quick The quick
brown fox brown fox
jumps over jumps over
the lˇazy"}, the lˇazy"},
["c", "shift-g"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c shift-g",
indoc! {" indoc! {"
The quick The quick
brown fox brown fox
jumps over jumps over
ˇ"}, ˇ"},
["c", "shift-g"],
) )
.await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_change_cc(cx: &mut gpui::TestAppContext) { async fn test_change_cc(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_neovim_compatible( cx.simulate(
"c c",
indoc! {" indoc! {"
The quick The quick
brownˇ fox brownˇ fox
jumps over jumps over
the lazy"}, the lazy"},
["c", "c"],
) )
.await; .await
.assert_matches();
cx.assert_neovim_compatible( cx.simulate(
"c c",
indoc! {" indoc! {"
ˇThe quick ˇThe quick
brown fox brown fox
jumps over jumps over
the lazy"}, the lazy"},
["c", "c"],
) )
.await; .await
.assert_matches();
cx.assert_neovim_compatible( cx.simulate(
"c c",
indoc! {" indoc! {"
The quick The quick
broˇwn fox broˇwn fox
jumˇps over jumps over
the lazy"}, the lazy"},
["c", "c"],
) )
.await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_change_gg(cx: &mut gpui::TestAppContext) { async fn test_change_gg(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_neovim_compatible( cx.simulate(
"c g g",
indoc! {" indoc! {"
The quick The quick
brownˇ fox brownˇ fox
jumps over jumps over
the lazy"}, the lazy"},
["c", "g", "g"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c g g",
indoc! {" indoc! {"
The quick The quick
brown fox brown fox
jumps over jumps over
the lˇazy"}, the lˇazy"},
["c", "g", "g"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c g g",
indoc! {" indoc! {"
The qˇuick The qˇuick
brown fox brown fox
jumps over jumps over
the lazy"}, the lazy"},
["c", "g", "g"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"c g g",
indoc! {" indoc! {"
ˇ ˇ
brown fox brown fox
jumps over jumps over
the lazy"}, the lazy"},
["c", "g", "g"],
) )
.await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
@ -499,8 +571,8 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
for count in 1..=5 { for count in 1..=5 {
cx.assert_binding_matches_all( cx.simulate_at_each_offset(
["c", &count.to_string(), "j"], &format!("c {count} j"),
indoc! {" indoc! {"
ˇThe quˇickˇ browˇn ˇThe quˇickˇ browˇn
ˇ ˇ
@ -508,7 +580,8 @@ mod test {
ˇthe lazy dog ˇthe lazy dog
"}, "},
) )
.await; .await
.assert_matches();
} }
} }
@ -517,8 +590,8 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
for count in 1..=5 { for count in 1..=5 {
cx.assert_binding_matches_all( cx.simulate_at_each_offset(
["c", &count.to_string(), "l"], &format!("c {count} l"),
indoc! {" indoc! {"
ˇThe quˇickˇ browˇn ˇThe quˇickˇ browˇn
ˇ ˇ
@ -526,7 +599,8 @@ mod test {
ˇthe lazy dog ˇthe lazy dog
"}, "},
) )
.await; .await
.assert_matches();
} }
} }
@ -535,16 +609,17 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
for count in 1..=5 { for count in 1..=5 {
for marked_text in cx.each_marked_position(indoc! {" cx.simulate_at_each_offset(
&format!("c {count} b"),
indoc! {"
ˇThe quˇickˇ browˇn ˇThe quˇickˇ browˇn
ˇ ˇ
ˇfox ˇjumpsˇ-ˇoˇver ˇfox ˇjumpsˇ-ˇoˇver
ˇthe lazy dog ˇthe lazy dog
"}) "},
{ )
cx.assert_neovim_compatible(&marked_text, ["c", &count.to_string(), "b"]) .await
.await; .assert_matches()
}
} }
} }
@ -553,8 +628,8 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
for count in 1..=5 { for count in 1..=5 {
cx.assert_binding_matches_all( cx.simulate_at_each_offset(
["c", &count.to_string(), "e"], &format!("c {count} e"),
indoc! {" indoc! {"
ˇThe quˇickˇ browˇn ˇThe quˇickˇ browˇn
ˇ ˇ
@ -562,7 +637,8 @@ mod test {
ˇthe lazy dog ˇthe lazy dog
"}, "},
) )
.await; .await
.assert_matches();
} }
} }
} }

View File

@ -158,280 +158,358 @@ mod test {
use crate::{ use crate::{
state::Mode, state::Mode,
test::{ExemptionFeatures, NeovimBackedTestContext, VimTestContext}, test::{NeovimBackedTestContext, VimTestContext},
}; };
#[gpui::test] #[gpui::test]
async fn test_delete_h(cx: &mut gpui::TestAppContext) { async fn test_delete_h(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "h"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert("Teˇst").await; cx.simulate("d h", "Teˇst").await.assert_matches();
cx.assert("Tˇest").await; cx.simulate("d h", "Tˇest").await.assert_matches();
cx.assert("ˇTest").await; cx.simulate("d h", "ˇTest").await.assert_matches();
cx.assert(indoc! {" cx.simulate(
"d h",
indoc! {"
Test Test
ˇtest"}) ˇtest"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_l(cx: &mut gpui::TestAppContext) { async fn test_delete_l(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "l"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert("ˇTest").await; cx.simulate("d l", "ˇTest").await.assert_matches();
cx.assert("Teˇst").await; cx.simulate("d l", "Teˇst").await.assert_matches();
cx.assert("Tesˇt").await; cx.simulate("d l", "Tesˇt").await.assert_matches();
cx.assert(indoc! {" cx.simulate(
"d l",
indoc! {"
Tesˇt Tesˇt
test"}) test"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_w(cx: &mut gpui::TestAppContext) { async fn test_delete_w(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_neovim_compatible( cx.simulate(
"d w",
indoc! {" indoc! {"
Test tesˇt Test tesˇt
test"}, test"},
["d", "w"],
) )
.await; .await
.assert_matches();
cx.assert_neovim_compatible("Teˇst", ["d", "w"]).await; cx.simulate("d w", "Teˇst").await.assert_matches();
cx.assert_neovim_compatible("Tˇest test", ["d", "w"]).await; cx.simulate("d w", "Tˇest test").await.assert_matches();
cx.assert_neovim_compatible( cx.simulate(
"d w",
indoc! {" indoc! {"
Test teˇst Test teˇst
test"}, test"},
["d", "w"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"d w",
indoc! {" indoc! {"
Test tesˇt Test tesˇt
test"}, test"},
["d", "w"],
) )
.await; .await
.assert_matches();
cx.assert_neovim_compatible( cx.simulate(
"d w",
indoc! {" indoc! {"
Test test Test test
ˇ ˇ
test"}, test"},
["d", "w"],
) )
.await; .await
.assert_matches();
let mut cx = cx.binding(["d", "shift-w"]); cx.simulate("d shift-w", "Test teˇst-test test")
cx.assert_neovim_compatible("Test teˇst-test test", ["d", "shift-w"]) .await
.await; .assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_next_word_end(cx: &mut gpui::TestAppContext) { async fn test_delete_next_word_end(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "e"]); let mut cx = NeovimBackedTestContext::new(cx).await;
// cx.assert("Teˇst Test").await; cx.simulate("d e", "Teˇst Test\n").await.assert_matches();
// cx.assert("Tˇest test").await; cx.simulate("d e", "Tˇest test\n").await.assert_matches();
cx.assert(indoc! {" cx.simulate(
Test teˇst "d e",
test"})
.await;
cx.assert(indoc! {"
Test tesˇt
test"})
.await;
cx.assert_exempted(
indoc! {" indoc! {"
Test test Test teˇst
ˇ
test"}, test"},
ExemptionFeatures::OperatorLastNewlineRemains,
) )
.await; .await
.assert_matches();
cx.simulate(
"d e",
indoc! {"
Test tesˇt
test"},
)
.await
.assert_matches();
let mut cx = cx.binding(["d", "shift-e"]); cx.simulate("d e", "Test teˇst-test test")
cx.assert("Test teˇst-test test").await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_b(cx: &mut gpui::TestAppContext) { async fn test_delete_b(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "b"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert("Teˇst Test").await; cx.simulate("d b", "Teˇst Test").await.assert_matches();
cx.assert("Test ˇtest").await; cx.simulate("d b", "Test ˇtest").await.assert_matches();
cx.assert("Test1 test2 ˇtest3").await; cx.simulate("d b", "Test1 test2 ˇtest3")
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"d b",
indoc! {"
Test test Test test
ˇtest"}) ˇtest"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"d b",
indoc! {"
Test test Test test
ˇ ˇ
test"}) test"},
.await; )
.await
.assert_matches();
let mut cx = cx.binding(["d", "shift-b"]); cx.simulate("d shift-b", "Test test-test ˇtest")
cx.assert("Test test-test ˇtest").await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_end_of_line(cx: &mut gpui::TestAppContext) { async fn test_delete_end_of_line(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "$"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert(indoc! {" cx.simulate(
"d $",
indoc! {"
The qˇuick The qˇuick
brown fox"}) brown fox"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"d $",
indoc! {"
The quick The quick
ˇ ˇ
brown fox"}) brown fox"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_0(cx: &mut gpui::TestAppContext) { async fn test_delete_0(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "0"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert(indoc! {" cx.simulate(
"d 0",
indoc! {"
The qˇuick The qˇuick
brown fox"}) brown fox"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"d 0",
indoc! {"
The quick The quick
ˇ ˇ
brown fox"}) brown fox"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_k(cx: &mut gpui::TestAppContext) { async fn test_delete_k(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "k"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert(indoc! {" cx.simulate(
"d k",
indoc! {"
The quick The quick
brown ˇfox brown ˇfox
jumps over"}) jumps over"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"d k",
indoc! {"
The quick The quick
brown fox brown fox
jumps ˇover"}) jumps ˇover"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"d k",
indoc! {"
The qˇuick The qˇuick
brown fox brown fox
jumps over"}) jumps over"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"d k",
indoc! {"
ˇbrown fox ˇbrown fox
jumps over"}) jumps over"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_j(cx: &mut gpui::TestAppContext) { async fn test_delete_j(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "j"]); let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert(indoc! {" cx.simulate(
"d j",
indoc! {"
The quick The quick
brown ˇfox brown ˇfox
jumps over"}) jumps over"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"d j",
indoc! {"
The quick The quick
brown fox brown fox
jumps ˇover"}) jumps ˇover"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"d j",
indoc! {"
The qˇuick The qˇuick
brown fox brown fox
jumps over"}) jumps over"},
.await; )
cx.assert(indoc! {" .await
.assert_matches();
cx.simulate(
"d j",
indoc! {"
The quick The quick
brown fox brown fox
ˇ"}) ˇ"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_end_of_document(cx: &mut gpui::TestAppContext) { async fn test_delete_end_of_document(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_neovim_compatible( cx.simulate(
"d shift-g",
indoc! {" indoc! {"
The quick The quick
brownˇ fox brownˇ fox
jumps over jumps over
the lazy"}, the lazy"},
["d", "shift-g"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"d shift-g",
indoc! {" indoc! {"
The quick The quick
brownˇ fox brownˇ fox
jumps over jumps over
the lazy"}, the lazy"},
["d", "shift-g"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"d shift-g",
indoc! {" indoc! {"
The quick The quick
brown fox brown fox
jumps over jumps over
the lˇazy"}, the lˇazy"},
["d", "shift-g"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"d shift-g",
indoc! {" indoc! {"
The quick The quick
brown fox brown fox
jumps over jumps over
ˇ"}, ˇ"},
["d", "shift-g"],
) )
.await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_gg(cx: &mut gpui::TestAppContext) { async fn test_delete_gg(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx) let mut cx = NeovimBackedTestContext::new(cx).await;
.await cx.simulate(
.binding(["d", "g", "g"]); "d g g",
cx.assert_neovim_compatible(
indoc! {" indoc! {"
The quick The quick
brownˇ fox brownˇ fox
jumps over jumps over
the lazy"}, the lazy"},
["d", "g", "g"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"d g g",
indoc! {" indoc! {"
The quick The quick
brown fox brown fox
jumps over jumps over
the lˇazy"}, the lˇazy"},
["d", "g", "g"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"d g g",
indoc! {" indoc! {"
The qˇuick The qˇuick
brown fox brown fox
jumps over jumps over
the lazy"}, the lazy"},
["d", "g", "g"],
) )
.await; .await
cx.assert_neovim_compatible( .assert_matches();
cx.simulate(
"d g g",
indoc! {" indoc! {"
ˇ ˇ
brown fox brown fox
jumps over jumps over
the lazy"}, the lazy"},
["d", "g", "g"],
) )
.await; .await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
@ -446,7 +524,7 @@ mod test {
); );
// Canceling operator twice reverts to normal mode with no active operator // Canceling operator twice reverts to normal mode with no active operator
cx.simulate_keystrokes(["d", "escape", "k"]); cx.simulate_keystrokes("d escape k");
assert_eq!(cx.active_operator(), None); assert_eq!(cx.active_operator(), None);
assert_eq!(cx.mode(), Mode::Normal); assert_eq!(cx.mode(), Mode::Normal);
cx.assert_editor_state(indoc! {" cx.assert_editor_state(indoc! {"
@ -467,7 +545,7 @@ mod test {
); );
// Canceling operator twice reverts to normal mode with no active operator // Canceling operator twice reverts to normal mode with no active operator
cx.simulate_keystrokes(["d", "y"]); cx.simulate_keystrokes("d y");
assert_eq!(cx.active_operator(), None); assert_eq!(cx.active_operator(), None);
assert_eq!(cx.mode(), Mode::Normal); assert_eq!(cx.mode(), Mode::Normal);
} }
@ -480,20 +558,18 @@ mod test {
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["d", "2", "d"]).await; cx.simulate_shared_keystrokes("d 2 d").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
the ˇlazy dog"}) the ˇlazy dog"});
.await;
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
The ˇquick brown The ˇquick brown
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["2", "d", "d"]).await; cx.simulate_shared_keystrokes("2 d d").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
the ˇlazy dog"}) the ˇlazy dog"});
.await;
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
The ˇquick brown The ˇquick brown
@ -502,16 +578,15 @@ mod test {
a star, and a star, and
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["2", "d", "2", "d"]).await; cx.simulate_shared_keystrokes("2 d 2 d").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
the ˇlazy dog"}) the ˇlazy dog"});
.await;
} }
#[gpui::test] #[gpui::test]
async fn test_delete_to_adjacent_character(cx: &mut gpui::TestAppContext) { async fn test_delete_to_adjacent_character(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_neovim_compatible("ˇax", ["d", "t", "x"]).await; cx.simulate("d t x", "ˇax").await.assert_matches();
cx.assert_neovim_compatible("aˇx", ["d", "t", "x"]).await; cx.simulate("d t x", "x").await.assert_matches();
} }
} }

View File

@ -191,33 +191,27 @@ mod test {
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["ctrl-a"]).await; cx.simulate_shared_keystrokes("ctrl-a").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
1ˇ3 1ˇ3
"}) "});
.await; cx.simulate_shared_keystrokes("ctrl-x").await;
cx.simulate_shared_keystrokes(["ctrl-x"]).await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
1ˇ2 1ˇ2
"}) "});
.await;
cx.simulate_shared_keystrokes(["9", "9", "ctrl-a"]).await; cx.simulate_shared_keystrokes("9 9 ctrl-a").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
11ˇ1 11ˇ1
"}) "});
.await; cx.simulate_shared_keystrokes("1 1 1 ctrl-x").await;
cx.simulate_shared_keystrokes(["1", "1", "1", "ctrl-x"]) cx.shared_state().await.assert_eq(indoc! {"
.await;
cx.assert_shared_state(indoc! {"
ˇ0 ˇ0
"}) "});
.await; cx.simulate_shared_keystrokes(".").await;
cx.simulate_shared_keystrokes(["."]).await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
-11ˇ1 -11ˇ1
"}) "});
.await;
} }
#[gpui::test] #[gpui::test]
@ -229,16 +223,14 @@ mod test {
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["ctrl-a"]).await; cx.simulate_shared_keystrokes("ctrl-a").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
1.ˇ3 1.ˇ3
"}) "});
.await; cx.simulate_shared_keystrokes("ctrl-x").await;
cx.simulate_shared_keystrokes(["ctrl-x"]).await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
1.ˇ2 1.ˇ2
"}) "});
.await;
} }
#[gpui::test] #[gpui::test]
@ -250,33 +242,32 @@ mod test {
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["ctrl-a"]).await; cx.simulate_shared_keystrokes("ctrl-a").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
111..ˇ3 111..ˇ3
"}) "});
.await; cx.simulate_shared_keystrokes("ctrl-x").await;
cx.simulate_shared_keystrokes(["ctrl-x"]).await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
111..ˇ2 111..ˇ2
"}) "});
.await;
} }
#[gpui::test] #[gpui::test]
async fn test_increment_radix(cx: &mut gpui::TestAppContext) { async fn test_increment_radix(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_matches_neovim("ˇ total: 0xff", ["ctrl-a"], " total: 0x10ˇ0") cx.simulate("ctrl-a", "ˇ total: 0xff")
.await; .await
cx.assert_matches_neovim("ˇ total: 0xff", ["ctrl-x"], " total: 0xfˇe") .assert_matches();
.await; cx.simulate("ctrl-x", "ˇ total: 0xff")
cx.assert_matches_neovim("ˇ total: 0xFF", ["ctrl-x"], " total: 0xFˇE") .await
.await; .assert_matches();
cx.assert_matches_neovim("(ˇ0b10f)", ["ctrl-a"], "(0b1ˇ1f)") cx.simulate("ctrl-x", "ˇ total: 0xFF")
.await; .await
cx.assert_matches_neovim("ˇ-1", ["ctrl-a"], "ˇ0").await; .assert_matches();
cx.assert_matches_neovim("banˇana", ["ctrl-a"], "banˇana") cx.simulate("ctrl-a", "(ˇ0b10f)").await.assert_matches();
.await; cx.simulate("ctrl-a", "ˇ-1").await.assert_matches();
cx.simulate("ctrl-a", "banˇana").await.assert_matches();
} }
#[gpui::test] #[gpui::test]
@ -291,33 +282,28 @@ mod test {
1"}) 1"})
.await; .await;
cx.simulate_shared_keystrokes(["j", "v", "shift-g", "g", "ctrl-a"]) cx.simulate_shared_keystrokes("j v shift-g g ctrl-a").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
1 1
ˇ2 ˇ2
3 2 3 2
4 4
5"}) 5"});
.await;
cx.simulate_shared_keystrokes(["shift-g", "ctrl-v", "g", "g"]) cx.simulate_shared_keystrokes("shift-g ctrl-v g g").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
«1ˇ» «1ˇ»
«2ˇ» «2ˇ»
«3ˇ» 2 «3ˇ» 2
«4ˇ» «4ˇ»
«5ˇ»"}) «5ˇ»"});
.await;
cx.simulate_shared_keystrokes(["g", "ctrl-x"]).await; cx.simulate_shared_keystrokes("g ctrl-x").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
ˇ0 ˇ0
0 0
0 2 0 2
0 0
0"}) 0"});
.await;
} }
} }

View File

@ -246,31 +246,29 @@ mod test {
fox ˇjumps over fox ˇjumps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["v", "w", "y"]).await; cx.simulate_shared_keystrokes("v w y").await;
cx.assert_shared_clipboard("jumps o").await; cx.shared_clipboard().await.assert_eq("jumps o");
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
The quick brown The quick brown
fox jumps oveˇr fox jumps oveˇr
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystroke("p").await; cx.simulate_shared_keystrokes("p").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
The quick brown The quick brown
fox jumps overjumps ˇo fox jumps overjumps ˇo
the lazy dog"}) the lazy dog"});
.await;
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
The quick brown The quick brown
fox jumps oveˇr fox jumps oveˇr
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystroke("shift-p").await; cx.simulate_shared_keystrokes("shift-p").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
The quick brown The quick brown
fox jumps ovejumps ˇor fox jumps ovejumps ˇor
the lazy dog"}) the lazy dog"});
.await;
// line mode // line mode
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
@ -278,25 +276,22 @@ mod test {
fox juˇmps over fox juˇmps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["d", "d"]).await; cx.simulate_shared_keystrokes("d d").await;
cx.assert_shared_clipboard("fox jumps over\n").await; cx.shared_clipboard().await.assert_eq("fox jumps over\n");
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
The quick brown The quick brown
the laˇzy dog"}) the laˇzy dog"});
.await; cx.simulate_shared_keystrokes("p").await;
cx.simulate_shared_keystroke("p").await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
The quick brown The quick brown
the lazy dog the lazy dog
ˇfox jumps over"}) ˇfox jumps over"});
.await; cx.simulate_shared_keystrokes("k shift-p").await;
cx.simulate_shared_keystrokes(["k", "shift-p"]).await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
The quick brown The quick brown
ˇfox jumps over ˇfox jumps over
the lazy dog the lazy dog
fox jumps over"}) fox jumps over"});
.await;
// multiline, cursor to first character of pasted text. // multiline, cursor to first character of pasted text.
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
@ -304,23 +299,21 @@ mod test {
fox jumps ˇover fox jumps ˇover
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["v", "j", "y"]).await; cx.simulate_shared_keystrokes("v j y").await;
cx.assert_shared_clipboard("over\nthe lazy do").await; cx.shared_clipboard().await.assert_eq("over\nthe lazy do");
cx.simulate_shared_keystroke("p").await; cx.simulate_shared_keystrokes("p").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
The quick brown The quick brown
fox jumps oˇover fox jumps oˇover
the lazy dover the lazy dover
the lazy dog"}) the lazy dog"});
.await; cx.simulate_shared_keystrokes("u shift-p").await;
cx.simulate_shared_keystrokes(["u", "shift-p"]).await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
The quick brown The quick brown
fox jumps ˇover fox jumps ˇover
the lazy doover the lazy doover
the lazy dog"}) the lazy dog"});
.await;
} }
#[gpui::test] #[gpui::test]
@ -340,7 +333,7 @@ mod test {
the lazy dog"}, the lazy dog"},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["v", "i", "w", "y"]); cx.simulate_keystrokes("v i w y");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The quick brown The quick brown
@ -348,7 +341,7 @@ mod test {
the lazy dog"}, the lazy dog"},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystroke("p"); cx.simulate_keystrokes("p");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The quick brown The quick brown
@ -377,7 +370,7 @@ mod test {
the lazy dog"}, the lazy dog"},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["v", "i", "w", "y"]); cx.simulate_keystrokes("v i w y");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The quick brown The quick brown
@ -385,7 +378,7 @@ mod test {
the lazy dog"}, the lazy dog"},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystroke("p"); cx.simulate_keystrokes("p");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The quick brown The quick brown
@ -397,7 +390,7 @@ mod test {
cx.read_from_clipboard().map(|item| item.text().clone()), cx.read_from_clipboard().map(|item| item.text().clone()),
Some("jumps".into()) Some("jumps".into())
); );
cx.simulate_keystrokes(["d", "d", "p"]); cx.simulate_keystrokes("d d p");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The quick brown The quick brown
@ -410,7 +403,7 @@ mod test {
Some("jumps".into()) Some("jumps".into())
); );
cx.write_to_clipboard(ClipboardItem::new("test-copy".to_string())); cx.write_to_clipboard(ClipboardItem::new("test-copy".to_string()));
cx.simulate_keystroke("shift-p"); cx.simulate_keystrokes("shift-p");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The quick brown The quick brown
@ -430,38 +423,31 @@ mod test {
fox jˇumps over fox jˇumps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["v", "i", "w", "y"]).await; cx.simulate_shared_keystrokes("v i w y").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
The quick brown The quick brown
fox ˇjumps over fox ˇjumps over
the lazy dog"}) the lazy dog"});
.await;
// paste in visual mode // paste in visual mode
cx.simulate_shared_keystrokes(["w", "v", "i", "w", "p"]) cx.simulate_shared_keystrokes("w v i w p").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
The quick brown The quick brown
fox jumps jumpˇs fox jumps jumpˇs
the lazy dog"}) the lazy dog"});
.await; cx.shared_clipboard().await.assert_eq("over");
cx.assert_shared_clipboard("over").await;
// paste in visual line mode // paste in visual line mode
cx.simulate_shared_keystrokes(["up", "shift-v", "shift-p"]) cx.simulate_shared_keystrokes("up shift-v shift-p").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
ˇover ˇover
fox jumps jumps fox jumps jumps
the lazy dog"}) the lazy dog"});
.await; cx.shared_clipboard().await.assert_eq("over");
cx.assert_shared_clipboard("over").await;
// paste in visual block mode // paste in visual block mode
cx.simulate_shared_keystrokes(["ctrl-v", "down", "down", "p"]) cx.simulate_shared_keystrokes("ctrl-v down down p").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
oveˇrver oveˇrver
overox jumps jumps overox jumps jumps
overhe lazy dog"}) overhe lazy dog"});
.await;
// copy in visual line mode // copy in visual line mode
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
@ -469,40 +455,33 @@ mod test {
fox juˇmps over fox juˇmps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["shift-v", "d"]).await; cx.simulate_shared_keystrokes("shift-v d").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
The quick brown The quick brown
the laˇzy dog"}) the laˇzy dog"});
.await;
// paste in visual mode // paste in visual mode
cx.simulate_shared_keystrokes(["v", "i", "w", "p"]).await; cx.simulate_shared_keystrokes("v i w p").await;
cx.assert_shared_state( cx.shared_state().await.assert_eq(&indoc! {"
&indoc! {"
The quick brown The quick brown
the_ the
ˇfox jumps over ˇfox jumps over
_dog"} dog"});
.replace('_', " "), // Hack for trailing whitespace cx.shared_clipboard().await.assert_eq("lazy");
)
.await;
cx.assert_shared_clipboard("lazy").await;
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
The quick brown The quick brown
fox juˇmps over fox juˇmps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["shift-v", "d"]).await; cx.simulate_shared_keystrokes("shift-v d").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
The quick brown The quick brown
the laˇzy dog"}) the laˇzy dog"});
.await;
// paste in visual line mode // paste in visual line mode
cx.simulate_shared_keystrokes(["k", "shift-v", "p"]).await; cx.simulate_shared_keystrokes("k shift-v p").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
ˇfox jumps over ˇfox jumps over
the lazy dog"}) the lazy dog"});
.await; cx.shared_clipboard().await.assert_eq("The quick brown\n");
cx.assert_shared_clipboard("The quick brown\n").await;
} }
#[gpui::test] #[gpui::test]
@ -514,47 +493,39 @@ mod test {
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["ctrl-v", "2", "j", "y"]) cx.simulate_shared_keystrokes("ctrl-v 2 j y").await;
.await; cx.shared_clipboard().await.assert_eq("q\nj\nl");
cx.assert_shared_clipboard("q\nj\nl").await; cx.simulate_shared_keystrokes("p").await;
cx.simulate_shared_keystrokes(["p"]).await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
The qˇquick brown The qˇquick brown
fox jjumps over fox jjumps over
the llazy dog"}) the llazy dog"});
.await; cx.simulate_shared_keystrokes("v i w shift-p").await;
cx.simulate_shared_keystrokes(["v", "i", "w", "shift-p"]) cx.shared_state().await.assert_eq(indoc! {"
.await;
cx.assert_shared_state(indoc! {"
The ˇq brown The ˇq brown
fox jjjumps over fox jjjumps over
the lllazy dog"}) the lllazy dog"});
.await; cx.simulate_shared_keystrokes("v i w shift-p").await;
cx.simulate_shared_keystrokes(["v", "i", "w", "shift-p"])
.await;
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
The ˇquick brown The ˇquick brown
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["ctrl-v", "j", "y"]).await; cx.simulate_shared_keystrokes("ctrl-v j y").await;
cx.assert_shared_clipboard("q\nj").await; cx.shared_clipboard().await.assert_eq("q\nj");
cx.simulate_shared_keystrokes(["l", "ctrl-v", "2", "j", "shift-p"]) cx.simulate_shared_keystrokes("l ctrl-v 2 j shift-p").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
The qˇqick brown The qˇqick brown
fox jjmps over fox jjmps over
the lzy dog"}) the lzy dog"});
.await;
cx.simulate_shared_keystrokes(["shift-v", "p"]).await; cx.simulate_shared_keystrokes("shift-v p").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
ˇq ˇq
j j
fox jjmps over fox jjmps over
the lzy dog"}) the lzy dog"});
.await;
} }
#[gpui::test] #[gpui::test]
@ -568,7 +539,7 @@ mod test {
"}, "},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["o", "a", "(", ")", "{", "escape"]); cx.simulate_keystrokes("o a ( ) { escape");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
class A { class A {
@ -578,7 +549,7 @@ mod test {
Mode::Normal, Mode::Normal,
); );
// cursor goes to the first non-blank character in the line; // cursor goes to the first non-blank character in the line;
cx.simulate_keystrokes(["y", "y", "p"]); cx.simulate_keystrokes("y y p");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
class A { class A {
@ -589,7 +560,7 @@ mod test {
Mode::Normal, Mode::Normal,
); );
// indentation is preserved when pasting // indentation is preserved when pasting
cx.simulate_keystrokes(["u", "shift-v", "up", "y", "shift-p"]); cx.simulate_keystrokes("u shift-v up y shift-p");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
ˇclass A { ˇclass A {
@ -612,16 +583,15 @@ mod test {
three three
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["y", "y", "3", "p"]).await; cx.simulate_shared_keystrokes("y y 3 p").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
one one
ˇone ˇone
one one
one one
two two
three three
"}) "});
.await;
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
one one
@ -629,13 +599,11 @@ mod test {
three three
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["y", "$", "$", "3", "p"]) cx.simulate_shared_keystrokes("y $ $ 3 p").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
one one
twotwotwotwˇo twotwotwotwˇo
three three
"}) "});
.await;
} }
} }

View File

@ -222,32 +222,32 @@ mod test {
// "o" // "o"
cx.set_shared_state("ˇhello").await; cx.set_shared_state("ˇhello").await;
cx.simulate_shared_keystrokes(["o", "w", "o", "r", "l", "d", "escape"]) cx.simulate_shared_keystrokes("o w o r l d escape").await;
.await; cx.shared_state().await.assert_eq("hello\nworlˇd");
cx.assert_shared_state("hello\nworlˇd").await; cx.simulate_shared_keystrokes(".").await;
cx.simulate_shared_keystrokes(["."]).await; cx.shared_state().await.assert_eq("hello\nworld\nworlˇd");
cx.assert_shared_state("hello\nworld\nworlˇd").await;
// "d" // "d"
cx.simulate_shared_keystrokes(["^", "d", "f", "o"]).await; cx.simulate_shared_keystrokes("^ d f o").await;
cx.simulate_shared_keystrokes(["g", "g", "."]).await; cx.simulate_shared_keystrokes("g g .").await;
cx.assert_shared_state("ˇ\nworld\nrld").await; cx.shared_state().await.assert_eq("ˇ\nworld\nrld");
// "p" (note that it pastes the current clipboard) // "p" (note that it pastes the current clipboard)
cx.simulate_shared_keystrokes(["j", "y", "y", "p"]).await; cx.simulate_shared_keystrokes("j y y p").await;
cx.simulate_shared_keystrokes(["shift-g", "y", "y", "."]) cx.simulate_shared_keystrokes("shift-g y y .").await;
.await; cx.shared_state()
cx.assert_shared_state("\nworld\nworld\nrld\nˇrld").await; .await
.assert_eq("\nworld\nworld\nrld\nˇrld");
// "~" (note that counts apply to the action taken, not . itself) // "~" (note that counts apply to the action taken, not . itself)
cx.set_shared_state("ˇthe quick brown fox").await; cx.set_shared_state("ˇthe quick brown fox").await;
cx.simulate_shared_keystrokes(["2", "~", "."]).await; cx.simulate_shared_keystrokes("2 ~ .").await;
cx.set_shared_state("THE ˇquick brown fox").await; cx.set_shared_state("THE ˇquick brown fox").await;
cx.simulate_shared_keystrokes(["3", "."]).await; cx.simulate_shared_keystrokes("3 .").await;
cx.set_shared_state("THE QUIˇck brown fox").await; cx.set_shared_state("THE QUIˇck brown fox").await;
cx.run_until_parked(); cx.run_until_parked();
cx.simulate_shared_keystrokes(["."]).await; cx.simulate_shared_keystrokes(".").await;
cx.assert_shared_state("THE QUICK ˇbrown fox").await; cx.shared_state().await.assert_eq("THE QUICK ˇbrown fox");
} }
#[gpui::test] #[gpui::test]
@ -255,16 +255,16 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await; let mut cx = VimTestContext::new(cx, true).await;
cx.set_state("hˇllo", Mode::Normal); cx.set_state("hˇllo", Mode::Normal);
cx.simulate_keystrokes(["i"]); cx.simulate_keystrokes("i");
// simulate brazilian input for ä. // simulate brazilian input for ä.
cx.update_editor(|editor, cx| { cx.update_editor(|editor, cx| {
editor.replace_and_mark_text_in_range(None, "\"", Some(1..1), cx); editor.replace_and_mark_text_in_range(None, "\"", Some(1..1), cx);
editor.replace_text_in_range(None, "ä", cx); editor.replace_text_in_range(None, "ä", cx);
}); });
cx.simulate_keystrokes(["escape"]); cx.simulate_keystrokes("escape");
cx.assert_state("hˇällo", Mode::Normal); cx.assert_state("hˇällo", Mode::Normal);
cx.simulate_keystrokes(["."]); cx.simulate_keystrokes(".");
cx.assert_state("hˇäällo", Mode::Normal); cx.assert_state("hˇäällo", Mode::Normal);
} }
@ -316,11 +316,11 @@ mod test {
}, },
]))) ])))
}); });
cx.simulate_keystrokes(["a", "."]); cx.simulate_keystrokes("a .");
request.next().await; request.next().await;
cx.condition(|editor, _| editor.context_menu_visible()) cx.condition(|editor, _| editor.context_menu_visible())
.await; .await;
cx.simulate_keystrokes(["down", "enter", "!", "escape"]); cx.simulate_keystrokes("down enter ! escape");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
@ -330,7 +330,7 @@ mod test {
"}, "},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["j", "."]); cx.simulate_keystrokes("j .");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
one.second! one.second!
@ -352,27 +352,23 @@ mod test {
the lazy dog" the lazy dog"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["v", "i", "w", "s", "o", "escape"]) cx.simulate_shared_keystrokes("v i w s o escape").await;
.await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"ˇo quick brown "ˇo quick brown
fox jumps over fox jumps over
the lazy dog" the lazy dog"
}) });
.await; cx.simulate_shared_keystrokes("j w .").await;
cx.simulate_shared_keystrokes(["j", "w", "."]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"o quick brown "o quick brown
fox ˇops over fox ˇops over
the lazy dog" the lazy dog"
}) });
.await; cx.simulate_shared_keystrokes("f r .").await;
cx.simulate_shared_keystrokes(["f", "r", "."]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"o quick brown "o quick brown
fox ops oveˇothe lazy dog" fox ops oveˇothe lazy dog"
}) });
.await;
// visual // visual
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
@ -383,33 +379,29 @@ mod test {
the lazy dog" the lazy dog"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["v", "j", "x"]).await; cx.simulate_shared_keystrokes("v j x").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"the ˇumps over "the ˇumps over
fox jumps over fox jumps over
fox jumps over fox jumps over
the lazy dog" the lazy dog"
}) });
.await; cx.simulate_shared_keystrokes(".").await;
cx.simulate_shared_keystrokes(["."]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"the ˇumps over "the ˇumps over
fox jumps over fox jumps over
the lazy dog" the lazy dog"
}) });
.await; cx.simulate_shared_keystrokes("w .").await;
cx.simulate_shared_keystrokes(["w", "."]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"the umps ˇumps over "the umps ˇumps over
the lazy dog" the lazy dog"
}) });
.await; cx.simulate_shared_keystrokes("j .").await;
cx.simulate_shared_keystrokes(["j", "."]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"the umps umps over "the umps umps over
the ˇog" the ˇog"
}) });
.await;
// block mode (3 rows) // block mode (3 rows)
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
@ -418,21 +410,19 @@ mod test {
the lazy dog" the lazy dog"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["ctrl-v", "j", "j", "shift-i", "o", "escape"]) cx.simulate_shared_keystrokes("ctrl-v j j shift-i o escape")
.await; .await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"ˇothe quick brown "ˇothe quick brown
ofox jumps over ofox jumps over
othe lazy dog" othe lazy dog"
}) });
.await; cx.simulate_shared_keystrokes("j 4 l .").await;
cx.simulate_shared_keystrokes(["j", "4", "l", "."]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"othe quick brown "othe quick brown
ofoxˇo jumps over ofoxˇo jumps over
otheo lazy dog" otheo lazy dog"
}) });
.await;
// line mode // line mode
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
@ -441,21 +431,19 @@ mod test {
the lazy dog" the lazy dog"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["shift-v", "shift-r", "o", "escape"]) cx.simulate_shared_keystrokes("shift-v shift-r o escape")
.await; .await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"ˇo "ˇo
fox jumps over fox jumps over
the lazy dog" the lazy dog"
}) });
.await; cx.simulate_shared_keystrokes("j .").await;
cx.simulate_shared_keystrokes(["j", "."]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"o "o
ˇo ˇo
the lazy dog" the lazy dog"
}) });
.await;
} }
#[gpui::test] #[gpui::test]
@ -468,27 +456,24 @@ mod test {
the lazy dog" the lazy dog"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["3", "d", "3", "l"]).await; cx.simulate_shared_keystrokes("3 d 3 l").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"ˇ brown "ˇ brown
fox jumps over fox jumps over
the lazy dog" the lazy dog"
}) });
.await; cx.simulate_shared_keystrokes("j .").await;
cx.simulate_shared_keystrokes(["j", "."]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
" brown " brown
ˇ over ˇ over
the lazy dog" the lazy dog"
}) });
.await; cx.simulate_shared_keystrokes("j 2 .").await;
cx.simulate_shared_keystrokes(["j", "2", "."]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
" brown " brown
over over
ˇe lazy dog" ˇe lazy dog"
}) });
.await;
} }
#[gpui::test] #[gpui::test]
@ -496,8 +481,8 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await; let mut cx = VimTestContext::new(cx, true).await;
cx.set_state("ˇhello\n", Mode::Normal); cx.set_state("ˇhello\n", Mode::Normal);
cx.simulate_keystrokes(["4", "i", "j", "cmd-shift-p", "escape"]); cx.simulate_keystrokes("4 i j cmd-shift-p escape");
cx.simulate_keystrokes(["escape"]); cx.simulate_keystrokes("escape");
cx.assert_state("ˇjhello\n", Mode::Normal); cx.assert_state("ˇjhello\n", Mode::Normal);
} }
@ -506,11 +491,10 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("ˇhello hello hello\n").await; cx.set_shared_state("ˇhello hello hello\n").await;
cx.simulate_shared_keystrokes(["c", "f", "o", "x", "escape"]) cx.simulate_shared_keystrokes("c f o x escape").await;
.await; cx.shared_state().await.assert_eq("ˇx hello hello\n");
cx.assert_shared_state("ˇx hello hello\n").await; cx.simulate_shared_keystrokes(": escape").await;
cx.simulate_shared_keystrokes([":", "escape"]).await; cx.simulate_shared_keystrokes(".").await;
cx.simulate_shared_keystrokes(["."]).await; cx.shared_state().await.assert_eq("ˇx hello\n");
cx.assert_shared_state("ˇx hello\n").await;
} }
} }

View File

@ -170,25 +170,25 @@ mod test {
cx.update_editor(|editor, cx| { cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 0.)) assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 0.))
}); });
cx.simulate_keystrokes(["ctrl-e"]); cx.simulate_keystrokes("ctrl-e");
cx.update_editor(|editor, cx| { cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 1.)) assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 1.))
}); });
cx.simulate_keystrokes(["2", "ctrl-e"]); cx.simulate_keystrokes("2 ctrl-e");
cx.update_editor(|editor, cx| { cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 3.)) assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 3.))
}); });
cx.simulate_keystrokes(["ctrl-y"]); cx.simulate_keystrokes("ctrl-y");
cx.update_editor(|editor, cx| { cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 2.)) assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 2.))
}); });
// does not select in normal mode // does not select in normal mode
cx.simulate_keystrokes(["g", "g"]); cx.simulate_keystrokes("g g");
cx.update_editor(|editor, cx| { cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 0.)) assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 0.))
}); });
cx.simulate_keystrokes(["ctrl-d"]); cx.simulate_keystrokes("ctrl-d");
cx.update_editor(|editor, cx| { cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 3.0)); assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 3.0));
assert_eq!( assert_eq!(
@ -198,11 +198,11 @@ mod test {
}); });
// does select in visual mode // does select in visual mode
cx.simulate_keystrokes(["g", "g"]); cx.simulate_keystrokes("g g");
cx.update_editor(|editor, cx| { cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 0.)) assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 0.))
}); });
cx.simulate_keystrokes(["v", "ctrl-d"]); cx.simulate_keystrokes("v ctrl-d");
cx.update_editor(|editor, cx| { cx.update_editor(|editor, cx| {
assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 3.0)); assert_eq!(editor.snapshot(cx).scroll_position(), point(0., 3.0));
assert_eq!( assert_eq!(
@ -234,18 +234,18 @@ mod test {
// skip over the scrolloff at the top // skip over the scrolloff at the top
// test ctrl-d // test ctrl-d
cx.simulate_shared_keystrokes(["4", "j", "ctrl-d"]).await; cx.simulate_shared_keystrokes("4 j ctrl-d").await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
cx.simulate_shared_keystrokes(["ctrl-d"]).await; cx.simulate_shared_keystrokes("ctrl-d").await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
cx.simulate_shared_keystrokes(["g", "g", "ctrl-d"]).await; cx.simulate_shared_keystrokes("g g ctrl-d").await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
// test ctrl-u // test ctrl-u
cx.simulate_shared_keystrokes(["ctrl-u"]).await; cx.simulate_shared_keystrokes("ctrl-u").await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
cx.simulate_shared_keystrokes(["ctrl-d", "ctrl-d", "4", "j", "ctrl-u", "ctrl-u"]) cx.simulate_shared_keystrokes("ctrl-d ctrl-d 4 j ctrl-u ctrl-u")
.await; .await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
} }
} }

View File

@ -523,34 +523,34 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await; let mut cx = VimTestContext::new(cx, true).await;
cx.set_state("ˇhi\nhigh\nhi\n", Mode::Normal); cx.set_state("ˇhi\nhigh\nhi\n", Mode::Normal);
cx.simulate_keystrokes(["*"]); cx.simulate_keystrokes("*");
cx.run_until_parked(); cx.run_until_parked();
cx.assert_state("hi\nhigh\nˇhi\n", Mode::Normal); cx.assert_state("hi\nhigh\nˇhi\n", Mode::Normal);
cx.simulate_keystrokes(["*"]); cx.simulate_keystrokes("*");
cx.run_until_parked(); cx.run_until_parked();
cx.assert_state("ˇhi\nhigh\nhi\n", Mode::Normal); cx.assert_state("ˇhi\nhigh\nhi\n", Mode::Normal);
cx.simulate_keystrokes(["#"]); cx.simulate_keystrokes("#");
cx.run_until_parked(); cx.run_until_parked();
cx.assert_state("hi\nhigh\nˇhi\n", Mode::Normal); cx.assert_state("hi\nhigh\nˇhi\n", Mode::Normal);
cx.simulate_keystrokes(["#"]); cx.simulate_keystrokes("#");
cx.run_until_parked(); cx.run_until_parked();
cx.assert_state("ˇhi\nhigh\nhi\n", Mode::Normal); cx.assert_state("ˇhi\nhigh\nhi\n", Mode::Normal);
cx.simulate_keystrokes(["2", "*"]); cx.simulate_keystrokes("2 *");
cx.run_until_parked(); cx.run_until_parked();
cx.assert_state("ˇhi\nhigh\nhi\n", Mode::Normal); cx.assert_state("ˇhi\nhigh\nhi\n", Mode::Normal);
cx.simulate_keystrokes(["g", "*"]); cx.simulate_keystrokes("g *");
cx.run_until_parked(); cx.run_until_parked();
cx.assert_state("hi\nˇhigh\nhi\n", Mode::Normal); cx.assert_state("hi\nˇhigh\nhi\n", Mode::Normal);
cx.simulate_keystrokes(["n"]); cx.simulate_keystrokes("n");
cx.assert_state("hi\nhigh\nˇhi\n", Mode::Normal); cx.assert_state("hi\nhigh\nˇhi\n", Mode::Normal);
cx.simulate_keystrokes(["g", "#"]); cx.simulate_keystrokes("g #");
cx.run_until_parked(); cx.run_until_parked();
cx.assert_state("hi\nˇhigh\nhi\n", Mode::Normal); cx.assert_state("hi\nˇhigh\nhi\n", Mode::Normal);
} }
@ -560,7 +560,7 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await; let mut cx = VimTestContext::new(cx, true).await;
cx.set_state("aa\nbˇb\ncc\ncc\ncc\n", Mode::Normal); cx.set_state("aa\nbˇb\ncc\ncc\ncc\n", Mode::Normal);
cx.simulate_keystrokes(["/", "c", "c"]); cx.simulate_keystrokes("/ c c");
let search_bar = cx.workspace(|workspace, cx| { let search_bar = cx.workspace(|workspace, cx| {
workspace workspace
@ -587,50 +587,50 @@ mod test {
) )
}); });
cx.simulate_keystrokes(["enter"]); cx.simulate_keystrokes("enter");
cx.assert_state("aa\nbb\nˇcc\ncc\ncc\n", Mode::Normal); cx.assert_state("aa\nbb\nˇcc\ncc\ncc\n", Mode::Normal);
// n to go to next/N to go to previous // n to go to next/N to go to previous
cx.simulate_keystrokes(["n"]); cx.simulate_keystrokes("n");
cx.assert_state("aa\nbb\ncc\nˇcc\ncc\n", Mode::Normal); cx.assert_state("aa\nbb\ncc\nˇcc\ncc\n", Mode::Normal);
cx.simulate_keystrokes(["shift-n"]); cx.simulate_keystrokes("shift-n");
cx.assert_state("aa\nbb\nˇcc\ncc\ncc\n", Mode::Normal); cx.assert_state("aa\nbb\nˇcc\ncc\ncc\n", Mode::Normal);
// ?<enter> to go to previous // ?<enter> to go to previous
cx.simulate_keystrokes(["?", "enter"]); cx.simulate_keystrokes("? enter");
cx.assert_state("aa\nbb\ncc\ncc\nˇcc\n", Mode::Normal); cx.assert_state("aa\nbb\ncc\ncc\nˇcc\n", Mode::Normal);
cx.simulate_keystrokes(["?", "enter"]); cx.simulate_keystrokes("? enter");
cx.assert_state("aa\nbb\ncc\nˇcc\ncc\n", Mode::Normal); cx.assert_state("aa\nbb\ncc\nˇcc\ncc\n", Mode::Normal);
// /<enter> to go to next // /<enter> to go to next
cx.simulate_keystrokes(["/", "enter"]); cx.simulate_keystrokes("/ enter");
cx.assert_state("aa\nbb\ncc\ncc\nˇcc\n", Mode::Normal); cx.assert_state("aa\nbb\ncc\ncc\nˇcc\n", Mode::Normal);
// ?{search}<enter> to search backwards // ?{search}<enter> to search backwards
cx.simulate_keystrokes(["?", "b", "enter"]); cx.simulate_keystrokes("? b enter");
cx.assert_state("aa\nbˇb\ncc\ncc\ncc\n", Mode::Normal); cx.assert_state("aa\nbˇb\ncc\ncc\ncc\n", Mode::Normal);
// works with counts // works with counts
cx.simulate_keystrokes(["4", "/", "c"]); cx.simulate_keystrokes("4 / c");
cx.simulate_keystrokes(["enter"]); cx.simulate_keystrokes("enter");
cx.assert_state("aa\nbb\ncc\ncˇc\ncc\n", Mode::Normal); cx.assert_state("aa\nbb\ncc\ncˇc\ncc\n", Mode::Normal);
// check that searching resumes from cursor, not previous match // check that searching resumes from cursor, not previous match
cx.set_state("ˇaa\nbb\ndd\ncc\nbb\n", Mode::Normal); cx.set_state("ˇaa\nbb\ndd\ncc\nbb\n", Mode::Normal);
cx.simulate_keystrokes(["/", "d"]); cx.simulate_keystrokes("/ d");
cx.simulate_keystrokes(["enter"]); cx.simulate_keystrokes("enter");
cx.assert_state("aa\nbb\nˇdd\ncc\nbb\n", Mode::Normal); cx.assert_state("aa\nbb\nˇdd\ncc\nbb\n", Mode::Normal);
cx.update_editor(|editor, cx| editor.move_to_beginning(&Default::default(), cx)); cx.update_editor(|editor, cx| editor.move_to_beginning(&Default::default(), cx));
cx.assert_state("ˇaa\nbb\ndd\ncc\nbb\n", Mode::Normal); cx.assert_state("ˇaa\nbb\ndd\ncc\nbb\n", Mode::Normal);
cx.simulate_keystrokes(["/", "b"]); cx.simulate_keystrokes("/ b");
cx.simulate_keystrokes(["enter"]); cx.simulate_keystrokes("enter");
cx.assert_state("aa\nˇbb\ndd\ncc\nbb\n", Mode::Normal); cx.assert_state("aa\nˇbb\ndd\ncc\nbb\n", Mode::Normal);
// check that searching switches to normal mode if in visual mode // check that searching switches to normal mode if in visual mode
cx.set_state("ˇone two one", Mode::Normal); cx.set_state("ˇone two one", Mode::Normal);
cx.simulate_keystrokes(["v", "l", "l"]); cx.simulate_keystrokes("v l l");
cx.assert_editor_state("«oneˇ» two one"); cx.assert_editor_state("«oneˇ» two one");
cx.simulate_keystrokes(["*"]); cx.simulate_keystrokes("*");
cx.assert_state("one two ˇone", Mode::Normal); cx.assert_state("one two ˇone", Mode::Normal);
} }
@ -638,13 +638,13 @@ mod test {
async fn test_non_vim_search(cx: &mut gpui::TestAppContext) { async fn test_non_vim_search(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, false).await; let mut cx = VimTestContext::new(cx, false).await;
cx.set_state("ˇone one one one", Mode::Normal); cx.set_state("ˇone one one one", Mode::Normal);
cx.simulate_keystrokes(["cmd-f"]); cx.simulate_keystrokes("cmd-f");
cx.run_until_parked(); cx.run_until_parked();
cx.assert_editor_state("«oneˇ» one one one"); cx.assert_editor_state("«oneˇ» one one one");
cx.simulate_keystrokes(["enter"]); cx.simulate_keystrokes("enter");
cx.assert_editor_state("one «oneˇ» one one"); cx.assert_editor_state("one «oneˇ» one one");
cx.simulate_keystrokes(["shift-enter"]); cx.simulate_keystrokes("shift-enter");
cx.assert_editor_state("«oneˇ» one one one"); cx.assert_editor_state("«oneˇ» one one one");
} }
@ -653,9 +653,8 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("ˇa.c. abcd a.c. abcd").await; cx.set_shared_state("ˇa.c. abcd a.c. abcd").await;
cx.simulate_shared_keystrokes(["v", "3", "l", "*"]).await; cx.simulate_shared_keystrokes("v 3 l *").await;
cx.assert_shared_state("a.c. abcd ˇa.c. abcd").await; cx.shared_state().await.assert_eq("a.c. abcd ˇa.c. abcd");
cx.assert_shared_mode(Mode::Normal).await;
} }
#[gpui::test] #[gpui::test]
@ -663,9 +662,9 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("ˇa.c. abcd a.c. abcd").await; cx.set_shared_state("ˇa.c. abcd a.c. abcd").await;
cx.simulate_shared_keystrokes(["d", "/", "c", "d"]).await; cx.simulate_shared_keystrokes("d / c d").await;
cx.simulate_shared_keystrokes(["enter"]).await; cx.simulate_shared_keystrokes("enter").await;
cx.assert_shared_state("ˇcd a.c. abcd").await; cx.shared_state().await.assert_eq("ˇcd a.c. abcd");
} }
#[gpui::test] #[gpui::test]
@ -673,24 +672,24 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("ˇa.c. abcd a.c. abcd").await; cx.set_shared_state("ˇa.c. abcd a.c. abcd").await;
cx.simulate_shared_keystrokes(["v", "/", "c", "d"]).await; cx.simulate_shared_keystrokes("v / c d").await;
cx.simulate_shared_keystrokes(["enter"]).await; cx.simulate_shared_keystrokes("enter").await;
cx.assert_shared_state("«a.c. abcˇ»d a.c. abcd").await; cx.shared_state().await.assert_eq("«a.c. abcˇ»d a.c. abcd");
cx.set_shared_state("a a aˇ a a a").await; cx.set_shared_state("a a aˇ a a a").await;
cx.simulate_shared_keystrokes(["v", "/", "a"]).await; cx.simulate_shared_keystrokes("v / a").await;
cx.simulate_shared_keystrokes(["enter"]).await; cx.simulate_shared_keystrokes("enter").await;
cx.assert_shared_state("a a a« aˇ» a a").await; cx.shared_state().await.assert_eq("a a a« aˇ» a a");
cx.simulate_shared_keystrokes(["/", "enter"]).await; cx.simulate_shared_keystrokes("/ enter").await;
cx.assert_shared_state("a a a« a aˇ» a").await; cx.shared_state().await.assert_eq("a a a« a aˇ» a");
cx.simulate_shared_keystrokes(["?", "enter"]).await; cx.simulate_shared_keystrokes("? enter").await;
cx.assert_shared_state("a a a« aˇ» a a").await; cx.shared_state().await.assert_eq("a a a« aˇ» a a");
cx.simulate_shared_keystrokes(["?", "enter"]).await; cx.simulate_shared_keystrokes("? enter").await;
cx.assert_shared_state("a a «ˇa »a a a").await; cx.shared_state().await.assert_eq("a a «ˇa »a a a");
cx.simulate_shared_keystrokes(["/", "enter"]).await; cx.simulate_shared_keystrokes("/ enter").await;
cx.assert_shared_state("a a a« aˇ» a a").await; cx.shared_state().await.assert_eq("a a a« aˇ» a a");
cx.simulate_shared_keystrokes(["/", "enter"]).await; cx.simulate_shared_keystrokes("/ enter").await;
cx.assert_shared_state("a a a« a aˇ» a").await; cx.shared_state().await.assert_eq("a a a« a aˇ» a");
} }
#[gpui::test] #[gpui::test]
@ -704,16 +703,14 @@ mod test {
" "
}) })
.await; .await;
cx.simulate_shared_keystrokes(["ctrl-v", "j", "/", "f"]) cx.simulate_shared_keystrokes("ctrl-v j / f").await;
.await; cx.simulate_shared_keystrokes("enter").await;
cx.simulate_shared_keystrokes(["enter"]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"«one twoˇ» "«one twoˇ»
«three »our «three »our
five six five six
" "
}) });
.await;
} }
// cargo test -p vim --features neovim test_replace_with_range // cargo test -p vim --features neovim test_replace_with_range
@ -732,10 +729,9 @@ mod test {
" "
}) })
.await; .await;
cx.simulate_shared_keystrokes([":", "2", ",", "5", "s", "/", "a", "/", "b"]) cx.simulate_shared_keystrokes(": 2 , 5 s / a / b").await;
.await; cx.simulate_shared_keystrokes("enter").await;
cx.simulate_shared_keystrokes(["enter"]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"a "a
b b
b b
@ -744,7 +740,6 @@ mod test {
a a
a a
" "
}) });
.await;
} }
} }

View File

@ -95,37 +95,37 @@ mod test {
// supports a single cursor // supports a single cursor
cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal); cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal);
cx.simulate_keystrokes(["s", "x"]); cx.simulate_keystrokes("s x");
cx.assert_editor_state("xˇbc\n"); cx.assert_editor_state("xˇbc\n");
// supports a selection // supports a selection
cx.set_state(indoc! {"a«bcˇ»\n"}, Mode::Visual); cx.set_state(indoc! {"a«bcˇ»\n"}, Mode::Visual);
cx.assert_editor_state("a«bcˇ»\n"); cx.assert_editor_state("a«bcˇ»\n");
cx.simulate_keystrokes(["s", "x"]); cx.simulate_keystrokes("s x");
cx.assert_editor_state("axˇ\n"); cx.assert_editor_state("axˇ\n");
// supports counts // supports counts
cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal); cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal);
cx.simulate_keystrokes(["2", "s", "x"]); cx.simulate_keystrokes("2 s x");
cx.assert_editor_state("xˇc\n"); cx.assert_editor_state("xˇc\n");
// supports multiple cursors // supports multiple cursors
cx.set_state(indoc! {"a«bcˇ»deˇffg\n"}, Mode::Normal); cx.set_state(indoc! {"a«bcˇ»deˇffg\n"}, Mode::Normal);
cx.simulate_keystrokes(["2", "s", "x"]); cx.simulate_keystrokes("2 s x");
cx.assert_editor_state("axˇdexˇg\n"); cx.assert_editor_state("axˇdexˇg\n");
// does not read beyond end of line // does not read beyond end of line
cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal); cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal);
cx.simulate_keystrokes(["5", "s", "x"]); cx.simulate_keystrokes("5 s x");
cx.assert_editor_state("\n"); cx.assert_editor_state("\n");
// it handles multibyte characters // it handles multibyte characters
cx.set_state(indoc! {"ˇcàfé\n"}, Mode::Normal); cx.set_state(indoc! {"ˇcàfé\n"}, Mode::Normal);
cx.simulate_keystrokes(["4", "s"]); cx.simulate_keystrokes("4 s");
cx.assert_editor_state("ˇ\n"); cx.assert_editor_state("ˇ\n");
// should transactionally undo selection changes // should transactionally undo selection changes
cx.simulate_keystrokes(["escape", "u"]); cx.simulate_keystrokes("escape u");
cx.assert_editor_state("ˇcàfé\n"); cx.assert_editor_state("ˇcàfé\n");
// it handles visual line mode // it handles visual line mode
@ -136,7 +136,7 @@ mod test {
gamma"}, gamma"},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["shift-v", "s"]); cx.simulate_keystrokes("shift-v s");
cx.assert_editor_state(indoc! {" cx.assert_editor_state(indoc! {"
alpha alpha
ˇ ˇ
@ -148,66 +148,86 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("The quick ˇbrown").await; cx.set_shared_state("The quick ˇbrown").await;
cx.simulate_shared_keystrokes(["v", "w", "c"]).await; cx.simulate_shared_keystrokes("v w c").await;
cx.assert_shared_state("The quick ˇ").await; cx.shared_state().await.assert_eq("The quick ˇ");
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
The ˇquick brown The ˇquick brown
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["v", "w", "j", "c"]).await; cx.simulate_shared_keystrokes("v w j c").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
The ˇver The ˇver
the lazy dog"}) the lazy dog"});
.await;
let cases = cx.each_marked_position(indoc! {" cx.simulate_at_each_offset(
The ˇquick brown "v w j c",
fox jumps ˇover indoc! {"
the ˇlazy dog"}); The ˇquick brown
for initial_state in cases { fox jumps ˇover
cx.assert_neovim_compatible(&initial_state, ["v", "w", "j", "c"]) the ˇlazy dog"},
.await; )
cx.assert_neovim_compatible(&initial_state, ["v", "w", "k", "c"]) .await
.await; .assert_matches();
} cx.simulate_at_each_offset(
"v w k c",
indoc! {"
The ˇquick brown
fox jumps ˇover
the ˇlazy dog"},
)
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_visual_line_change(cx: &mut gpui::TestAppContext) { async fn test_visual_line_change(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx) let mut cx = NeovimBackedTestContext::new(cx).await;
.await cx.simulate(
.binding(["shift-v", "c"]); "shift-v c",
cx.assert(indoc! {" indoc! {"
The quˇick brown The quˇick brown
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"},
.await; )
.await
.assert_matches();
// Test pasting code copied on change // Test pasting code copied on change
cx.simulate_shared_keystrokes(["escape", "j", "p"]).await; cx.simulate_shared_keystrokes("escape j p").await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"shift-v c",
indoc! {"
The quick brown The quick brown
fox juˇmps over fox juˇmps over
the laˇzy dog"}) the laˇzy dog"},
.await; )
let mut cx = cx.binding(["shift-v", "j", "c"]); .await
cx.assert(indoc! {" .assert_matches();
cx.simulate(
"shift-v j c",
indoc! {"
The quˇick brown The quˇick brown
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"},
.await; )
.await
.assert_matches();
// Test pasting code copied on delete // Test pasting code copied on delete
cx.simulate_shared_keystrokes(["escape", "j", "p"]).await; cx.simulate_shared_keystrokes("escape j p").await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
cx.assert_all(indoc! {" cx.simulate_at_each_offset(
"shift-v j c",
indoc! {"
The quick brown The quick brown
fox juˇmps over fox juˇmps over
the laˇzy dog"}) the laˇzy dog"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
@ -222,55 +242,46 @@ mod test {
// normal mode // normal mode
cx.set_shared_state(initial_state).await; cx.set_shared_state(initial_state).await;
cx.simulate_shared_keystrokes(["shift-s", "o"]).await; cx.simulate_shared_keystrokes("shift-s o").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
The quick brown The quick brown
the lazy dog the lazy dog
"}) "});
.await;
// visual mode // visual mode
cx.set_shared_state(initial_state).await; cx.set_shared_state(initial_state).await;
cx.simulate_shared_keystrokes(["v", "k", "shift-s", "o"]) cx.simulate_shared_keystrokes("v k shift-s o").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
the lazy dog the lazy dog
"}) "});
.await;
// visual block mode // visual block mode
cx.set_shared_state(initial_state).await; cx.set_shared_state(initial_state).await;
cx.simulate_shared_keystrokes(["ctrl-v", "j", "shift-s", "o"]) cx.simulate_shared_keystrokes("ctrl-v j shift-s o").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
The quick brown The quick brown
"}) "});
.await;
// visual mode including newline // visual mode including newline
cx.set_shared_state(initial_state).await; cx.set_shared_state(initial_state).await;
cx.simulate_shared_keystrokes(["v", "$", "shift-s", "o"]) cx.simulate_shared_keystrokes("v $ shift-s o").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
The quick brown The quick brown
the lazy dog the lazy dog
"}) "});
.await;
// indentation // indentation
cx.set_neovim_option("shiftwidth=4").await; cx.set_neovim_option("shiftwidth=4").await;
cx.set_shared_state(initial_state).await; cx.set_shared_state(initial_state).await;
cx.simulate_shared_keystrokes([">", ">", "shift-s", "o"]) cx.simulate_shared_keystrokes("> > shift-s o").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
The quick brown The quick brown
the lazy dog the lazy dog
"}) "});
.await;
} }
} }

View File

@ -962,7 +962,7 @@ mod test {
use crate::{ use crate::{
state::Mode, state::Mode,
test::{ExemptionFeatures, NeovimBackedTestContext, VimTestContext}, test::{NeovimBackedTestContext, VimTestContext},
}; };
const WORD_LOCATIONS: &str = indoc! {" const WORD_LOCATIONS: &str = indoc! {"
@ -985,28 +985,36 @@ mod test {
async fn test_change_word_object(cx: &mut gpui::TestAppContext) { async fn test_change_word_object(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_binding_matches_all(["c", "i", "w"], WORD_LOCATIONS) cx.simulate_at_each_offset("c i w", WORD_LOCATIONS)
.await; .await
cx.assert_binding_matches_all(["c", "i", "shift-w"], WORD_LOCATIONS) .assert_matches();
.await; cx.simulate_at_each_offset("c i shift-w", WORD_LOCATIONS)
cx.assert_binding_matches_all(["c", "a", "w"], WORD_LOCATIONS) .await
.await; .assert_matches();
cx.assert_binding_matches_all(["c", "a", "shift-w"], WORD_LOCATIONS) cx.simulate_at_each_offset("c a w", WORD_LOCATIONS)
.await; .await
.assert_matches();
cx.simulate_at_each_offset("c a shift-w", WORD_LOCATIONS)
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
async fn test_delete_word_object(cx: &mut gpui::TestAppContext) { async fn test_delete_word_object(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_binding_matches_all(["d", "i", "w"], WORD_LOCATIONS) cx.simulate_at_each_offset("d i w", WORD_LOCATIONS)
.await; .await
cx.assert_binding_matches_all(["d", "i", "shift-w"], WORD_LOCATIONS) .assert_matches();
.await; cx.simulate_at_each_offset("d i shift-w", WORD_LOCATIONS)
cx.assert_binding_matches_all(["d", "a", "w"], WORD_LOCATIONS) .await
.await; .assert_matches();
cx.assert_binding_matches_all(["d", "a", "shift-w"], WORD_LOCATIONS) cx.simulate_at_each_offset("d a w", WORD_LOCATIONS)
.await; .await
.assert_matches();
cx.simulate_at_each_offset("d a shift-w", WORD_LOCATIONS)
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
@ -1021,160 +1029,21 @@ mod test {
cx.assert_shared_state("The quick «brownˇ»\nfox").await; cx.assert_shared_state("The quick «brownˇ»\nfox").await;
*/ */
cx.set_shared_state("The quick brown\nˇ\nfox").await; cx.set_shared_state("The quick brown\nˇ\nfox").await;
cx.simulate_shared_keystrokes(["v"]).await; cx.simulate_shared_keystrokes("v").await;
cx.assert_shared_state("The quick brown\n«\nˇ»fox").await; cx.shared_state()
cx.simulate_shared_keystrokes(["i", "w"]).await;
cx.assert_shared_state("The quick brown\n«\nˇ»fox").await;
cx.assert_binding_matches_all(["v", "i", "w"], WORD_LOCATIONS)
.await;
cx.assert_binding_matches_all_exempted(
["v", "h", "i", "w"],
WORD_LOCATIONS,
ExemptionFeatures::NonEmptyVisualTextObjects,
)
.await;
cx.assert_binding_matches_all_exempted(
["v", "l", "i", "w"],
WORD_LOCATIONS,
ExemptionFeatures::NonEmptyVisualTextObjects,
)
.await;
cx.assert_binding_matches_all(["v", "i", "shift-w"], WORD_LOCATIONS)
.await;
cx.assert_binding_matches_all_exempted(
["v", "i", "h", "shift-w"],
WORD_LOCATIONS,
ExemptionFeatures::NonEmptyVisualTextObjects,
)
.await;
cx.assert_binding_matches_all_exempted(
["v", "i", "l", "shift-w"],
WORD_LOCATIONS,
ExemptionFeatures::NonEmptyVisualTextObjects,
)
.await;
cx.assert_binding_matches_all_exempted(
["v", "a", "w"],
WORD_LOCATIONS,
ExemptionFeatures::AroundObjectLeavesWhitespaceAtEndOfLine,
)
.await;
cx.assert_binding_matches_all_exempted(
["v", "a", "shift-w"],
WORD_LOCATIONS,
ExemptionFeatures::AroundObjectLeavesWhitespaceAtEndOfLine,
)
.await;
}
const SENTENCE_EXAMPLES: &[&'static str] = &[
"ˇThe quick ˇbrownˇ?ˇ ˇFox Jˇumpsˇ!ˇ Ovˇer theˇ lazyˇ.",
indoc! {"
ˇThe quick ˇbrownˇ
fox jumps over
the lazy doˇgˇ.ˇ ˇThe quick ˇ
brown fox jumps over
"},
indoc! {"
The quick brown fox jumps.
Over the lazy dog
ˇ
ˇ
ˇ fox-jumpˇs over
the lazy dog.ˇ
ˇ
"},
r#"ˇThe ˇquick brownˇ.)ˇ]ˇ'ˇ" Brown ˇfox jumpsˇ.ˇ "#,
];
#[gpui::test]
async fn test_change_sentence_object(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx)
.await .await
.binding(["c", "i", "s"]); .assert_eq("The quick brown\n«\nˇ»fox");
cx.add_initial_state_exemptions( cx.simulate_shared_keystrokes("i w").await;
"The quick brown fox jumps.\nOver the lazy dog\nˇ\nˇ\n fox-jumps over\nthe lazy dog.\n\n", cx.shared_state()
ExemptionFeatures::SentenceOnEmptyLines);
cx.add_initial_state_exemptions(
"The quick brown fox jumps.\nOver the lazy dog\n\n\nˇ foxˇ-ˇjumpˇs over\nthe lazy dog.\n\n",
ExemptionFeatures::SentenceAtStartOfLineWithWhitespace);
cx.add_initial_state_exemptions(
"The quick brown fox jumps.\nOver the lazy dog\n\n\n fox-jumps over\nthe lazy dog.ˇ\nˇ\n",
ExemptionFeatures::SentenceAfterPunctuationAtEndOfFile);
for sentence_example in SENTENCE_EXAMPLES {
cx.assert_all(sentence_example).await;
}
let mut cx = cx.binding(["c", "a", "s"]);
cx.add_initial_state_exemptions(
"The quick brown?ˇ Fox Jumps! Over the lazy.",
ExemptionFeatures::IncorrectLandingPosition,
);
cx.add_initial_state_exemptions(
"The quick brown.)]\'\" Brown fox jumps.ˇ ",
ExemptionFeatures::AroundObjectLeavesWhitespaceAtEndOfLine,
);
for sentence_example in SENTENCE_EXAMPLES {
cx.assert_all(sentence_example).await;
}
}
#[gpui::test]
async fn test_delete_sentence_object(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx)
.await .await
.binding(["d", "i", "s"]); .assert_eq("The quick brown\n«\nˇ»fox");
cx.add_initial_state_exemptions(
"The quick brown fox jumps.\nOver the lazy dog\nˇ\nˇ\n fox-jumps over\nthe lazy dog.\n\n",
ExemptionFeatures::SentenceOnEmptyLines);
cx.add_initial_state_exemptions(
"The quick brown fox jumps.\nOver the lazy dog\n\n\nˇ foxˇ-ˇjumpˇs over\nthe lazy dog.\n\n",
ExemptionFeatures::SentenceAtStartOfLineWithWhitespace);
cx.add_initial_state_exemptions(
"The quick brown fox jumps.\nOver the lazy dog\n\n\n fox-jumps over\nthe lazy dog.ˇ\nˇ\n",
ExemptionFeatures::SentenceAfterPunctuationAtEndOfFile);
for sentence_example in SENTENCE_EXAMPLES { cx.simulate_at_each_offset("v i w", WORD_LOCATIONS)
cx.assert_all(sentence_example).await;
}
let mut cx = cx.binding(["d", "a", "s"]);
cx.add_initial_state_exemptions(
"The quick brown?ˇ Fox Jumps! Over the lazy.",
ExemptionFeatures::IncorrectLandingPosition,
);
cx.add_initial_state_exemptions(
"The quick brown.)]\'\" Brown fox jumps.ˇ ",
ExemptionFeatures::AroundObjectLeavesWhitespaceAtEndOfLine,
);
for sentence_example in SENTENCE_EXAMPLES {
cx.assert_all(sentence_example).await;
}
}
#[gpui::test]
async fn test_visual_sentence_object(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx)
.await .await
.binding(["v", "i", "s"]); .assert_matches();
for sentence_example in SENTENCE_EXAMPLES { cx.simulate_at_each_offset("v i shift-w", WORD_LOCATIONS)
cx.assert_all_exempted(sentence_example, ExemptionFeatures::SentenceOnEmptyLines) .await
.await; .assert_matches();
}
let mut cx = cx.binding(["v", "a", "s"]);
for sentence_example in SENTENCE_EXAMPLES {
cx.assert_all_exempted(
sentence_example,
ExemptionFeatures::AroundSentenceStartingBetweenIncludesWrongWhitespace,
)
.await;
}
} }
const PARAGRAPH_EXAMPLES: &[&'static str] = &[ const PARAGRAPH_EXAMPLES: &[&'static str] = &[
@ -1237,10 +1106,12 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
for paragraph_example in PARAGRAPH_EXAMPLES { for paragraph_example in PARAGRAPH_EXAMPLES {
cx.assert_binding_matches_all(["c", "i", "p"], paragraph_example) cx.simulate_at_each_offset("c i p", paragraph_example)
.await; .await
cx.assert_binding_matches_all(["c", "a", "p"], paragraph_example) .assert_matches();
.await; cx.simulate_at_each_offset("c a p", paragraph_example)
.await
.assert_matches();
} }
} }
@ -1249,60 +1120,15 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
for paragraph_example in PARAGRAPH_EXAMPLES { for paragraph_example in PARAGRAPH_EXAMPLES {
cx.assert_binding_matches_all(["d", "i", "p"], paragraph_example) cx.simulate_at_each_offset("d i p", paragraph_example)
.await; .await
cx.assert_binding_matches_all(["d", "a", "p"], paragraph_example) .assert_matches();
.await; cx.simulate_at_each_offset("d a p", paragraph_example)
.await
.assert_matches();
} }
} }
#[gpui::test]
async fn test_paragraph_object_with_landing_positions_not_at_beginning_of_line(
cx: &mut gpui::TestAppContext,
) {
// Landing position not at the beginning of the line
const PARAGRAPH_LANDING_POSITION_EXAMPLE: &'static str = indoc! {"
The quick brown fox jumpsˇ
over the lazy dog.ˇ
ˇ ˇ\
ˇ ˇ
ˇ\ ˇ\
ˇThe quick brown fox jumpsˇ
ˇover the lazy dog.ˇ
ˇ ˇ\
ˇ
ˇ ˇ\
ˇ\ ˇ\
"};
let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_binding_matches_all_exempted(
["c", "i", "p"],
PARAGRAPH_LANDING_POSITION_EXAMPLE,
ExemptionFeatures::IncorrectLandingPosition,
)
.await;
cx.assert_binding_matches_all_exempted(
["c", "a", "p"],
PARAGRAPH_LANDING_POSITION_EXAMPLE,
ExemptionFeatures::IncorrectLandingPosition,
)
.await;
cx.assert_binding_matches_all_exempted(
["d", "i", "p"],
PARAGRAPH_LANDING_POSITION_EXAMPLE,
ExemptionFeatures::IncorrectLandingPosition,
)
.await;
cx.assert_binding_matches_all_exempted(
["d", "a", "p"],
PARAGRAPH_LANDING_POSITION_EXAMPLE,
ExemptionFeatures::IncorrectLandingPosition,
)
.await;
}
#[gpui::test] #[gpui::test]
async fn test_visual_paragraph_object(cx: &mut gpui::TestAppContext) { async fn test_visual_paragraph_object(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
@ -1332,27 +1158,24 @@ mod test {
]; ];
for paragraph_example in EXAMPLES { for paragraph_example in EXAMPLES {
cx.assert_binding_matches_all(["v", "i", "p"], paragraph_example) cx.simulate_at_each_offset("v i p", paragraph_example)
.await; .await
cx.assert_binding_matches_all(["v", "a", "p"], paragraph_example) .assert_matches();
.await; cx.simulate_at_each_offset("v a p", paragraph_example)
.await
.assert_matches();
} }
} }
// Test string with "`" for opening surrounders and "'" for closing surrounders // Test string with "`" for opening surrounders and "'" for closing surrounders
const SURROUNDING_MARKER_STRING: &str = indoc! {" const SURROUNDING_MARKER_STRING: &str = indoc! {"
ˇTh'ˇe ˇ`ˇ'ˇquˇi`ˇck broˇ'wn` ˇTh'ˇe ˇ`ˇ'ˇquˇi`ˇck broˇ'wn`
'ˇfox juˇmps ovˇ`ˇer 'ˇfox juˇmps ov`ˇer
the ˇlazy dˇ'ˇ`ˇg"}; the ˇlazy d'o`ˇg"};
const SURROUNDING_OBJECTS: &[(char, char)] = &[ const SURROUNDING_OBJECTS: &[(char, char)] = &[
('\'', '\''), // Quote ('"', '"'), // Double Quote
('`', '`'), // Back Quote ('(', ')'), // Parentheses
('"', '"'), // Double Quote
('(', ')'), // Parentheses
('[', ']'), // SquareBrackets
('{', '}'), // CurlyBrackets
('<', '>'), // AngleBrackets
]; ];
#[gpui::test] #[gpui::test]
@ -1364,14 +1187,18 @@ mod test {
.replace('`', &start.to_string()) .replace('`', &start.to_string())
.replace('\'', &end.to_string()); .replace('\'', &end.to_string());
cx.assert_binding_matches_all(["c", "i", &start.to_string()], &marked_string) cx.simulate_at_each_offset(&format!("c i {start}"), &marked_string)
.await; .await
cx.assert_binding_matches_all(["c", "i", &end.to_string()], &marked_string) .assert_matches();
.await; cx.simulate_at_each_offset(&format!("c i {end}"), &marked_string)
cx.assert_binding_matches_all(["c", "a", &start.to_string()], &marked_string) .await
.await; .assert_matches();
cx.assert_binding_matches_all(["c", "a", &end.to_string()], &marked_string) cx.simulate_at_each_offset(&format!("c a {start}"), &marked_string)
.await; .await
.assert_matches();
cx.simulate_at_each_offset(&format!("c a {end}"), &marked_string)
.await
.assert_matches();
} }
} }
#[gpui::test] #[gpui::test]
@ -1383,53 +1210,48 @@ mod test {
"helˇlo \"world\"!" "helˇlo \"world\"!"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["v", "i", "\""]).await; cx.simulate_shared_keystrokes("v i \"").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"hello \"«worldˇ»\"!" "hello \"«worldˇ»\"!"
}) });
.await;
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
"hello \"wˇorld\"!" "hello \"wˇorld\"!"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["v", "i", "\""]).await; cx.simulate_shared_keystrokes("v i \"").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"hello \"«worldˇ»\"!" "hello \"«worldˇ»\"!"
}) });
.await;
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
"hello \"wˇorld\"!" "hello \"wˇorld\"!"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["v", "a", "\""]).await; cx.simulate_shared_keystrokes("v a \"").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"hello« \"world\"ˇ»!" "hello« \"world\"ˇ»!"
}) });
.await;
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
"hello \"wˇorld\" !" "hello \"wˇorld\" !"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["v", "a", "\""]).await; cx.simulate_shared_keystrokes("v a \"").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"hello «\"world\" ˇ»!" "hello «\"world\" ˇ»!"
}) });
.await;
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
"hello \"wˇorld\" "hello \"wˇorld\"
goodbye" goodbye"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["v", "a", "\""]).await; cx.simulate_shared_keystrokes("v a \"").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"hello «\"world\" ˇ» "hello «\"world\" ˇ»
goodbye" goodbye"
}) });
.await;
} }
#[gpui::test] #[gpui::test]
@ -1445,15 +1267,14 @@ mod test {
}" }"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["v", "i", "{"]).await; cx.simulate_shared_keystrokes("v i {").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
func empty(a string) bool { func empty(a string) bool {
« if a == \"\" { « if a == \"\" {
return true return true
} }
return false return false
ˇ»}"}) ˇ»}"});
.await;
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
"func empty(a string) bool { "func empty(a string) bool {
if a == \"\" { if a == \"\" {
@ -1463,15 +1284,14 @@ mod test {
}" }"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["v", "i", "{"]).await; cx.simulate_shared_keystrokes("v i {").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
func empty(a string) bool { func empty(a string) bool {
if a == \"\" { if a == \"\" {
« return true « return true
ˇ» } ˇ» }
return false return false
}"}) }"});
.await;
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
"func empty(a string) bool { "func empty(a string) bool {
@ -1482,15 +1302,14 @@ mod test {
}" }"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["v", "i", "{"]).await; cx.simulate_shared_keystrokes("v i {").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
func empty(a string) bool { func empty(a string) bool {
if a == \"\" { if a == \"\" {
« return true « return true
ˇ» } ˇ» }
return false return false
}"}) }"});
.await;
} }
#[gpui::test] #[gpui::test]
@ -1502,21 +1321,19 @@ mod test {
"h\"e\\\"lˇlo \\\"world\"!" "h\"e\\\"lˇlo \\\"world\"!"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["v", "i", "\""]).await; cx.simulate_shared_keystrokes("v i \"").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"h\"«e\\\"llo \\\"worldˇ»\"!" "h\"«e\\\"llo \\\"worldˇ»\"!"
}) });
.await;
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
"hello \"teˇst \\\"inside\\\" world\"" "hello \"teˇst \\\"inside\\\" world\""
}) })
.await; .await;
cx.simulate_shared_keystrokes(["v", "i", "\""]).await; cx.simulate_shared_keystrokes("v i \"").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"hello \"«test \\\"inside\\\" worldˇ»\"" "hello \"«test \\\"inside\\\" worldˇ»\""
}) });
.await;
} }
#[gpui::test] #[gpui::test]
@ -1530,7 +1347,7 @@ mod test {
}, },
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["c", "i", "|"]); cx.simulate_keystrokes("c i |");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
fn boop() { fn boop() {
@ -1539,7 +1356,7 @@ mod test {
}, },
Mode::Insert, Mode::Insert,
); );
cx.simulate_keystrokes(["escape", "1", "8", "|"]); cx.simulate_keystrokes("escape 1 8 |");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
fn boop() { fn boop() {
@ -1549,7 +1366,7 @@ mod test {
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["v", "a", "|"]); cx.simulate_keystrokes("v a |");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
fn boop() { fn boop() {
@ -1566,7 +1383,7 @@ mod test {
// Generic arguments // Generic arguments
cx.set_state("fn boop<A: ˇDebug, B>() {}", Mode::Normal); cx.set_state("fn boop<A: ˇDebug, B>() {}", Mode::Normal);
cx.simulate_keystrokes(["v", "i", "a"]); cx.simulate_keystrokes("v i a");
cx.assert_state("fn boop<«A: Debugˇ», B>() {}", Mode::Visual); cx.assert_state("fn boop<«A: Debugˇ», B>() {}", Mode::Visual);
// Function arguments // Function arguments
@ -1574,11 +1391,11 @@ mod test {
"fn boop(ˇarg_a: (Tuple, Of, Types), arg_b: String) {}", "fn boop(ˇarg_a: (Tuple, Of, Types), arg_b: String) {}",
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["d", "a", "a"]); cx.simulate_keystrokes("d a a");
cx.assert_state("fn boop(ˇarg_b: String) {}", Mode::Normal); cx.assert_state("fn boop(ˇarg_b: String) {}", Mode::Normal);
cx.set_state("std::namespace::test(\"strinˇg\", a.b.c())", 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 a");
cx.assert_state("std::namespace::test(«\"string\", ˇ»a.b.c())", Mode::Visual); cx.assert_state("std::namespace::test(«\"string\", ˇ»a.b.c())", Mode::Visual);
// Tuple, vec, and array arguments // Tuple, vec, and array arguments
@ -1586,34 +1403,34 @@ mod test {
"fn boop(arg_a: (Tuple, Ofˇ, Types), arg_b: String) {}", "fn boop(arg_a: (Tuple, Ofˇ, Types), arg_b: String) {}",
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["c", "i", "a"]); cx.simulate_keystrokes("c i a");
cx.assert_state( cx.assert_state(
"fn boop(arg_a: (Tuple, ˇ, Types), arg_b: String) {}", "fn boop(arg_a: (Tuple, ˇ, Types), arg_b: String) {}",
Mode::Insert, Mode::Insert,
); );
cx.set_state("let a = (test::call(), 'p', my_macro!{ˇ});", Mode::Normal); cx.set_state("let a = (test::call(), 'p', my_macro!{ˇ});", Mode::Normal);
cx.simulate_keystrokes(["c", "a", "a"]); cx.simulate_keystrokes("c a a");
cx.assert_state("let a = (test::call(), 'p'ˇ);", Mode::Insert); cx.assert_state("let a = (test::call(), 'p'ˇ);", Mode::Insert);
cx.set_state("let a = [test::call(ˇ), 300];", Mode::Normal); cx.set_state("let a = [test::call(ˇ), 300];", Mode::Normal);
cx.simulate_keystrokes(["c", "i", "a"]); cx.simulate_keystrokes("c i a");
cx.assert_state("let a = [ˇ, 300];", Mode::Insert); cx.assert_state("let a = [ˇ, 300];", Mode::Insert);
cx.set_state( cx.set_state(
"let a = vec![Vec::new(), vecˇ![test::call(), 300]];", "let a = vec![Vec::new(), vecˇ![test::call(), 300]];",
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["c", "a", "a"]); cx.simulate_keystrokes("c a a");
cx.assert_state("let a = vec![Vec::new()ˇ];", Mode::Insert); cx.assert_state("let a = vec![Vec::new()ˇ];", Mode::Insert);
// Cursor immediately before / after brackets // Cursor immediately before / after brackets
cx.set_state("let a = [test::call(first_arg)ˇ]", Mode::Normal); cx.set_state("let a = [test::call(first_arg)ˇ]", Mode::Normal);
cx.simulate_keystrokes(["v", "i", "a"]); cx.simulate_keystrokes("v i a");
cx.assert_state("let a = [«test::call(first_arg)ˇ»]", Mode::Visual); cx.assert_state("let a = [«test::call(first_arg)ˇ»]", Mode::Visual);
cx.set_state("let a = [test::callˇ(first_arg)]", Mode::Normal); cx.set_state("let a = [test::callˇ(first_arg)]", Mode::Normal);
cx.simulate_keystrokes(["v", "i", "a"]); cx.simulate_keystrokes("v i a");
cx.assert_state("let a = [«test::call(first_arg)ˇ»]", Mode::Visual); cx.assert_state("let a = [«test::call(first_arg)ˇ»]", Mode::Visual);
} }
@ -1626,14 +1443,18 @@ mod test {
.replace('`', &start.to_string()) .replace('`', &start.to_string())
.replace('\'', &end.to_string()); .replace('\'', &end.to_string());
cx.assert_binding_matches_all(["d", "i", &start.to_string()], &marked_string) cx.simulate_at_each_offset(&format!("d i {start}"), &marked_string)
.await; .await
cx.assert_binding_matches_all(["d", "i", &end.to_string()], &marked_string) .assert_matches();
.await; cx.simulate_at_each_offset(&format!("d i {end}"), &marked_string)
cx.assert_binding_matches_all(["d", "a", &start.to_string()], &marked_string) .await
.await; .assert_matches();
cx.assert_binding_matches_all(["d", "a", &end.to_string()], &marked_string) cx.simulate_at_each_offset(&format!("d a {start}"), &marked_string)
.await; .await
.assert_matches();
cx.simulate_at_each_offset(&format!("d a {end}"), &marked_string)
.await
.assert_matches();
} }
} }
@ -1642,17 +1463,17 @@ mod test {
let mut cx = VimTestContext::new_html(cx).await; let mut cx = VimTestContext::new_html(cx).await;
cx.set_state("<html><head></head><body><b>hˇi!</b></body>", Mode::Normal); cx.set_state("<html><head></head><body><b>hˇi!</b></body>", Mode::Normal);
cx.simulate_keystrokes(["v", "i", "t"]); cx.simulate_keystrokes("v i t");
cx.assert_state( cx.assert_state(
"<html><head></head><body><b>«hi!ˇ»</b></body>", "<html><head></head><body><b>«hi!ˇ»</b></body>",
Mode::Visual, Mode::Visual,
); );
cx.simulate_keystrokes(["a", "t"]); cx.simulate_keystrokes("a t");
cx.assert_state( cx.assert_state(
"<html><head></head><body>«<b>hi!</b>ˇ»</body>", "<html><head></head><body>«<b>hi!</b>ˇ»</body>",
Mode::Visual, Mode::Visual,
); );
cx.simulate_keystrokes(["a", "t"]); cx.simulate_keystrokes("a t");
cx.assert_state( cx.assert_state(
"<html><head></head>«<body><b>hi!</b></body>ˇ»", "<html><head></head>«<body><b>hi!</b></body>ˇ»",
Mode::Visual, Mode::Visual,
@ -1663,12 +1484,12 @@ mod test {
"<html><head></head><body> ˇ <b>hi!</b></body>", "<html><head></head><body> ˇ <b>hi!</b></body>",
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["v", "i", "t"]); cx.simulate_keystrokes("v i t");
cx.assert_state( cx.assert_state(
"<html><head></head><body> <b>«hi!ˇ»</b></body>", "<html><head></head><body> <b>«hi!ˇ»</b></body>",
Mode::Visual, Mode::Visual,
); );
cx.simulate_keystrokes(["a", "t"]); cx.simulate_keystrokes("a t");
cx.assert_state( cx.assert_state(
"<html><head></head><body> «<b>hi!</b>ˇ»</body>", "<html><head></head><body> «<b>hi!</b>ˇ»</body>",
Mode::Visual, Mode::Visual,
@ -1679,12 +1500,12 @@ mod test {
"<html><head></head><body><bˇ>hi!</b><b>hello!</b></body>", "<html><head></head><body><bˇ>hi!</b><b>hello!</b></body>",
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["v", "a", "t"]); cx.simulate_keystrokes("v a t");
cx.assert_state( cx.assert_state(
"<html><head></head><body>«<b>hi!</b>ˇ»<b>hello!</b></body>", "<html><head></head><body>«<b>hi!</b>ˇ»<b>hello!</b></body>",
Mode::Visual, Mode::Visual,
); );
cx.simulate_keystrokes(["i", "t"]); cx.simulate_keystrokes("i t");
cx.assert_state( cx.assert_state(
"<html><head></head><body>«<b>hi!</b><b>hello!</b>ˇ»</body>", "<html><head></head><body>«<b>hi!</b><b>hello!</b>ˇ»</body>",
Mode::Visual, Mode::Visual,
@ -1695,12 +1516,12 @@ mod test {
"<html><head></head><body><«b>hi!ˇ»</b></body>", "<html><head></head><body><«b>hi!ˇ»</b></body>",
Mode::Visual, Mode::Visual,
); );
cx.simulate_keystrokes(["i", "t"]); cx.simulate_keystrokes("i t");
cx.assert_state( cx.assert_state(
"<html><head></head><body><b>«hi!ˇ»</b></body>", "<html><head></head><body><b>«hi!ˇ»</b></body>",
Mode::Visual, Mode::Visual,
); );
cx.simulate_keystrokes(["a", "t"]); cx.simulate_keystrokes("a t");
cx.assert_state( cx.assert_state(
"<html><head></head><body>«<b>hi!</b>ˇ»</body>", "<html><head></head><body>«<b>hi!</b>ˇ»</body>",
Mode::Visual, Mode::Visual,
@ -1710,7 +1531,7 @@ mod test {
"<html><head></head><body><«b>hi!</ˇ»b></body>", "<html><head></head><body><«b>hi!</ˇ»b></body>",
Mode::Visual, Mode::Visual,
); );
cx.simulate_keystrokes(["a", "t"]); cx.simulate_keystrokes("a t");
cx.assert_state( cx.assert_state(
"<html><head></head>«<body><b>hi!</b></body>ˇ»", "<html><head></head>«<body><b>hi!</b></body>ˇ»",
Mode::Visual, Mode::Visual,

View File

@ -148,9 +148,9 @@ mod test {
#[gpui::test] #[gpui::test]
async fn test_enter_and_exit_replace_mode(cx: &mut gpui::TestAppContext) { async fn test_enter_and_exit_replace_mode(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await; let mut cx = VimTestContext::new(cx, true).await;
cx.simulate_keystroke("shift-r"); cx.simulate_keystrokes("shift-r");
assert_eq!(cx.mode(), Mode::Replace); assert_eq!(cx.mode(), Mode::Replace);
cx.simulate_keystroke("escape"); cx.simulate_keystrokes("escape");
assert_eq!(cx.mode(), Mode::Normal); assert_eq!(cx.mode(), Mode::Normal);
} }
@ -164,14 +164,11 @@ mod test {
fox jumps over fox jumps over
the lazy dog."}) the lazy dog."})
.await; .await;
cx.simulate_shared_keystrokes(["shift-r", "O", "n", "e"]) cx.simulate_shared_keystrokes("shift-r O n e").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
Oneˇ quick brown Oneˇ quick brown
fox jumps over fox jumps over
the lazy dog."}) the lazy dog."});
.await;
assert_eq!(Mode::Replace, cx.neovim_mode().await);
// test replace with line ending // test replace with line ending
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
@ -179,13 +176,11 @@ mod test {
fox jumps over fox jumps over
the lazy dog."}) the lazy dog."})
.await; .await;
cx.simulate_shared_keystrokes(["shift-r", "O", "n", "e"]) cx.simulate_shared_keystrokes("shift-r O n e").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
The quick browOneˇ The quick browOneˇ
fox jumps over fox jumps over
the lazy dog."}) the lazy dog."});
.await;
// test replace with blank line // test replace with blank line
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
@ -194,28 +189,12 @@ mod test {
fox jumps over fox jumps over
the lazy dog."}) the lazy dog."})
.await; .await;
cx.simulate_shared_keystrokes(["shift-r", "O", "n", "e"]) cx.simulate_shared_keystrokes("shift-r O n e").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
The quick brown The quick brown
Oneˇ Oneˇ
fox jumps over fox jumps over
the lazy dog."}) the lazy dog."});
.await;
// test replace with multi cursor
cx.set_shared_state(indoc! {"
ˇThe quick brown
fox jumps over
the lazy ˇdog."})
.await;
cx.simulate_shared_keystrokes(["shift-r", "O", "n", "e"])
.await;
cx.assert_shared_state(indoc! {"
Oneˇ quick brown
fox jumps over
the lazy Oneˇ."})
.await;
// test replace with newline // test replace with newline
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
@ -223,37 +202,39 @@ mod test {
fox jumps over fox jumps over
the lazy dog."}) the lazy dog."})
.await; .await;
cx.simulate_shared_keystrokes(["shift-r", "enter", "O", "n", "e"]) cx.simulate_shared_keystrokes("shift-r enter O n e").await;
.await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! {"
The qu The qu
Oneˇ brown Oneˇ brown
fox jumps over fox jumps over
the lazy dog."}) the lazy dog."});
.await;
// test replace with multi cursor and newline // test replace with multi cursor and newline
cx.set_shared_state(indoc! {" cx.set_state(
indoc! {"
ˇThe quick brown ˇThe quick brown
fox jumps over fox jumps over
the lazy ˇdog."}) the lazy ˇdog."},
.await; Mode::Normal,
cx.simulate_shared_keystrokes(["shift-r", "O", "n", "e"]) );
.await; cx.simulate_keystrokes("shift-r O n e");
cx.assert_shared_state(indoc! {" cx.assert_state(
indoc! {"
Oneˇ quick brown Oneˇ quick brown
fox jumps over fox jumps over
the lazy Oneˇ."}) the lazy Oneˇ."},
.await; Mode::Replace,
cx.simulate_shared_keystrokes(["enter", "T", "w", "o"]) );
.await; cx.simulate_keystrokes("enter T w o");
cx.assert_shared_state(indoc! {" cx.assert_state(
indoc! {"
One One
Twoˇck brown Twoˇck brown
fox jumps over fox jumps over
the lazy One the lazy One
Twoˇ"}) Twoˇ"},
.await; Mode::Replace,
);
} }
#[gpui::test] #[gpui::test]
@ -276,60 +257,23 @@ mod test {
fox jumps over fox jumps over
the lazy dog." the lazy dog."
}, },
// replace undo with multi cursor
indoc! {"
The quick browˇn
fox jumps over
the lazy ˇdog."
},
]; ];
for example in UNDO_REPLACE_EXAMPLES { for example in UNDO_REPLACE_EXAMPLES {
// normal undo // normal undo
cx.assert_binding_matches( cx.simulate("shift-r O n e backspace backspace backspace", example)
[ .await
"shift-r", .assert_matches();
"O",
"n",
"e",
"backspace",
"backspace",
"backspace",
],
example,
)
.await;
// undo with new line // undo with new line
cx.assert_binding_matches( cx.simulate("shift-r O enter e backspace backspace backspace", example)
[ .await
"shift-r", .assert_matches();
"O", cx.simulate(
"enter", "shift-r O enter n enter e backspace backspace backspace backspace backspace",
"e",
"backspace",
"backspace",
"backspace",
],
example, example,
) )
.await; .await
cx.assert_binding_matches( .assert_matches();
[
"shift-r",
"O",
"enter",
"n",
"enter",
"e",
"backspace",
"backspace",
"backspace",
"backspace",
"backspace",
],
example,
)
.await;
} }
} }
@ -337,16 +281,10 @@ mod test {
async fn test_replace_multicursor(cx: &mut gpui::TestAppContext) { async fn test_replace_multicursor(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new(cx, true).await; let mut cx = VimTestContext::new(cx, true).await;
cx.set_state("ˇabcˇabcabc", Mode::Normal); cx.set_state("ˇabcˇabcabc", Mode::Normal);
cx.simulate_keystrokes(["shift-r", "1", "2", "3", "4"]); cx.simulate_keystrokes("shift-r 1 2 3 4");
cx.assert_state("1234ˇ234ˇbc", Mode::Replace); cx.assert_state("1234ˇ234ˇbc", Mode::Replace);
assert_eq!(cx.mode(), Mode::Replace); assert_eq!(cx.mode(), Mode::Replace);
cx.simulate_keystrokes([ cx.simulate_keystrokes("backspace backspace backspace backspace backspace");
"backspace",
"backspace",
"backspace",
"backspace",
"backspace",
]);
cx.assert_state("ˇabˇcabcabc", Mode::Replace); cx.assert_state("ˇabˇcabcabc", Mode::Replace);
} }
@ -355,7 +293,7 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await; let mut cx = VimTestContext::new(cx, true).await;
cx.set_state("ˇaaaa", Mode::Normal); cx.set_state("ˇaaaa", Mode::Normal);
cx.simulate_keystrokes(["0", "shift-r", "b", "b", "b", "escape", "u"]); cx.simulate_keystrokes("0 shift-r b b b escape u");
cx.assert_state("ˇaaaa", Mode::Normal); cx.assert_state("ˇaaaa", Mode::Normal);
} }
} }

View File

@ -527,7 +527,7 @@ mod test {
the lazy dog."}, the lazy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["y", "s", "i", "w", "{"]); cx.simulate_keystrokes("y s i w {");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇ{ quick } brown The ˇ{ quick } brown
@ -544,7 +544,7 @@ mod test {
the lazy dog."}, the lazy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["y", "s", "i", "w", "}"]); cx.simulate_keystrokes("y s i w }");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇ{quick} brown The ˇ{quick} brown
@ -561,7 +561,7 @@ mod test {
the lazy dog."}, the lazy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["y", "s", "$", "}"]); cx.simulate_keystrokes("y s $ }");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The quˇ{ick brown} The quˇ{ick brown}
@ -578,7 +578,7 @@ mod test {
the laˇzy dog."}, the laˇzy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["y", "s", "i", "w", "'"]); cx.simulate_keystrokes("y s i w '");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇ'quick' brown The ˇ'quick' brown
@ -595,7 +595,7 @@ mod test {
the laˇzy dog."}, the laˇzy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["y", "s", "$", "'"]); cx.simulate_keystrokes("y s $ '");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The quˇ'ick brown' The quˇ'ick brown'
@ -612,7 +612,7 @@ mod test {
the laˇzy dog."}, the laˇzy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["y", "s", "$", "1"]); cx.simulate_keystrokes("y s $ 1");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The quˇ1ick brown1 The quˇ1ick brown1
@ -629,7 +629,7 @@ mod test {
the lazy dog."}, the lazy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["y", "s", "s", "{"]); cx.simulate_keystrokes("y s s {");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
ˇ{ The quick brown } ˇ{ The quick brown }
@ -645,7 +645,7 @@ mod test {
the lazy dog."}, the lazy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["y", "s", "s", "{"]); cx.simulate_keystrokes("y s s {");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
ˇ{ The quick brown } ˇ{ The quick brown }
@ -653,7 +653,7 @@ mod test {
the lazy dog."}, the lazy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["2", "y", "s", "s", ")"]); cx.simulate_keystrokes("2 y s s )");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
ˇ({ The quick brown } ˇ({ The quick brown }
@ -675,7 +675,7 @@ mod test {
the lazy dog."}, the lazy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["d", "s", "{"]); cx.simulate_keystrokes("d s {");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇquick brown The ˇquick brown
@ -692,7 +692,7 @@ mod test {
the lazy dog."}, the lazy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["d", "s", "["]); cx.simulate_keystrokes("d s [");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The {quˇick} brown The {quˇick} brown
@ -710,7 +710,7 @@ mod test {
the lazy dog."}, the lazy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["d", "s", "{"]); cx.simulate_keystrokes("d s {");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The {quick} brˇown The {quick} brˇown
@ -727,7 +727,7 @@ mod test {
the lazy dog."}, the lazy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["d", "s", "{"]); cx.simulate_keystrokes("d s {");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇquick brown The ˇquick brown
@ -744,7 +744,7 @@ mod test {
the [laˇzy] dog."}, the [laˇzy] dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["d", "s", "]"]); cx.simulate_keystrokes("d s ]");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇquick brown The ˇquick brown
@ -761,7 +761,7 @@ mod test {
the [laˇzy] dog."}, the [laˇzy] dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["d", "s", "["]); cx.simulate_keystrokes("d s [");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇquick brown The ˇquick brown
@ -777,7 +777,7 @@ mod test {
the [laˇzy ] dog."}, the [laˇzy ] dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["d", "s", "["]); cx.simulate_keystrokes("d s [");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇquick brown The ˇquick brown
@ -796,7 +796,7 @@ mod test {
the {laˇzy} dog."}, the {laˇzy} dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["d", "s", "{"]); cx.simulate_keystrokes("d s {");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The [quick] brown The [quick] brown
@ -815,7 +815,7 @@ mod test {
}"}, }"},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["d", "s", "}"]); cx.simulate_keystrokes("d s }");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
fn test_surround() ˇ fn test_surround() ˇ
@ -838,7 +838,7 @@ mod test {
the lazy dog."}, the lazy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["c", "s", "{", "["]); cx.simulate_keystrokes("c s { [");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇ[ quick ] brown The ˇ[ quick ] brown
@ -855,7 +855,7 @@ mod test {
the {laˇzy} dog."}, the {laˇzy} dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["c", "s", "{", "["]); cx.simulate_keystrokes("c s { [");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇ[ quick ] brown The ˇ[ quick ] brown
@ -872,7 +872,7 @@ mod test {
the {laˇzy} dog."}, the {laˇzy} dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["c", "s", "{", "["]); cx.simulate_keystrokes("c s { [");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇ[ quick ] brown The ˇ[ quick ] brown
@ -889,7 +889,7 @@ mod test {
the {laˇzy} dog."}, the {laˇzy} dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["c", "s", "{", "]"]); cx.simulate_keystrokes("c s { ]");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇ[quick] brown The ˇ[quick] brown
@ -906,7 +906,7 @@ mod test {
the [laˇzy] dog."}, the [laˇzy] dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["c", "s", "[", "'"]); cx.simulate_keystrokes("c s [ '");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The {quick} brown The {quick} brown
@ -925,7 +925,7 @@ mod test {
};"}, };"},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["c", "s", "{", "["]); cx.simulate_keystrokes("c s { [");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
fn test_surround() ˇ[ fn test_surround() ˇ[
@ -948,7 +948,7 @@ mod test {
the lazy dog."}, the lazy dog."},
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["y", "s", "i", "w", "["]); cx.simulate_keystrokes("y s i w [");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇ[ quick ] brown The ˇ[ quick ] brown
@ -957,7 +957,7 @@ mod test {
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["c", "s", "[", "}"]); cx.simulate_keystrokes("c s [ }");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇ{quick} brown The ˇ{quick} brown
@ -966,7 +966,7 @@ mod test {
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["d", "s", "{"]); cx.simulate_keystrokes("d s {");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇquick brown The ˇquick brown
@ -975,7 +975,7 @@ mod test {
Mode::Normal, Mode::Normal,
); );
cx.simulate_keystrokes(["u"]); cx.simulate_keystrokes("u");
cx.assert_state( cx.assert_state(
indoc! {" indoc! {"
The ˇ{quick} brown The ˇ{quick} brown

File diff suppressed because it is too large Load Diff

View File

@ -1,92 +0,0 @@
use std::ops::{Deref, DerefMut};
use crate::state::Mode;
use super::{ExemptionFeatures, NeovimBackedTestContext, SUPPORTED_FEATURES};
pub struct NeovimBackedBindingTestContext<const COUNT: usize> {
cx: NeovimBackedTestContext,
keystrokes_under_test: [&'static str; COUNT],
}
impl<const COUNT: usize> NeovimBackedBindingTestContext<COUNT> {
pub fn new(keystrokes_under_test: [&'static str; COUNT], cx: NeovimBackedTestContext) -> Self {
Self {
cx,
keystrokes_under_test,
}
}
pub fn consume(self) -> NeovimBackedTestContext {
self.cx
}
pub fn binding<const NEW_COUNT: usize>(
self,
keystrokes: [&'static str; NEW_COUNT],
) -> NeovimBackedBindingTestContext<NEW_COUNT> {
self.consume().binding(keystrokes)
}
pub async fn assert(&mut self, marked_positions: &str) {
self.cx
.assert_binding_matches(self.keystrokes_under_test, marked_positions)
.await;
}
pub async fn assert_exempted(&mut self, marked_positions: &str, feature: ExemptionFeatures) {
if SUPPORTED_FEATURES.contains(&feature) {
self.cx
.assert_binding_matches(self.keystrokes_under_test, marked_positions)
.await
}
}
pub fn assert_manual(
&mut self,
initial_state: &str,
mode_before: Mode,
state_after: &str,
mode_after: Mode,
) {
self.cx.assert_binding(
self.keystrokes_under_test,
initial_state,
mode_before,
state_after,
mode_after,
);
}
pub async fn assert_all(&mut self, marked_positions: &str) {
self.cx
.assert_binding_matches_all(self.keystrokes_under_test, marked_positions)
.await
}
pub async fn assert_all_exempted(
&mut self,
marked_positions: &str,
feature: ExemptionFeatures,
) {
if SUPPORTED_FEATURES.contains(&feature) {
self.cx
.assert_binding_matches_all(self.keystrokes_under_test, marked_positions)
.await
}
}
}
impl<const COUNT: usize> Deref for NeovimBackedBindingTestContext<COUNT> {
type Target = NeovimBackedTestContext;
fn deref(&self) -> &Self::Target {
&self.cx
}
}
impl<const COUNT: usize> DerefMut for NeovimBackedBindingTestContext<COUNT> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.cx
}
}

View File

@ -1,4 +1,3 @@
use editor::test::editor_test_context::ContextHandle;
use gpui::{px, size, BorrowAppContext, Context}; use gpui::{px, size, BorrowAppContext, Context};
use indoc::indoc; use indoc::indoc;
use settings::SettingsStore; use settings::SettingsStore;
@ -7,57 +6,132 @@ use std::{
panic, thread, panic, thread,
}; };
use collections::{HashMap, HashSet};
use language::language_settings::{AllLanguageSettings, SoftWrap}; use language::language_settings::{AllLanguageSettings, SoftWrap};
use util::test::marked_text_offsets; use util::test::marked_text_offsets;
use super::{neovim_connection::NeovimConnection, NeovimBackedBindingTestContext, VimTestContext}; use super::{neovim_connection::NeovimConnection, VimTestContext};
use crate::state::Mode; use crate::state::Mode;
pub const SUPPORTED_FEATURES: &[ExemptionFeatures] = &[];
/// Enum representing features we have tests for but which don't work, yet. Used
/// to add exemptions and automatically
#[derive(PartialEq, Eq)]
pub enum ExemptionFeatures {
// MOTIONS
// When an operator completes at the end of the file, an extra newline is left
OperatorLastNewlineRemains,
// OBJECTS
// Resulting position after the operation is slightly incorrect for unintuitive reasons.
IncorrectLandingPosition,
// Operator around the text object at the end of the line doesn't remove whitespace.
AroundObjectLeavesWhitespaceAtEndOfLine,
// Sentence object on empty lines
SentenceOnEmptyLines,
// Whitespace isn't included with text objects at the start of the line
SentenceAtStartOfLineWithWhitespace,
// Whitespace around sentences is slightly incorrect when starting between sentences
AroundSentenceStartingBetweenIncludesWrongWhitespace,
// Non empty selection with text objects in visual mode
NonEmptyVisualTextObjects,
// Sentence Doesn't backtrack when its at the end of the file
SentenceAfterPunctuationAtEndOfFile,
}
impl ExemptionFeatures {
pub fn supported(&self) -> bool {
SUPPORTED_FEATURES.contains(self)
}
}
pub struct NeovimBackedTestContext { pub struct NeovimBackedTestContext {
cx: VimTestContext, cx: VimTestContext,
// Lookup for exempted assertions. Keyed by the insertion text, and with a value indicating which
// bindings are exempted. If None, all bindings are ignored for that insertion text.
exemptions: HashMap<String, Option<HashSet<String>>>,
pub(crate) neovim: NeovimConnection, pub(crate) neovim: NeovimConnection,
last_set_state: Option<String>, last_set_state: Option<String>,
recent_keystrokes: Vec<String>, recent_keystrokes: Vec<String>,
}
is_dirty: bool, #[derive(Default)]
pub struct SharedState {
neovim: String,
editor: String,
initial: String,
neovim_mode: Mode,
editor_mode: Mode,
recent_keystrokes: String,
}
impl SharedState {
#[track_caller]
pub fn assert_matches(&self) {
if self.neovim != self.editor || self.neovim_mode != self.editor_mode {
panic!(
indoc! {"Test failed (zed does not match nvim behaviour)
# initial state:
{}
# keystrokes:
{}
# neovim ({}):
{}
# zed ({}):
{}"},
self.initial,
self.recent_keystrokes,
self.neovim_mode,
self.neovim,
self.editor_mode,
self.editor,
)
}
}
#[track_caller]
pub fn assert_eq(&mut self, marked_text: &str) {
let marked_text = marked_text.replace('•', " ");
if self.neovim == marked_text
&& self.neovim == self.editor
&& self.neovim_mode == self.editor_mode
{
return;
}
let message = if self.neovim != marked_text {
"Test is incorrect (currently expected != neovim_state)"
} else {
"Editor does not match nvim behaviour"
};
panic!(
indoc! {"{}
# initial state:
{}
# keystrokes:
{}
# currently expected:
{}
# neovim ({}):
{}
# zed ({}):
{}"},
message,
self.initial,
self.recent_keystrokes,
marked_text.replace(" \n", "\n"),
self.neovim_mode,
self.neovim.replace(" \n", "\n"),
self.editor_mode,
self.editor.replace(" \n", "\n"),
)
}
}
pub struct SharedClipboard {
neovim: String,
editor: String,
state: SharedState,
}
impl SharedClipboard {
#[track_caller]
pub fn assert_eq(&self, expected: &str) {
if expected == self.neovim && self.neovim == self.editor {
return;
}
let message = if expected == self.neovim {
"Test is incorrect (currently expected != neovim_state)"
} else {
"Editor does not match nvim behaviour"
};
panic!(
indoc! {"{}
# initial state:
{}
# keystrokes:
{}
# currently expected:
{}
# neovim clipboard:
{}
# zed clipboard:
{}"},
message,
self.state.initial,
self.state.recent_keystrokes,
expected,
self.neovim,
self.editor
)
}
} }
impl NeovimBackedTestContext { impl NeovimBackedTestContext {
@ -78,49 +152,13 @@ impl NeovimBackedTestContext {
.to_string(); .to_string();
Self { Self {
cx: VimTestContext::new(cx, true).await, cx: VimTestContext::new(cx, true).await,
exemptions: Default::default(),
neovim: NeovimConnection::new(test_name).await, neovim: NeovimConnection::new(test_name).await,
last_set_state: None, last_set_state: None,
recent_keystrokes: Default::default(), recent_keystrokes: Default::default(),
is_dirty: false,
} }
} }
pub fn add_initial_state_exemptions(
&mut self,
marked_positions: &str,
missing_feature: ExemptionFeatures, // Feature required to support this exempted test case
) {
if !missing_feature.supported() {
let (unmarked_text, cursor_offsets) = marked_text_offsets(marked_positions);
for cursor_offset in cursor_offsets.iter() {
let mut marked_text = unmarked_text.clone();
marked_text.insert(*cursor_offset, 'ˇ');
// None represents all key bindings being exempted for that initial state
self.exemptions.insert(marked_text, None);
}
}
}
pub async fn simulate_shared_keystroke(&mut self, keystroke_text: &str) -> ContextHandle {
self.neovim.send_keystroke(keystroke_text).await;
self.simulate_keystroke(keystroke_text)
}
pub async fn simulate_shared_keystrokes<const COUNT: usize>(
&mut self,
keystroke_texts: [&str; COUNT],
) {
for keystroke_text in keystroke_texts.into_iter() {
self.recent_keystrokes.push(keystroke_text.to_string());
self.neovim.send_keystroke(keystroke_text).await;
}
self.simulate_keystrokes(keystroke_texts);
}
pub async fn set_shared_state(&mut self, marked_text: &str) { pub async fn set_shared_state(&mut self, marked_text: &str) {
let mode = if marked_text.contains('»') { let mode = if marked_text.contains('»') {
Mode::Visual Mode::Visual
@ -131,7 +169,21 @@ impl NeovimBackedTestContext {
self.last_set_state = Some(marked_text.to_string()); self.last_set_state = Some(marked_text.to_string());
self.recent_keystrokes = Vec::new(); self.recent_keystrokes = Vec::new();
self.neovim.set_state(marked_text).await; self.neovim.set_state(marked_text).await;
self.is_dirty = true; }
pub async fn simulate_shared_keystrokes(&mut self, keystroke_texts: &str) {
for keystroke_text in keystroke_texts.split(' ') {
self.recent_keystrokes.push(keystroke_text.to_string());
self.neovim.send_keystroke(keystroke_text).await;
}
self.simulate_keystrokes(keystroke_texts);
}
#[must_use]
pub async fn simulate(&mut self, keystrokes: &str, initial_state: &str) -> SharedState {
self.set_shared_state(initial_state).await;
self.simulate_shared_keystrokes(keystrokes).await;
self.shared_state().await
} }
pub async fn set_shared_wrap(&mut self, columns: u32) { pub async fn set_shared_wrap(&mut self, columns: u32) {
@ -186,241 +238,51 @@ impl NeovimBackedTestContext {
self.neovim.set_option(option).await; self.neovim.set_option(option).await;
} }
pub async fn assert_shared_state(&mut self, marked_text: &str) { #[must_use]
self.is_dirty = false; pub async fn shared_clipboard(&mut self) -> SharedClipboard {
let marked_text = marked_text.replace('•', " "); SharedClipboard {
let neovim = self.neovim_state().await; state: self.shared_state().await,
let neovim_mode = self.neovim_mode().await; neovim: self.neovim.read_register('"').await,
let editor = self.editor_state(); editor: self.read_from_clipboard().unwrap().text().clone(),
let editor_mode = self.mode();
if neovim == marked_text && neovim == editor && neovim_mode == editor_mode {
return;
}
let initial_state = self
.last_set_state
.as_ref()
.unwrap_or(&"N/A".to_string())
.clone();
let message = if neovim != marked_text {
"Test is incorrect (currently expected != neovim_state)"
} else {
"Editor does not match nvim behaviour"
};
panic!(
indoc! {"{}
# initial state:
{}
# keystrokes:
{}
# currently expected:
{}
# neovim ({}):
{}
# zed ({}):
{}"},
message,
initial_state,
self.recent_keystrokes.join(" "),
marked_text.replace(" \n", "\n"),
neovim_mode,
neovim.replace(" \n", "\n"),
editor_mode,
editor.replace(" \n", "\n"),
)
}
pub async fn assert_shared_clipboard(&mut self, text: &str) {
let neovim = self.neovim.read_register('"').await;
let editor = self.read_from_clipboard().unwrap().text().clone();
if text == neovim && text == editor {
return;
}
let message = if neovim != text {
"Test is incorrect (currently expected != neovim)"
} else {
"Editor does not match nvim behaviour"
};
let initial_state = self
.last_set_state
.as_ref()
.unwrap_or(&"N/A".to_string())
.clone();
panic!(
indoc! {"{}
# initial state:
{}
# keystrokes:
{}
# currently expected:
{}
# neovim clipboard:
{}
# zed clipboard:
{}"},
message,
initial_state,
self.recent_keystrokes.join(" "),
text,
neovim,
editor
)
}
pub async fn neovim_state(&mut self) -> String {
self.neovim.marked_text().await
}
pub async fn neovim_mode(&mut self) -> Mode {
self.neovim.mode().await.unwrap()
}
pub async fn assert_shared_mode(&mut self, mode: Mode) {
let neovim = self.neovim_mode().await;
let editor = self.cx.mode();
if neovim != mode || editor != mode {
panic!(
indoc! {"Test failed (zed does not match nvim behaviour)
# desired mode:
{:?}
# neovim mode:
{:?}
# zed mode:
{:?}"},
mode, neovim, editor,
)
} }
} }
pub async fn assert_state_matches(&mut self) { #[must_use]
self.is_dirty = false; pub async fn shared_state(&mut self) -> SharedState {
let neovim = self.neovim_state().await; let (mode, marked_text) = self.neovim.state().await;
let neovim_mode = self.neovim_mode().await; SharedState {
let editor = self.editor_state(); neovim: marked_text,
let editor_mode = self.mode(); neovim_mode: mode,
let initial_state = self editor: self.editor_state(),
.last_set_state editor_mode: self.mode(),
.as_ref() initial: self
.unwrap_or(&"N/A".to_string()) .last_set_state
.clone(); .as_ref()
.cloned()
if neovim != editor || neovim_mode != editor_mode { .unwrap_or("N/A".to_string()),
panic!( recent_keystrokes: self.recent_keystrokes.join(" "),
indoc! {"Test failed (zed does not match nvim behaviour)
# initial state:
{}
# keystrokes:
{}
# neovim ({}):
{}
# zed ({}):
{}"},
initial_state,
self.recent_keystrokes.join(" "),
neovim_mode,
neovim,
editor_mode,
editor,
)
} }
} }
pub async fn assert_binding_matches<const COUNT: usize>( #[must_use]
pub async fn simulate_at_each_offset(
&mut self, &mut self,
keystrokes: [&str; COUNT], keystrokes: &str,
initial_state: &str, marked_positions: &str,
) { ) -> SharedState {
if let Some(possible_exempted_keystrokes) = self.exemptions.get(initial_state) { let (unmarked_text, cursor_offsets) = marked_text_offsets(marked_positions);
match possible_exempted_keystrokes {
Some(exempted_keystrokes) => { for cursor_offset in cursor_offsets.iter() {
if exempted_keystrokes.contains(&format!("{keystrokes:?}")) { let mut marked_text = unmarked_text.clone();
// This keystroke was exempted for this insertion text marked_text.insert(*cursor_offset, 'ˇ');
return;
} let state = self.simulate(keystrokes, &marked_text).await;
} if state.neovim != state.editor || state.neovim_mode != state.editor_mode {
None => { return state;
// All keystrokes for this insertion text are exempted
return;
}
} }
} }
let _state_context = self.set_shared_state(initial_state).await; SharedState::default()
let _keystroke_context = self.simulate_shared_keystrokes(keystrokes).await;
self.assert_state_matches().await;
}
pub async fn assert_binding_matches_all<const COUNT: usize>(
&mut self,
keystrokes: [&str; COUNT],
marked_positions: &str,
) {
let (unmarked_text, cursor_offsets) = marked_text_offsets(marked_positions);
for cursor_offset in cursor_offsets.iter() {
let mut marked_text = unmarked_text.clone();
marked_text.insert(*cursor_offset, 'ˇ');
self.assert_binding_matches(keystrokes, &marked_text).await;
}
}
pub fn each_marked_position(&self, marked_positions: &str) -> Vec<String> {
let (unmarked_text, cursor_offsets) = marked_text_offsets(marked_positions);
let mut ret = Vec::with_capacity(cursor_offsets.len());
for cursor_offset in cursor_offsets.iter() {
let mut marked_text = unmarked_text.clone();
marked_text.insert(*cursor_offset, 'ˇ');
ret.push(marked_text)
}
ret
}
pub async fn assert_neovim_compatible<const COUNT: usize>(
&mut self,
marked_positions: &str,
keystrokes: [&str; COUNT],
) {
self.set_shared_state(&marked_positions).await;
self.simulate_shared_keystrokes(keystrokes).await;
self.assert_state_matches().await;
}
pub async fn assert_matches_neovim<const COUNT: usize>(
&mut self,
marked_positions: &str,
keystrokes: [&str; COUNT],
result: &str,
) {
self.set_shared_state(marked_positions).await;
self.simulate_shared_keystrokes(keystrokes).await;
self.assert_shared_state(result).await;
}
pub async fn assert_binding_matches_all_exempted<const COUNT: usize>(
&mut self,
keystrokes: [&str; COUNT],
marked_positions: &str,
feature: ExemptionFeatures,
) {
if SUPPORTED_FEATURES.contains(&feature) {
self.assert_binding_matches_all(keystrokes, marked_positions)
.await
}
}
pub fn binding<const COUNT: usize>(
self,
keystrokes: [&'static str; COUNT],
) -> NeovimBackedBindingTestContext<COUNT> {
NeovimBackedBindingTestContext::new(keystrokes, self)
} }
} }
@ -438,17 +300,6 @@ impl DerefMut for NeovimBackedTestContext {
} }
} }
// a common mistake in tests is to call set_shared_state when
// you mean asswert_shared_state. This notices that and lets
// you know.
impl Drop for NeovimBackedTestContext {
fn drop(&mut self) {
if self.is_dirty {
panic!("Test context was dropped after set_shared_state before assert_shared_state")
}
}
}
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use crate::test::NeovimBackedTestContext; use crate::test::NeovimBackedTestContext;
@ -457,8 +308,8 @@ mod test {
#[gpui::test] #[gpui::test]
async fn neovim_backed_test_context_works(cx: &mut TestAppContext) { async fn neovim_backed_test_context_works(cx: &mut TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
cx.set_shared_state("This is a tesˇt").await; cx.set_shared_state("This is a tesˇt").await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
} }
} }

View File

@ -40,7 +40,7 @@ static NEOVIM_LOCK: ReentrantMutex<()> = ReentrantMutex::new(());
pub enum NeovimData { pub enum NeovimData {
Put { state: String }, Put { state: String },
Key(String), Key(String),
Get { state: String, mode: Option<Mode> }, Get { state: String, mode: Mode },
ReadRegister { name: char, value: String }, ReadRegister { name: char, value: String },
Exec { command: String }, Exec { command: String },
SetOption { value: String }, SetOption { value: String },
@ -218,7 +218,7 @@ impl NeovimConnection {
} }
if let Some(NeovimData::Get { mode, state }) = self.data.back() { if let Some(NeovimData::Get { mode, state }) = self.data.back() {
if *mode == Some(Mode::Normal) && *state == marked_text { if *mode == Mode::Normal && *state == marked_text {
return; return;
} }
} }
@ -230,7 +230,7 @@ impl NeovimConnection {
#[cfg(not(feature = "neovim"))] #[cfg(not(feature = "neovim"))]
pub async fn set_state(&mut self, marked_text: &str) { pub async fn set_state(&mut self, marked_text: &str) {
if let Some(NeovimData::Get { mode, state: text }) = self.data.front() { if let Some(NeovimData::Get { mode, state: text }) = self.data.front() {
if *mode == Some(Mode::Normal) && *text == marked_text { if *mode == Mode::Normal && *text == marked_text {
return; return;
} }
self.data.pop_front(); self.data.pop_front();
@ -334,7 +334,7 @@ impl NeovimConnection {
} }
#[cfg(feature = "neovim")] #[cfg(feature = "neovim")]
pub async fn state(&mut self) -> (Option<Mode>, String) { pub async fn state(&mut self) -> (Mode, String) {
let nvim_buffer = self let nvim_buffer = self
.nvim .nvim
.get_current_buf() .get_current_buf()
@ -369,12 +369,13 @@ impl NeovimConnection {
.expect("Could not find mode value"); .expect("Could not find mode value");
let mode = match nvim_mode_text.as_ref() { let mode = match nvim_mode_text.as_ref() {
"i" => Some(Mode::Insert), "i" => Mode::Insert,
"n" => Some(Mode::Normal), "n" => Mode::Normal,
"v" => Some(Mode::Visual), "v" => Mode::Visual,
"V" => Some(Mode::VisualLine), "V" => Mode::VisualLine,
"\x16" => Some(Mode::VisualBlock), "R" => Mode::Replace,
_ => None, "\x16" => Mode::VisualBlock,
_ => panic!("unexpected vim mode: {nvim_mode_text}"),
}; };
let mut selections = Vec::new(); let mut selections = Vec::new();
@ -382,7 +383,7 @@ impl NeovimConnection {
// Zed uses the index of the positions between the characters, so we need // Zed uses the index of the positions between the characters, so we need
// to add one to the end in visual mode. // to add one to the end in visual mode.
match mode { match mode {
Some(Mode::VisualBlock) if selection_row != cursor_row => { Mode::VisualBlock if selection_row != cursor_row => {
// in zed we fake a block selection by using multiple cursors (one per line) // in zed we fake a block selection by using multiple cursors (one per line)
// this code emulates that. // this code emulates that.
// to deal with casees where the selection is not perfectly rectangular we extract // to deal with casees where the selection is not perfectly rectangular we extract
@ -415,7 +416,7 @@ impl NeovimConnection {
} }
} }
} }
Some(Mode::Visual) | Some(Mode::VisualLine) | Some(Mode::VisualBlock) => { Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {
if (selection_row, selection_col) > (cursor_row, cursor_col) { if (selection_row, selection_col) > (cursor_row, cursor_col) {
let selection_line_length = let selection_line_length =
self.read_position("echo strlen(getline(line('v')))").await; self.read_position("echo strlen(getline(line('v')))").await;
@ -439,7 +440,7 @@ impl NeovimConnection {
Point::new(selection_row, selection_col)..Point::new(cursor_row, cursor_col), Point::new(selection_row, selection_col)..Point::new(cursor_row, cursor_col),
) )
} }
Some(Mode::Insert) | Some(Mode::Normal) | Some(Mode::Replace) | None => selections Mode::Insert | Mode::Normal | Mode::Replace => selections
.push(Point::new(selection_row, selection_col)..Point::new(cursor_row, cursor_col)), .push(Point::new(selection_row, selection_col)..Point::new(cursor_row, cursor_col)),
} }
@ -457,7 +458,7 @@ impl NeovimConnection {
} }
#[cfg(not(feature = "neovim"))] #[cfg(not(feature = "neovim"))]
pub async fn state(&mut self) -> (Option<Mode>, String) { pub async fn state(&mut self) -> (Mode, String) {
if let Some(NeovimData::Get { state: raw, mode }) = self.data.front() { if let Some(NeovimData::Get { state: raw, mode }) = self.data.front() {
(*mode, raw.to_string()) (*mode, raw.to_string())
} else { } else {
@ -465,14 +466,6 @@ impl NeovimConnection {
} }
} }
pub async fn mode(&mut self) -> Option<Mode> {
self.state().await.0
}
pub async fn marked_text(&mut self) -> String {
self.state().await.1
}
fn test_data_path(test_case_id: &str) -> PathBuf { fn test_data_path(test_case_id: &str) -> PathBuf {
let mut data_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let mut data_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
data_path.push("test_data"); data_path.push("test_data");

View File

@ -145,9 +145,9 @@ impl VimTestContext {
assert_eq!(self.mode(), mode, "{}", self.assertion_context()); assert_eq!(self.mode(), mode, "{}", self.assertion_context());
} }
pub fn assert_binding<const COUNT: usize>( pub fn assert_binding(
&mut self, &mut self,
keystrokes: [&str; COUNT], keystrokes: &str,
initial_state: &str, initial_state: &str,
initial_mode: Mode, initial_mode: Mode,
state_after: &str, state_after: &str,
@ -160,9 +160,9 @@ impl VimTestContext {
assert_eq!(self.active_operator(), None, "{}", self.assertion_context()); assert_eq!(self.active_operator(), None, "{}", self.assertion_context());
} }
pub fn assert_binding_normal<const COUNT: usize>( pub fn assert_binding_normal(
&mut self, &mut self,
keystrokes: [&str; COUNT], keystrokes: &str,
initial_state: &str, initial_state: &str,
state_after: &str, state_after: &str,
) { ) {

View File

@ -597,33 +597,32 @@ mod test {
// entering visual mode should select the character // entering visual mode should select the character
// under cursor // under cursor
cx.simulate_shared_keystrokes(["v"]).await; cx.simulate_shared_keystrokes("v").await;
cx.assert_shared_state(indoc! { "The «qˇ»uick brown cx.shared_state()
.await
.assert_eq(indoc! { "The «qˇ»uick brown
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"});
.await;
cx.update_editor(|editor, cx| assert_eq!(cursor, editor.pixel_position_of_cursor(cx))); cx.update_editor(|editor, cx| assert_eq!(cursor, editor.pixel_position_of_cursor(cx)));
// forwards motions should extend the selection // forwards motions should extend the selection
cx.simulate_shared_keystrokes(["w", "j"]).await; cx.simulate_shared_keystrokes("w j").await;
cx.assert_shared_state(indoc! { "The «quick brown cx.shared_state().await.assert_eq(indoc! { "The «quick brown
fox jumps »ver fox jumps »ver
the lazy dog"}) the lazy dog"});
.await;
cx.simulate_shared_keystrokes(["escape"]).await; cx.simulate_shared_keystrokes("escape").await;
assert_eq!(Mode::Normal, cx.neovim_mode().await); cx.shared_state().await.assert_eq(indoc! { "The quick brown
cx.assert_shared_state(indoc! { "The quick brown
fox jumps ˇover fox jumps ˇover
the lazy dog"}) the lazy dog"});
.await;
// motions work backwards // motions work backwards
cx.simulate_shared_keystrokes(["v", "k", "b"]).await; cx.simulate_shared_keystrokes("v k b").await;
cx.assert_shared_state(indoc! { "The «ˇquick brown cx.shared_state()
.await
.assert_eq(indoc! { "The «ˇquick brown
fox jumps o»ver fox jumps o»ver
the lazy dog"}) the lazy dog"});
.await;
// works on empty lines // works on empty lines
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
@ -633,23 +632,21 @@ mod test {
"}) "})
.await; .await;
let cursor = cx.update_editor(|editor, cx| editor.pixel_position_of_cursor(cx)); let cursor = cx.update_editor(|editor, cx| editor.pixel_position_of_cursor(cx));
cx.simulate_shared_keystrokes(["v"]).await; cx.simulate_shared_keystrokes("v").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
a a
« «
ˇ»b ˇ»b
"}) "});
.await;
cx.update_editor(|editor, cx| assert_eq!(cursor, editor.pixel_position_of_cursor(cx))); cx.update_editor(|editor, cx| assert_eq!(cursor, editor.pixel_position_of_cursor(cx)));
// toggles off again // toggles off again
cx.simulate_shared_keystrokes(["v"]).await; cx.simulate_shared_keystrokes("v").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
a a
ˇ ˇ
b b
"}) "});
.await;
// works at the end of a document // works at the end of a document
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
@ -658,13 +655,11 @@ mod test {
ˇ"}) ˇ"})
.await; .await;
cx.simulate_shared_keystrokes(["v"]).await; cx.simulate_shared_keystrokes("v").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
a a
b b
ˇ"}) ˇ"});
.await;
assert_eq!(cx.mode(), cx.neovim_mode().await);
} }
#[gpui::test] #[gpui::test]
@ -677,16 +672,15 @@ mod test {
the lazy dog" the lazy dog"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["shift-v"]).await; cx.simulate_shared_keystrokes("shift-v").await;
cx.assert_shared_state(indoc! { "The «qˇ»uick brown cx.shared_state()
.await
.assert_eq(indoc! { "The «qˇ»uick brown
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"});
.await; cx.simulate_shared_keystrokes("x").await;
assert_eq!(cx.mode(), cx.neovim_mode().await); cx.shared_state().await.assert_eq(indoc! { "fox ˇjumps over
cx.simulate_shared_keystrokes(["x"]).await; the lazy dog"});
cx.assert_shared_state(indoc! { "fox ˇjumps over
the lazy dog"})
.await;
// it should work on empty lines // it should work on empty lines
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
@ -694,17 +688,15 @@ mod test {
ˇ ˇ
b"}) b"})
.await; .await;
cx.simulate_shared_keystrokes(["shift-v"]).await; cx.simulate_shared_keystrokes("shift-v").await;
cx.assert_shared_state(indoc! { " cx.shared_state().await.assert_eq(indoc! {"
a a
« «
ˇ»b"}) ˇ»b"});
.await; cx.simulate_shared_keystrokes("x").await;
cx.simulate_shared_keystrokes(["x"]).await; cx.shared_state().await.assert_eq(indoc! {"
cx.assert_shared_state(indoc! { "
a a
ˇb"}) ˇb"});
.await;
// it should work at the end of the document // it should work at the end of the document
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
@ -713,54 +705,60 @@ mod test {
ˇ"}) ˇ"})
.await; .await;
let cursor = cx.update_editor(|editor, cx| editor.pixel_position_of_cursor(cx)); let cursor = cx.update_editor(|editor, cx| editor.pixel_position_of_cursor(cx));
cx.simulate_shared_keystrokes(["shift-v"]).await; cx.simulate_shared_keystrokes("shift-v").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
a a
b b
ˇ"}) ˇ"});
.await;
assert_eq!(cx.mode(), cx.neovim_mode().await);
cx.update_editor(|editor, cx| assert_eq!(cursor, editor.pixel_position_of_cursor(cx))); cx.update_editor(|editor, cx| assert_eq!(cursor, editor.pixel_position_of_cursor(cx)));
cx.simulate_shared_keystrokes(["x"]).await; cx.simulate_shared_keystrokes("x").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
a a
ˇb"}) ˇb"});
.await;
} }
#[gpui::test] #[gpui::test]
async fn test_visual_delete(cx: &mut gpui::TestAppContext) { async fn test_visual_delete(cx: &mut gpui::TestAppContext) {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.assert_binding_matches(["v", "w"], "The quick ˇbrown") cx.simulate("v w", "The quick ˇbrown")
.await; .await
.assert_matches();
cx.assert_binding_matches(["v", "w", "x"], "The quick ˇbrown") cx.simulate("v w x", "The quick ˇbrown")
.await; .await
cx.assert_binding_matches( .assert_matches();
["v", "w", "j", "x"], cx.simulate(
"v w j x",
indoc! {" indoc! {"
The ˇquick brown The ˇquick brown
fox jumps over fox jumps over
the lazy dog"}, the lazy dog"},
) )
.await; .await
.assert_matches();
// Test pasting code copied on delete // Test pasting code copied on delete
cx.simulate_shared_keystrokes(["j", "p"]).await; cx.simulate_shared_keystrokes("j p").await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
let mut cx = cx.binding(["v", "w", "j", "x"]); cx.simulate_at_each_offset(
cx.assert_all(indoc! {" "v w j x",
indoc! {"
The ˇquick brown The ˇquick brown
fox jumps over fox jumps over
the ˇlazy dog"}) the ˇlazy dog"},
.await; )
let mut cx = cx.binding(["v", "b", "k", "x"]); .await
cx.assert_all(indoc! {" .assert_matches();
cx.simulate_at_each_offset(
"v b k x",
indoc! {"
The ˇquick brown The ˇquick brown
fox jumps ˇover fox jumps ˇover
the ˇlazy dog"}) the ˇlazy dog"},
.await; )
.await
.assert_matches();
} }
#[gpui::test] #[gpui::test]
@ -772,34 +770,32 @@ mod test {
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["shift-v", "x"]).await; cx.simulate_shared_keystrokes("shift-v x").await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
// Test pasting code copied on delete // Test pasting code copied on delete
cx.simulate_shared_keystroke("p").await; cx.simulate_shared_keystrokes("p").await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
The quick brown The quick brown
fox jumps over fox jumps over
the laˇzy dog"}) the laˇzy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["shift-v", "x"]).await; cx.simulate_shared_keystrokes("shift-v x").await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
cx.assert_shared_clipboard("the lazy dog\n").await; cx.shared_clipboard().await.assert_eq("the lazy dog\n");
for marked_text in cx.each_marked_position(indoc! {" cx.set_shared_state(indoc! {"
The quˇick brown The quˇick brown
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"})
{ .await;
cx.set_shared_state(&marked_text).await; cx.simulate_shared_keystrokes("shift-v j x").await;
cx.simulate_shared_keystrokes(["shift-v", "j", "x"]).await; cx.shared_state().await.assert_matches();
cx.assert_state_matches().await; // Test pasting code copied on delete
// Test pasting code copied on delete cx.simulate_shared_keystrokes("p").await;
cx.simulate_shared_keystroke("p").await; cx.shared_state().await.assert_matches();
cx.assert_state_matches().await;
}
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
The ˇlong line The ˇlong line
@ -807,8 +803,8 @@ mod test {
crash crash
"}) "})
.await; .await;
cx.simulate_shared_keystrokes(["shift-v", "$", "x"]).await; cx.simulate_shared_keystrokes("shift-v $ x").await;
cx.assert_state_matches().await; cx.shared_state().await.assert_matches();
} }
#[gpui::test] #[gpui::test]
@ -816,53 +812,48 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("The quick ˇbrown").await; cx.set_shared_state("The quick ˇbrown").await;
cx.simulate_shared_keystrokes(["v", "w", "y"]).await; cx.simulate_shared_keystrokes("v w y").await;
cx.assert_shared_state("The quick ˇbrown").await; cx.shared_state().await.assert_eq("The quick ˇbrown");
cx.assert_shared_clipboard("brown").await; cx.shared_clipboard().await.assert_eq("brown");
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
The ˇquick brown The ˇquick brown
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["v", "w", "j", "y"]).await; cx.simulate_shared_keystrokes("v w j y").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
The ˇquick brown The ˇquick brown
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"});
.await; cx.shared_clipboard().await.assert_eq(indoc! {"
cx.assert_shared_clipboard(indoc! {"
quick brown quick brown
fox jumps o"}) fox jumps o"});
.await;
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
The quick brown The quick brown
fox jumps over fox jumps over
the ˇlazy dog"}) the ˇlazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["v", "w", "j", "y"]).await; cx.simulate_shared_keystrokes("v w j y").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
The quick brown The quick brown
fox jumps over fox jumps over
the ˇlazy dog"}) the ˇlazy dog"});
.await; cx.shared_clipboard().await.assert_eq("lazy d");
cx.assert_shared_clipboard("lazy d").await; cx.simulate_shared_keystrokes("shift-v y").await;
cx.simulate_shared_keystrokes(["shift-v", "y"]).await; cx.shared_clipboard().await.assert_eq("the lazy dog\n");
cx.assert_shared_clipboard("the lazy dog\n").await;
let mut cx = cx.binding(["v", "b", "k", "y"]);
cx.set_shared_state(indoc! {" cx.set_shared_state(indoc! {"
The ˇquick brown The ˇquick brown
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["v", "b", "k", "y"]).await; cx.simulate_shared_keystrokes("v b k y").await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
ˇThe quick brown ˇThe quick brown
fox jumps over fox jumps over
the lazy dog"}) the lazy dog"});
.await;
assert_eq!( assert_eq!(
cx.read_from_clipboard() cx.read_from_clipboard()
.map(|item| item.text().clone()) .map(|item| item.text().clone())
@ -875,15 +866,15 @@ mod test {
fox ˇjumps over fox ˇjumps over
the lazy dog"}) the lazy dog"})
.await; .await;
cx.simulate_shared_keystrokes(["shift-v", "shift-g", "shift-y"]) cx.simulate_shared_keystrokes("shift-v shift-g shift-y")
.await; .await;
cx.assert_shared_state(indoc! {" cx.shared_state().await.assert_eq(indoc! {"
The quick brown The quick brown
ˇfox jumps over ˇfox jumps over
the lazy dog"}) the lazy dog"});
.await; cx.shared_clipboard()
cx.assert_shared_clipboard("fox jumps over\nthe lazy dog\n") .await
.await; .assert_eq("fox jumps over\nthe lazy dog\n");
} }
#[gpui::test] #[gpui::test]
@ -896,64 +887,56 @@ mod test {
the lazy dog" the lazy dog"
}) })
.await; .await;
cx.simulate_shared_keystrokes(["ctrl-v"]).await; cx.simulate_shared_keystrokes("ctrl-v").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"The «qˇ»uick brown "The «qˇ»uick brown
fox jumps over fox jumps over
the lazy dog" the lazy dog"
}) });
.await; cx.simulate_shared_keystrokes("2 down").await;
cx.simulate_shared_keystrokes(["2", "down"]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"The «qˇ»uick brown "The «qˇ»uick brown
fox «»umps over fox «»umps over
the «»azy dog" the «»azy dog"
}) });
.await; cx.simulate_shared_keystrokes("e").await;
cx.simulate_shared_keystrokes(["e"]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"The «quicˇ»k brown "The «quicˇ»k brown
fox «jumpˇ»s over fox «jumpˇ»s over
the «lazyˇ» dog" the «lazyˇ» dog"
}) });
.await; cx.simulate_shared_keystrokes("^").await;
cx.simulate_shared_keystrokes(["^"]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"«ˇThe q»uick brown "«ˇThe q»uick brown
«ˇfox j»umps over «ˇfox j»umps over
«ˇthe l»azy dog" «ˇthe l»azy dog"
}) });
.await; cx.simulate_shared_keystrokes("$").await;
cx.simulate_shared_keystrokes(["$"]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"The «quick brownˇ» "The «quick brownˇ»
fox «jumps overˇ» fox «jumps overˇ»
the «lazy dogˇ»" the «lazy dogˇ»"
}) });
.await; cx.simulate_shared_keystrokes("shift-f space").await;
cx.simulate_shared_keystrokes(["shift-f", " "]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"The «quickˇ» brown "The «quickˇ» brown
fox «jumpsˇ» over fox «jumpsˇ» over
the «lazy ˇ»dog" the «lazy ˇ»dog"
}) });
.await;
// toggling through visual mode works as expected // toggling through visual mode works as expected
cx.simulate_shared_keystrokes(["v"]).await; cx.simulate_shared_keystrokes("v").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"The «quick brown "The «quick brown
fox jumps over fox jumps over
the lazy ˇ»dog" the lazy ˇ»dog"
}) });
.await; cx.simulate_shared_keystrokes("ctrl-v").await;
cx.simulate_shared_keystrokes(["ctrl-v"]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"The «quickˇ» brown "The «quickˇ» brown
fox «jumpsˇ» over fox «jumpsˇ» over
the «lazy ˇ»dog" the «lazy ˇ»dog"
}) });
.await;
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
"The ˇquick "The ˇquick
@ -965,9 +948,8 @@ mod test {
" "
}) })
.await; .await;
cx.simulate_shared_keystrokes(["ctrl-v", "down", "down"]) cx.simulate_shared_keystrokes("ctrl-v down down").await;
.await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"The«ˇ q»uick "The«ˇ q»uick
bro«ˇwn» bro«ˇwn»
foxˇ foxˇ
@ -975,10 +957,9 @@ mod test {
lazy dog lazy dog
" "
}) });
.await; cx.simulate_shared_keystrokes("down").await;
cx.simulate_shared_keystrokes(["down"]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"The «qˇ»uick "The «qˇ»uick
brow«» brow«»
fox fox
@ -986,10 +967,9 @@ mod test {
lazy dog lazy dog
" "
}) });
.await; cx.simulate_shared_keystrokes("left").await;
cx.simulate_shared_keystroke("left").await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"The«ˇ q»uick "The«ˇ q»uick
bro«ˇwn» bro«ˇwn»
foxˇ foxˇ
@ -997,10 +977,9 @@ mod test {
lazy dog lazy dog
" "
}) });
.await; cx.simulate_shared_keystrokes("s o escape").await;
cx.simulate_shared_keystrokes(["s", "o", "escape"]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"Theˇouick "Theˇouick
broo broo
foxo foxo
@ -1008,8 +987,7 @@ mod test {
lazy dog lazy dog
" "
}) });
.await;
// https://github.com/zed-industries/zed/issues/6274 // https://github.com/zed-industries/zed/issues/6274
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
@ -1020,16 +998,14 @@ mod test {
" "
}) })
.await; .await;
cx.simulate_shared_keystrokes(["l", "ctrl-v", "j", "j"]) cx.simulate_shared_keystrokes("l ctrl-v j j").await;
.await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"The «qˇ»uick brown "The «qˇ»uick brown
fox «»umps over fox «»umps over
the lazy dog the lazy dog
" "
}) });
.await;
} }
#[gpui::test] #[gpui::test]
@ -1043,15 +1019,13 @@ mod test {
" "
}) })
.await; .await;
cx.simulate_shared_keystrokes(["ctrl-v", "right", "down"]) cx.simulate_shared_keystrokes("ctrl-v right down").await;
.await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"The «quˇ»ick brown "The «quˇ»ick brown
fox «juˇ»mps over fox «juˇ»mps over
the lazy dog the lazy dog
" "
}) });
.await;
} }
#[gpui::test] #[gpui::test]
@ -1065,24 +1039,21 @@ mod test {
" "
}) })
.await; .await;
cx.simulate_shared_keystrokes(["ctrl-v", "9", "down"]).await; cx.simulate_shared_keystrokes("ctrl-v 9 down").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"«Tˇ»he quick brown "«Tˇ»he quick brown
«»ox jumps over «»ox jumps over
«»he lazy dog «»he lazy dog
ˇ" ˇ"
}) });
.await;
cx.simulate_shared_keystrokes(["shift-i", "k", "escape"]) cx.simulate_shared_keystrokes("shift-i k escape").await;
.await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"ˇkThe quick brown "ˇkThe quick brown
kfox jumps over kfox jumps over
kthe lazy dog kthe lazy dog
k" k"
}) });
.await;
cx.set_shared_state(indoc! { cx.set_shared_state(indoc! {
"ˇThe quick brown "ˇThe quick brown
@ -1091,22 +1062,20 @@ mod test {
" "
}) })
.await; .await;
cx.simulate_shared_keystrokes(["ctrl-v", "9", "down"]).await; cx.simulate_shared_keystrokes("ctrl-v 9 down").await;
cx.assert_shared_state(indoc! { cx.shared_state().await.assert_eq(indoc! {
"«Tˇ»he quick brown "«Tˇ»he quick brown
«»ox jumps over «»ox jumps over
«»he lazy dog «»he lazy dog
ˇ" ˇ"
}) });
.await; cx.simulate_shared_keystrokes("c k escape").await;
cx.simulate_shared_keystrokes(["c", "k", "escape"]).await; cx.shared_state().await.assert_eq(indoc! {
cx.assert_shared_state(indoc! {
"ˇkhe quick brown "ˇkhe quick brown
kox jumps over kox jumps over
khe lazy dog khe lazy dog
k" k"
}) });
.await;
} }
#[gpui::test] #[gpui::test]
@ -1114,19 +1083,26 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("hello (in [parˇens] o)").await; cx.set_shared_state("hello (in [parˇens] o)").await;
cx.simulate_shared_keystrokes(["ctrl-v", "l"]).await; cx.simulate_shared_keystrokes("ctrl-v l").await;
cx.simulate_shared_keystrokes(["a", "]"]).await; cx.simulate_shared_keystrokes("a ]").await;
cx.assert_shared_state("hello (in «[parens]ˇ» o)").await; cx.shared_state()
cx.simulate_shared_keystrokes(["i", "("]).await; .await
cx.assert_shared_state("hello («in [parens] oˇ»)").await; .assert_eq("hello (in «[parens]ˇ» o)");
cx.simulate_shared_keystrokes("i (").await;
cx.shared_state()
.await
.assert_eq("hello («in [parens] oˇ»)");
cx.set_shared_state("hello in a wˇord again.").await; cx.set_shared_state("hello in a wˇord again.").await;
cx.simulate_shared_keystrokes(["ctrl-v", "l", "i", "w"]) cx.simulate_shared_keystrokes("ctrl-v l i w").await;
.await; cx.shared_state()
cx.assert_shared_state("hello in a w«ordˇ» again.").await; .await
.assert_eq("hello in a w«ordˇ» again.");
assert_eq!(cx.mode(), Mode::VisualBlock); assert_eq!(cx.mode(), Mode::VisualBlock);
cx.simulate_shared_keystrokes(["o", "a", "s"]).await; cx.simulate_shared_keystrokes("o a s").await;
cx.assert_shared_state("«ˇhello in a word» again.").await; cx.shared_state()
.await
.assert_eq("«ˇhello in a word» again.");
} }
#[gpui::test] #[gpui::test]
@ -1134,9 +1110,9 @@ mod test {
let mut cx = VimTestContext::new(cx, true).await; let mut cx = VimTestContext::new(cx, true).await;
cx.set_state("aˇbc", Mode::Normal); cx.set_state("aˇbc", Mode::Normal);
cx.simulate_keystrokes(["ctrl-v"]); cx.simulate_keystrokes("ctrl-v");
assert_eq!(cx.mode(), Mode::VisualBlock); assert_eq!(cx.mode(), Mode::VisualBlock);
cx.simulate_keystrokes(["cmd-shift-p", "escape"]); cx.simulate_keystrokes("cmd-shift-p escape");
assert_eq!(cx.mode(), Mode::VisualBlock); assert_eq!(cx.mode(), Mode::VisualBlock);
} }
@ -1145,32 +1121,28 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("aaˇ aa aa aa aa").await; cx.set_shared_state("aaˇ aa aa aa aa").await;
cx.simulate_shared_keystrokes(["/", "a", "a", "enter"]) cx.simulate_shared_keystrokes("/ a a enter").await;
.await; cx.shared_state().await.assert_eq("aa ˇaa aa aa aa");
cx.assert_shared_state("aa ˇaa aa aa aa").await; cx.simulate_shared_keystrokes("g n").await;
cx.simulate_shared_keystrokes(["g", "n"]).await; cx.shared_state().await.assert_eq("aa «aaˇ» aa aa aa");
cx.assert_shared_state("aa «aaˇ» aa aa aa").await; cx.simulate_shared_keystrokes("g n").await;
cx.simulate_shared_keystrokes(["g", "n"]).await; cx.shared_state().await.assert_eq("aa «aa aaˇ» aa aa");
cx.assert_shared_state("aa «aa aaˇ» aa aa").await; cx.simulate_shared_keystrokes("escape d g n").await;
cx.simulate_shared_keystrokes(["escape", "d", "g", "n"]) cx.shared_state().await.assert_eq("aa aa ˇ aa aa");
.await;
cx.assert_shared_state("aa aa ˇ aa aa").await;
cx.set_shared_state("aaˇ aa aa aa aa").await; cx.set_shared_state("aaˇ aa aa aa aa").await;
cx.simulate_shared_keystrokes(["/", "a", "a", "enter"]) cx.simulate_shared_keystrokes("/ a a enter").await;
.await; cx.shared_state().await.assert_eq("aa ˇaa aa aa aa");
cx.assert_shared_state("aa ˇaa aa aa aa").await; cx.simulate_shared_keystrokes("3 g n").await;
cx.simulate_shared_keystrokes(["3", "g", "n"]).await; cx.shared_state().await.assert_eq("aa aa aa «aaˇ» aa");
cx.assert_shared_state("aa aa aa «aaˇ» aa").await;
cx.set_shared_state("aaˇ aa aa aa aa").await; cx.set_shared_state("aaˇ aa aa aa aa").await;
cx.simulate_shared_keystrokes(["/", "a", "a", "enter"]) cx.simulate_shared_keystrokes("/ a a enter").await;
.await; cx.shared_state().await.assert_eq("aa ˇaa aa aa aa");
cx.assert_shared_state("aa ˇaa aa aa aa").await; cx.simulate_shared_keystrokes("g shift-n").await;
cx.simulate_shared_keystrokes(["g", "shift-n"]).await; cx.shared_state().await.assert_eq("aa «ˇaa» aa aa aa");
cx.assert_shared_state("aa «ˇaa» aa aa aa").await; cx.simulate_shared_keystrokes("g shift-n").await;
cx.simulate_shared_keystrokes(["g", "shift-n"]).await; cx.shared_state().await.assert_eq("«ˇaa aa» aa aa aa");
cx.assert_shared_state("«ˇaa aa» aa aa aa").await;
} }
#[gpui::test] #[gpui::test]
@ -1178,16 +1150,15 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("aaˇ aa aa aa aa").await; cx.set_shared_state("aaˇ aa aa aa aa").await;
cx.simulate_shared_keystrokes(["/", "a", "a", "enter"]) cx.simulate_shared_keystrokes("/ a a enter").await;
.await; cx.shared_state().await.assert_eq("aa ˇaa aa aa aa");
cx.assert_shared_state("aa ˇaa aa aa aa").await; cx.simulate_shared_keystrokes("d g n").await;
cx.simulate_shared_keystrokes(["d", "g", "n"]).await;
cx.assert_shared_state("aa ˇ aa aa aa").await; cx.shared_state().await.assert_eq("aa ˇ aa aa aa");
cx.simulate_shared_keystrokes(["."]).await; cx.simulate_shared_keystrokes(".").await;
cx.assert_shared_state("aa ˇ aa aa").await; cx.shared_state().await.assert_eq("aa ˇ aa aa");
cx.simulate_shared_keystrokes(["."]).await; cx.simulate_shared_keystrokes(".").await;
cx.assert_shared_state("aa ˇ aa").await; cx.shared_state().await.assert_eq("aa ˇ aa");
} }
#[gpui::test] #[gpui::test]
@ -1195,14 +1166,12 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("aaˇ aa aa aa aa").await; cx.set_shared_state("aaˇ aa aa aa aa").await;
cx.simulate_shared_keystrokes(["/", "a", "a", "enter"]) cx.simulate_shared_keystrokes("/ a a enter").await;
.await; cx.shared_state().await.assert_eq("aa ˇaa aa aa aa");
cx.assert_shared_state("aa ˇaa aa aa aa").await; cx.simulate_shared_keystrokes("c g n x escape").await;
cx.simulate_shared_keystrokes(["c", "g", "n", "x", "escape"]) cx.shared_state().await.assert_eq("aa ˇx aa aa aa");
.await; cx.simulate_shared_keystrokes(".").await;
cx.assert_shared_state("aa ˇx aa aa aa").await; cx.shared_state().await.assert_eq("aa x ˇx aa aa");
cx.simulate_shared_keystrokes(["."]).await;
cx.assert_shared_state("aa x ˇx aa aa").await;
} }
#[gpui::test] #[gpui::test]
@ -1210,23 +1179,19 @@ mod test {
let mut cx = NeovimBackedTestContext::new(cx).await; let mut cx = NeovimBackedTestContext::new(cx).await;
cx.set_shared_state("aaˇ aa aa aa aa").await; cx.set_shared_state("aaˇ aa aa aa aa").await;
cx.simulate_shared_keystrokes(["/", "b", "b", "enter"]) cx.simulate_shared_keystrokes("/ b b enter").await;
.await; cx.shared_state().await.assert_eq("aaˇ aa aa aa aa");
cx.assert_shared_state("aaˇ aa aa aa aa").await; cx.simulate_shared_keystrokes("c g n x escape").await;
cx.simulate_shared_keystrokes(["c", "g", "n", "x", "escape"]) cx.shared_state().await.assert_eq("aaˇaa aa aa aa");
.await; cx.simulate_shared_keystrokes(".").await;
cx.assert_shared_state("aaˇaa aa aa aa").await; cx.shared_state().await.assert_eq("aaˇa aa aa aa");
cx.simulate_shared_keystrokes(["."]).await;
cx.assert_shared_state("aaˇa aa aa aa").await;
cx.set_shared_state("aaˇ bb aa aa aa").await; cx.set_shared_state("aaˇ bb aa aa aa").await;
cx.simulate_shared_keystrokes(["/", "b", "b", "enter"]) cx.simulate_shared_keystrokes("/ b b enter").await;
.await; cx.shared_state().await.assert_eq("aa ˇbb aa aa aa");
cx.assert_shared_state("aa ˇbb aa aa aa").await; cx.simulate_shared_keystrokes("c g n x escape").await;
cx.simulate_shared_keystrokes(["c", "g", "n", "x", "escape"]) cx.shared_state().await.assert_eq("aa ˇx aa aa aa");
.await; cx.simulate_shared_keystrokes(".").await;
cx.assert_shared_state("aa ˇx aa aa aa").await; cx.shared_state().await.assert_eq("aa ˇx aa aa aa");
cx.simulate_shared_keystrokes(["."]).await;
cx.assert_shared_state("aa ˇx aa aa aa").await;
} }
} }

View File

@ -9,7 +9,7 @@
{"Key":"g"} {"Key":"g"}
{"Key":"h"} {"Key":"h"}
{"Key":"t"} {"Key":"t"}
{"Key":" "} {"Key":"space"}
{"Key":"t"} {"Key":"t"}
{"Key":"h"} {"Key":"h"}
{"Key":"i"} {"Key":"i"}

View File

@ -6,7 +6,7 @@
{"Key":"c"} {"Key":"c"}
{"Key":"c"} {"Key":"c"}
{"Get":{"state":"ˇ\nbrown fox\njumps over\nthe lazy","mode":"Insert"}} {"Get":{"state":"ˇ\nbrown fox\njumps over\nthe lazy","mode":"Insert"}}
{"Put":{"state":"The quick\n broˇwn fox\njumˇps over\nthe lazy"}} {"Put":{"state":"The quick\n broˇwn fox\njumps over\nthe lazy"}}
{"Key":"c"} {"Key":"c"}
{"Key":"c"} {"Key":"c"}
{"Get":{"state":"The quick\n ˇ\nˇ\nthe lazy","mode":"Insert"}} {"Get":{"state":"The quick\n ˇ\njumps over\nthe lazy","mode":"Insert"}}

View File

@ -1,3 +1,11 @@
{"Put":{"state":"Teˇst Test\n"}}
{"Key":"d"}
{"Key":"e"}
{"Get":{"state":"Teˇ Test\n","mode":"Normal"}}
{"Put":{"state":"Tˇest test\n"}}
{"Key":"d"}
{"Key":"e"}
{"Get":{"state":"Tˇ test\n","mode":"Normal"}}
{"Put":{"state":"Test teˇst\ntest"}} {"Put":{"state":"Test teˇst\ntest"}}
{"Key":"d"} {"Key":"d"}
{"Key":"e"} {"Key":"e"}
@ -8,5 +16,5 @@
{"Get":{"state":"Test teˇs","mode":"Normal"}} {"Get":{"state":"Test teˇs","mode":"Normal"}}
{"Put":{"state":"Test teˇst-test test"}} {"Put":{"state":"Test teˇst-test test"}}
{"Key":"d"} {"Key":"d"}
{"Key":"shift-e"} {"Key":"e"}
{"Get":{"state":"Test teˇ test","mode":"Normal"}} {"Get":{"state":"Test teˇ-test test","mode":"Normal"}}

View File

@ -17,6 +17,7 @@
{"Key":"down"} {"Key":"down"}
{"Key":"y"} {"Key":"y"}
{"Key":"y"} {"Key":"y"}
{"Get":{"state":"fn boop() {\nˇ barp()\n bazp()\n}\n","mode":"Normal"}}
{"ReadRegister":{"name":"\"","value":" barp()\n bazp()\n"}} {"ReadRegister":{"name":"\"","value":" barp()\n bazp()\n"}}
{"Key":"z"} {"Key":"z"}
{"Key":"o"} {"Key":"o"}

View File

@ -1,10 +1,10 @@
{"Key":"i"} {"Key":"i"}
{"Get":{"state":"ˇ","mode":"Insert"}} {"Get":{"state":"ˇ","mode":"Insert"}}
{"Key":"shift-T"} {"Key":"shift-t"}
{"Key":"e"} {"Key":"e"}
{"Key":"s"} {"Key":"s"}
{"Key":"t"} {"Key":"t"}
{"Key":" "} {"Key":"space"}
{"Key":"t"} {"Key":"t"}
{"Key":"e"} {"Key":"e"}
{"Key":"s"} {"Key":"s"}

View File

@ -2,6 +2,7 @@
{"Key":"v"} {"Key":"v"}
{"Key":"w"} {"Key":"w"}
{"Key":"y"} {"Key":"y"}
{"Get":{"state":"The quick brown\nfox ˇjumps over\nthe lazy dog","mode":"Normal"}}
{"ReadRegister":{"name":"\"","value":"jumps o"}} {"ReadRegister":{"name":"\"","value":"jumps o"}}
{"Put":{"state":"The quick brown\nfox jumps oveˇr\nthe lazy dog"}} {"Put":{"state":"The quick brown\nfox jumps oveˇr\nthe lazy dog"}}
{"Key":"p"} {"Key":"p"}
@ -12,6 +13,7 @@
{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog"}} {"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog"}}
{"Key":"d"} {"Key":"d"}
{"Key":"d"} {"Key":"d"}
{"Get":{"state":"The quick brown\nthe laˇzy dog","mode":"Normal"}}
{"ReadRegister":{"name":"\"","value":"fox jumps over\n"}} {"ReadRegister":{"name":"\"","value":"fox jumps over\n"}}
{"Get":{"state":"The quick brown\nthe laˇzy dog","mode":"Normal"}} {"Get":{"state":"The quick brown\nthe laˇzy dog","mode":"Normal"}}
{"Key":"p"} {"Key":"p"}
@ -23,6 +25,7 @@
{"Key":"v"} {"Key":"v"}
{"Key":"j"} {"Key":"j"}
{"Key":"y"} {"Key":"y"}
{"Get":{"state":"The quick brown\nfox jumps ˇover\nthe lazy dog","mode":"Normal"}}
{"ReadRegister":{"name":"\"","value":"over\nthe lazy do"}} {"ReadRegister":{"name":"\"","value":"over\nthe lazy do"}}
{"Key":"p"} {"Key":"p"}
{"Get":{"state":"The quick brown\nfox jumps oˇover\nthe lazy dover\nthe lazy dog","mode":"Normal"}} {"Get":{"state":"The quick brown\nfox jumps oˇover\nthe lazy dover\nthe lazy dog","mode":"Normal"}}

View File

@ -3,6 +3,7 @@
{"Key":"2"} {"Key":"2"}
{"Key":"j"} {"Key":"j"}
{"Key":"y"} {"Key":"y"}
{"Get":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog","mode":"Normal"}}
{"ReadRegister":{"name":"\"","value":"q\nj\nl"}} {"ReadRegister":{"name":"\"","value":"q\nj\nl"}}
{"Key":"p"} {"Key":"p"}
{"Get":{"state":"The qˇquick brown\nfox jjumps over\nthe llazy dog","mode":"Normal"}} {"Get":{"state":"The qˇquick brown\nfox jjumps over\nthe llazy dog","mode":"Normal"}}
@ -19,6 +20,7 @@
{"Key":"ctrl-v"} {"Key":"ctrl-v"}
{"Key":"j"} {"Key":"j"}
{"Key":"y"} {"Key":"y"}
{"Get":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog","mode":"Normal"}}
{"ReadRegister":{"name":"\"","value":"q\nj"}} {"ReadRegister":{"name":"\"","value":"q\nj"}}
{"Key":"l"} {"Key":"l"}
{"Key":"ctrl-v"} {"Key":"ctrl-v"}

View File

@ -16,12 +16,6 @@
{"Key":"n"} {"Key":"n"}
{"Key":"e"} {"Key":"e"}
{"Get":{"state":"The quick brown\nOneˇ\nfox jumps over\nthe lazy dog.","mode":"Replace"}} {"Get":{"state":"The quick brown\nOneˇ\nfox jumps over\nthe lazy dog.","mode":"Replace"}}
{"Put":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy ˇdog."}}
{"Key":"shift-r"}
{"Key":"O"}
{"Key":"n"}
{"Key":"e"}
{"Get":{"state":"Oneˇ quick brown\nfox jumps over\nthe lazy Oneˇ.","mode":"Replace"}}
{"Put":{"state":"The quˇick brown\nfox jumps over\nthe lazy dog."}} {"Put":{"state":"The quˇick brown\nfox jumps over\nthe lazy dog."}}
{"Key":"shift-r"} {"Key":"shift-r"}
{"Key":"enter"} {"Key":"enter"}
@ -29,20 +23,3 @@
{"Key":"n"} {"Key":"n"}
{"Key":"e"} {"Key":"e"}
{"Get":{"state":"The qu\nOneˇ brown\nfox jumps over\nthe lazy dog.","mode":"Replace"}} {"Get":{"state":"The qu\nOneˇ brown\nfox jumps over\nthe lazy dog.","mode":"Replace"}}
{"Put":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy ˇdog."}}
{"Key":"shift-r"}
{"Key":"O"}
{"Key":"n"}
{"Key":"e"}
{"Get":{"state":"Oneˇ quick brown\nfox jumps over\nthe lazy Oneˇ.","mode":"Replace"}}
{"Key":"enter"}
{"Key":"T"}
{"Key":"w"}
{"Key":"o"}
{"Get":{"state":"One\nTwoˇck brown\nfox jumps over\nthe lazy One\nTwoˇ","mode":"Replace"}}
{"Put":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy ˇdog."}}
{"Key":"shift-r"}
{"Key":"O"}
{"Key":"n"}
{"Key":"e"}
{"Get":{"state":"Oneˇ quick brown\nfox jumps over\nthe lazy Oneˇ.","mode":"Replace"}}

View File

@ -91,34 +91,3 @@
{"Key":"backspace"} {"Key":"backspace"}
{"Key":"backspace"} {"Key":"backspace"}
{"Get":{"state":"The quick brown\nˇ\nfox jumps over\nthe lazy dog.","mode":"Replace"}} {"Get":{"state":"The quick brown\nˇ\nfox jumps over\nthe lazy dog.","mode":"Replace"}}
{"Put":{"state":"The quick browˇn\nfox jumps over\nthe lazy ˇdog."}}
{"Key":"shift-r"}
{"Key":"O"}
{"Key":"n"}
{"Key":"e"}
{"Key":"backspace"}
{"Key":"backspace"}
{"Key":"backspace"}
{"Get":{"state":"The quick browˇn\nfox jumps over\nthe lazy ˇdog.","mode":"Replace"}}
{"Put":{"state":"The quick browˇn\nfox jumps over\nthe lazy ˇdog."}}
{"Key":"shift-r"}
{"Key":"O"}
{"Key":"enter"}
{"Key":"e"}
{"Key":"backspace"}
{"Key":"backspace"}
{"Key":"backspace"}
{"Get":{"state":"The quick browˇn\nfox jumps over\nthe lazy ˇdog.","mode":"Replace"}}
{"Put":{"state":"The quick browˇn\nfox jumps over\nthe lazy ˇdog."}}
{"Key":"shift-r"}
{"Key":"O"}
{"Key":"enter"}
{"Key":"n"}
{"Key":"enter"}
{"Key":"e"}
{"Key":"backspace"}
{"Key":"backspace"}
{"Key":"backspace"}
{"Key":"backspace"}
{"Key":"backspace"}
{"Get":{"state":"The quick browˇn\nfox jumps over\nthe lazy ˇdog.","mode":"Replace"}}

View File

@ -11,7 +11,7 @@
{"Key":"$"} {"Key":"$"}
{"Get":{"state":"The «quick brownˇ»\nfox «jumps overˇ»\nthe «lazy dogˇ»","mode":"VisualBlock"}} {"Get":{"state":"The «quick brownˇ»\nfox «jumps overˇ»\nthe «lazy dogˇ»","mode":"VisualBlock"}}
{"Key":"shift-f"} {"Key":"shift-f"}
{"Key":" "} {"Key":"space"}
{"Get":{"state":"The «quickˇ» brown\nfox «jumpsˇ» over\nthe «lazy ˇ»dog","mode":"VisualBlock"}} {"Get":{"state":"The «quickˇ» brown\nfox «jumpsˇ» over\nthe «lazy ˇ»dog","mode":"VisualBlock"}}
{"Key":"v"} {"Key":"v"}
{"Get":{"state":"The «quick brown\nfox jumps over\nthe lazy ˇ»dog","mode":"Visual"}} {"Get":{"state":"The «quick brown\nfox jumps over\nthe lazy ˇ»dog","mode":"Visual"}}

View File

@ -15,6 +15,18 @@
{"Key":"j"} {"Key":"j"}
{"Key":"c"} {"Key":"c"}
{"Get":{"state":"The ˇver\nthe lazy dog","mode":"Insert"}} {"Get":{"state":"The ˇver\nthe lazy dog","mode":"Insert"}}
{"Put":{"state":"The quick brown\nfox jumps ˇover\nthe lazy dog"}}
{"Key":"v"}
{"Key":"w"}
{"Key":"j"}
{"Key":"c"}
{"Get":{"state":"The quick brown\nfox jumps ˇhe lazy dog","mode":"Insert"}}
{"Put":{"state":"The quick brown\nfox jumps over\nthe ˇlazy dog"}}
{"Key":"v"}
{"Key":"w"}
{"Key":"j"}
{"Key":"c"}
{"Get":{"state":"The quick brown\nfox jumps over\nthe ˇog","mode":"Insert"}}
{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} {"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}}
{"Key":"v"} {"Key":"v"}
{"Key":"w"} {"Key":"w"}
@ -24,24 +36,12 @@
{"Put":{"state":"The quick brown\nfox jumps ˇover\nthe lazy dog"}} {"Put":{"state":"The quick brown\nfox jumps ˇover\nthe lazy dog"}}
{"Key":"v"} {"Key":"v"}
{"Key":"w"} {"Key":"w"}
{"Key":"j"}
{"Key":"c"}
{"Get":{"state":"The quick brown\nfox jumps ˇhe lazy dog","mode":"Insert"}}
{"Put":{"state":"The quick brown\nfox jumps ˇover\nthe lazy dog"}}
{"Key":"v"}
{"Key":"w"}
{"Key":"k"} {"Key":"k"}
{"Key":"c"} {"Key":"c"}
{"Get":{"state":"The quick brown\nˇver\nthe lazy dog","mode":"Insert"}} {"Get":{"state":"The quick brown\nˇver\nthe lazy dog","mode":"Insert"}}
{"Put":{"state":"The quick brown\nfox jumps over\nthe ˇlazy dog"}} {"Put":{"state":"The quick brown\nfox jumps over\nthe ˇlazy dog"}}
{"Key":"v"} {"Key":"v"}
{"Key":"w"} {"Key":"w"}
{"Key":"j"}
{"Key":"c"}
{"Get":{"state":"The quick brown\nfox jumps over\nthe ˇog","mode":"Insert"}}
{"Put":{"state":"The quick brown\nfox jumps over\nthe ˇlazy dog"}}
{"Key":"v"}
{"Key":"w"}
{"Key":"k"} {"Key":"k"}
{"Key":"c"} {"Key":"c"}
{"Get":{"state":"The quick brown\nfox jumpsˇazy dog","mode":"Insert"}} {"Get":{"state":"The quick brown\nfox jumpsˇazy dog","mode":"Insert"}}

View File

@ -20,6 +20,7 @@
{"ReadRegister":{"name":"\"","value":"lazy d"}} {"ReadRegister":{"name":"\"","value":"lazy d"}}
{"Key":"shift-v"} {"Key":"shift-v"}
{"Key":"y"} {"Key":"y"}
{"Get":{"state":"The quick brown\nfox jumps over\nˇthe lazy dog","mode":"Normal"}}
{"ReadRegister":{"name":"\"","value":"the lazy dog\n"}} {"ReadRegister":{"name":"\"","value":"the lazy dog\n"}}
{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} {"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}}
{"Key":"v"} {"Key":"v"}