Cursor keymap (#31702)

Peter Tripp and Joseph Lyons created

To use this, spawn `weclome: toggle base keymap selector` from the
command palette.

<img width="589" alt="Screenshot 2025-05-29 at 14 07 35"
src="https://github.com/user-attachments/assets/0d4c4eff-6a3b-40f4-9032-5d8ca7664d20"
/>

MacOS is well tested to match Cursor. The [curors keymap
documentation](https://docs.cursor.com/kbd) is does not explicitly state
windows/linux keymap entries only "All Cmd keys can be replaced with
Ctrl on Windows." so that is what we've done. We welcome feedback /
refinements.

Note, because this provides a mapping for `cmd-k` (macos) and `ctrl-k`
(linux/windows) using this keymap will disable all of the default
chorded keymap entries which have `cmd-k` / `ctrl-k` as a prefix. For
example `cmd-k cmd-s` for open keymap will no longer function.

Release Notes:

- Added Cursor compatibility keymap

---------

Co-authored-by: Joseph Lyons <joseph@zed.dev>

Change summary

assets/keymaps/default-linux.json         |  6 
assets/keymaps/default-macos.json         |  8 +-
assets/keymaps/linux/cursor.json          | 85 +++++++++++++++++++++++++
assets/keymaps/macos/cursor.json          | 85 +++++++++++++++++++++++++
crates/welcome/src/base_keymap_setting.rs | 10 ++
5 files changed, 185 insertions(+), 9 deletions(-)

Detailed changes

assets/keymaps/default-linux.json 🔗

@@ -127,9 +127,7 @@
       "shift-f10": "editor::OpenContextMenu",
       "ctrl-shift-e": "editor::ToggleEditPrediction",
       "f9": "editor::ToggleBreakpoint",
-      "shift-f9": "editor::EditLogBreakpoint",
-      "ctrl-shift-backspace": "editor::GoToPreviousChange",
-      "ctrl-shift-alt-backspace": "editor::GoToNextChange"
+      "shift-f9": "editor::EditLogBreakpoint"
     }
   },
   {
@@ -148,6 +146,8 @@
       "ctrl->": "assistant::QuoteSelection",
       "ctrl-<": "assistant::InsertIntoEditor",
       "ctrl-alt-e": "editor::SelectEnclosingSymbol",
+      "ctrl-shift-backspace": "editor::GoToPreviousChange",
+      "ctrl-shift-alt-backspace": "editor::GoToNextChange",
       "alt-enter": "editor::OpenSelectionsInMultibuffer"
     }
   },

assets/keymaps/default-macos.json 🔗

@@ -546,9 +546,7 @@
       "cmd-\\": "pane::SplitRight",
       "cmd-k v": "markdown::OpenPreviewToTheSide",
       "cmd-shift-v": "markdown::OpenPreview",
-      "ctrl-cmd-c": "editor::DisplayCursorNames",
-      "cmd-shift-backspace": "editor::GoToPreviousChange",
-      "cmd-shift-alt-backspace": "editor::GoToNextChange"
+      "ctrl-cmd-c": "editor::DisplayCursorNames"
     }
   },
   {
@@ -556,7 +554,9 @@
     "use_key_equivalents": true,
     "bindings": {
       "cmd-shift-o": "outline::Toggle",
-      "ctrl-g": "go_to_line::Toggle"
+      "ctrl-g": "go_to_line::Toggle",
+      "cmd-shift-backspace": "editor::GoToPreviousChange",
+      "cmd-shift-alt-backspace": "editor::GoToNextChange"
     }
   },
   {

assets/keymaps/linux/cursor.json 🔗

@@ -0,0 +1,85 @@
+[
+  // Cursor for MacOS. See: https://docs.cursor.com/kbd
+  {
+    "context": "Workspace",
+    "use_key_equivalents": true,
+    "bindings": {
+      "ctrl-i": "agent::ToggleFocus",
+      "ctrl-shift-i": "agent::ToggleFocus",
+      "ctrl-l": "agent::ToggleFocus",
+      "ctrl-shift-l": "agent::ToggleFocus",
+      "ctrl-alt-b": "agent::ToggleFocus",
+      "ctrl-shift-j": "agent::OpenConfiguration"
+    }
+  },
+  {
+    "context": "Editor && mode == full",
+    "use_key_equivalents": true,
+    "bindings": {
+      "ctrl-i": "agent::ToggleFocus",
+      "ctrl-shift-i": "agent::ToggleFocus",
+      "ctrl-shift-l": "assistant::QuoteSelection", // In cursor uses "Ask" mode
+      "ctrl-l": "assistant::QuoteSelection", // In cursor uses "Agent" mode
+      "ctrl-k": "assistant::InlineAssist",
+      "ctrl-shift-k": "assistant::InsertIntoEditor"
+    }
+  },
+  {
+    "context": "InlineAssistEditor",
+    "use_key_equivalents": true,
+    "bindings": {
+      "ctrl-shift-backspace": "editor::Cancel"
+      // "alt-enter": // Quick Question
+      // "ctrl-shift-enter": // Full File Context
+      // "ctrl-shift-k": // Toggle input focus (editor <> inline assist)
+    }
+  },
+  {
+    "context": "AgentPanel || ContextEditor || (MessageEditor > Editor)",
+    "use_key_equivalents": true,
+    "bindings": {
+      "ctrl-i": "workspace::ToggleRightDock",
+      "ctrl-shift-i": "workspace::ToggleRightDock",
+      "ctrl-l": "workspace::ToggleRightDock",
+      "ctrl-shift-l": "workspace::ToggleRightDock",
+      "ctrl-alt-b": "workspace::ToggleRightDock",
+      "ctrl-w": "workspace::ToggleRightDock", // technically should close chat
+      "ctrl-.": "agent::ToggleProfileSelector",
+      "ctrl-/": "agent::ToggleModelSelector",
+      "ctrl-shift-backspace": "editor::Cancel",
+      "ctrl-r": "agent::NewThread",
+      "ctrl-shift-v": "editor::Paste",
+      "ctrl-shift-k": "assistant::InsertIntoEditor"
+      // "escape": "agent::ToggleFocus"
+      ///// Enable when Zed supports multiple thread tabs
+      // "ctrl-t": // new thread tab
+      // "ctrl-[": // next thread tab
+      // "ctrl-]": // next thread tab
+      ///// Enable if Zed adds support for keyboard navigation of thread elements
+      // "tab": // cycle to next message
+      // "shift-tab": // cycle to previous message
+    }
+  },
+  {
+    "context": "Editor && editor_agent_diff",
+    "use_key_equivalents": true,
+    "bindings": {
+      "ctrl-enter": "agent::KeepAll",
+      "ctrl-backspace": "agent::RejectAll"
+    }
+  },
+  {
+    "context": "Editor && mode == full && edit_prediction",
+    "use_key_equivalents": true,
+    "bindings": {
+      "ctrl-right": "editor::AcceptPartialEditPrediction"
+    }
+  },
+  {
+    "context": "Terminal",
+    "use_key_equivalents": true,
+    "bindings": {
+      "ctrl-k": "assistant::InlineAssist"
+    }
+  }
+]

assets/keymaps/macos/cursor.json 🔗

@@ -0,0 +1,85 @@
+[
+  // Cursor for MacOS. See: https://docs.cursor.com/kbd
+  {
+    "context": "Workspace",
+    "use_key_equivalents": true,
+    "bindings": {
+      "cmd-i": "agent::ToggleFocus",
+      "cmd-shift-i": "agent::ToggleFocus",
+      "cmd-l": "agent::ToggleFocus",
+      "cmd-shift-l": "agent::ToggleFocus",
+      "cmd-alt-b": "agent::ToggleFocus",
+      "cmd-shift-j": "agent::OpenConfiguration"
+    }
+  },
+  {
+    "context": "Editor && mode == full",
+    "use_key_equivalents": true,
+    "bindings": {
+      "cmd-i": "agent::ToggleFocus",
+      "cmd-shift-i": "agent::ToggleFocus",
+      "cmd-shift-l": "assistant::QuoteSelection", // In cursor uses "Ask" mode
+      "cmd-l": "assistant::QuoteSelection", // In cursor uses "Agent" mode
+      "cmd-k": "assistant::InlineAssist",
+      "cmd-shift-k": "assistant::InsertIntoEditor"
+    }
+  },
+  {
+    "context": "InlineAssistEditor",
+    "use_key_equivalents": true,
+    "bindings": {
+      "cmd-shift-backspace": "editor::Cancel"
+      // "alt-enter": // Quick Question
+      // "cmd-shift-enter": // Full File Context
+      // "cmd-shift-k": // Toggle input focus (editor <> inline assist)
+    }
+  },
+  {
+    "context": "AgentPanel || ContextEditor || (MessageEditor > Editor)",
+    "use_key_equivalents": true,
+    "bindings": {
+      "cmd-i": "workspace::ToggleRightDock",
+      "cmd-shift-i": "workspace::ToggleRightDock",
+      "cmd-l": "workspace::ToggleRightDock",
+      "cmd-shift-l": "workspace::ToggleRightDock",
+      "cmd-alt-b": "workspace::ToggleRightDock",
+      "cmd-w": "workspace::ToggleRightDock", // technically should close chat
+      "cmd-.": "agent::ToggleProfileSelector",
+      "cmd-/": "agent::ToggleModelSelector",
+      "cmd-shift-backspace": "editor::Cancel",
+      "cmd-r": "agent::NewThread",
+      "cmd-shift-v": "editor::Paste",
+      "cmd-shift-k": "assistant::InsertIntoEditor"
+      // "escape": "agent::ToggleFocus"
+      ///// Enable when Zed supports multiple thread tabs
+      // "cmd-t": // new thread tab
+      // "cmd-[": // next thread tab
+      // "cmd-]": // next thread tab
+      ///// Enable if Zed adds support for keyboard navigation of thread elements
+      // "tab": // cycle to next message
+      // "shift-tab": // cycle to previous message
+    }
+  },
+  {
+    "context": "Editor && editor_agent_diff",
+    "use_key_equivalents": true,
+    "bindings": {
+      "cmd-enter": "agent::KeepAll",
+      "cmd-backspace": "agent::RejectAll"
+    }
+  },
+  {
+    "context": "Editor && mode == full && edit_prediction",
+    "use_key_equivalents": true,
+    "bindings": {
+      "cmd-right": "editor::AcceptPartialEditPrediction"
+    }
+  },
+  {
+    "context": "Terminal",
+    "use_key_equivalents": true,
+    "bindings": {
+      "cmd-k": "assistant::InlineAssist"
+    }
+  }
+]

crates/welcome/src/base_keymap_setting.rs 🔗

@@ -16,6 +16,7 @@ pub enum BaseKeymap {
     Atom,
     TextMate,
     Emacs,
+    Cursor,
     None,
 }
 
@@ -28,6 +29,7 @@ impl Display for BaseKeymap {
             BaseKeymap::Atom => write!(f, "Atom"),
             BaseKeymap::TextMate => write!(f, "TextMate"),
             BaseKeymap::Emacs => write!(f, "Emacs (beta)"),
+            BaseKeymap::Cursor => write!(f, "Cursor (beta)"),
             BaseKeymap::None => write!(f, "None"),
         }
     }
@@ -35,22 +37,24 @@ impl Display for BaseKeymap {
 
 impl BaseKeymap {
     #[cfg(target_os = "macos")]
-    pub const OPTIONS: [(&'static str, Self); 6] = [
+    pub const OPTIONS: [(&'static str, Self); 7] = [
         ("VSCode (Default)", Self::VSCode),
         ("Atom", Self::Atom),
         ("JetBrains", Self::JetBrains),
         ("Sublime Text", Self::SublimeText),
         ("Emacs (beta)", Self::Emacs),
         ("TextMate", Self::TextMate),
+        ("Cursor (beta)", Self::Cursor),
     ];
 
     #[cfg(not(target_os = "macos"))]
-    pub const OPTIONS: [(&'static str, Self); 5] = [
+    pub const OPTIONS: [(&'static str, Self); 6] = [
         ("VSCode (Default)", Self::VSCode),
         ("Atom", Self::Atom),
         ("JetBrains", Self::JetBrains),
         ("Sublime Text", Self::SublimeText),
         ("Emacs (beta)", Self::Emacs),
+        ("Cursor (beta)", Self::Cursor),
     ];
 
     pub fn asset_path(&self) -> Option<&'static str> {
@@ -61,6 +65,7 @@ impl BaseKeymap {
             BaseKeymap::Atom => Some("keymaps/macos/atom.json"),
             BaseKeymap::TextMate => Some("keymaps/macos/textmate.json"),
             BaseKeymap::Emacs => Some("keymaps/macos/emacs.json"),
+            BaseKeymap::Cursor => Some("keymaps/macos/cursor.json"),
             BaseKeymap::VSCode => None,
             BaseKeymap::None => None,
         }
@@ -71,6 +76,7 @@ impl BaseKeymap {
             BaseKeymap::SublimeText => Some("keymaps/linux/sublime_text.json"),
             BaseKeymap::Atom => Some("keymaps/linux/atom.json"),
             BaseKeymap::Emacs => Some("keymaps/linux/emacs.json"),
+            BaseKeymap::Cursor => Some("keymaps/linux/cursor.json"),
             BaseKeymap::TextMate => None,
             BaseKeymap::VSCode => None,
             BaseKeymap::None => None,