vim: Fix >... (#15404)

Conrad Irwin created

Co-Authored-By: @Alextopher

Release Notes:

- vim: Fixed a hang when repeating an aborted operation
([#15399](https://github.com/zed-industries/zed/issues/15399)).

Change summary

crates/vim/src/test.rs                                 | 12 ++++++
crates/vim/src/vim.rs                                  | 24 +++---------
crates/vim/test_data/test_record_replay_recursion.json |  6 +++
3 files changed, 24 insertions(+), 18 deletions(-)

Detailed changes

crates/vim/src/test.rs 🔗

@@ -1448,3 +1448,15 @@ async fn test_visual_indent_count(cx: &mut gpui::TestAppContext) {
     cx.simulate_keystrokes("shift-v 2 <");
     cx.assert_state("    ˇhi", Mode::Normal);
 }
+
+#[gpui::test]
+async fn test_record_replay_recursion(cx: &mut gpui::TestAppContext) {
+    let mut cx = NeovimBackedTestContext::new(cx).await;
+
+    cx.set_shared_state("ˇhello world").await;
+    cx.simulate_shared_keystrokes(">").await;
+    cx.simulate_shared_keystrokes(".").await;
+    cx.simulate_shared_keystrokes(".").await;
+    cx.simulate_shared_keystrokes(".").await;
+    cx.shared_state().await.assert_eq("ˇhello world"); // takes a _long_ time
+}

crates/vim/src/vim.rs 🔗

@@ -189,25 +189,13 @@ fn observe_keystrokes(keystroke_event: &KeystrokeEvent, cx: &mut WindowContext)
         return;
     }
 
-    Vim::update(cx, |vim, cx| match vim.active_operator() {
-        Some(
-            Operator::FindForward { .. }
-            | Operator::FindBackward { .. }
-            | Operator::Replace
-            | Operator::Digraph { .. }
-            | Operator::AddSurrounds { .. }
-            | Operator::ChangeSurrounds { .. }
-            | Operator::DeleteSurrounds
-            | Operator::Mark
-            | Operator::Jump { .. }
-            | Operator::Register
-            | Operator::RecordRegister
-            | Operator::ReplayRegister,
-        ) => {}
-        Some(_) => {
-            vim.clear_operator(cx);
+    Vim::update(cx, |vim, cx| {
+        if let Some(operator) = vim.active_operator() {
+            if !operator.is_waiting(vim.state().mode) {
+                vim.clear_operator(cx);
+                vim.stop_recording_immediately(Box::new(ClearOperators))
+            }
         }
-        _ => {}
     });
 }