Vim Cheatsheet

Search and Replace

Use this Vim reference while you build software engineering projects, review code, or refresh the syntax you reach for most.

Searching in a File

KeyAction
/patternSearch forward
?patternSearch backward
nNext match, same direction
NPrevious match
*Search forward for the word under the cursor
#Search backward for it
g* g#Same, but match partial words too
/ then EnterRepeat the last search
//e then EnterRepeat, but land on the end of the match
:nohClear the search highlight
:set hlsearch      " highlight all matches
:set incsearch     " jump as you type
:set ignorecase    " case insensitive…
:set smartcase     " …unless the pattern has an uppercase letter

Search is a motion, so it composes with operators: d/end deletes from the cursor up to the next "end", and y?start yanks back to the previous "start".

Search Offsets

SuffixCursor lands
/pat/eOn the last character of the match
/pat/e+1One past the match
/pat/b+2Two characters into the match
/pat/+1On the line after the match
/pat/-1On the line before it

Pattern Syntax

Vim's regex is its own dialect. The \v ("very magic") prefix makes it behave much more like PCRE.

PatternMatches
.Any character
*Zero or more of the previous atom
\+One or more (+ with \v)
\?Zero or one
\{2,5}Between 2 and 5
\{-}Zero or more, non-greedy
^ $Start / end of line
\< \>Start / end of word
|Alternation (| plain, ` with \v`)
\(…\)Group ((…) with \v)
\1Backreference to group 1
[abc]Character class
[^abc]Negated class
\d \DDigit / non-digit
\w \WWord character / non-word
\s \SWhitespace / non-whitespace
\a \l \uAlphabetic / lowercase / uppercase
\zs \zeSet the start / end of the match inside a larger pattern
\%VOnly inside the Visual selection
\c \CForce case insensitive / sensitive
/\vfoo|bar          " very magic: alternation without backslashes
/\v(\d{3})-(\d{4})  " groups without backslashes
/\vfunction\s+\w+   " a function declaration
/^\s*$              " a blank line
/\<the\>            " the word 'the', not 'there'
/config\zs\d\+      " match only the digits after 'config'
/\v^(\s*)\1         " a doubled indent
PrefixEscaping level
\vvery magic: most punctuation is special (closest to PCRE)
\mmagic (the default)
\Mnomagic: only ^ and $ are special
\Vvery nomagic: almost everything is literal

\V is the one to reach for when searching for a path or a URL full of slashes and dots.

Substitute

:s/old/new/            " first match on this line
:s/old/new/g           " every match on this line
:%s/old/new/g          " every match in the file
:%s/old/new/gc         " …confirming each one
:%s/old/new/gi         " case insensitive
:5,20s/old/new/g       " lines 5 to 20
:.,+10s/old/new/g      " this line and the next 10
:'<,'>s/old/new/g      " the last Visual selection
:.,$s/old/new/g        " here to end of file
:%s/old//gn            " count matches without changing anything
:%s//new/g             " reuse the last search pattern
:&&                    " repeat the last substitute with its flags
:%s/old/new/gI         " force case sensitive
FlagEffect
gEvery match on the line, not just the first
cConfirm each replacement
i / IForce case insensitive / sensitive
nReport the count, change nothing
eDo not error when there is no match

Substitution Replacements

In the replacementInserts
&The whole match
\0The whole match
\1 to \9Capture group n
~The previous replacement string
\u \lUppercase / lowercase the next character
\U \LUppercase / lowercase until \E
\EEnd a \U / \L run
\rA newline
\nA null byte (use \r for a line break)
\=exprThe result of a Vimscript expression
:%s/\vfoo(\d+)/bar\1/g          " foo42 becomes bar42
:%s/\v(\w+)\s+(\w+)/\2 \1/      " swap two words
:%s/\v<(\w)/\u\1/g              " capitalize every word
:%s/.*/\L&/                     " lowercase every line
:%s/,/\r/g                      " split on commas into lines
:%s/^/\=line('.').'. '/         " number the lines
:%s/\v(\d+)/\=submatch(1)*2/g   " double every number

Across Many Files

:grep -r "TODO" .           " search with the external grep
:vimgrep /TODO/ **/*.js     " search with Vim's own engine
:vimgrep /TODO/ `git ls-files`
:copen                      " open the quickfix list of results
:cnext  :cprev              " step through matches
:cfirst :clast
:cdo s/old/new/ge \| update " substitute in every quickfix FILE ENTRY
:cfdo %s/old/new/ge \| update  " substitute once per FILE
:argadd **/*.py             " build an argument list
:argdo %s/old/new/ge \| update " substitute across the arglist

:cdo and :argdo are how a project-wide rename gets done. The e flag stops the loop from aborting on files with no match, and update writes only the buffers that actually changed.

Quickfix and Location Lists

CommandAction
:copen / :ccloseOpen / close the quickfix window
:cnext / :cprevNext / previous entry
:cc 5Jump to entry 5
:cfirst / :clastFirst / last entry
:colder / :cnewerPrevious / next quickfix list
:lopen, :lnext, …The same, for the window-local location list
:makeRun makeprg and load the errors
:cexpr system('cmd')Load any command's output as a quickfix list

Quickfix is Vim's generic "list of file positions" and every tool that reports file:line:message can feed it, from compilers to linters to grep.