vim netrw (#7962)

Conrad Irwin created

- Tidy up vim netrw bindings (c.f.
https://github.com/zed-industries/zed/issues/4270,
https://github.com/zed-industries/zed/pull/7757)
- Add vim commands for panels

Release Notes:

- vim: add commands to toggle panels `:E[xplore]`, `:C[ollab]`,
`:Ch[at]`, `:N[otification]`, `:A[I]`, `:te[rm]` (or `:T[erm]`).

Change summary

Cargo.lock                |  2 -
assets/keymaps/vim.json   | 30 ++++++----------
crates/vim/Cargo.toml     |  2 -
crates/vim/src/command.rs | 71 +++++++++++++++++++++++++++++++---------
4 files changed, 66 insertions(+), 39 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -10837,7 +10837,6 @@ dependencies = [
  "collections",
  "command_palette",
  "copilot",
- "diagnostics",
  "editor",
  "futures 0.3.28",
  "gpui",
@@ -10849,7 +10848,6 @@ dependencies = [
  "nvim-rs",
  "parking_lot 0.11.2",
  "project",
- "project_panel",
  "regex",
  "release_channel",
  "search",

assets/keymaps/vim.json 🔗

@@ -509,31 +509,25 @@
     }
   },
   {
-    // Directory expansion
+    // netrw compatibility
     "context": "ProjectPanel && not_editing",
     "bindings": {
-      "escape": "project_panel::ToggleFocus",
-      "enter": "project_panel::Open",
-      "o": "project_panel::Open",
-      "t": "project_panel::Open",
-      "v": "project_panel::Open",
-      "d": "project_panel::NewDirectory",
+      ":": "command_palette::Toggle",
       "%": "project_panel::NewFile",
-      "shift-r": "project_panel::Rename",
-      "m m": "project_panel::Cut",
-      "m c": "project_panel::Copy",
-      "m t": "project_panel::Paste",
-      "x": "project_panel::RevealInFinder",
-      "l": "project_panel::ExpandSelectedEntry",
+      "/": "project_panel::NewSearchInDirectory",
+      "d": "project_panel::NewDirectory",
+      "enter": "project_panel::Open",
+      "escape": "project_panel::ToggleFocus",
       "h": "project_panel::CollapseSelectedEntry",
-      // Move up and down
       "j": "menu::SelectNext",
       "k": "menu::SelectPrev",
+      "l": "project_panel::ExpandSelectedEntry",
+      "o": "project_panel::Open",
       "shift-d": "project_panel::Delete",
-      "/": "project_panel::NewSearchInDirectory",
-      // zed specific
-      "q p": "project_panel::CopyPath",
-      "q r": "project_panel::CopyRelativePath"
+      "shift-r": "project_panel::Rename",
+      "t": "project_panel::Open",
+      "v": "project_panel::Open",
+      "x": "project_panel::RevealInFinder"
     }
   }
 ]

crates/vim/Cargo.toml 🔗

@@ -20,8 +20,6 @@ collections.workspace = true
 command_palette.workspace = true
 # HACK: We're only depending on `copilot` here for `CommandPaletteFilter`.  See the attached comment on that type.
 copilot.workspace = true
-project_panel.workspace = true
-diagnostics.workspace = true
 editor.workspace = true
 gpui.workspace = true
 itertools = "0.10"

crates/vim/src/command.rs 🔗

@@ -31,7 +31,7 @@ pub fn register(workspace: &mut Workspace, _: &mut ViewContext<Workspace>) {
     });
 }
 
-pub fn command_interceptor(mut query: &str, _: &AppContext) -> Option<CommandInterceptResult> {
+pub fn command_interceptor(mut query: &str, cx: &AppContext) -> Option<CommandInterceptResult> {
     // Note: this is a very poor simulation of vim's command palette.
     // In the future we should adjust it to handle parsing range syntax,
     // and then calling the appropriate commands with/without ranges.
@@ -203,7 +203,10 @@ pub fn command_interceptor(mut query: &str, _: &AppContext) -> Option<CommandInt
         ),
 
         // quickfix / loclist (merged together for now)
-        "cl" | "cli" | "clis" | "clist" => ("clist", diagnostics::Deploy.boxed_clone()),
+        "cl" | "cli" | "clis" | "clist" => (
+            "clist",
+            cx.build_action("diagnostics::Deploy", None).unwrap(),
+        ),
         "cc" => ("cc", editor::actions::Hover.boxed_clone()),
         "ll" => ("ll", editor::actions::Hover.boxed_clone()),
         "cn" | "cne" | "cnex" | "cnext" => ("cnext", editor::actions::GoToDiagnostic.boxed_clone()),
@@ -234,21 +237,55 @@ pub fn command_interceptor(mut query: &str, _: &AppContext) -> Option<CommandInt
         "sor i" | "sort i" => ("sort i", SortLinesCaseInsensitive.boxed_clone()),
 
         // Explore, etc.
-        "E" | "Ex" | "Exp" | "Expl" | "Explo" | "Explor" | "Explore" => {
-            ("Explore", project_panel::ToggleFocus.boxed_clone())
-        }
-        "H" | "He" | "Hex" | "Hexp" | "Hexpl" | "Hexplo" | "Hexplor" | "Hexplore" => {
-            ("Hexplore", project_panel::ToggleFocus.boxed_clone())
-        }
-        "L" | "Le" | "Lex" | "Lexp" | "Lexpl" | "Lexplo" | "Lexplor" | "Lexplore" => {
-            ("Lexplore", project_panel::ToggleFocus.boxed_clone())
-        }
-        "S" | "Se" | "Sex" | "Sexp" | "Sexpl" | "Sexplo" | "Sexplor" | "Sexplore" => {
-            ("Sexplore", project_panel::ToggleFocus.boxed_clone())
-        }
-        "Ve" | "Vex" | "Vexp" | "Vexpl" | "Vexplo" | "Vexplor" | "Vexplore" => {
-            ("Vexplore", project_panel::ToggleFocus.boxed_clone())
-        }
+        "E" | "Ex" | "Exp" | "Expl" | "Explo" | "Explor" | "Explore" => (
+            "Explore",
+            cx.build_action("project_panel::ToggleFocus", None).unwrap(),
+        ),
+        "H" | "He" | "Hex" | "Hexp" | "Hexpl" | "Hexplo" | "Hexplor" | "Hexplore" => (
+            "Hexplore",
+            cx.build_action("project_panel::ToggleFocus", None).unwrap(),
+        ),
+        "L" | "Le" | "Lex" | "Lexp" | "Lexpl" | "Lexplo" | "Lexplor" | "Lexplore" => (
+            "Lexplore",
+            cx.build_action("project_panel::ToggleFocus", None).unwrap(),
+        ),
+        "S" | "Se" | "Sex" | "Sexp" | "Sexpl" | "Sexplo" | "Sexplor" | "Sexplore" => (
+            "Sexplore",
+            cx.build_action("project_panel::ToggleFocus", None).unwrap(),
+        ),
+        "Ve" | "Vex" | "Vexp" | "Vexpl" | "Vexplo" | "Vexplor" | "Vexplore" => (
+            "Vexplore",
+            cx.build_action("project_panel::ToggleFocus", None).unwrap(),
+        ),
+        "te" | "ter" | "term" => (
+            "term",
+            cx.build_action("terminal_panel::ToggleFocus", None)
+                .unwrap(),
+        ),
+        // Zed panes
+        "T" | "Te" | "Ter" | "Term" => (
+            "Term",
+            cx.build_action("terminal_panel::ToggleFocus", None)
+                .unwrap(),
+        ),
+        "C" | "Co" | "Col" | "Coll" | "Colla" | "Collab" => (
+            "Collab",
+            cx.build_action("collab_panel::ToggleFocus", None).unwrap(),
+        ),
+        "Ch" | "Cha" | "Chat" => (
+            "Chat",
+            cx.build_action("chat_panel::ToggleFocus", None).unwrap(),
+        ),
+        "No" | "Not" | "Noti" | "Notif" | "Notifi" | "Notific" | "Notifica" | "Notificat"
+        | "Notificati" | "Notificatio" | "Notification" => (
+            "Notifications",
+            cx.build_action("notification_panel::ToggleFocus", None)
+                .unwrap(),
+        ),
+        "A" | "AI" | "Ai" => (
+            "AI",
+            cx.build_action("assistant::ToggleFocus", None).unwrap(),
+        ),
 
         // goto (other ranges handled under _ => )
         "$" => ("$", EndOfDocument.boxed_clone()),