key-bindings.md

  1---
  2title: Key Bindings and Shortcuts - Zed
  3description: Customize Zed's keyboard shortcuts. Rebind actions, create key sequences, and set context-specific bindings.
  4---
  5
  6# Key bindings
  7
  8Zed's key binding system is fully customizable. You can rebind any action, create key sequences, and define context-specific bindings.
  9
 10## Predefined Keymaps
 11
 12If you're used to a specific editor's defaults, you can change your `base_keymap` through the settings window ({#kb zed::OpenSettings}) or directly through your `settings.json` file ({#kb zed::OpenSettingsFile}).
 13We currently support:
 14
 15- VS Code (default)
 16- Atom
 17- Emacs (Beta)
 18- JetBrains
 19- Sublime Text
 20- TextMate
 21- Cursor
 22- None (disables _all_ key bindings)
 23
 24This setting can also be changed via the command palette through the `zed: toggle base keymap selector` action.
 25
 26You can also enable `vim_mode` or `helix_mode`, which add modal bindings.
 27For more information, see the documentation for [Vim mode](./vim.md) and [Helix mode](./helix.md).
 28
 29## Word and subword navigation
 30
 31Zed exposes word and subword motions as separate actions.
 32
 33- Word motions stop at whitespace and punctuation boundaries.
 34- Subword motions also stop inside identifiers such as `camelCase`, `PascalCase`, and `snake_case`.
 35
 36In the default macOS and Linux keymaps:
 37
 38- `alt-left` / `alt-right` move by word
 39- `shift-alt-left` / `shift-alt-right` select by word
 40- `ctrl-alt-left` / `ctrl-alt-right` move by subword
 41- `ctrl-alt-shift-left` / `ctrl-alt-shift-right` select by subword
 42
 43If you use the JetBrains base keymap, Zed makes editor-local `alt-left` / `alt-right` and `shift-alt-left` / `shift-alt-right` use subword motions by default to match JetBrains-style CamelHump navigation. Outside the editor, the JetBrains keymap keeps its existing pane navigation bindings.
 44
 45If you want to customize this behavior further, open the keymap editor with {#kb zed::OpenKeymap} or edit your `keymap.json` directly.
 46
 47If you are using a base keymap other than JetBrains and want `alt-left` / `alt-right` to use CamelHump-style subword motions, add this to your `keymap.json`:
 48
 49```json [keymap]
 50[
 51  {
 52    "context": "Editor",
 53    "bindings": {
 54      "alt-left": "editor::MoveToPreviousSubwordStart",
 55      "alt-right": "editor::MoveToNextSubwordEnd",
 56      "shift-alt-left": "editor::SelectToPreviousSubwordStart",
 57      "shift-alt-right": "editor::SelectToNextSubwordEnd"
 58    }
 59  }
 60]
 61```
 62
 63If you use the JetBrains base keymap and want `alt-left` / `alt-right` to keep moving between tabs in the editor, add this override:
 64
 65```json [keymap]
 66[
 67  {
 68    "context": "Editor",
 69    "bindings": {
 70      "alt-left": "pane::ActivatePreviousItem",
 71      "alt-right": "pane::ActivateNextItem"
 72    }
 73  }
 74]
 75```
 76
 77## Keymap Editor
 78
 79You can access the keymap editor through the {#kb zed::OpenKeymap} action or by running {#action zed::OpenKeymap} action from the command palette. You can easily add or change a keybind for an action with the `Change Keybinding` or `Add Keybinding` button on the command pallets left bottom corner.
 80
 81In there, you can see all of the existing actions in Zed as well as the associated keybindings set to them by default.
 82
 83You can also customize them right from there, either by clicking on the pencil icon that appears when you hover over a particular action, by double-clicking on the action row, or by pressing the `enter` key.
 84
 85Anything that you end up doing on the keymap editor also gets reflected on the `keymap.json` file.
 86
 87## User Keymaps
 88
 89The keymap file is stored in the following locations for each platform:
 90
 91- macOS/Linux: `~/.config/zed/keymap.json`
 92- Windows: `~\AppData\Roaming\Zed/keymap.json`
 93
 94You can open the keymap with the {#action zed::OpenKeymapFile} action from the command palette.
 95
 96This file contains a JSON array of objects with `"bindings"`.
 97If no `"context"` is set, the bindings are always active.
 98If it is set, the binding is only active when the [context matches](#contexts).
 99
100Within each binding section, a [key sequence](#keybinding-syntax) is mapped to [an action](#actions).
101If conflicts are detected, they are resolved as [described below](#precedence).
102
103If you are using a non-QWERTY, Latin-character keyboard, you may want to set `use_key_equivalents` to `true`. See [Non-QWERTY keyboards](#non-qwerty-keyboards) for more information.
104
105For example:
106
107```json [keymap]
108[
109  {
110    "bindings": {
111      "ctrl-right": "editor::SelectLargerSyntaxNode",
112      "ctrl-left": "editor::SelectSmallerSyntaxNode"
113    }
114  },
115  {
116    "context": "ProjectPanel && not_editing",
117    "bindings": {
118      "o": "project_panel::Open"
119    }
120  }
121]
122```
123
124You can see all of Zed's default bindings for each platform in the default keymaps files:
125
126- [macOS](https://github.com/zed-industries/zed/blob/main/assets/keymaps/default-macos.json)
127- [Windows](https://github.com/zed-industries/zed/blob/main/assets/keymaps/default-windows.json)
128- [Linux](https://github.com/zed-industries/zed/blob/main/assets/keymaps/default-linux.json).
129
130If you want to debug problems with custom keymaps, you can use `dev: Open Key Context View` from the command palette.
131Please file [an issue](https://github.com/zed-industries/zed) if you run into something you think should work but isn't.
132
133### Keybinding Syntax
134
135Zed has the ability to match against not just a single keypress, but a sequence of keys typed in order. Each key in the `"bindings"` map is a sequence of keypresses separated with a space.
136
137Each keypress is a sequence of modifiers followed by a key. The modifiers are:
138
139- `ctrl-` The control key
140- `cmd-`, `win-` or `super-` for the platform modifier (Command on macOS, Windows key on Windows, and the Super key on Linux).
141- `alt-` for alt (option on macOS)
142- `shift-` The shift key
143- `fn-` The function key
144- `secondary-` Equivalent to `cmd` when Zed is running on macOS and `ctrl` when on Windows and Linux
145
146The keys can be any single Unicode codepoint that your keyboard generates (for example `a`, `0`, `£` or `ç`), or any named key (`tab`, `f1`, `shift`, or `cmd`). If you are using a non-Latin layout (e.g. Cyrillic), you can bind either to the Cyrillic character or the Latin character that key generates with `cmd` pressed.
147
148A few examples:
149
150```json [keymap]
151{
152  "bindings": {
153    "cmd-k cmd-s": "zed::OpenKeymap", // matches ⌘-k then ⌘-s
154    "space e": "editor::ShowCompletions", // type space then e
155    "ç": "editor::ShowCompletions", // matches ⌥-c
156    "shift shift": "file_finder::Toggle" // matches pressing and releasing shift twice
157  }
158}
159```
160
161The `shift-` modifier can only be used in combination with a letter to indicate the uppercase version. For example, `shift-g` matches typing `G`. Although on many keyboards shift is used to type punctuation characters like `(`, the keypress is not considered to be modified, and so `shift-(` does not match.
162
163The `alt-` modifier can be used on many layouts to generate a different key. For example, on a macOS US keyboard, the combination `alt-c` types `ç`. You can match against either in your keymap file, though by convention, Zed spells this combination as `alt-c`.
164
165It is possible to match against typing a modifier key on its own. For example, `shift shift` can be used to implement JetBrains' 'Search Everywhere' shortcut. In this case, the binding happens on key release instead of on keypress.
166
167### Contexts
168
169If a binding group has a `"context"` key, it will be matched against the currently active contexts in Zed.
170
171Zed's contexts make up a tree, with the root being `Workspace`. Workspaces contain Panes and Panels, and Panes contain Editors, etc. The easiest way to see what contexts are active at a given moment is the key context view, which you can get to with the `dev: open key context view` command in the command palette.
172
173For example:
174
175```
176# in an editor, it might look like this:
177Workspace os=macos keyboard_layout=com.apple.keylayout.QWERTY
178  Pane
179    Editor mode=full extension=md vim_mode=insert
180
181# in the project panel
182Workspace os=macos
183  Dock
184    ProjectPanel not_editing
185```
186
187Context expressions can contain the following syntax:
188
189- `X && Y`, `X || Y` to and/or two conditions
190- `!X` to check that a condition is false
191- `(X)` for grouping
192- `X > Y` to match if an ancestor in the tree matches X and this layer matches Y.
193
194For example:
195
196- `"context": "Editor"` - matches any editor (including inline inputs)
197- `"context": "Editor && mode == full"` - matches the main editors used for editing code
198- `"context": "!Editor && !Terminal"` - matches anywhere except where an Editor or Terminal is focused
199- `"context": "os == macos > Editor"` - matches any editor on macOS.
200
201It's worth noting that attributes are only available on the node they are defined on. This means that if you want to (for example) only enable a keybinding when the debugger is stopped in vim normal mode, you need to do `debugger_stopped > vim_mode == normal`.
202
203> Note: Before Zed v0.197.x, the `!` operator only looked at one node at a time, and `>` meant "parent" not "ancestor". This meant that `!Editor` would match the context `Workspace > Pane > Editor`, because (confusingly) the Pane matches `!Editor`, and that `os == macos > Editor` did not match the context `Workspace > Pane > Editor` because of the intermediate `Pane` node.
204
205If you're using Vim mode, we have information on how [vim modes influence the context](./vim.md#contexts). Helix mode is built on top of Vim mode and uses the same contexts.
206
207### Actions
208
209Almost all of Zed's functionality is exposed as actions.
210Although there is no explicitly documented list, you can find most of them by searching in the command palette, by looking in the default keymaps for [macOS](https://github.com/zed-industries/zed/blob/main/assets/keymaps/default-macos.json), [Windows](https://github.com/zed-industries/zed/blob/main/assets/keymaps/default-windows.json) or [Linux](https://github.com/zed-industries/zed/blob/main/assets/keymaps/default-linux.json), or by using Zed's autocomplete in your keymap file.
211
212Most actions do not require any arguments, and so you can bind them as strings: `"ctrl-a": "language_selector::Toggle"`. Some require a single argument and must be bound as an array: `"cmd-1": ["workspace::ActivatePane", 0]`. Some actions require multiple arguments and are bound as an array of a string and an object: `"ctrl-a": ["pane::DeploySearch", { "replace_enabled": true }]`.
213
214### Precedence
215
216When multiple keybindings have the same keystroke and are active at the same time, precedence is resolved in two ways:
217
218- Bindings that match on lower nodes in the context tree win. This means that if you have a binding with a context of `Editor`, it will take precedence over a binding with a context of `Workspace`. Bindings with no context match at the lowest level in the tree.
219- If there are multiple bindings that match at the same level in the tree, then the binding defined later takes precedence. As user keybindings are loaded after system keybindings, this allows user bindings to take precedence over built-in keybindings.
220
221The other kind of conflict that arises is when you have two bindings, one of which is a prefix of the other. For example, if you have `"ctrl-w":"editor::DeleteToNextWordEnd"` and `"ctrl-w left":"editor::DeleteToEndOfLine"`.
222
223When this happens, and both bindings are active in the current context, Zed will wait for 1 second after you type `ctrl-w` to see if you're about to type `left`. If you don't type anything, or if you type a different key, then `DeleteToNextWordEnd` will be triggered. If you do, then `DeleteToEndOfLine` will be triggered.
224
225### Non-QWERTY keyboards
226
227Zed's support for non-QWERTY keyboards is still a work in progress.
228
229If your keyboard can type the full ASCII range (DVORAK, COLEMAK, etc.), then shortcuts should work as you expect.
230
231Otherwise, read on...
232
233#### macOS
234
235On Cyrillic, Hebrew, Armenian, and other keyboards that are mostly non-ASCII, macOS automatically maps keys to the ASCII range when `cmd` is held. Zed takes this a step further, and it can always match key-presses against either the ASCII layout or the real layout, regardless of modifiers and the `use_key_equivalents` setting. For example, in Thai, pressing `ctrl-ๆ` will match bindings associated with `ctrl-q` or `ctrl-ๆ`.
236
237On keyboards that support extended Latin alphabets (French AZERTY, German QWERTZ, etc.), it is often not possible to type the entire ASCII range without `option`. This introduces an ambiguity: `option-2` produces `@`. To ensure that all the built-in keyboard shortcuts can still be typed on these keyboards, we move key bindings around. For example, shortcuts bound to `@` on QWERTY are moved to `"` on a Spanish layout. This mapping is based on the macOS system defaults and can be seen by running `dev: open key context view` from the command palette.
238
239If you are defining shortcuts in your personal keymap, you can opt into the key equivalent mapping by setting `use_key_equivalents` to `true` in your keymap:
240
241```json [keymap]
242[
243  {
244    "use_key_equivalents": true,
245    "bindings": {
246      "ctrl->": "editor::Indent" // parsed as ctrl-: when a German QWERTZ keyboard is active
247    }
248  }
249]
250```
251
252### Linux
253
254Since v0.196.0, on Linux, if the key that you type doesn't produce an ASCII character, then we use the QWERTY-layout equivalent key for keyboard shortcuts. This means that many shortcuts can be typed on many layouts.
255
256We do not yet remap shortcuts so every built-in shortcut is typeable on every layout. If your layout cannot type some ASCII characters, you may need custom key bindings. We plan to improve this.
257
258## Tips and tricks
259
260### Disabling a binding
261
262If you'd like a given binding to do nothing in a given context, you can use
263`null` as the action. This is useful if you hit the key binding by accident and
264want to disable it, or if you want to type the character that would be typed by
265the sequence, or if you want to disable multikey bindings starting with that key.
266
267```json [keymap]
268[
269  {
270    "context": "Workspace",
271    "bindings": {
272      "cmd-r": null // cmd-r will do nothing when the Workspace context is active
273    }
274  }
275]
276```
277
278A `null` binding follows the same precedence rules as normal actions, so it disables all bindings that would match further up in the tree too. If you'd like a binding that matches further up in the tree to take precedence over a lower binding, you need to rebind it to the action you want in the context you want.
279
280This is useful for preventing Zed from falling back to a default key binding when the action you specified is conditional and propagates. For example, `buffer_search::DeployReplace` only triggers when the search bar is not in view. If the search bar is in view, it would propagate and trigger the default action set for that key binding, such as opening the right dock. To prevent this from happening:
281
282```json [keymap]
283[
284  {
285    "context": "Workspace",
286    "bindings": {
287      "cmd-r": null // cmd-r will do nothing when the search bar is in view
288    }
289  },
290  {
291    "context": "Workspace",
292    "bindings": {
293      "cmd-r": "buffer_search::DeployReplace" // cmd-r will deploy replace when the search bar is not in view
294    }
295  }
296]
297```
298
299### Remapping keys
300
301A common request is to be able to map from a single keystroke to a sequence. You can do this with the `workspace::SendKeystrokes` action.
302
303```json [keymap]
304[
305  {
306    "bindings": {
307      // Move down four times
308      "alt-down": ["workspace::SendKeystrokes", "down down down down"],
309      // Expand the selection (editor::SelectLargerSyntaxNode);
310      // copy to the clipboard; and then undo the selection expansion.
311      "cmd-alt-c": [
312        "workspace::SendKeystrokes",
313        "ctrl-shift-right ctrl-shift-right ctrl-shift-right cmd-c ctrl-shift-left ctrl-shift-left ctrl-shift-left"
314      ]
315    }
316  },
317  {
318    "context": "Editor && vim_mode == insert",
319    "bindings": {
320      "j k": ["workspace::SendKeystrokes", "escape"]
321    }
322  }
323]
324```
325
326There are some limitations to this, notably:
327
328- Any asynchronous operation will not happen until after all your key bindings have been dispatched. For example, this means that while you can use a binding to open a file (as in the `cmd-alt-r` example), you cannot send further keystrokes and hope to have them interpreted by the new view.
329- Other examples of asynchronous things are: opening the command palette, communicating with a language server, changing the language of a buffer, anything that hits the network.
330- There is a limit of 100 simulated keys at a time.
331
332The argument to `SendKeystrokes` is a space-separated list of keystrokes (using the same syntax as above). Due to the way that keystrokes are parsed, any segment that is not recognized as a keypress will be sent verbatim to the currently focused input field.
333
334If the argument to `SendKeystrokes` contains the binding used to trigger it, it will use the next-highest-precedence definition of that binding. This allows you to extend the default behavior of a key binding.
335
336### Forward keys to terminal
337
338If you're on Linux or Windows, you might find yourself wanting to forward key combinations to the built-in terminal instead of them being handled by Zed.
339
340For example, `ctrl-n` creates a new tab in Zed on Linux. If you want to send `ctrl-n` to the built-in terminal when it's focused, add the following to your keymap:
341
342```json [keymap]
343{
344  "context": "Terminal",
345  "bindings": {
346    "ctrl-n": ["terminal::SendKeystroke", "ctrl-n"]
347  }
348}
349```
350
351### Task Key bindings
352
353You can also bind keys to launch Zed Tasks defined in your `tasks.json`.
354See the [tasks documentation](tasks.md#custom-keybindings-for-tasks) for more.