vim.md

  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 Zed provides to help you navigate and edit your code, and generally how to make the most of vim mode in Zed.
  4
  5You'll learn how to:
  6
  7- Understand the core differences between Zed's vim mode and traditional Vim
  8- Enable or disable vim mode
  9- Make the most of Zed-specific features within vim mode
 10- Customize vim mode key bindings
 11- Configure vim mode settings
 12
 13Whether you're new to vim mode or an experienced Vim user looking to optimize your Zed experience, this guide will help you harness the full power of modal editing in Zed.
 14
 15## Zed's vim mode design
 16
 17Vim 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.
 18
 19This includes support for semantic navigation, multiple cursors, or other features usually provided by plugins like surrounding text.
 20
 21So, 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.
 22
 23### Core differences
 24
 25There are four types of features in vim mode that use Zed's core functionality, leading to some differences in behavior:
 26
 271. **Motions**: vim mode uses Zed's semantic parsing to tune the behavior of motions per language. For example, in Rust, jumping to matching bracket with `%` works with the pipe character `|`. In JavaScript, `w` considers `$` to be a word character.
 282. **Visual block selections**: vim mode uses Zed's multiple cursor to emulate visual block selections, making block selections a lot more flexible. For example, anything you insert after a block selection updates on every line in real-time, and you can add or remove cursors anytime.
 293. **Macros**: vim mode uses Zed's recording system for vim macros. So, you can capture and replay more complex actions, like autocompletion.
 304. **Search and replace**: vim mode uses Zed's search system, so, the syntax for regular expressions is slightly different compared to Vim. [Head to the Regex differences section](#regex-differences) for details.
 31
 32> **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 on GitHub](https://github.com/zed-industries/zed/issues).
 33
 34## Enabling and disabling vim mode
 35
 36When you first open Zed, you'll see a checkbox on the welcome screen that allows you to enable vim mode.
 37
 38If 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`.
 39
 40> **Note**: This command toggles the following property in your user settings:
 41>
 42> ```json [settings]
 43> {
 44>   "vim_mode": true
 45> }
 46> ```
 47
 48## Zed-specific features
 49
 50Zed 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.
 51
 52Vim mode has several "core Zed" key bindings that will help you make the most of Zed's specific feature set.
 53
 54### Language server
 55
 56The following commands use the language server to help you navigate and refactor your code.
 57
 58| Command                                  | Default Shortcut |
 59| ---------------------------------------- | ---------------- |
 60| Go to definition                         | `g d`            |
 61| Go to declaration                        | `g D`            |
 62| Go to type definition                    | `g y`            |
 63| Go to implementation                     | `g I`            |
 64| Rename (change definition)               | `c d`            |
 65| Go to All references to the current word | `g A`            |
 66| Find symbol in current file              | `g s`            |
 67| Find symbol in entire project            | `g S`            |
 68| Go to next diagnostic                    | `g ]` or `] d`   |
 69| Go to previous diagnostic                | `g [` or `[ d`   |
 70| Show inline error (hover)                | `g h`            |
 71| Open the code actions menu               | `g .`            |
 72
 73### Git
 74
 75| Command                         | Default Shortcut |
 76| ------------------------------- | ---------------- |
 77| Go to next git change           | `] c`            |
 78| Go to previous git change       | `[ c`            |
 79| Expand diff hunk                | `d o`            |
 80| Toggle staged                   | `d O`            |
 81| Stage and next (in diff view)   | `d u`            |
 82| Unstage and next (in diff view) | `d U`            |
 83| Restore change                  | `d p`            |
 84
 85### Tree-sitter
 86
 87Tree-sitter is a powerful tool that Zed uses to understand the structure of your code. Zed provides motions that change the current cursor position, and text objects that can be used as the target of actions.
 88
 89| Command                         | Default Shortcut            |
 90| ------------------------------- | --------------------------- |
 91| Go to next/previous method      | `] m` / `[ m`               |
 92| Go to next/previous method end  | `] M` / `[ M`               |
 93| Go to next/previous section     | `] ]` / `[ [`               |
 94| Go to next/previous section end | `] [` / `[ ]`               |
 95| Go to next/previous comment     | `] /`, `] *` / `[ /`, `[ *` |
 96| Select a larger syntax node     | `[ x`                       |
 97| Select a smaller syntax node    | `] x`                       |
 98
 99| Text Objects                                               | Default Shortcut |
100| ---------------------------------------------------------- | ---------------- |
101| Around a class, definition, etc.                           | `a c`            |
102| Inside a class, definition, etc.                           | `i c`            |
103| Around a function, method etc.                             | `a f`            |
104| Inside a function, method, etc.                            | `i f`            |
105| A comment                                                  | `g c`            |
106| An argument, or list item, etc.                            | `i a`            |
107| An argument, or list item, etc. (including trailing comma) | `a a`            |
108| Around an HTML-like tag                                    | `a t`            |
109| Inside an HTML-like tag                                    | `i t`            |
110| The current indent level, and one line before and after    | `a I`            |
111| The current indent level, and one line before              | `a i`            |
112| The current indent level                                   | `i i`            |
113
114Note that the definitions for the targets of the `[m` family of motions are the same as the
115boundaries defined by `af`. The targets of the `[[` are the same as those defined by `ac`, though
116if there are no classes, then functions are also used. Similarly `gc` is used to find `[ /`. `g c`
117
118The definition of functions, classes and comments is language dependent, and support can be added
119to extensions by adding a [`textobjects.scm`]. The definition of arguments and tags operates at
120the Tree-sitter level, but looks for certain patterns in the parse tree and is not currently configurable
121per language.
122
123### Multi cursor
124
125These commands help you manage multiple cursors in Zed.
126
127| Command                                                      | Default Shortcut |
128| ------------------------------------------------------------ | ---------------- |
129| Add a cursor selecting the next copy of the current word     | `g l`            |
130| Add a cursor selecting the previous copy of the current word | `g L`            |
131| Skip latest word selection, and add next                     | `g >`            |
132| Skip latest word selection, and add previous                 | `g <`            |
133| Add a visual selection for every copy of the current word    | `g a`            |
134
135### Pane management
136
137These commands open new panes or jump to specific panes.
138
139| Command                                    | Default Shortcut   |
140| ------------------------------------------ | ------------------ |
141| Open a project-wide search                 | `g /`              |
142| Open the current search excerpt            | `g <space>`        |
143| Open the current search excerpt in a split | `<ctrl-w> <space>` |
144| Go to definition in a split                | `<ctrl-w> g d`     |
145| Go to type definition in a split           | `<ctrl-w> g D`     |
146
147### In insert mode
148
149The following commands help you bring up Zed's completion menu, request a suggestion from GitHub Copilot, or open the inline AI assistant without leaving insert mode.
150
151| Command                                                                      | Default Shortcut |
152| ---------------------------------------------------------------------------- | ---------------- |
153| Open the completion menu                                                     | `ctrl-x ctrl-o`  |
154| Request GitHub Copilot suggestion (requires GitHub Copilot to be configured) | `ctrl-x ctrl-c`  |
155| Open the inline AI assistant (requires a configured assistant)               | `ctrl-x ctrl-a`  |
156| Open the code actions menu                                                   | `ctrl-x ctrl-l`  |
157| Hides all suggestions                                                        | `ctrl-x ctrl-z`  |
158
159### Supported plugins
160
161Zed's vim mode includes some features that are usually provided by very popular plugins in the Vim ecosystem:
162
163- You can surround text objects with `ys` (yank surround), change surrounding with `cs`, and delete surrounding with `ds`.
164- You can comment and uncomment selections with `gc` in visual mode and `gcc` in normal mode.
165- The project panel supports many shortcuts modeled after the Vim plugin `netrw`: navigation with `hjkl`, open file with `o`, open file in a new tab with `t`, etc.
166- You can add key bindings to your keymap to navigate "camelCase" names. [Head down to the Optional key bindings](#optional-key-bindings) section to learn how.
167- You can use `gR` to do [ReplaceWithRegister](https://github.com/vim-scripts/ReplaceWithRegister).
168- You can use `cx` for [vim-exchange](https://github.com/tommcdo/vim-exchange) functionality. Note that it does not have a default binding in visual mode, but you can add one to your keymap (refer to the [optional key bindings](#optional-key-bindings) section).
169- You can navigate to indent depths relative to your cursor with the [indent wise](https://github.com/jeetsukumaran/vim-indentwise) plugin `[-`, `]-`, `[+`, `]+`, `[=`, `]=`.
170- You can select quoted text with AnyQuotes and bracketed text with AnyBrackets text objects. Zed also provides MiniQuotes and MiniBrackets which offer alternative selection behavior based on the [mini.ai](https://github.com/echasnovski/mini.nvim/blob/main/readmes/mini-ai.md) Neovim plugin. See the [Quote and Bracket text objects](#quote-and-bracket-text-objects) section below for details.
171- You can configure AnyQuotes, AnyBrackets, MiniQuotes, and MiniBrackets text objects for selecting quoted and bracketed text using different selection strategies. See the [Any Bracket Functionality](#any-bracket-functionality) section below for details.
172
173### Any Bracket Functionality
174
175Zed offers two different strategies for selecting text surrounded by any quote, or any bracket. These text objects are **not enabled by default** and must be configured in your keymap to be used.
176
177#### Included Characters
178
179Each text object type works with specific characters:
180
181| Text Object              | Characters                                                                             |
182| ------------------------ | -------------------------------------------------------------------------------------- |
183| AnyQuotes/MiniQuotes     | Single quote (`'`), Double quote (`"`), Backtick (`` ` ``)                             |
184| AnyBrackets/MiniBrackets | Parentheses (`()`), Square brackets (`[]`), Curly braces (`{}`), Angle brackets (`<>`) |
185
186Both "Any" and "Mini" variants work with the same character sets, but differ in their selection strategy.
187
188#### AnyQuotes and AnyBrackets (Traditional Vim behavior)
189
190These text objects implement traditional Vim behavior:
191
192- **Selection priority**: Finds the innermost (closest) quotes or brackets first
193- **Fallback mechanism**: If none are found, falls back to the current line
194- **Character-based matching**: Focuses solely on open and close characters without considering syntax
195- **Vanilla Vim similarity**: AnyBrackets matches the behavior of commands like `ci<`, `ci(`, etc., in vanilla Vim, including potential edge cases (like considering `>` in `=>` as a closing delimiter)
196
197#### MiniQuotes and MiniBrackets (mini.ai behavior)
198
199These text objects implement the behavior of the [mini.ai](https://github.com/echasnovski/mini.nvim/blob/main/readmes/mini-ai.md) Neovim plugin:
200
201- **Selection priority**: Searches the current line first before expanding outward
202- **Tree-sitter integration**: Uses Tree-sitter queries for more context-aware selections
203- **Syntax-aware matching**: Can distinguish between actual brackets and similar characters in other contexts (like `>` in `=>`)
204
205#### Choosing Between Approaches
206
207- Use **AnyQuotes/AnyBrackets** if you:
208
209  - Prefer traditional Vim behavior
210  - Want consistent character-based selection prioritizing innermost delimiters
211  - Need behavior that closely matches vanilla Vim's text objects
212
213- Use **MiniQuotes/MiniBrackets** if you:
214  - Prefer the mini.ai plugin behavior
215  - Want more context-aware selections using Tree-sitter
216  - Prefer current-line priority when searching
217
218#### Example Configuration
219
220To use these text objects, you need to add bindings to your keymap. Here's an example configuration that makes them available when using text object operators (`i` and `a`) or change-surrounds (`cs`):
221
222```json [settings]
223{
224  "context": "vim_operator == a || vim_operator == i || vim_operator == cs",
225  "bindings": {
226    // Traditional Vim behavior
227    "q": "vim::AnyQuotes",
228    "b": "vim::AnyBrackets",
229
230    // mini.ai plugin behavior
231    "Q": "vim::MiniQuotes",
232    "B": "vim::MiniBrackets"
233  }
234}
235```
236
237With this configuration, you can use commands like:
238
239- `cib` - Change inside brackets using AnyBrackets behavior
240- `ciB` - Change inside brackets using MiniBrackets behavior
241- `ciq` - Change inside quotes using AnyQuotes behavior
242- `ciQ` - Change inside quotes using MiniQuotes behavior
243
244## Command palette
245
246Vim mode allows you to open Zed's command palette with `:`. You can then type to access any usual Zed command. Additionally, vim mode adds aliases for popular Vim commands to ensure your muscle memory transfers to Zed. For example, you can write `:w` or `:write` to save the file.
247
248Below, you'll find tables listing the commands you can use in the command palette. We put optional characters in square brackets to indicate that you can omit them.
249
250> **Note**: We don't emulate the full power of Vim's command line yet. In particular, commands currently do not support arguments. Please [file issues on GitHub](https://github.com/zed-industries/zed) as you find things that are missing from the command palette.
251
252### File and window management
253
254This table shows commands for managing windows, tabs, and panes. As commands don't support arguments currently, you cannot specify a filename when saving or creating a new file.
255
256| Command        | Description                                          |
257| -------------- | ---------------------------------------------------- |
258| `:w[rite][!]`  | Save the current file                                |
259| `:wq[!]`       | Save the file and close the buffer                   |
260| `:q[uit][!]`   | Close the buffer                                     |
261| `:wa[ll][!]`   | Save all open files                                  |
262| `:wqa[ll][!]`  | Save all open files and close all buffers            |
263| `:qa[ll][!]`   | Close all buffers                                    |
264| `:[e]x[it][!]` | Close the buffer                                     |
265| `:up[date]`    | Save the current file                                |
266| `:cq`          | Quit completely (close all running instances of Zed) |
267| `:vs[plit]`    | Split the pane vertically                            |
268| `:sp[lit]`     | Split the pane horizontally                          |
269| `:new`         | Create a new file in a horizontal split              |
270| `:vne[w]`      | Create a new file in a vertical split                |
271| `:tabedit`     | Create a new file in a new tab                       |
272| `:tabnew`      | Create a new file in a new tab                       |
273| `:tabn[ext]`   | Go to the next tab                                   |
274| `:tabp[rev]`   | Go to previous tab                                   |
275| `:tabc[lose]`  | Close the current tab                                |
276| `:ls`          | Show all buffers                                     |
277
278> **Note:** The `!` character is used to force the command to execute without saving changes or prompting before overwriting a file.
279
280### Ex commands
281
282These ex commands open Zed's various panels and windows.
283
284| Command                      | Default Shortcut |
285| ---------------------------- | ---------------- |
286| Open the project panel       | `:E[xplore]`     |
287| Open the collaboration panel | `:C[ollab]`      |
288| Open the chat panel          | `:Ch[at]`        |
289| Open the AI panel            | `:A[I]`          |
290| Open the git panel           | `:G[it]`         |
291| Open the debug panel         | `:D[ebug]`       |
292| Open the notifications panel | `:No[tif]`       |
293| Open the feedback window     | `:fe[edback]`    |
294| Open the diagnostics window  | `:cl[ist]`       |
295| Open the terminal            | `:te[rm]`        |
296| Open the extensions window   | `:Ext[ensions]`  |
297
298### Navigating diagnostics
299
300These commands navigate diagnostics.
301
302| Command                  | Description                    |
303| ------------------------ | ------------------------------ |
304| `:cn[ext]` or `:ln[ext]` | Go to the next diagnostic      |
305| `:cp[rev]` or `:lp[rev]` | Go to the previous diagnostics |
306| `:cc` or `:ll`           | Open the errors page           |
307
308### Git
309
310These commands interact with the version control system git.
311
312| Command         | Description                                             |
313| --------------- | ------------------------------------------------------- |
314| `:dif[fupdate]` | View the diff under the cursor (`d o` in normal mode)   |
315| `:rev[ert]`     | Revert the diff under the cursor (`d p` in normal mode) |
316
317### Jump
318
319These commands jump to specific positions in the file.
320
321| Command             | Description                         |
322| ------------------- | ----------------------------------- |
323| `:<number>`         | Jump to a line number               |
324| `:$`                | Jump to the end of the file         |
325| `:/foo` and `:?foo` | Jump to next/prev line matching foo |
326
327### Replacement
328
329This command replaces text. It emulates the substitute command in vim. The substitute command uses regular expressions, and Zed uses a slightly different syntax than vim. You can learn more about Zed's syntax below, [in the regex differences section](#regex-differences). Zed will replace only the first occurrence of the search pattern in the current line. To replace all matches append the `g` flag.
330
331| Command                 | Description                       |
332| ----------------------- | --------------------------------- |
333| `:[range]s/foo/bar/[g]` | Replace instances of foo with bar |
334
335### Editing
336
337These commands help you edit text.
338
339| Command           | Description                                             |
340| ----------------- | ------------------------------------------------------- |
341| `:j[oin]`         | Join the current line                                   |
342| `:d[elete][l][p]` | Delete the current line                                 |
343| `:s[ort] [i]`     | Sort the current selection (with i, case-insensitively) |
344| `:y[ank]`         | Yank (copy) the current selection or line               |
345
346### Set
347
348These commands modify editor options locally for the current buffer.
349
350| Command                         | Description                                                                                   |
351| ------------------------------- | --------------------------------------------------------------------------------------------- |
352| `:se[t] [no]wrap`               | Lines longer than the width of the window will wrap and displaying continues on the next line |
353| `:se[t] [no]nu[mber]`           | Print the line number in front of each line                                                   |
354| `:se[t] [no]r[elative]nu[mber]` | Changes the displayed number to be relative to the cursor                                     |
355| `:se[t] [no]i[gnore]c[ase]`     | Controls whether the buffer and project search use case-sensitive matching                    |
356
357### Command mnemonics
358
359As any Zed command is available, you may find that it's helpful to remember mnemonics that run the correct command. For example:
360
361- `:diffs` for "toggle all hunk diffs"
362- `:cpp` for "copy path to file"
363- `:crp` for "copy relative path"
364- `:reveal` for "reveal in finder"
365- `:zlog` for "open zed log"
366- `:clank` for "cancel language server work"
367
368## Customizing key bindings
369
370In this section, we'll learn how to customize the key bindings of Zed's vim mode. You'll learn:
371
372- How to select the correct context for your new key bindings.
373- Useful contexts for vim mode key bindings.
374- Common key bindings to customize for extra productivity.
375
376### Selecting the correct context
377
378Zed's key bindings are evaluated only when the `"context"` property matches your location in the editor. For example, if you add key bindings to the `"Editor"` context, they will only work when you're editing a file. If you add key bindings to the `"Workspace"` context, they will work everywhere in Zed. Here's an example of a key binding that saves when you're editing a file:
379
380```json [settings]
381{
382  "context": "Editor",
383  "bindings": {
384    "ctrl-s": "file::Save"
385  }
386}
387```
388
389Contexts are nested, so when you're editing a file, the context is the `"Editor"` context, which is inside the `"Pane"` context, which is inside the `"Workspace"` context. That's why any key bindings you add to the `"Workspace"` context will work when you're editing a file. Here's an example:
390
391```json [keymap]
392// This key binding will work when you're editing a file. It comes built into Zed by default as the workspace: save command.
393{
394  "context": "Workspace",
395  "bindings": {
396    "ctrl-s": "workspace::Save"
397  }
398}
399```
400
401Contexts are expressions. They support boolean operators like `&&` (and) and `||` (or). For example, you can use the context `"Editor && vim_mode == normal"` to create key bindings that only work when you're editing a file _and_ you're in vim's normal mode.
402
403Vim mode adds several contexts to the `"Editor"` context:
404
405| Operator             | Description                                                                                                                                                                        |
406| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
407| VimControl           | Indicates that vim keybindings should work. Currently an alias for `vim_mode == normal \|\| vim_mode == visual \|\| vim_mode == operator`, but the definition may change over time |
408| vim_mode == normal   | Normal mode                                                                                                                                                                        |
409| vim_mode == visual   | Visual mode                                                                                                                                                                        |
410| vim_mode == insert   | Insert mode                                                                                                                                                                        |
411| vim_mode == replace  | Replace mode                                                                                                                                                                       |
412| vim_mode == waiting  | Waiting for an arbitrary key (e.g., after typing `f` or `t`)                                                                                                                       |
413| vim_mode == operator | Waiting for another binding to trigger (e.g., after typing `c` or `d`)                                                                                                             |
414| vim_operator         | Set to `none` unless `vim_mode == operator`, in which case it is set to the current operator's default keybinding (e.g., after typing `d`, `vim_operator == d`)                    |
415
416> **Note**: Contexts are matched only on one level at a time. So it is possible to use the expression `"Editor && vim_mode == normal"`, but `"Workspace && vim_mode == normal"` will never match because we set the vim context at the `"Editor"` level.
417
418### Useful contexts for vim mode key bindings
419
420Here's a template with useful vim mode contexts to help you customize your vim mode key bindings. You can copy it and integrate it into your user keymap.
421
422```json [keymap]
423[
424  {
425    "context": "VimControl && !menu",
426    "bindings": {
427      // Put key bindings here if you want them to work in normal & visual mode.
428    }
429  },
430  {
431    "context": "vim_mode == normal && !menu",
432    "bindings": {
433      // "shift-y": ["workspace::SendKeystrokes", "y $"] // Use neovim's yank behavior: yank to end of line.
434    }
435  },
436  {
437    "context": "vim_mode == insert",
438    "bindings": {
439      // "j k": "vim::NormalBefore" // In insert mode, make jk escape to normal mode.
440    }
441  },
442  {
443    "context": "EmptyPane || SharedScreen",
444    "bindings": {
445      // Put key bindings here (in addition to the context above) if you want them to
446      // work when no editor exists.
447      // "space f": "file_finder::Toggle"
448    }
449  }
450]
451```
452
453> **Note**: If you would like to emulate Vim's `map` commands (`nmap`, etc.), you can use the action `workspace::SendKeystrokes` in the correct context.
454
455### Optional key bindings
456
457By default, you can navigate between the different files open in the editor with shortcuts like `ctrl+w` followed by one of `hjkl` to move to the left, down, up, or right, respectively.
458
459But you cannot use the same shortcuts to move between all the editor docks (the terminal, project panel, assistant panel, ...). If you want to use the same shortcuts to navigate to the docks, you can add the following key bindings to your user keymap.
460
461```json [settings]
462{
463  "context": "Dock",
464  "bindings": {
465    "ctrl-w h": "workspace::ActivatePaneLeft",
466    "ctrl-w l": "workspace::ActivatePaneRight",
467    "ctrl-w k": "workspace::ActivatePaneUp",
468    "ctrl-w j": "workspace::ActivatePaneDown"
469    // ... or other keybindings
470  }
471}
472```
473
474Subword motion, which allows you to navigate and select individual words in camelCase or snake_case, is not enabled by default. To enable it, add these bindings to your keymap.
475
476```json [settings]
477{
478  "context": "VimControl && !menu && vim_mode != operator",
479  "bindings": {
480    "w": "vim::NextSubwordStart",
481    "b": "vim::PreviousSubwordStart",
482    "e": "vim::NextSubwordEnd",
483    "g e": "vim::PreviousSubwordEnd"
484  }
485}
486```
487
488Vim mode comes with shortcuts to surround the selection in normal mode (`ys`), but it doesn't have a shortcut to add surrounds in visual mode. By default, `shift-s` substitutes the selection (erases the text and enters insert mode). To use `shift-s` to add surrounds in visual mode, you can add the following object to your keymap.
489
490```json [settings]
491{
492  "context": "vim_mode == visual",
493  "bindings": {
494    "shift-s": "vim::PushAddSurrounds"
495  }
496}
497```
498
499In non-modal text editors, cursor navigation typically wraps when moving past line ends. Zed, however, handles this behavior exactly like Vim by default: the cursor stops at line boundaries. If you prefer your cursor to wrap between lines, override these keybindings:
500
501```json [settings]
502// In VimScript, this would look like this:
503// set whichwrap+=<,>,[,],h,l
504{
505  "context": "VimControl && !menu",
506  "bindings": {
507    "left": "vim::WrappingLeft",
508    "right": "vim::WrappingRight",
509    "h": "vim::WrappingLeft",
510    "l": "vim::WrappingRight"
511  }
512}
513```
514
515The [Sneak motion](https://github.com/justinmk/vim-sneak) feature allows for quick navigation to any two-character sequence in your text. You can enable it by adding the following keybindings to your keymap. By default, the `s` key is mapped to `vim::Substitute`. Adding these bindings will override that behavior, so ensure this change aligns with your workflow preferences.
516
517```json [settings]
518{
519  "context": "vim_mode == normal || vim_mode == visual",
520  "bindings": {
521    "s": "vim::PushSneak",
522    "shift-s": "vim::PushSneakBackward"
523  }
524}
525```
526
527The [vim-exchange](https://github.com/tommcdo/vim-exchange) feature does not have a default binding for visual mode, as the `shift-x` binding conflicts with the default `shift-x` binding for visual mode (`vim::VisualDeleteLine`). To assign the default vim-exchange binding, add the following keybinding to your keymap:
528
529```json [settings]
530{
531  "context": "vim_mode == visual",
532  "bindings": {
533    "shift-x": "vim::Exchange"
534  }
535}
536```
537
538### Restoring common text editing and Zed keybindings
539
540If you're using vim mode on Linux or Windows, you may find it overrides keybindings you can't live without: `ctrl+v` to paste, `ctrl+f` to search, etc. You can restore them by copying this data into your keymap:
541
542```json [keymap]
543{
544  "context": "Editor && !menu",
545  "bindings": {
546    "ctrl-c": "editor::Copy",               // vim default: return to normal mode
547    "ctrl-x": "editor::Cut",                // vim default: decrement
548    "ctrl-v": "editor::Paste",              // vim default: visual block mode
549    "ctrl-y": "editor::Undo",               // vim default: line up
550    "ctrl-f": "buffer_search::Deploy",      // vim default: page down
551    "ctrl-o": "workspace::Open",            // vim default: go back
552    "ctrl-s": "workspace::Save",            // vim default: show signature
553    "ctrl-a": "editor::SelectAll",          // vim default: increment
554    "ctrl-b": "workspace::ToggleLeftDock"   // vim default: down
555  }
556},
557```
558
559## Changing vim mode settings
560
561You can change the following settings to modify vim mode's behavior:
562
563| Property                     | Description                                                                                                                                                                                   | Default Value |
564| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
565| default_mode                 | The default mode to start in. One of "normal", "insert", "replace", "visual", "visual_line", "visual_block", "helix_normal".                                                                  | "normal"      |
566| use_system_clipboard         | Determines how system clipboard is used:<br><ul><li>"always": use for all operations</li><li>"never": only use when explicitly specified</li><li>"on_yank": use for yank operations</li></ul> | "always"      |
567| use_multiline_find           | deprecated                                                                                                                                                                                    |
568| use_smartcase_find           | If `true`, `f` and `t` motions are case-insensitive when the target letter is lowercase.                                                                                                      | false         |
569| toggle_relative_line_numbers | If `true`, line numbers are relative in normal mode and absolute in insert mode, giving you the best of both options.                                                                         | false         |
570| custom_digraphs              | An object that allows you to add custom digraphs. Read below for an example.                                                                                                                  | {}            |
571| highlight_on_yank_duration   | The duration of the highlight animation(in ms). Set to `0` to disable                                                                                                                         | 200           |
572
573Here's an example of adding a digraph for the zombie emoji. This allows you to type `ctrl-k f z` to insert a zombie emoji. You can add as many digraphs as you like.
574
575```json [settings]
576{
577  "vim": {
578    "custom_digraphs": {
579      "fz": "🧟‍♀️"
580    }
581  }
582}
583```
584
585Here's an example of these settings changed:
586
587```json [settings]
588{
589  "vim": {
590    "default_mode": "insert",
591    "use_system_clipboard": "never",
592    "use_smartcase_find": true,
593    "toggle_relative_line_numbers": true,
594    "highlight_on_yank_duration": 50,
595    "custom_digraphs": {
596      "fz": "🧟‍♀️"
597    }
598  }
599}
600```
601
602## Useful core Zed settings for vim mode
603
604Here are a few general Zed settings that can help you fine-tune your Vim experience:
605
606| Property                | Description                                                                                                                                                   | Default Value        |
607| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
608| cursor_blink            | If `true`, the cursor blinks.                                                                                                                                 | `true`               |
609| relative_line_numbers   | If `"enabled"`, line numbers in the left gutter are relative to the cursor. If `"wrapped"`, they also display for wrapped lines.                              | `"disabled"`         |
610| scrollbar               | Object that controls the scrollbar display. Set to `{ "show": "never" }` to hide the scroll bar.                                                              | `{ "show": "auto" }` |
611| scroll_beyond_last_line | If set to `"one_page"`, allows scrolling up to one page beyond the last line. Set to `"off"` to prevent this behavior.                                        | `"one_page"`         |
612| vertical_scroll_margin  | The number of lines to keep above or below the cursor when scrolling. Set to `0` to allow the cursor to go up to the edges of the screen vertically.          | `3`                  |
613| gutter.line_numbers     | Controls the display of line numbers in the gutter. Set the `"line_numbers"` property to `false` to hide line numbers.                                        | `true`               |
614| command_aliases         | Object that defines aliases for commands in the command palette. You can use it to define shortcut names for commands you use often. Read below for examples. | `{}`                 |
615
616Here's an example of these settings changed:
617
618```json [settings]
619{
620  // Disable cursor blink
621  "cursor_blink": false,
622  // Use relative line numbers
623  "relative_line_numbers": "enabled",
624  // Hide the scroll bar
625  "scrollbar": { "show": "never" },
626  // Prevent the buffer from scrolling beyond the last line
627  "scroll_beyond_last_line": "off",
628  // Allow the cursor to reach the edges of the screen
629  "vertical_scroll_margin": 0,
630  "gutter": {
631    // Disable line numbers completely
632    "line_numbers": false
633  },
634  "command_aliases": {
635    "W": "w",
636    "Wq": "wq",
637    "Q": "q"
638  }
639}
640```
641
642The `command_aliases` property is a single object that maps keys or key sequences to vim mode commands. The example above defines multiple aliases: `W` for `w`, `Wq` for `wq`, and `Q` for `q`.
643
644## Regex differences
645
646Zed uses a different regular expression engine from Vim. This means that you will have to use a different syntax in some cases. Here are the most common differences:
647
648- **Capture groups**: Vim uses `\(` and `\)` to represent capture groups, in Zed these are `(` and `)`. On the flip side, in Vim, `(` and `)` represent literal parentheses, but in Zed these must be escaped to `\(` and `\)`.
649- **Matches**: When replacing, Vim uses the backslash character followed by a number to represent a matched capture group. For example, `\1`. Zed uses the dollar sign instead. So, when in Vim you use `\0` to represent the entire match, in Zed the syntax is `$0` instead. Same for numbered capture groups: `\1` in Vim is `$1` in Zed.
650- **Global option**: By default, in Vim, regex searches only match the first occurrence on a line, and you append `/g` at the end of your query to find all matches. In Zed, regex searches are global by default.
651- **Case sensitivity**: Vim uses `/i` to indicate a case-insensitive search. In Zed you can either write `(?i)` at the start of the pattern or toggle case-sensitivity with the shortcut {#kb search::ToggleCaseSensitive}.
652
653> **Note**: To help with the transition, the command palette will fix parentheses and replace groups for you when you write a Vim-style substitute command, `:%s//`. So, Zed will convert `%s:/\(a\)(b)/\1/` into a search for "(a)\(b\)" and a replacement of "$1".
654
655For the full syntax supported by Zed's regex engine [see the regex crate documentation](https://docs.rs/regex/latest/regex/#syntax).