A Vim banner

The Vim cheatsheet I keep coming back to

Every few months I watch someone open Vim on a server, panic, and reach for nano. And I must admit that, sometimes, it could be me. This is the cheatsheet I keep within arm’s reach instead: the commands I actually use daily as a developer, plus a handful of power techniques that turn Vim from “the editor I can’t quit” into the fastest tool in the terminal.

Modes: the mental model

Everything in Vim makes sense once you accept that it is a modal editor. You are always in a mode, and keys mean different things depending on which one. There are four you care about: Normal (move and operate), Insert (type text), Visual (select), and Command-line (run : commands).

State diagram of Vim modes: Normal in the center, with Insert, Visual and Command-line modes reached via i/v/: and left via Esc
KeyAction
iInsert before cursor
IInsert at line start
aAppend after cursor
AAppend at line end
oOpen new line below
OOpen new line above
vVisual character mode
VVisual line mode
Ctrl+vVisual block mode
EscReturn to Normal mode
:Enter Command-line mode

When in doubt, hit Esc. Normal mode is home base - every workflow below starts there.

Moving around

Motions are the vocabulary of Vim: every edit command below can be combined with them (delete + word = dw).

KeyAction
h j k l← ↓ ↑ β†’ (character)
w / WNext word / WORD start
b / BPrev word / WORD start
e / EWord / WORD end
0Start of line
^First non-blank char
$End of line
ggFirst line of file
GLast line of file
:NGo to line N
%Jump to matching bracket
{ / }Prev / next blank line
Ctrl+dScroll half-page down
Ctrl+uScroll half-page up
zzCenter cursor on screen

Editing

KeyAction
xDelete char under cursor
XDelete char before cursor
ddDelete (cut) current line
DDelete to end of line
dwDelete to next word
yyYank (copy) current line
ywYank word
pPaste after cursor
PPaste before cursor
ccChange entire line
cwChange word
CChange to end of line
rReplace single char
REnter Replace mode
~Toggle case of char
JJoin line below to current

Undo & redo

KeyAction
uUndo last change
UUndo all changes on line
Ctrl+rRedo
.Repeat last change

. is the most underrated key in Vim. Make a change once, then replay it anywhere with a single keystroke.

Search & replace

KeyAction
/patSearch forward for pattern
?patSearch backward for pattern
nNext match
NPrevious match
*Search word under cursor β†’
#Search word under cursor ←
:%s/old/new/gReplace all in file
:%s/old/new/gcReplace all with confirm
:s/old/new/gReplace in current line
:nohClear search highlight

Files, buffers, windows & tabs

Vim happily edits many files at once: buffers are open files, windows are views onto them, tabs are collections of windows.

A Vim session with two vertical windows showing folded C source code

File operations

KeyAction
:wWrite (save) file
:w fileSave as file
:qQuit
:q!Quit without saving
:wqSave and quit
ZZSave and quit (shortcut)
ZQQuit without saving (shortcut)
:e fileOpen / edit file
:r fileRead file into buffer
:waSave all open buffers
:qa!Close all, discard changes

Buffers & windows

KeyAction
:lsList open buffers
:bnNext buffer
:bpPrevious buffer
:bdDelete (close) buffer
:spSplit window horizontally
:vspSplit window vertically
Ctrl+w wCycle between windows
Ctrl+w h/j/k/lNavigate windows ← ↓ ↑ β†’
Ctrl+w qClose current window
Ctrl+w =Equalise window sizes

Tabs

KeyAction
:tabnewOpen new tab
:tabe fileOpen file in new tab
gtNext tab
gTPrevious tab
:tabcloseClose current tab
:tabonlyClose all other tabs

Visual mode

KeyAction
yYank selected
dDelete selected
cChange selected
>Indent selected right
<Indent selected left
~Toggle case of selected
uLowercase selected
UUppercase selected
:Run ex command on range
gvRe-select last visual

Marks & jumps

KeyAction
maSet mark a at cursor
`aJump to mark a (exact)
'aJump to mark a (line)
``Jump to previous position
Ctrl+oJump list - older
Ctrl+iJump list - newer
:marksList all marks

Macros & registers

KeyAction
qaRecord macro into register a
qStop recording macro
@aRun macro in register a
@@Repeat last macro
5@aRun macro a Γ— 5
:regShow all registers
"ayYank into register a
"apPaste from register a
"+yYank to system clipboard
"+pPaste from system clipboard

Text objects

Text objects are why ciw feels like magic: they describe what to operate on (inner word, inside quotes…), independent of where the cursor sits within it.

KeyAction
ciwChange inner word
cawChange around word
ci"Change inside quotes
ci(Change inside parens
ci{Change inside braces
ci[Change inside brackets
ditDelete inner HTML tag
yipYank inner paragraph
vasVisual select around sentence
vapVisual select around paragraph

Indentation & folding

KeyAction
>>Indent current line right
<<Indent current line left
=GAuto-indent to end of file
gg=GAuto-indent entire file
gqFormat/wrap selected text
zaToggle fold at cursor
zo / zcOpen / close fold
zR / zMOpen / close all folds

Useful Ex commands

The command line (:) is a full editor language of its own - and q: even opens a searchable history of everything you’ve typed there.

Vim’s command-line window showing a history of previously run Ex commands
KeyAction
:set nuShow line numbers
:set rnuRelative line numbers
:set icCase-insensitive search
:set pastePaste mode (no autoindent)
:syntax onEnable syntax highlighting
:! cmdRun shell command
:r !cmdInsert shell output
:sortSort selected lines
:g/pat/dDelete lines matching pattern
:v/pat/dDelete lines NOT matching

Power techniques

The tables above are the vocabulary. Here is the grammar - the combinations that pay for the learning curve.

Comment a block of lines with Visual Block

For # comments (Python / Bash / YAML) - works the same for // or --:

  1. Move to the first line to comment, in the first column.
  2. Enter Visual Block mode: Ctrl+v.
  3. Select down to the last line with j (or a count like 9j).
  4. Press I (capital i - insert at block start).
  5. Type #, then press Esc - the # appears on every selected line.

To uncomment: put the cursor on the # of the first line, Ctrl+v, select down with j, then x - the whole column of # disappears at once.

Comment a range with :norm

  1. Visually select lines (with V) or use a line range like :5,20.
  2. Run :'<,'>norm I# - inserts # at the start of each line.
  3. To uncomment: :'<,'>norm ^x - jumps to the first non-blank char and deletes it.

:norm replays any Normal-mode keystrokes on every line of a range. Pair it with anything - it’s bulk editing without recording a macro.

Append text to the end of multiple lines

  1. Visual Block: Ctrl+v, select lines with j.
  2. Press $ to extend the selection to each line’s end.
  3. Press A, type your text, press Esc.

Example: append a comma to 10 lines for a quick CSV fix - Ctrl+v β†’ 9j β†’ $ β†’ A β†’ , β†’ Esc.

Increment numbers in a column

  1. Visual Block: Ctrl+v, select the number column.
  2. g Ctrl+a - sequentially increments each number (1, 2, 3…); Ctrl+a alone increments all by 1.
  3. g Ctrl+x - sequentially decrements.

Global search and execute

  • :g/TODO/d - delete every line containing TODO.
  • :g/def /norm O# --- - insert a banner before every Python function.
  • :v/import/d - keep only lines matching import (inverse global).

Dot-repeat a change across the file

  1. Make the change once (e.g. ciw β†’ type replacement β†’ Esc).
  2. Jump to the next target with n.
  3. Repeat with . - iterate n . n . through the file.

More surgical than :%s///g - you eyeball each occurrence before applying.

Sort and deduplicate

  • :sort - sort selected lines alphabetically; :sort! reverses.
  • :sort u - sort and remove duplicates.
  • :sort n - sort numerically.

Run a macro on every matching line

  1. Record the macro into register q: qqq.
  2. Run :g/pattern/norm @q - executes it on every matching line.

:wq - write. quit. ship it.


Images: Vim logo (GPL) and Vim modes diagram by Harp (CC BY-SA 4.0); split-window screenshot (GPL) and command-history screenshot by Vitaly Zdanevich (CC0) - all via Wikimedia Commons.