Vim
Use when asked to write Vim/Neovim keybindings or config (.vimrc, init.vim, init.lua), explain Vim's modal editing model or motion/operator grammar, write Vimscript or Neovim Lua config, or debug plugin setups (vim-plug, packer.nvim, lazy.nvim).
Vim (and Neovim, its actively-developed fork) is a modal text editor: the same keys mean different things depending on the current mode. This is the one idea everything else builds on.
Modes
- Normal (the default,
Escalways returns here) — keys are commands, not text. - Insert (
i,a,o, …) — keys are literal text. - Visual (
v,V,Ctrl-v) — select a region (character/line/block), then apply an operator to it. - Command-line (
:) — ex commands (:w,:%s/.../.../g,:q).
The grammar: operator + motion (+ count)
Normal-mode commands compose as [count] operator {motion|text-object}. This is the core productivity idea — learn the pieces, not a list of memorized whole commands.
- Operators:
d(delete),c(change: delete + enter Insert),y(yank/copy),>/<(indent),=(reindent). - Motions:
w/b/e(word forward/back/end),0/^/$(line start/first non-blank/end),f{char}/t{char}(find/till a character on the line),gg/G(buffer start/end),{/}(paragraph). - Text objects (pair with an operator, not standalone motions):
iw/aw(inner/a word),i"/a",i(/a(,ip/ap(paragraph),it/at(tag).
Examples: dw deletes to the next word start. ci" deletes inside the quotes under the cursor and enters Insert. 3dd deletes 3 lines. d} deletes to the next paragraph break. . repeats the last change verbatim — the highest-leverage single key in Vim once you're composing edits this way.
Registers, marks, macros
- Registers hold yanked/deleted text:
"ayyyanks a line into registera;"appastes it. The unnamed register ("", default fory/d/p) is separate from the system clipboard ("+y/"+pon most builds). - Marks bookmark a position:
masets marka; `a `jumps to it exactly,'a` jumps to its line. - Macros record a command sequence:
qastarts recording into registera,qstops,@areplays it,10@areplays it 10 times,@@repeats the last-played macro.
Configuration
Vim: ~/.vimrc, Vimscript. Neovim: ~/.config/nvim/init.vim (Vimscript) or init.lua (Lua — the modern default for Neovim config and plugins).
" ~/.vimrc / init.vim (Vimscript)
set number relativenumber
set expandtab shiftwidth=2 tabstop=2
set ignorecase smartcase
nnoremap <leader>f :find<space>
-- init.lua (Neovim)
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.expandtab = true
vim.opt.shiftwidth = 2
vim.keymap.set('n', '<leader>f', ':find ', { desc = 'Find file' })
Plugin managers: Vim commonly uses vim-plug; Neovim commonly uses lazy.nvim (lazy-loaded, Lua-native) or the older packer.nvim.
-- lazy.nvim plugin spec
require('lazy').setup({
{ 'nvim-treesitter/nvim-treesitter', build = ':TSUpdate' },
{ 'neovim/nvim-lspconfig' },
})
Common pitfalls
mapvsnoremap. Plainmap/nmap/imapare recursive — if your new mapping's right-hand side matches another mapping, it triggers that one too, which surprises people. Default tonoremap/nnoremap/inoremapunless you specifically want recursive expansion.- Fighting Insert mode instead of leaving it. Reaching for arrow keys or long Backspace runs inside Insert mode is a sign the edit should have been a Normal-mode operator+motion instead — leave Insert (
Esc), do the edit, and only re-enter Insert if more typing is actually needed. :%s/foo/bar/gwithoutc. Add thecflag (:%s/foo/bar/gc) to confirm each substitution when you're not certain the pattern is scoped tightly enough.- Vimscript's line-continuation and
letscoping quirks when porting config from someone else's dotfiles — a bare variable in a.vimrcis global by default; uses:(script-local) orl:(function-local) prefixes deliberately.
Learn more
:help(or:Tutorfor the interactive tutorial) — the built-in reference; authoritative for the exact Vim/Neovim version installed.- Neovim documentation
- vim-plug, lazy.nvim, nvim-lspconfig
- Learn Vimscript the Hard Way — deep dive into Vimscript specifically.