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 [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 declaration
 21g y     Go to type definition
 22g I     Go to implementation
 23
 24c d     Rename (change definition)
 25g A     Go to All references to the current word
 26
 27g s   Find symbol in current file
 28g S   Find symbol in entire project
 29
 30g ]   Go to next diagnostic
 31g [   Go to previous diagnostic
 32] d   Go to next diagnostic
 33[ d   Go to previous diagnostic
 34g h   Show inline error (hover)
 35g .   Open the code actions menu
 36
 37# Git
 38] c   Go to next git change
 39[ c   Go to previous git change
 40
 41# Treesitter
 42] x   Select a smaller syntax node
 43[ x   Select a larger syntax node
 44
 45# Multi cursor
 46g l   Add a visual selection for the next copy of the current word
 47g L   The same, but backwards
 48g >   Skip latest word selection, and add next.
 49g <   The same, but backwards
 50g a   Add a visual selection for every copy of the current word
 51
 52# Pane management
 53g /        Open a project-wide search
 54g <space>  Open the current search excerpt
 55<ctrl-w> <space>  Open the current search excerpt in a split
 56<ctrl-w> g d      Go to definition in a split
 57<ctrl-w> g D      Go to type definition in a split
 58
 59# Insert mode
 60ctrl-x ctrl-o  Open the completion menu
 61ctrl-x ctrl-c  Request GitHub Copilot suggestion (if configured)
 62ctrl-x ctrl-a  Open the inline AI assistant (if configured)
 63ctrl-x ctrl-l  Open the code actions menu
 64ctrl-x ctrl-z  Hides all suggestions
 65
 66# Ex commands
 67:E[xplore]    Open the project panel
 68:C[ollab]     Open the collaboration panel
 69:Ch[at]       Open the chat panel
 70:A[I]         Open the AI panel
 71:No[tif]      Open the notifications panel
 72:fe[edback]   Open the feedback window
 73:cl[ist]      Open the diagnostics window
 74:te[rm]       Open the terminal
 75:Ext[ensions] Open the extensions window
 76```
 77
 78Vim 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.
 79
 80Vim mode emulates visual block mode using Zed's multiple cursor support. This again leads to some differences, but is much more powerful.
 81
 82Vim'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.
 83
 84Finally, 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.
 85
 86## Custom key bindings
 87
 88You can edit your personal key bindings with `:keymap`.
 89For vim-specific shortcuts, you may find the following template a good place to start.
 90
 91> **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).
 92
 93```json
 94[
 95  {
 96    "context": "VimControl && !menu",
 97    "bindings": {
 98      // put key-bindings here if you want them to work in normal & visual mode
 99    }
100  },
101  {
102    "context": "vim_mode == insert",
103    "bindings": {
104      // "j k": "vim::NormalBefore" // remap jk in insert mode to escape.
105    }
106  },
107  {
108    "context": "EmptyPane || SharedScreen",
109    "bindings": {
110      // put key-bindings here (in addition to above) if you want them to
111      // work when no editor exists
112      // "space f": "file_finder::Toggle"
113    }
114  }
115]
116```
117
118If 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.
119
120You 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).
121
122#### Contexts
123
124Zed'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.
125
126Vim mode adds several contexts to the `Editor`:
127
128- `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`).
129- `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`).
130- `"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.
131
132### Restoring some sense of normality
133
134If you're using Vim mode on Linux or Windows, you may find that it has overridden keybindings
135that you can't live without. You can restore them to their defaults by copying these into your keymap:
136
137```json
138{
139  "context": "Editor && !menu",
140  "bindings": {
141    "ctrl-c": "editor::Copy",          // vim default: return to normal mode
142    "ctrl-x": "editor::Cut",           // vim default: decrement
143    "ctrl-v": "editor::Paste",         // vim default: visual block mode
144    "ctrl-y": "editor::Undo",          // vim default: line up
145    "ctrl-f": "buffer_search::Deploy", // vim default: page down
146    "ctrl-o": "workspace::Open",       // vim default: go back
147    "ctrl-a": "editor::SelectAll",     // vim default: increment
148  }
149},
150```
151
152## Command palette
153
154Vim 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.
155
156Additionally 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.
157
158We 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.
159
160As mentioned above, one thing to be aware of is that the regex engine is slightly different from vim's in `:%s/a/b`.
161
162Currently supported vim-specific commands:
163
164```
165# window management
166:w[rite][!], :wq[!], :q[uit][!], :wa[ll][!], :wqa[ll][!], :qa[ll][!], :[e]x[it][!], :up[date]
167    to save/close tab(s) and pane(s) (no filename is supported yet)
168:cq
169    to quit completely.
170:vs[plit], :sp[lit]
171    to split vertically/horizontally (no filename is supported yet)
172:new, :vne[w]
173    to create a new file in a new pane above or to the left
174:tabedit, :tabnew
175    to create a new file in a new tab.
176:tabn[ext], :tabp[rev]
177    to go to previous/next tabs
178:tabc[lose]
179    to close the current tab
180
181# navigating diagnostics
182:cn[ext], :cp[rev], :ln[ext], :lp[rev]
183    to go to the next/prev diagnostics
184:cc, :ll
185    to open the errors page
186
187# jump to position
188:<number>
189    to jump to a line number
190:$
191    to jump to the end of the file
192:/foo and :?foo
193    to jump to next/prev line matching foo
194
195# replacement (/g is always assumed and Zed uses different regex syntax to vim)
196:%s/foo/bar/
197  to replace instances of foo with bar
198:X,Ys/foo/bar/
199    to limit replacement between line X and Y
200    other ranges are not yet implemented
201
202# editing
203:j[oin]
204    to join the current line (no range is yet supported)
205:d[elete][l][p]
206    to delete the current line (no range is yet supported)
207:s[ort] [i]
208    to sort the current selection (with i, case-insensitively)
209```
210
211As any Zed command is available, you may find that it's helpful to remember mnemonics that run the correct command. For example:
212
213```
214:diff   Toggle Hunk [Diff]
215:diffs  Toggle all Hunk [Diffs]
216:revert Revert Selected Hunks
217:cpp    [C]o[p]y [P]ath to file
218:crp    [C]opy [r]elative [P]ath
219:reveal [Reveal] in finder
220:zlog   Open [Z]ed Log
221```
222
223## Settings
224
225Vim mode is not enabled by default. To enable Vim mode, you need to add the following configuration to your settings file:
226
227```json
228{
229  "vim_mode": true
230}
231```
232
233Alternatively, you can enable Vim mode by running the `toggle vim mode` command from the command palette.
234
235Some vim settings are available to modify the default vim behavior:
236
237```json
238{
239  "vim": {
240    // "always": use system clipboard when no register is specified
241    // "never": don't use system clipboard unless "+ or "* is specified
242    // "on_yank": use system clipboard for yank operations when no register is specified
243    "use_system_clipboard": "always",
244    // Lets `f` and `t` motions extend across multiple lines
245    "use_multiline_find": true
246  }
247}
248```
249
250There are also a few Zed settings that you may also enjoy if you use vim mode:
251
252```json
253{
254  // disable cursor blink
255  "cursor_blink": false,
256  // use relative line numbers
257  "relative_line_numbers": true,
258  // hide the scroll bar
259  "scrollbar": { "show": "never" },
260  // prevent the buffer from scrolling beyond the last line
261  "scroll_beyond_last_line": "off",
262  // allow cursor to reach edges of screen
263  "vertical_scroll_margin": 0,
264  "gutter": {
265    // disable line numbers completely:
266    "line_numbers": false
267  },
268  "command_aliases": {
269    "W": "w",
270    "Wq": "wq",
271    "Q": "q"
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  {
296    "context": "VimControl && !menu && vim_mode != operator",
297    "bindings": {
298      "w": "vim::NextSubwordStart",
299      "b": "vim::PreviousSubwordStart",
300      "e": "vim::NextSubwordEnd",
301      "g e": "vim::PreviousSubwordEnd"
302    }
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": "vim_mode == visual",
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).