1# Vim Mode
2
3Zed includes a Vim emulation layer known as "vim mode". On this page, you will learn how to turn Zed's vim mode on or off, what tools and commands are available, and how to customize keybindings.
4
5## Philosophy
6
7Vim mode tries to offer a familiar experience to Vim users: it replicates the behavior of motions and commands precisely when it makes sense and uses Zed-specific functionality to provide an editing experience that "just works" without requiring configuration on your part. This includes support for semantic navigation, multiple cursors, or other features usually provided by plugins like surrounding text.
8
9So, Zed's vim mode does not replicate Vim one-to-one, but it meshes Vim's modal design with Zed's modern features to provide a more fluid experience. It's also configurable, so you can add your own key bindings or override the defaults.
10
11> **Note:** The foundations of Zed's vim mode should already cover many use cases, and we're always looking to improve it. If you find missing features that you rely on in your workflow, please [file an issue](https://github.com/zed-industries/zed/issues).
12
13## Enabling and disabling vim mode
14
15When you first open Zed, a checkbox will appear on the welcome screen, allowing you to enable vim mode.
16
17If you missed this, you can toggle vim mode on or off anytime by opening the command palette and using the workspace command `toggle vim mode`.
18
19## Zed-specific features
20
21Zed is built on a modern foundation that (among other things) uses tree-sitter and language servers to understand the content of the file you're editing and supports multiple cursors out of the box.
22
23Vim mode has several "core Zed" key bindings that will help you make the most of Zed's specific feature set.
24
25```
26# Language server
27g d Go to definition
28g D Go to declaration
29g y Go to type definition
30g I Go to implementation
31
32c d Rename (change definition)
33g A Go to All references to the current word
34
35g s Find symbol in current file
36g S Find symbol in entire project
37
38g ] Go to next diagnostic
39g [ Go to previous diagnostic
40] d Go to next diagnostic
41[ d Go to previous diagnostic
42g h Show inline error (hover)
43g . Open the code actions menu
44
45# Git
46] c Go to next git change
47[ c Go to previous git change
48
49# Treesitter
50] x Select a smaller syntax node
51[ x Select a larger syntax node
52
53# Multi cursor
54g l Add a visual selection for the next copy of the current word
55g L The same, but backwards
56g > Skip latest word selection, and add next.
57g < The same, but backwards
58g a Add a visual selection for every copy of the current word
59
60# Pane management
61g / Open a project-wide search
62g <space> Open the current search excerpt
63<ctrl-w> <space> Open the current search excerpt in a split
64<ctrl-w> g d Go to definition in a split
65<ctrl-w> g D Go to type definition in a split
66
67# Insert mode
68ctrl-x ctrl-o Open the completion menu
69ctrl-x ctrl-c Request GitHub Copilot suggestion (if configured)
70ctrl-x ctrl-a Open the inline AI assistant (if configured)
71ctrl-x ctrl-l Open the code actions menu
72ctrl-x ctrl-z Hides all suggestions
73
74# Ex commands
75:E[xplore] Open the project panel
76:C[ollab] Open the collaboration panel
77:Ch[at] Open the chat panel
78:A[I] Open the AI panel
79:No[tif] Open the notifications panel
80:fe[edback] Open the feedback window
81:cl[ist] Open the diagnostics window
82:te[rm] Open the terminal
83:Ext[ensions] Open the extensions window
84```
85
86Vim mode uses Zed to define concepts like "brackets" (for the `%` key) and "words" (for motions like `w` and `e`). This does lead to some differences, but they are mostly positive. For example `%` considers `|` to be a bracket in languages like Rust; and `w` considers `$` to be a word-character in languages like Javascript.
87
88Vim mode emulates visual block mode using Zed's multiple cursor support. This again leads to some differences, but is much more powerful.
89
90Vim's macro support (`q` and `@`) is implemented using Zed's actions. This lets us support recording and replaying of autocompleted code, etc. Unlike Vim, Zed does not re-use the yank registers for recording macros, they are two separate namespaces.
91
92Finally, vim mode's search and replace functionality is backed by Zed's. This means that the pattern syntax is slightly different, see the section on [Regex differences](#regex-differences) for details.
93
94## Custom key bindings
95
96You can edit your personal key bindings with `:keymap`.
97For vim-specific shortcuts, you may find the following template a good place to start.
98
99> **Note:** We made some breaking changes in Zed version `0.145.0`. For older versions, see [the previous version of this document](https://github.com/zed-industries/zed/blob/c67aeaa9c58619a58708722ac7d7a78c75c29336/docs/src/vim.md#L90).
100
101```json
102[
103 {
104 "context": "VimControl && !menu",
105 "bindings": {
106 // put key-bindings here if you want them to work in normal & visual mode
107 }
108 },
109 {
110 "context": "vim_mode == insert",
111 "bindings": {
112 // "j k": "vim::NormalBefore" // remap jk in insert mode to escape.
113 }
114 },
115 {
116 "context": "EmptyPane || SharedScreen",
117 "bindings": {
118 // put key-bindings here (in addition to above) if you want them to
119 // work when no editor exists
120 // "space f": "file_finder::Toggle"
121 }
122 }
123]
124```
125
126If you would like to emulate vim's `map` (`nmap` etc.) commands you can bind to the [`workspace::SendKeystrokes`](./key-bindings.md#remapping-keys) action in the correct context.
127
128You can see the bindings that are enabled by default in vim mode [here](https://github.com/zed-industries/zed/blob/main/assets/keymaps/vim.json).
129
130### Contexts
131
132Zed's keyboard bindings are evaluated only when the `"context"` matches the location you are in on the screen. Locations are nested, so when you're editing you're in the `"Workspace"` location is at the top, containing a `"Pane"` which contains an `"Editor"`. Contexts are matched only on one level at a time. So it is possible to combine `Editor && vim_mode == normal`, but `Workspace && vim_mode == normal` will never match because we set the vim context at the `Editor` level.
133
134Vim mode adds several contexts to the `Editor`:
135
136- `vim_mode` is similar to, but not identical to, the current mode. It starts as one of `normal`, `visual`, `insert` or `replace` (depending on your mode). If you are mid-way through typing a sequence, `vim_mode` will be either `waiting` if it's waiting for an arbitrary key (for example after typing `f` or `t`), or `operator` if it's waiting for another binding to trigger (for example after typing `c` or `d`).
137- `vim_operator` is set to `none` unless `vim_mode == operator` in which case it is set to the current operator's default keybinding (for example after typing `d`, `vim_operator == d`).
138- `"VimControl"` indicates that vim keybindings should work. It is currently an alias for `vim_mode == normal || vim_mode == visual || vim_mode == operator`, but the definition may change over time.
139
140### Restoring common text editing keybindings
141
142If you're using vim mode on Linux or Windows, you may find it overrides keybindings you can't live without: <kbd>Ctrl</kbd>+<kbd>v</kbd> to copy, <kbd>Ctrl</kbd>+<kbd>f</kbd> to search, etc. You can restore them by copying this data into your keymap:
143
144```json
145{
146 "context": "Editor && !menu",
147 "bindings": {
148 "ctrl-c": "editor::Copy", // vim default: return to normal mode
149 "ctrl-x": "editor::Cut", // vim default: decrement
150 "ctrl-v": "editor::Paste", // vim default: visual block mode
151 "ctrl-y": "editor::Undo", // vim default: line up
152 "ctrl-f": "buffer_search::Deploy", // vim default: page down
153 "ctrl-o": "workspace::Open", // vim default: go back
154 "ctrl-a": "editor::SelectAll", // vim default: increment
155 }
156},
157```
158
159## Command palette
160
161Vim mode allows you to enable Zed’s command palette with `:`. This means that you can use vim's command palette to run any action that Zed supports.
162
163Additionally vim mode contains a number of aliases for popular vim commands to ensure that muscle memory works. For example `:w<enter>` will save the file.
164
165We do not (yet) emulate the full power of vim’s command line, in particular we special case specific patterns instead of using vim's range selection syntax, and we do not support arguments to commands yet. Please reach out on [GitHub](https://github.com/zed-industries/zed) as you find things that are missing from the command palette.
166
167As mentioned above, one thing to be aware of is that the regex engine is slightly different from vim's in `:%s/a/b`.
168
169Currently supported vim-specific commands:
170
171```
172# window management
173:w[rite][!], :wq[!], :q[uit][!], :wa[ll][!], :wqa[ll][!], :qa[ll][!], :[e]x[it][!], :up[date]
174 to save/close tab(s) and pane(s) (no filename is supported yet)
175:cq
176 to quit completely.
177:vs[plit], :sp[lit]
178 to split vertically/horizontally (no filename is supported yet)
179:new, :vne[w]
180 to create a new file in a new pane above or to the left
181:tabedit, :tabnew
182 to create a new file in a new tab.
183:tabn[ext], :tabp[rev]
184 to go to previous/next tabs
185:tabc[lose]
186 to close the current tab
187
188# navigating diagnostics
189:cn[ext], :cp[rev], :ln[ext], :lp[rev]
190 to go to the next/prev diagnostics
191:cc, :ll
192 to open the errors page
193
194# jump to position
195:<number>
196 to jump to a line number
197:$
198 to jump to the end of the file
199:/foo and :?foo
200 to jump to next/prev line matching foo
201
202# replacement (/g is always assumed and Zed uses different regex syntax to vim)
203:%s/foo/bar/
204 to replace instances of foo with bar
205:X,Ys/foo/bar/
206 to limit replacement between line X and Y
207 other ranges are not yet implemented
208
209# editing
210:j[oin]
211 to join the current line (no range is yet supported)
212:d[elete][l][p]
213 to delete the current line (no range is yet supported)
214:s[ort] [i]
215 to sort the current selection (with i, case-insensitively)
216```
217
218As any Zed command is available, you may find that it's helpful to remember mnemonics that run the correct command. For example:
219
220```
221:diff Toggle Hunk [Diff]
222:diffs Toggle all Hunk [Diffs]
223:revert Revert Selected Hunks
224:cpp [C]o[p]y [P]ath to file
225:crp [C]opy [r]elative [P]ath
226:reveal [Reveal] in finder
227:zlog Open [Z]ed Log
228```
229
230## Settings
231
232Vim mode is not enabled by default. To enable vim mode, you need to add the following configuration to your settings file:
233
234```json
235{
236 "vim_mode": true
237}
238```
239
240Alternatively, you can enable vim mode by running the `toggle vim mode` command from the command palette.
241
242Some vim settings are available to modify the default vim behavior:
243
244```json
245{
246 "vim": {
247 // "always": use system clipboard when no register is specified
248 // "never": don't use system clipboard unless "+ or "* is specified
249 // "on_yank": use system clipboard for yank operations when no register is specified
250 "use_system_clipboard": "always",
251 // Let `f` and `t` motions extend across multiple lines
252 "use_multiline_find": true,
253 // Let `f` and `t` motions match case insensitively if the target is lowercase
254 "use_smartcase_find": true,
255 // Use relative line numbers in normal mode, absolute in insert mode
256 // c.f. https://github.com/jeffkreeftmeijer/vim-numbertoggle
257 "toggle_relative_line_numbers": true,
258 // Add custom digraphs (e.g. ctrl-k f z will insert a zombie emoji)
259 "custom_digraphs": {
260 "fz": "🧟♀️"
261 }
262 }
263}
264```
265
266There are also a few Zed settings that you may also enjoy if you use vim mode:
267
268```json
269{
270 // disable cursor blink
271 "cursor_blink": false,
272 // use relative line numbers
273 "relative_line_numbers": true,
274 // hide the scroll bar
275 "scrollbar": { "show": "never" },
276 // prevent the buffer from scrolling beyond the last line
277 "scroll_beyond_last_line": "off",
278 // allow cursor to reach edges of screen
279 "vertical_scroll_margin": 0,
280 "gutter": {
281 // disable line numbers completely:
282 "line_numbers": false
283 },
284 "command_aliases": {
285 "W": "w",
286 "Wq": "wq",
287 "Q": "q"
288 }
289}
290```
291
292If you want to navigate between the editor and docks (terminal, project panel, AI assistant, ...) just like you navigate between splits you can use the following key bindings:
293
294```json
295{
296 "context": "Dock",
297 "bindings": {
298 "ctrl-w h": ["workspace::ActivatePaneInDirection", "Left"],
299 "ctrl-w l": ["workspace::ActivatePaneInDirection", "Right"],
300 "ctrl-w k": ["workspace::ActivatePaneInDirection", "Up"],
301 "ctrl-w j": ["workspace::ActivatePaneInDirection", "Down"]
302 // ... or other keybindings
303 }
304}
305```
306
307Subword motion is not enabled by default. To enable it, add these bindings to your keymap.
308
309```json
310[
311 {
312 "context": "VimControl && !menu && vim_mode != operator",
313 "bindings": {
314 "w": "vim::NextSubwordStart",
315 "b": "vim::PreviousSubwordStart",
316 "e": "vim::NextSubwordEnd",
317 "g e": "vim::PreviousSubwordEnd"
318 }
319 }
320]
321```
322
323Surrounding the selection in visual mode is also not enabled by default (`shift-s` normally behaves like `c`). To enable it, add the following to your keymap.
324
325```json
326{
327 "context": "vim_mode == visual",
328 "bindings": {
329 "shift-s": [
330 "vim::PushOperator",
331 {
332 "AddSurrounds": {}
333 }
334 ]
335 }
336}
337```
338
339## Supported plugins
340
341Zed has nascent support for some Vim plugins:
342
343- From `vim-surround`, `ys`, `cs` and `ds` work. Though you cannot add new HTML tags yet.
344- From `vim-commentary`, `gc` in visual mode and `gcc` in normal mode. Though you cannot operate on arbitrary objects yet.
345- From `netrw`, most keybindings are supported in the project panel.
346- From `vim-spider`/`CamelCaseMotion` you can use subword motions as described above.
347
348## Regex differences
349
350Zed uses a different regular expression engine from Vim. This means that you will have to use a different syntax for some things.
351
352Notably:
353
354- Vim uses `\(` and `\)` to represent capture groups, in Zed these are `(` and `)`.
355- On the flip side, `(` and `)` represent literal parentheses, but in Zed these must be escaped to `\(` and `\)`.
356- When replacing, Vim uses `\0` to represent the entire match, in Zed this is `$0`, same for numbered capture groups `\1` -> `$1`.
357- Vim uses `/g` to indicate "all matches on one line", in Zed this is implied
358- Vim uses `/i` to indicate "case-insensitive", in Zed you can either use `(?i)` at the start of the pattern or toggle case-sensitivity with `cmd-option-c`.
359
360To help with the transition, the command palette will fix parentheses and replace groups for you when you run `:%s//`. So `%s:/\(a\)(b)/\1/` will be converted into a search for "(a)\(b\)" and a replacement of "$1".
361
362For the full syntax supported by Zed's regex engine see the [regex crate documentation](https://docs.rs/regex/latest/regex/#syntax).