Fix undo in replace mode (#10086)

Conrad Irwin and Petros created

Fixes: #10031

Co-Authored-By: Petros <petros@amignosis.com>

Release Notes:

- vim: Fix undo grouping in Replace mode
([#10031](https://github.com/zed-industries/zed/issues/10031)).

---------

Co-authored-by: Petros <petros@amignosis.com>

Change summary

crates/vim/src/replace.rs | 9 +++++++++
crates/vim/src/vim.rs     | 6 ++++--
2 files changed, 13 insertions(+), 2 deletions(-)

Detailed changes

crates/vim/src/replace.rs 🔗

@@ -349,4 +349,13 @@ mod test {
         ]);
         cx.assert_state("ˇabˇcabcabc", Mode::Replace);
     }
+
+    #[gpui::test]
+    async fn test_replace_undo(cx: &mut gpui::TestAppContext) {
+        let mut cx = VimTestContext::new(cx, true).await;
+
+        cx.set_state("ˇaaaa", Mode::Normal);
+        cx.simulate_keystrokes(["0", "shift-r", "b", "b", "b", "escape", "u"]);
+        cx.assert_state("ˇaaaa", Mode::Normal);
+    }
 }

crates/vim/src/vim.rs 🔗

@@ -390,7 +390,7 @@ impl Vim {
             {
                 visual_block_motion(true, editor, cx, |_, point, goal| Some((point, goal)))
             }
-            if last_mode == Mode::Insert {
+            if last_mode == Mode::Insert || last_mode == Mode::Replace {
                 if let Some(prior_tx) = prior_tx {
                     editor.group_until_transaction(prior_tx, cx)
                 }
@@ -502,7 +502,9 @@ impl Vim {
 
     fn transaction_begun(&mut self, transaction_id: TransactionId, _: &mut WindowContext) {
         self.update_state(|state| {
-            let mode = if (state.mode == Mode::Insert || state.mode == Mode::Normal)
+            let mode = if (state.mode == Mode::Insert
+                || state.mode == Mode::Replace
+                || state.mode == Mode::Normal)
                 && state.current_tx.is_none()
             {
                 state.current_tx = Some(transaction_id);