diff --git a/crates/vim/src/normal/repeat.rs b/crates/vim/src/normal/repeat.rs index e0b515595db013b23730c535df64123aa4dd6707..e47b2b350f9644f99fe7d8ec924ff0f0b9ab23f7 100644 --- a/crates/vim/src/normal/repeat.rs +++ b/crates/vim/src/normal/repeat.rs @@ -230,8 +230,19 @@ impl Vim { window: &mut Window, cx: &mut Context, ) { - let count = Vim::take_count(cx); + if self.active_operator().is_some() { + Vim::update_globals(cx, |globals, _| { + globals.recording_actions.clear(); + globals.recording_count = None; + globals.dot_recording = false; + globals.stop_recording_after_next_action = false; + }); + self.clear_operator(window, cx); + return; + } + Vim::take_forced_motion(cx); + let count = Vim::take_count(cx); let Some((mut actions, selection, mode)) = Vim::update_globals(cx, |globals, _| { let actions = globals.recorded_actions.clone(); @@ -810,4 +821,91 @@ mod test { cx.simulate_shared_keystrokes("@ b").await; cx.shared_state().await.assert_eq("aaaaaaabbbˇd"); } + + #[gpui::test] + async fn test_repeat_clear(cx: &mut gpui::TestAppContext) { + let mut cx = VimTestContext::new(cx, true).await; + + // Check that, when repeat is preceded by something other than a number, + // the current operator is cleared, in order to prevent infinite loops. + cx.set_state("ˇhello world", Mode::Normal); + cx.simulate_keystrokes("d ."); + assert_eq!(cx.active_operator(), None); + } + + #[gpui::test] + async fn test_repeat_clear_repeat(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await; + + cx.set_shared_state(indoc! { + "ˇthe quick brown + fox jumps over + the lazy dog" + }) + .await; + cx.simulate_shared_keystrokes("d d").await; + cx.shared_state().await.assert_eq(indoc! { + "ˇfox jumps over + the lazy dog" + }); + cx.simulate_shared_keystrokes("d . .").await; + cx.shared_state().await.assert_eq(indoc! { + "ˇthe lazy dog" + }); + } + + #[gpui::test] + async fn test_repeat_clear_count(cx: &mut gpui::TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await; + + cx.set_shared_state(indoc! { + "ˇthe quick brown + fox jumps over + the lazy dog" + }) + .await; + cx.simulate_shared_keystrokes("d d").await; + cx.shared_state().await.assert_eq(indoc! { + "ˇfox jumps over + the lazy dog" + }); + cx.simulate_shared_keystrokes("2 d .").await; + cx.shared_state().await.assert_eq(indoc! { + "ˇfox jumps over + the lazy dog" + }); + cx.simulate_shared_keystrokes(".").await; + cx.shared_state().await.assert_eq(indoc! { + "ˇthe lazy dog" + }); + + cx.set_shared_state(indoc! { + "ˇthe quick brown + fox jumps over + the lazy dog + the quick brown + fox jumps over + the lazy dog" + }) + .await; + cx.simulate_shared_keystrokes("2 d d").await; + cx.shared_state().await.assert_eq(indoc! { + "ˇthe lazy dog + the quick brown + fox jumps over + the lazy dog" + }); + cx.simulate_shared_keystrokes("5 d .").await; + cx.shared_state().await.assert_eq(indoc! { + "ˇthe lazy dog + the quick brown + fox jumps over + the lazy dog" + }); + cx.simulate_shared_keystrokes(".").await; + cx.shared_state().await.assert_eq(indoc! { + "ˇfox jumps over + the lazy dog" + }); + } } diff --git a/crates/vim/src/state.rs b/crates/vim/src/state.rs index d1c52e8f53a2214c3e46473c59b15ea1f6f4f407..eba4476ea878932518dc8a3951e04f4c6ea96d29 100644 --- a/crates/vim/src/state.rs +++ b/crates/vim/src/state.rs @@ -217,6 +217,7 @@ pub struct VimGlobals { pub forced_motion: bool, pub stop_recording_after_next_action: bool, pub ignore_current_insertion: bool, + pub recording_count: Option, pub recorded_count: Option, pub recording_actions: Vec, pub recorded_actions: Vec, @@ -898,6 +899,7 @@ impl VimGlobals { if self.stop_recording_after_next_action { self.dot_recording = false; self.recorded_actions = std::mem::take(&mut self.recording_actions); + self.recorded_count = self.recording_count.take(); self.stop_recording_after_next_action = false; } } @@ -924,6 +926,7 @@ impl VimGlobals { if self.stop_recording_after_next_action { self.dot_recording = false; self.recorded_actions = std::mem::take(&mut self.recording_actions); + self.recorded_count = self.recording_count.take(); self.stop_recording_after_next_action = false; } } diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index 9f31b3d3ac0c23457d585990de3a0b201f08b795..f87c562c8a0821f5dfea66dd33b1c44ca6021f42 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -1258,7 +1258,7 @@ impl Vim { }; if global_state.dot_recording { - global_state.recorded_count = count; + global_state.recording_count = count; } count } @@ -1516,7 +1516,7 @@ impl Vim { if !globals.dot_replaying { globals.dot_recording = true; globals.recording_actions = Default::default(); - globals.recorded_count = None; + globals.recording_count = None; let selections = self.editor().map(|editor| { editor.update(cx, |editor, cx| { @@ -1586,6 +1586,7 @@ impl Vim { .recording_actions .push(ReplayableAction::Action(action.boxed_clone())); globals.recorded_actions = mem::take(&mut globals.recording_actions); + globals.recorded_count = globals.recording_count.take(); globals.dot_recording = false; globals.stop_recording_after_next_action = false; } diff --git a/crates/vim/test_data/test_repeat_clear_count.json b/crates/vim/test_data/test_repeat_clear_count.json new file mode 100644 index 0000000000000000000000000000000000000000..352c6ca4a8d2ee0534d3b695e2eb36ad26bc62d8 --- /dev/null +++ b/crates/vim/test_data/test_repeat_clear_count.json @@ -0,0 +1,21 @@ +{"Put":{"state":"ˇthe quick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"d"} +{"Key":"d"} +{"Get":{"state":"ˇfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"2"} +{"Key":"d"} +{"Key":"."} +{"Get":{"state":"ˇfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"."} +{"Get":{"state":"ˇthe lazy dog","mode":"Normal"}} +{"Put":{"state":"ˇthe quick brown\nfox jumps over\nthe lazy dog\nthe quick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"2"} +{"Key":"d"} +{"Key":"d"} +{"Get":{"state":"ˇthe lazy dog\nthe quick brown\nfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"5"} +{"Key":"d"} +{"Key":"."} +{"Get":{"state":"ˇthe lazy dog\nthe quick brown\nfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"."} +{"Get":{"state":"ˇfox jumps over\nthe lazy dog","mode":"Normal"}} diff --git a/crates/vim/test_data/test_repeat_clear_repeat.json b/crates/vim/test_data/test_repeat_clear_repeat.json new file mode 100644 index 0000000000000000000000000000000000000000..39d96e2a3759d75994e24e6ad80a3ef00b64259b --- /dev/null +++ b/crates/vim/test_data/test_repeat_clear_repeat.json @@ -0,0 +1,8 @@ +{"Put":{"state":"ˇthe quick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"d"} +{"Key":"d"} +{"Get":{"state":"ˇfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"d"} +{"Key":"."} +{"Key":"."} +{"Get":{"state":"ˇthe lazy dog","mode":"Normal"}}