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
| Key | Action |
|---|---|
/pattern | Search forward |
?pattern | Search backward |
n | Next match, same direction |
N | Previous match |
* | Search forward for the word under the cursor |
# | Search backward for it |
g* g# | Same, but match partial words too |
/ then Enter | Repeat the last search |
//e then Enter | Repeat, but land on the end of the match |
:noh | Clear 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
| Suffix | Cursor lands |
|---|---|
/pat/e | On the last character of the match |
/pat/e+1 | One past the match |
/pat/b+2 | Two characters into the match |
/pat/+1 | On the line after the match |
/pat/-1 | On 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.
| Pattern | Matches | |
|---|---|---|
. | 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) | |
\1 | Backreference to group 1 | |
[abc] | Character class | |
[^abc] | Negated class | |
\d \D | Digit / non-digit | |
\w \W | Word character / non-word | |
\s \S | Whitespace / non-whitespace | |
\a \l \u | Alphabetic / lowercase / uppercase | |
\zs \ze | Set the start / end of the match inside a larger pattern | |
\%V | Only inside the Visual selection | |
\c \C | Force 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
| Prefix | Escaping level |
|---|---|
\v | very magic: most punctuation is special (closest to PCRE) |
\m | magic (the default) |
\M | nomagic: only ^ and $ are special |
\V | very 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
| Flag | Effect |
|---|---|
g | Every match on the line, not just the first |
c | Confirm each replacement |
i / I | Force case insensitive / sensitive |
n | Report the count, change nothing |
e | Do not error when there is no match |
Substitution Replacements
| In the replacement | Inserts |
|---|---|
& | The whole match |
\0 | The whole match |
\1 to \9 | Capture group n |
~ | The previous replacement string |
\u \l | Uppercase / lowercase the next character |
\U \L | Uppercase / lowercase until \E |
\E | End a \U / \L run |
\r | A newline |
\n | A null byte (use \r for a line break) |
\=expr | The 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
| Command | Action |
|---|---|
:copen / :cclose | Open / close the quickfix window |
:cnext / :cprev | Next / previous entry |
:cc 5 | Jump to entry 5 |
:cfirst / :clast | First / last entry |
:colder / :cnewer | Previous / next quickfix list |
:lopen, :lnext, … | The same, for the window-local location list |
:make | Run 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.