1# Key bindings
2
3Zed has a very customizable key binding system — you can tweak everything to work exactly how your fingers expect!
4
5## Predefined keymaps
6
7If you're used to a specific editor's defaults you can set a `base_keymap` in your [settings file](./configuring-zed.md). We currently have:
8
9- VSCode (default)
10- Atom
11- JetBrains
12- SublimeText
13- TextMate
14- None (disables _all_ key bindings)
15
16You can also enable `vim_mode`, which adds vim bindings too.
17
18## User keymaps
19
20Zed reads your keymap from `~/.zed/keymap.json` on MacOS (or `~/.config/zed/keymap.json` on Linux). You can open the file within Zed with {#kb zed::OpenKeymap}, or via `zed: Open Keymap` in the command palette.
21
22The file contains a JSON array of objects with `"bindings"`. If no `"context"` is set the bindings are always active. If it is set the binding is only active when the [context matches](#contexts).
23
24Within each binding section a [key sequence](#keybinding-syntax) is mapped to an [action](#actions). If conflicts are detected they are resolved as [described below](#precedence).
25
26If you are using a non-QWERTY, Latin-character keyboard, you may want to set `use_layout_keys` to `true`. See [Non-QWERTY keyboards](#non-qwerty-keyboards) for more information.
27
28For example:
29
30```json
31[
32 {
33 "bindings": {
34 "ctrl-right": "editor::SelectLargerSyntaxNode",
35 "ctrl-left": "editor::SelectSmallerSyntaxNode"
36 }
37 },
38 {
39 "context": "ProjectPanel && not_editing",
40 "bindings": {
41 "o": "project_panel::Open"
42 }
43 }
44]
45```
46
47You can see all of Zed's default bindings in the default keymaps for [MacOS](https://github.com/zed-industries/zed/blob/main/assets/keymaps/default-macos.json) or [Linux](https://github.com/zed-industries/zed/blob/main/assets/keymaps/default-linux.json).
48
49If you want to debug problems with custom keymaps you can use `debug: Open Key Context View` from the command palette. Please file [an issue](https://github.com/zed-industries/zed) if you run into something you think should work but isn't.
50
51### Keybinding syntax
52
53Zed 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.
54
55Each key press is a sequence of modifiers followed by a key. The modifiers are:
56
57- `ctrl-` The control key
58- `cmd-`, `win-` or `super-` for the platform modifier (Command on macOS, Windows key on Windows, and the Super key on Linux).
59- `alt-` for alt (option on macOS)
60- `shift-` The shift key
61- `fn-` The function key
62
63The 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 that key generates with `cmd` pressed.
64
65A few examples:
66
67```json
68 "bindings": {
69 "cmd-k cmd-s": "zed::OpenKeymap", // matches ⌘-k then ⌘-s
70 "space e": "editor::Complete", // type space then e
71 "ç": "editor::Complete", // matches ⌥-c
72 "shift shift": "file_finder::Toggle", // matches pressing and releasing shift twice
73 }
74```
75
76The `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.
77
78The `alt-` modifier can be used on many layouts to generate a different key. For example on 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`.
79
80It 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 key press.
81
82### Contexts
83
84If a binding group has a `"context"` key it will be matched against the currently active contexts in Zed.
85
86Zed'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 `debug: Open Key Context View` in the command palette.
87
88Contexts can contain extra attributes in addition to the name, so that you can (for example) match only in markdown files with `"context": "Editor && extension==md"`. It's worth noting that you can only use attributes at the level they are defined.
89
90For example:
91
92```
93# in an editor, it might look like this:
94Workspace os=macos keyboard_layout=com.apple.keylayout.QWERTY
95 Pane
96 Editor mode=full extension=md inline_completion vim_mode=insert
97
98# in the project panel
99Workspace os=macos
100 Dock
101 ProjectPanel not_editing
102```
103
104Context expressions can contain the following syntax:
105
106- `X && Y`, `X || Y` to and/or two conditions
107- `!X` to negate a condition
108- `(X)` for grouping
109- `X > Y` to match if a parent in the tree matches X and this layer matches Y.
110
111If you're using Vim mode, we have information on how [vim modes influence the context](./vim.md#contexts)
112
113### Actions
114
115Pretty much all of Zed's functionality is exposed as actions. Although there is
116no explicitly documented list, you can find most of them by searching in the
117command palette, by looking in the default keymaps for
118[MacOS](https://github.com/zed-industries/zed/blob/main/assets/keymaps/default-macos.json)
119or
120[Linux](https://github.com/zed-industries/zed/blob/main/assets/keymaps/default-linux.json), or by using Zed's autocomplete in your keymap file.
121
122Most 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 }]`.
123
124### Precedence
125
126When multiple keybindings have the same keystroke and are active at the same time, precedence is resolved in two ways:
127
128- 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.
129- 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 builtin keybindings.
130
131The 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"`.
132
133When 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.
134
135### Non-QWERTY keyboards
136
137As of Zed 0.162.0, Zed has some support for non-QWERTY keyboards on macOS. Better support for non-QWERTY keyboards on Linux is planned.
138
139There are roughly three categories of keyboard to consider:
140
141Keyboards that support full ASCII (QWERTY, DVORAK, COLEMAK, etc.). On these keyboards bindings are resolved based on the character that would be generated by the key. So to type `cmd-[`, find the key labelled `[` and press it with command.
142
143Keyboards that are mostly non-ASCII, but support full ASCII when the command key is pressed. For example Cyrillic keyboards, Armenian, Hebrew, etc. On these keyboards bindings are resolved based on the character that would be generated by typing the key with command pressed. So to type `ctrl-a`, find the key that generates `cmd-a`. For these keyboards, keyboard shortcuts are displayed in the app using their ASCII equivalents. If the ASCII-equivalents are not printed on your keyboard, you can use the macOS keyboard viewer and holding down the `cmd` key to find things (though often the ASCII equivalents are in a QWERTY layout).
144
145Finally keyboards that support extended Latin alphabets (usually ISO keyboards) require the most support. For example French AZERTY, German QWERTZ, etc. On these keyboards it is often not possible to type the entire ASCII range without option. To ensure that shortcuts _can_ be typed without option, keyboard shortcuts are mapped to "key equivalents" in the same way as [macOS](). This mapping is defined per layout, and is a compromise between leaving keyboard shortcuts triggered by the same character they are defined with, keeping shortcuts in the same place as a QWERTY layout, and moving shortcuts out of the way of system shortcuts.
146
147For example on a German QWERTZ keyboard, the `cmd->` shortcut is moved to `cmd-:` because `cmd->` is the system window switcher and this is where that shortcut is typed on a QWERTY keyboard. `cmd-+` stays the same because + is still typable without option, and as a result, `cmd-[` and `cmd-]` become `cmd-ö` and `cmd-ä`, moving out of the way of the `+` key.
148
149If 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:
150
151```json
152[
153 {
154 "use_key_equivalents": true,
155 "bindings": {
156 "ctrl->": "editor::Indent" // parsed as ctrl-: when a German QWERTZ keyboard is active
157 }
158 }
159]
160```
161
162## Tips and tricks
163
164### Disabling a binding
165
166If you'd like a given binding to do nothing in a given context you can use
167`null` as the action. This is useful if you hit the keybinding by accident and
168want to disable it, or if you want to type the character that would be typed by
169the sequence (for example to disable the builtin `alt-t` binding), or if you
170want to disable multikey bindings starting with that key.
171
172```
173"bindings": { "cmd-k": null }
174```
175
176A `null` has the same precedence rules as normal actions. So 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.
177
178### Remapping keys
179
180A common request is to be able to map from a single keystroke to a sequence. You can do this with the `workspace::SendKeystrokes` action.
181
182```json
183[
184 {
185 "bindings": {
186 "alt-down": ["workspace::SendKeystrokes", "down down down down"],
187 "cmd-alt-c": [
188 "workspace::SendKeystrokes",
189 "cmd-shift-p copy relative path enter"
190 ],
191 "cmd-alt-r": ["workspace::SendKeystrokes", "cmd-p README enter"]
192 }
193 },
194 {
195 "context": "Editor && vim_mode == insert",
196 "bindings": {
197 "j k": ["workspace::SendKeystrokes", "escape"]
198 }
199 }
200]
201```
202
203There are some limitations to this, notably:
204
205- 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.
206- 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.
207- There is a limit of 100 simulated keys at a time.
208
209The 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.
210
211If 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 behaviour of a key binding.
212
213### Forward keys to terminal
214
215If 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.
216
217For 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:
218
219```json
220{
221 "context": "Terminal",
222 "bindings": {
223 "ctrl-n": ["terminal::SendKeystroke", "ctrl-n"]
224 }
225}
226```
227
228### Task Key bindings
229
230You can also bind keys to launch Zed Tasks defined in your tasks.json.
231See the [tasks documentation](tasks.md#custom-keybindings-for-tasks) for more.