Remove editor::Cancel binding from vim

Conrad Irwin created

When you hit <escape> in the command palette, it first editor::Cancel
because the command palette is also a focused editor; this binding was
catching before the `menu::Cancel` that you probably want.

From looking at the uses of editor::Cancel it seems like the only way to
trigger this is with <escape> in an editor. Rather than trying to hook
into the existing editor cancel and add vim-specific behaviour, we'll
instead take responsibility for binding directly to <escape> when
necessary.

Fixes: zed-industries/community#1347

Change summary

assets/keymaps/vim.json                 | 10 ++++++++--
crates/vim/src/test.rs                  | 14 ++++++++++++++
crates/vim/src/test/vim_test_context.rs |  2 ++
crates/vim/src/vim.rs                   | 23 ++---------------------
4 files changed, 26 insertions(+), 23 deletions(-)

Detailed changes

assets/keymaps/vim.json 🔗

@@ -93,7 +93,10 @@
       ],
       "ctrl-o": "pane::GoBack",
       "ctrl-]": "editor::GoToDefinition",
-      "escape": "editor::Cancel",
+      "escape": [
+        "vim::SwitchMode",
+        "Normal"
+      ],
       "0": "vim::StartOfLine", // When no number operator present, use start of line motion
       "1": [
         "vim::Number",
@@ -325,7 +328,10 @@
     "bindings": {
       "tab": "vim::Tab",
       "enter": "vim::Enter",
-      "escape": "editor::Cancel"
+      "escape": [
+        "vim::SwitchMode",
+        "Normal"
+      ]
     }
   }
 ]

crates/vim/src/test.rs 🔗

@@ -4,6 +4,7 @@ mod neovim_connection;
 mod vim_binding_test_context;
 mod vim_test_context;
 
+use command_palette::CommandPalette;
 pub use neovim_backed_binding_test_context::*;
 pub use neovim_backed_test_context::*;
 pub use vim_binding_test_context::*;
@@ -139,3 +140,16 @@ async fn test_indent_outdent(cx: &mut gpui::TestAppContext) {
     cx.simulate_keystrokes(["shift-v", "down", ">", ">"]);
     cx.assert_editor_state("aa\n    b«b\n    cˇ»c");
 }
+
+#[gpui::test]
+async fn test_escape_command_palette(cx: &mut gpui::TestAppContext) {
+    let mut cx = VimTestContext::new(cx, true).await;
+
+    cx.set_state("aˇbc\n", Mode::Normal);
+    cx.simulate_keystrokes(["i", "cmd-shift-p"]);
+
+    assert!(cx.workspace(|workspace, _| workspace.modal::<CommandPalette>().is_some()));
+    cx.simulate_keystroke("escape");
+    assert!(!cx.workspace(|workspace, _| workspace.modal::<CommandPalette>().is_some()));
+    cx.assert_state("aˇbc\n", Mode::Insert);
+}

crates/vim/src/test/vim_test_context.rs 🔗

@@ -21,12 +21,14 @@ impl<'a> VimTestContext<'a> {
         cx.update(|cx| {
             search::init(cx);
             crate::init(cx);
+            command_palette::init(cx);
         });
 
         cx.update(|cx| {
             cx.update_global(|store: &mut SettingsStore, cx| {
                 store.update_user_settings::<VimModeSetting>(cx, |s| *s = Some(enabled));
             });
+            settings::KeymapFile::load_asset("keymaps/default.json", cx).unwrap();
             settings::KeymapFile::load_asset("keymaps/vim.json", cx).unwrap();
         });
 

crates/vim/src/vim.rs 🔗

@@ -12,7 +12,7 @@ mod visual;
 
 use anyhow::Result;
 use collections::CommandPaletteFilter;
-use editor::{Bias, Cancel, Editor, EditorMode, Event};
+use editor::{Bias, Editor, EditorMode, Event};
 use gpui::{
     actions, impl_actions, AppContext, Subscription, ViewContext, ViewHandle, WeakViewHandle,
     WindowContext,
@@ -64,22 +64,6 @@ pub fn init(cx: &mut AppContext) {
         Vim::update(cx, |vim, cx| vim.push_number(n, cx));
     });
 
-    // Editor Actions
-    cx.add_action(|_: &mut Editor, _: &Cancel, cx| {
-        // If we are in aren't in normal mode or have an active operator, swap to normal mode
-        // Otherwise forward cancel on to the editor
-        let vim = Vim::read(cx);
-        if vim.state.mode != Mode::Normal || vim.active_operator().is_some() {
-            WindowContext::defer(cx, |cx| {
-                Vim::update(cx, |state, cx| {
-                    state.switch_mode(Mode::Normal, false, cx);
-                });
-            });
-        } else {
-            cx.propagate_action();
-        }
-    });
-
     cx.add_action(|_: &mut Workspace, _: &Tab, cx| {
         Vim::active_editor_input_ignored(" ".into(), cx)
     });
@@ -109,10 +93,7 @@ pub fn observe_keystrokes(cx: &mut WindowContext) {
     cx.observe_keystrokes(|_keystroke, _result, handled_by, cx| {
         if let Some(handled_by) = handled_by {
             // Keystroke is handled by the vim system, so continue forward
-            // Also short circuit if it is the special cancel action
-            if handled_by.namespace() == "vim"
-                || (handled_by.namespace() == "editor" && handled_by.name() == "Cancel")
-            {
+            if handled_by.namespace() == "vim" {
                 return true;
             }
         }