vim.md

  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 leave feedback in the editor itself (`:feedback`), or [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
 81Finally, 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.
 82
 83## Custom key bindings
 84
 85You can edit your personal key bindings with `:keymap`.
 86For vim-specific shortcuts, you may find the following template a good place to start:
 87
 88```json
 89[
 90  {
 91    "context": "Editor && (vim_mode == normal || vim_mode == visual) && !VimWaiting && !menu",
 92    "bindings": {
 93      // put key-bindings here if you want them to work in normal & visual mode
 94    }
 95  },
 96  {
 97    "context": "Editor && vim_mode == normal && !VimWaiting && !menu",
 98    "bindings": {
 99      // put key-bindings here if you want them to work only in normal mode
100      // "down": ["workspace::SendKeystrokes", "4 j"]
101      // "up": ["workspace::SendKeystrokes", "4 k"]
102    }
103  },
104  {
105    "context": "Editor && vim_mode == visual && !VimWaiting && !menu",
106    "bindings": {
107      // visual, visual line & visual block modes
108    }
109  },
110  {
111    "context": "Editor && vim_mode == insert && !menu",
112    "bindings": {
113      // put key-bindings here if you want them to work in insert mode
114      // e.g.
115      // "j j": "vim::NormalBefore" // remap jj in insert mode to escape.
116    }
117  },
118  {
119    "context": "EmptyPane || SharedScreen",
120    "bindings": {
121      // put key-bindings here (in addition to above) if you want them to
122      // work when no editor exists
123      // e.g.
124      // "space f": "file_finder::Toggle"
125    }
126  }
127]
128```
129
130If 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.
131
132You 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).
133
134The 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.
135
136### Examples
137
138Binding `jk` to exit insert mode and go to normal mode:
139
140```
141{
142  "context": "Editor && vim_mode == insert && !menu",
143  "bindings": {
144    "j k": ["vim::SwitchMode", "Normal"]
145  }
146}
147```
148
149### Restoring some sense of normality
150
151If you're using Vim mode on Linux or Windows, you may find that it has overridden keybindings
152that you can't live without. You can restore them to their defaults by copying these into your keymap:
153
154```
155{
156  "context": "Editor && !VimWaiting && !menu",
157  "bindings": {
158    "ctrl-c": "editor::Copy",          // vim default: return to normal mode
159    "ctrl-x": "editor::Cut",           // vim default: increment
160    "ctrl-v": "editor::Paste",         // vim default: visual block mode
161    "ctrl-y": "editor::Undo",          // vim default: line up
162    "ctrl-f": "buffer_search::Deploy", // vim default: page down
163    "ctrl-o": "workspace::Open",       // vim default: go back
164    "ctrl-a": "editor::SelectAll",     // vim default: increment
165  }
166},
167```
168
169## Command palette
170
171Vim 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.
172
173Additionally 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.
174
175We 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.
176
177As mentioned above, one thing to be aware of is that the regex engine is slightly different from vim's in `:%s/a/b`.
178
179Currently supported vim-specific commands:
180
181```
182# window management
183:w[rite][!], :wq[!], :q[uit][!], :wa[ll][!], :wqa[ll][!], :qa[ll][!], :[e]x[it][!], :up[date]
184    to save/close tab(s) and pane(s) (no filename is supported yet)
185:cq
186    to quit completely.
187:vs[plit], :sp[lit]
188    to split vertically/horizontally (no filename is supported yet)
189:new, :vne[w]
190    to create a new file in a new pane above or to the left
191:tabedit, :tabnew
192    to create a new file in a new tab.
193:tabn[ext], :tabp[rev]
194    to go to previous/next tabs
195:tabc[lose]
196    to close the current tab
197
198# navigating diagnostics
199:cn[ext], :cp[rev], :ln[ext], :lp[rev]
200    to go to the next/prev diagnostics
201:cc, :ll
202    to open the errors page
203
204# jump to position
205:<number>
206    to jump to a line number
207:$
208    to jump to the end of the file
209:/foo and :?foo
210    to jump to next/prev line matching foo
211
212# replacement (/g is always assumed and Zed uses different regex syntax to vim)
213:%s/foo/bar/
214  to replace instances of foo with bar
215:X,Ys/foo/bar/
216    to limit replacement between line X and Y
217    other ranges are not yet implemented
218
219# editing
220:j[oin]
221    to join the current line (no range is yet supported)
222:d[elete][l][p]
223    to delete the current line (no range is yet supported)
224:s[ort] [i]
225    to sort the current selection (with i, case-insensitively)
226```
227
228As any Zed command is available, you may find that it's helpful to remember mnemonics that run the correct command. For example:
229
230```
231:diff   Toggle Hunk [Diff]
232:diffs  Toggle all Hunk [Diffs]
233:revert Revert Selected Hunks
234:cpp    [C]o[p]y [P]ath to file
235:crp    [C]opy [r]elative [P]ath
236:reveal [Reveal] in finder
237:zlog   Open [Z]ed Log
238```
239
240## Settings
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    // Lets `f` and `t` motions extend across multiple lines
252    "use_multiline_find": true
253  }
254}
255```
256
257There are also a few Zed settings that you may also enjoy if you use vim mode:
258
259```json
260{
261  // disable cursor blink
262  "cursor_blink": false,
263  // use relative line numbers
264  "relative_line_numbers": true,
265  // hide the scroll bar
266  "scrollbar": { "show": "never" },
267  // allow cursor to reach edges of screen
268  "vertical_scroll_margin": 0,
269  "gutter": {
270    // disable line numbers completely:
271    "line_numbers": false
272  }
273}
274```
275
276If 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:
277
278```json
279{
280  "context": "Dock",
281  "bindings": {
282    "ctrl-w h": ["workspace::ActivatePaneInDirection", "Left"],
283    "ctrl-w l": ["workspace::ActivatePaneInDirection", "Right"],
284    "ctrl-w k": ["workspace::ActivatePaneInDirection", "Up"],
285    "ctrl-w j": ["workspace::ActivatePaneInDirection", "Down"]
286    // ... or other keybindings
287  }
288}
289```
290
291Subword motion is not enabled by default. To enable it, add these bindings to your keymap.
292
293```json
294  {
295    "context": "Editor && VimControl && !VimWaiting && !menu",
296    "bindings": {
297      "w": "vim::NextSubwordStart",
298      "b": "vim::PreviousSubwordStart",
299      "e": "vim::NextSubwordEnd",
300      "g e": "vim::PreviousSubwordEnd"
301    }
302  },
303```
304
305Surrounding 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.
306
307```json
308  {
309    "context": "Editor && vim_mode == visual && !VimWaiting && !VimObject",
310    "bindings": {
311      "shift-s": [
312        "vim::PushOperator",
313        {
314          "AddSurrounds": {}
315        }
316      ]
317    }
318  }
319```
320
321## Supported plugins
322
323Zed has nascent support for some Vim plugins:
324
325- From `vim-surround`, `ys`, `cs` and `ds` work. Though you cannot add new HTML tags yet.
326- From `vim-commentary`, `gc` in visual mode and `gcc` in normal mode. Though you cannot operate on arbitrary objects yet.
327- From `netrw`, most keybindings are supported in the project panel.
328- From `vim-spider`/`CamelCaseMotion` you can use subword motions as described above.
329
330## Regex differences
331
332Zed uses a different regular expression engine from Vim. This means that you will have to use a different syntax for some things.
333
334Notably:
335
336- Vim uses `\(` and `\)` to represent capture groups, in Zed these are `(` and `)`.
337- On the flip side, `(` and `)` represent literal parentheses, but in Zed these must be escaped to `\(` and `\)`.
338- When replacing, Vim uses `\0` to represent the entire match, in Zed this is `$0`, same for numbered capture groups `\1` -> `$1`.
339- Vim uses `/g` to indicate "all matches on one line", in Zed this is implied
340- 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`.
341
342To 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".
343
344For the full syntax supported by Zed's regex engine see the [regex crate documentation](https://docs.rs/regex/latest/regex/#syntax).