Vim Cheatsheet
Ex Commands and the Global Command
Use this Vim reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Ex Command Ranges
Every : command can take a range. Ranges are what turn one substitution into a project-wide edit.
| Range | Means |
|---|---|
:5 | Line 5 |
:. | The current line |
:$ | The last line |
:% | The whole file (same as 1,$) |
:5,20 | Lines 5 through 20 |
:.,+5 | Here and the next 5 lines |
:-3,. | The 3 lines above through here |
:'a,'b | From mark a to mark b |
:'<,'> | The last Visual selection |
:/start/,/end/ | From the next "start" to the next "end" |
:.,/end/ | Here to the next "end" |
:0 | Above the first line (for :put and :r) |
Moving and Copying Lines
| Command | Action |
|---|---|
:m 0 | Move this line to the top |
:m $ | Move it to the bottom |
:m +1 | Move it down one |
:m -2 | Move it up one |
:5,10m 20 | Move lines 5-10 to after line 20 |
:t . or :copy . | Duplicate this line below |
:1,5t $ | Copy lines 1-5 to the end |
:'<,'>m '>+1 | Move the selection down one line |
:d | Delete this line |
:5,10d a | Delete lines 5-10 into register a |
:y | Yank this line |
:normal dd | Run a Normal-mode command from Ex |
:%normal A; | Append a semicolon to every line |
Global Command
:g runs an Ex command on every line matching a pattern. It is the single most powerful command in Vim.
:g/pattern/cmd " run cmd on every matching line :v/pattern/cmd " run cmd on every NON-matching line :g!/pattern/cmd " same as :v
| Recipe | Does |
|---|---|
:g/TODO/d | Delete every line containing TODO |
:v/keep/d | Delete every line that does not contain "keep" |
:g/^$/d | Delete every blank line |
:g/^\s*$/d | Delete every whitespace-only line |
:g/pattern/normal dd | Same as :g/pattern/d, the long way |
:g/pattern/t $ | Copy every match to the end of the file |
:g/pattern/m 0 | Move every match to the top, reversing order |
:g/pattern/m $ | Move every match to the bottom, order preserved |
:g/pattern/s/old/new/g | Substitute only on matching lines |
:g/^/m 0 | Reverse the whole file |
:g/pattern/normal @a | Run macro a on every matching line |
:g/pattern/-1d | Delete the line above each match |
:g/pattern/+1d | Delete the line below each match |
:g/{/,/}/d | Delete every brace block |
:g/pattern/# | Print matching lines with numbers |
:g/pattern/y A | Collect every match into register a |
" Collect every import line into a register, then paste them elsewhere qaq " clear register a :g/^import/y A " append each match to a :$put a " dump them at the end " Number only the lines inside a list :g/^- /s/^- /\=line('.').'. '/
:v (invert) is underrated: "keep only the lines I care about" is usually shorter to express than "delete all the lines I do not".
Command-Line Mode Editing
| Key | Action |
|---|---|
Ctrl-r Ctrl-w | Insert the word under the cursor |
Ctrl-r Ctrl-a | Insert the WORD under the cursor |
Ctrl-r Ctrl-f | Insert the filename under the cursor |
Ctrl-r {reg} | Insert a register |
Ctrl-r = | Insert an expression result |
Ctrl-w | Delete the previous word |
Ctrl-u | Clear the line |
Ctrl-b / Ctrl-e | Start / end of the line |
Up / Down | History filtered by what you typed |
Ctrl-p / Ctrl-n | Unfiltered history |
Tab | Complete |
Ctrl-d | List the completion candidates |
Ctrl-f | Open the command-line window to edit history as a buffer |
q: | Same command-line window, from Normal mode |
q/ | The search history window |
The command-line window (q:) is a real buffer, so you can navigate your command history with normal motions, edit a long command comfortably, and press Enter to run it.
History and Repeat
:history " command history :history / " search history :history : " Ex command history @: " repeat the last Ex command @@ " repeat it again :@a " run register a as Ex commands :normal! @a " run register a as Normal-mode keys, ignoring mappings
Expressions
:echo line('.') " current line number :echo line('$') " last line number :echo col('.') " current column :echo expand('%') " current filename, relative :echo expand('%:p') " absolute path :echo expand('%:h') " directory :echo expand('%:t') " tail (basename) :echo expand('%:r') " root (no extension) :echo expand('%:e') " extension :echo getline('.') " text of the current line :echo getline(1,'$') " every line as a list :echo &filetype " an option's value :echo @a " a register's contents :echo bufnr('%') " current buffer number :echo strftime('%F') " today's date :echo system('git branch --show-current') :put =range(1,10) " insert the numbers 1 to 10 :put =strftime('%F') " insert today's date
Terminal Mode
:terminal " open a shell in a buffer :term ls -la " run one command in a terminal buffer :vert term " in a vertical split :term ++close cmd " close the window when the command exits
| Key | Action |
|---|---|
Ctrl-\ Ctrl-n | Leave Terminal mode for Normal mode |
Ctrl-w N | Same, in Vim |
i or a | Return to Terminal mode |
Ctrl-w : | Run an Ex command from Terminal mode |
Ctrl-w "{reg} | Paste a register into the terminal |
tnoremap <Esc> <C-\><C-n> " make Esc leave the terminal
Shell Escapes
:!cmd " run a shell command, show the output :!! " repeat the last shell command :sh " drop to a shell, `exit` to come back Ctrl-z " suspend Vim, `fg` to resume :!% " run the current file as a program :!node % " run the current file with node :silent !cmd " run without the press-Enter prompt :!git add % " stage the file you are editing
Ctrl-z then fg is the fastest round trip to a shell, since it reuses the shell that launched Vim instead of starting a new one.