Allow vim counts with undo and redo (#13950)

Matt Fellenz created

These were previously passed directly to the editor module, which knows
nothing about vim counts. Instead, implement new actions in the vim
module which take the count and use it to invoke the corresponding
action in the editor module, properly repeated.

Release Notes:

- Fixed vim undo and redo commands not taking counts.

Change summary

assets/keymaps/vim.json  |  4 ++--
crates/vim/src/normal.rs | 23 +++++++++++++++++++++++
2 files changed, 25 insertions(+), 2 deletions(-)

Detailed changes

assets/keymaps/vim.json 🔗

@@ -232,8 +232,8 @@
       "ctrl-x": "vim::Decrement",
       "p": "vim::Paste",
       "shift-p": ["vim::Paste", { "before": true }],
-      "u": "editor::Undo",
-      "ctrl-r": "editor::Redo",
+      "u": "vim::Undo",
+      "ctrl-r": "vim::Redo",
       "r": ["vim::PushOperator", "Replace"],
       "s": "vim::Substitute",
       "shift-s": "vim::SubstituteLine",

crates/vim/src/normal.rs 🔗

@@ -65,6 +65,8 @@ actions!(
         Indent,
         Outdent,
         ToggleComments,
+        Undo,
+        Redo,
     ]
 );
 
@@ -180,6 +182,27 @@ pub(crate) fn register(workspace: &mut Workspace, cx: &mut ViewContext<Workspace
         });
     });
 
+    workspace.register_action(|_: &mut Workspace, _: &Undo, cx| {
+        Vim::update(cx, |vim, cx| {
+            let times = vim.take_count(cx);
+            vim.update_active_editor(cx, |_, editor, cx| {
+                for _ in 0..times.unwrap_or(1) {
+                    editor.undo(&editor::actions::Undo, cx);
+                }
+            });
+        })
+    });
+    workspace.register_action(|_: &mut Workspace, _: &Redo, cx| {
+        Vim::update(cx, |vim, cx| {
+            let times = vim.take_count(cx);
+            vim.update_active_editor(cx, |_, editor, cx| {
+                for _ in 0..times.unwrap_or(1) {
+                    editor.redo(&editor::actions::Redo, cx);
+                }
+            });
+        })
+    });
+
     paste::register(workspace, cx);
     repeat::register(workspace, cx);
     scroll::register(workspace, cx);