1# Vim Mode
2
3Zed includes a vim emulation layer known as "vim mode". This document aims to describe how it works, and how to make the most out of it.
4
5## Philosophy
6
7Vim mode in Zed is supposed to primarily "do what you expect": it mostly tries to copy vim exactly, but will use Zed-specific functionality when available to make things smoother.
8
9This means Zed will never be 100% Vim compatible, but should be 100% Vim familiar! We expect that our Vim mode already copes with 90% of your workflow, and we'd like to keep improving it. If you find things that you can’t yet do in Vim mode, but which you rely on in your current workflow, please [file an issue](https://github.com/zed-industries/zed/issues).
10
11## Zed-specific features
12
13Zed 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.
14
15Vim mode has several "core Zed" key bindings, that will help you make the most of Zed's specific feature set.
16
17```
18# Language server
19g d Go to definition
20g D Go to type definition
21g cmd-d Go to implementation
22c d Rename (change definition)
23g A Go to All references to the current word
24
25g s Find symbol in current file
26g S Find symbol in entire project
27
28g ] Go to next diagnostic
29g [ Go to previous diagnostic
30] d Go to next diagnostic
31[ d Go to previous diagnostic
32g h Show inline error (hover)
33g . Open the code actions menu
34
35# Git
36] c Go to next git change
37[ c Go to previous git change
38
39# Treesitter
40] x Select a smaller syntax node
41[ x Select a larger syntax node
42
43# Multi cursor
44g l Add a visual selection for the next copy of the current word
45g L The same, but backwards
46g > Skip latest word selection, and add next.
47g < The same, but backwards
48g a Add a visual selection for every copy of the current word
49
50# Pane management
51g / Open a project-wide search
52g <space> Open the current search excerpt
53<ctrl-w> <space> Open the current search excerpt in a split
54<ctrl-w> g d Go to definition in a split
55<ctrl-w> g D Go to type definition in a split
56
57# Insert mode
58i a / a a Select the function argument the cursor is in
59ctrl-x ctrl-o Open the completion menu
60ctrl-x ctrl-c Request GitHub Copilot suggestion (if configured)
61ctrl-x ctrl-a Open the inline AI assistant (if configured)
62ctrl-x ctrl-l Open the code actions menu
63ctrl-x ctrl-z Hides all suggestions
64
65# Ex commands
66:E[xplore] Open the project panel
67:C[ollab] Open the collaboration panel
68:Ch[at] Open the chat panel
69:A[I] Open the AI panel
70:No[tif] Open the notifications panel
71:fe[edback] Open the feedback window
72:cl[ist] Open the diagnostics window
73:te[rm] Open the terminal
74:Ext[ensions] Open the extensions window
75```
76
77Vim 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.
78
79Vim mode emulates visual block mode using Zed's multiple cursor support. This again leads to some differences, but is much more powerful.
80
81Vim'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.
82
83Finally, 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.
84
85## Custom key bindings
86
87You can edit your personal key bindings with `:keymap`.
88For vim-specific shortcuts, you may find the following template a good place to start:
89
90```json
91[
92 {
93 "context": "Editor && (vim_mode == normal || vim_mode == visual) && !VimWaiting && !menu",
94 "bindings": {
95 // put key-bindings here if you want them to work in normal & visual mode
96 }
97 },
98 {
99 "context": "Editor && vim_mode == normal && !VimWaiting && !menu",
100 "bindings": {
101 // put key-bindings here if you want them to work only in normal mode
102 // "down": ["workspace::SendKeystrokes", "4 j"]
103 // "up": ["workspace::SendKeystrokes", "4 k"]
104 }
105 },
106 {
107 "context": "Editor && vim_mode == visual && !VimWaiting && !menu",
108 "bindings": {
109 // visual, visual line & visual block modes
110 }
111 },
112 {
113 "context": "Editor && vim_mode == insert && !menu",
114 "bindings": {
115 // put key-bindings here if you want them to work in insert mode
116 // e.g.
117 // "j j": "vim::NormalBefore" // remap jj in insert mode to escape.
118 }
119 },
120 {
121 "context": "EmptyPane || SharedScreen",
122 "bindings": {
123 // put key-bindings here (in addition to above) if you want them to
124 // work when no editor exists
125 // e.g.
126 // "space f": "file_finder::Toggle"
127 }
128 }
129]
130```
131
132If you would like to emulate vim's `map` (`nmap` etc.) commands you can bind to the [`workspace::SendKeystrokes`](/docs/key-bindings#remapping-keys) action in the correct context.
133
134You 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).
135
136The details of the context are a little out of scope for this doc, but suffice to say that `menu` is true when a menu is open (e.g. the completions menu), `VimWaiting` is true after you type `f` or `t` when we’re waiting for a new key (and you probably don’t want bindings to happen). Please reach out on [GitHub](https://github.com/zed-industries/zed) if you want help making a key bindings work.
137
138### Examples
139
140Binding `jk` to exit insert mode and go to normal mode:
141
142```
143{
144 "context": "Editor && vim_mode == insert && !menu",
145 "bindings": {
146 "j k": ["vim::SwitchMode", "Normal"]
147 }
148}
149```
150
151### Restoring some sense of normality
152
153If you're using Vim mode on Linux or Windows, you may find that it has overridden keybindings
154that you can't live without. You can restore them to their defaults by copying these into your keymap:
155
156```
157{
158 "context": "Editor && !VimWaiting && !menu",
159 "bindings": {
160 "ctrl-c": "editor::Copy", // vim default: return to normal mode
161 "ctrl-x": "editor::Cut", // vim default: increment
162 "ctrl-v": "editor::Paste", // vim default: visual block mode
163 "ctrl-y": "editor::Undo", // vim default: line up
164 "ctrl-f": "buffer_search::Deploy", // vim default: page down
165 "ctrl-o": "workspace::Open", // vim default: go back
166 "ctrl-a": "editor::SelectAll", // vim default: increment
167 }
168},
169```
170
171## Command palette
172
173Vim 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.
174
175Additionally 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.
176
177We 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.
178
179As mentioned above, one thing to be aware of is that the regex engine is slightly different from vim's in `:%s/a/b`.
180
181Currently supported vim-specific commands:
182
183```
184# window management
185:w[rite][!], :wq[!], :q[uit][!], :wa[ll][!], :wqa[ll][!], :qa[ll][!], :[e]x[it][!], :up[date]
186 to save/close tab(s) and pane(s) (no filename is supported yet)
187:cq
188 to quit completely.
189:vs[plit], :sp[lit]
190 to split vertically/horizontally (no filename is supported yet)
191:new, :vne[w]
192 to create a new file in a new pane above or to the left
193:tabedit, :tabnew
194 to create a new file in a new tab.
195:tabn[ext], :tabp[rev]
196 to go to previous/next tabs
197:tabc[lose]
198 to close the current tab
199
200# navigating diagnostics
201:cn[ext], :cp[rev], :ln[ext], :lp[rev]
202 to go to the next/prev diagnostics
203:cc, :ll
204 to open the errors page
205
206# jump to position
207:<number>
208 to jump to a line number
209:$
210 to jump to the end of the file
211:/foo and :?foo
212 to jump to next/prev line matching foo
213
214# replacement (/g is always assumed and Zed uses different regex syntax to vim)
215:%s/foo/bar/
216 to replace instances of foo with bar
217:X,Ys/foo/bar/
218 to limit replacement between line X and Y
219 other ranges are not yet implemented
220
221# editing
222:j[oin]
223 to join the current line (no range is yet supported)
224:d[elete][l][p]
225 to delete the current line (no range is yet supported)
226:s[ort] [i]
227 to sort the current selection (with i, case-insensitively)
228```
229
230As any Zed command is available, you may find that it's helpful to remember mnemonics that run the correct command. For example:
231
232```
233:diff Toggle Hunk [Diff]
234:diffs Toggle all Hunk [Diffs]
235:revert Revert Selected Hunks
236:cpp [C]o[p]y [P]ath to file
237:crp [C]opy [r]elative [P]ath
238:reveal [Reveal] in finder
239:zlog Open [Z]ed Log
240```
241
242## Settings
243
244Some vim settings are available to modify the default vim behavior:
245
246```json
247{
248 "vim": {
249 // "always": use system clipboard when no register is specified
250 // "never": don't use system clipboard unless "+ or "* is specified
251 // "on_yank": use system clipboard for yank operations when no register is specified
252 "use_system_clipboard": "always",
253 // Lets `f` and `t` motions extend across multiple lines
254 "use_multiline_find": true
255 }
256}
257```
258
259There are also a few Zed settings that you may also enjoy if you use vim mode:
260
261```json
262{
263 // disable cursor blink
264 "cursor_blink": false,
265 // use relative line numbers
266 "relative_line_numbers": true,
267 // hide the scroll bar
268 "scrollbar": { "show": "never" },
269 // allow cursor to reach edges of screen
270 "vertical_scroll_margin": 0,
271 "gutter": {
272 // disable line numbers completely:
273 "line_numbers": false
274 }
275}
276```
277
278If 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:
279
280```json
281{
282 "context": "Dock",
283 "bindings": {
284 "ctrl-w h": ["workspace::ActivatePaneInDirection", "Left"],
285 "ctrl-w l": ["workspace::ActivatePaneInDirection", "Right"],
286 "ctrl-w k": ["workspace::ActivatePaneInDirection", "Up"],
287 "ctrl-w j": ["workspace::ActivatePaneInDirection", "Down"]
288 // ... or other keybindings
289 }
290}
291```
292
293Subword motion is not enabled by default. To enable it, add these bindings to your keymap.
294
295```json
296 {
297 "context": "Editor && VimControl && !VimWaiting && !menu",
298 "bindings": {
299 "w": "vim::NextSubwordStart",
300 "b": "vim::PreviousSubwordStart",
301 "e": "vim::NextSubwordEnd",
302 "g e": "vim::PreviousSubwordEnd"
303 }
304 },
305```
306
307Surrounding 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.
308
309```json
310 {
311 "context": "Editor && vim_mode == visual && !VimWaiting && !VimObject",
312 "bindings": {
313 "shift-s": [
314 "vim::PushOperator",
315 {
316 "AddSurrounds": {}
317 }
318 ]
319 }
320 }
321```
322
323## Supported plugins
324
325Zed has nascent support for some Vim plugins:
326
327- From `vim-surround`, `ys`, `cs` and `ds` work. Though you cannot add new HTML tags yet.
328- From `vim-commentary`, `gc` in visual mode and `gcc` in normal mode. Though you cannot operate on arbitrary objects yet.
329- From `netrw`, most keybindings are supported in the project panel.
330- From `vim-spider`/`CamelCaseMotion` you can use subword motions as described above.
331
332## Regex differences
333
334Zed uses a different regular expression engine from Vim. This means that you will have to use a different syntax for some things.
335
336Notably:
337
338- Vim uses `\(` and `\)` to represent capture groups, in Zed these are `(` and `)`.
339- On the flip side, `(` and `)` represent literal parentheses, but in Zed these must be escaped to `\(` and `\)`.
340- When replacing, Vim uses `\0` to represent the entire match, in Zed this is `$0`, same for numbered capture groups `\1` -> `$1`.
341- Vim uses `/g` to indicate "all matches on one line", in Zed this is implied
342- 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`.
343
344To 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".
345
346For the full syntax supported by Zed's regex engine see the [regex crate documentation](https://docs.rs/regex/latest/regex/#syntax).