Vim mode in Zed: setup, keys and settings
Zed has Vim mode built in: tick the Vim mode checkbox on the welcome screen, run workspace: toggle vim mode from the command palette, or add "vim_mode": true to your settings. Motions, operators, text objects, macros and many : commands work, plus Zed-specific keys such as gd for go to definition and cd for rename. Customise keys in keymap.json with contexts like vim_mode == insert.
| Keys | What they do |
|---|---|
| gd / gD | Go to definition / declaration |
| gy / gI | Go to type definition / implementation |
| cd | Rename the symbol (language server) |
| gA | All references to the symbol |
| gs / gS | Symbols in this file / in the project |
]d / [d | Next / previous diagnostic |
| gh / g. | Show the error under the cursor / code actions |
]c / [c | Next / previous git change |
| gl / gL | Add a cursor at the next / previous copy of the word |
| ga | Select every copy of the visual selection |
| af / if, ac / ic | Function and class text objects (Tree-sitter) |
| ia / aa | Argument text object, without / with its trailing comma |
Turn on Vim mode
Three ways, all doing the same thing:
- First launch: tick the Vim mode checkbox on the welcome screen.
- Command palette: run
workspace: toggle vim mode. - Settings file: add
"vim_mode": trueto your user settings.
Esc takes you back to Normal mode as usual. For relative line numbers, set Zed's core "relative_line_numbers" to "enabled", or use the Vim setting toggle_relative_line_numbers (below) to have them only in Normal mode.
Vim settings worth changing
Vim options go in a "vim" object in your settings:
"use_system_clipboard":"always"(the default),"never", or"on_yank". Unlike Vim, Zed uses the system clipboard by default; pick"never"if you want yanks to stay inside the editor."use_smartcase_find": makes f and t case-insensitive when the letter you type is lowercase. Off by default."toggle_relative_line_numbers": relative numbers in Normal mode, absolute in Insert mode. Off by default."highlight_on_yank_duration": how long a yank is highlighted, in milliseconds (200 by default; 0 turns it off)."gdefault": makes:sreplace every match on a line by default; thegflag then flips it back. Off by default."default_mode": the mode new editors start in,"normal"by default.
One core setting matters too: "command_aliases" maps names you type at the : prompt to Zed commands, for example "W": "w".
Customise keys: jk to Escape and more
Key bindings live in Zed's keymap.json (~/.config/zed/keymap.json on macOS and Linux); run zed: open keymap file from the command palette to open it. It holds an array, and each entry has a "context" that says when it applies and a set of "bindings". For j k to leave Insert mode, add this entry to the array:
{"context": "vim_mode == insert","bindings": { "j k": "vim::NormalBefore" }}
The contexts that matter for Vim are vim_mode == normal, visual, insert, replace, waiting and operator, and VimControl, which covers Normal, Visual and Operator-pending together. Combine them with && and ||, for example "Editor && vim_mode == normal".
The Zed docs include ready-made snippets for the most common requests: Ctrl-w with h j k l to move between docks and panes, subword motions for w, b and e (vim::NextSubwordStart and friends), s as a sneak motion (vim::PushSneak) instead of substitute, and giving Ctrl-c, Ctrl-v and Ctrl-f back to Zed.
Plugins you get for free
Zed has its own versions of several favourite Vim plugins, on by default:
- Surround: ys, cs and ds, as in vim-surround.
- Comment: gcc in Normal mode, gc in Visual mode, as in vim-commentary.
- ReplaceWithRegister: gR. Exchange: cx.
- Indent navigation:
[-,]-,[+,]+,[=,]=jump by indentation level, as in vim-indentwise. - Tree-sitter motions:
]mand[mfor the next and previous method,]]and[[for sections,]/for comments. - Insert mode completion: Ctrl-x Ctrl-o for completions, Ctrl-x Ctrl-l for code actions.
Warm up: a text object and a comment
Two things Zed's Vim mode does out of the box. Change the string with ci" (change inside the quotes), then comment out the debug line with gcc.
This editor needs a keyboard. Read on, and play it at your computer.
Which colon commands work
Zed's command line covers the everyday ones: :w, :wq, :q, :wa, :qa, :x, :up, splits (:sp, :vs, :new, :vne), tabs (:tabnew, :tabn, :tabp, :tabc), :bd and :ls. It also has jumps (:42, :$, :/foo), :s with ranges, :j, :d, :y, :sort and :sort i, and :set for wrap, number, relativenumber and ignorecase. Commands such as :E (explore), :te (terminal) and :G (git) open Zed's own panels.
What it doesn't do is take arguments: you can't name a file in :w newname.txt, and most of Vim's command-line power isn't emulated.
Known differences from Vim
The Zed docs are upfront that Vim mode is not a one-to-one copy:
- Language-aware motions. Zed uses its own semantics in places: in Rust, % also jumps between matching
|characters, and w treats$as part of a word in JavaScript. - Visual block mode is emulated with multiple cursors, so text you insert appears on every line as you type rather than when you press Esc.
- Macros use Zed's own recording, which can capture actions such as accepting a completion.
- Regex in search and
:suses(and)for groups instead of\(and\), and$1instead of\1in replacements. Searches are global by default. - No vimrc and no Vim plugins. All configuration goes through Zed's settings and
keymap.json.
For most editing, none of this gets in the way. The motions are the same as in Vim, and the course teaches them in a real editor in the browser.
The keys behind the differences
Each of these works in Zed, with the differences described above. Type them from memory.
Questions
- How do I turn off Vim mode in Zed?
- Run
workspace: toggle vim modefrom the command palette, or set"vim_mode": falsein your settings. - How do I map jk to Escape in Zed?
- In
keymap.json, add an entry with"context": "vim_mode == insert"and"bindings": { "j k": "vim::NormalBefore" }. - Does Zed vim mode read my .vimrc?
- No. Zed reads its own settings and
keymap.json. Vim options go in the"vim"settings object, and mappings go inkeymap.jsonwith a Vim context.