Vim Cheat Sheet
Table of Contents:
- Saving & Exiting Vim
- Navigation
- Editing
- VISUAL mode
- Text Objects
- Search & Replace
- Macros
- Marks
- Files and Windows
- Tabs
- Terminal
- Spellcheck
- Misc Commands
- Ctrl-R and the Expression Register
- Comparing buffers with vimdiff
- Folding
Saving & Exiting Vim
|
|
NOTE: the :cq command is useful in situations when we need to exit-cancel, for example when running <Esc>v in bash shell set -o vi, when exiting using :cq the command won’t be executed automatically. Another example is when exiting the output window of git rebase, :cq will cancel the rebase operation.
Navigation
Movement
|
|
|
|
Note: When navigating lines with hjkl^$, if a line is too long and is wrapped, pressing j will move down to the next line even if the current line is wrapping 2 or more lines, to go down 1 “visual” line use gj instead. The g prefix works the same for other navigation commands hjkl^$ (g^ and g$ for start and end of visual line). A very useful mapping is to map <up><down> or jk to move by visual lines as long as they aren’t prefixed with {count} so we can still use up and down motions (e.g. 10j) for whole lines:
nnoremap <expr> <Down> (v:count == 0 ? 'g<down>' : '<down>')
vnoremap <expr> <Down> (v:count == 0 ? 'g<down>' : '<down>')
nnoremap <expr> <Up> (v:count == 0 ? 'g<up>' : '<up>')
vnoremap <expr> <Up> (v:count == 0 ? 'g<up>' : '<up>')Scrolling
|
|
Editing
Insert & Exit
|
|
Undo & Repeat
|
|
Basic Editing
|
|
Notes:
-
All (c)hange commands end with the editor in INSERT mode
-
All double-char commands (i.e.
dd,cc,yy, etc) can be thought of as a shortcut to0{operator}$, the breakdown is as follows:
|
|
- The above can also be combined with a {count} prefix, for example 2dd will delete 2 lines below. A similar result could also be achieved using the full expression of the operator and motion:
{operator}{count}{motion}, i.e.d1jwill delete 2 lines down (cursor line + 1 down) andy2wwill yank 2 words forward. In similar fashion the VISUAL mode operatorvcan be used, e.g.vi}will visually select everything inside the curly braces.
INSERT mode
|
|
Note: Any NORMAL mode motion can be run from INSERT mode by using <ctrl-o>{op} or <alt+{op}> (only works on some keyboards). Alternatively, if we’re in ex mode we can use :norm {cmd}. For example: say we want to append text at the end of the line we can simply press <alt+A> or <ctrl-o>A which will take us to the end of the line, all without leaving INSERT mode. The same can be achieved from ex mode with <Esc>:norm A, even though the latter isn’t useful for this specific example it can be useful in many other cases where more complex commands are required (e.g. using the global command: :g/regex/norm >> will indent all lines matching the regex)
Cut, copy and paste
|
|
Copy paste using ex mode:
|
|
Notes:
-
To paste a register directly from INSERT or ex mode use
<ctrl-r>followed by a register name. -
By default the
Ycommand is mapped toyy(yank line) which isn’t consisnt with the behaviors ofCandD(from cursor to end of line), a very useful mapping for both NORMAL and VISUAL mode is:
|
|
- By default all modification operators
d c xcopy the modified text to the unnamed"register (unlessset clipboardwas set) which can be confusing at first. For example, let’s say we want to overwrite a word with yanked text, we would naturally dociw<Esc>porciw<ctrl-r>"only to find out the same word would be pasted (and not our yanked text), to work around that we can tell thecoperator to copy the text into the ‘blackhole’ register instead:"_ciw. Alternatively we can also use the yank register0which contains the content of the last yank operation using"0por"0P(to paste before the cursor). A few useful mappings for my leader key (by default\, personally I use\<space>) are below, so if I want to change a word without it polluting my registers I would run<leader>bciw, similarly if I wish to delete a line I would run<leader>dd:
|
|
- In addition to being copied to the default register (
"or*), every ‘deleted’ text is also copied into the ‘small delete’ registers {1-9}. To view the latest deletes run:reg[isters]or:di[splay]. A neat trick to cycle through the delete registers is to use"1pand then runu., the undo+repeat advances the ‘pasted register’ so it will perform"2p,"3pand so forth.
VISUAL mode
Selections
|
|
Notes:
-
The above are just some of the available commands as any text object or motion can be used, e.g.
viwwill visually select current word orvatwill select an entire tag:<a>some text</a> -
A neat trick you can do with VISUAL mode is using visual modes as motion operators, If you perform
d2j, it will delete all three lines. That’s becausejis a linewise motion. If you instead pressedd<c-V>2j, it would convert the motion to blockwise and delete just the column characters instead. For more information read Hillel Wayne’s blog: At least one Vim trick you might not know. -
VISUAL mode has a nice feature to expand selection based on blocks, say we wanted to select the inside of an
ifcondition in C, we do so withvi(orvi), if we wanted to expand the selection to the outer block we can just runi{ori}(without having to cancel the selection and pressvagain).
Operators
|
|
Notes:
-
Some operators, namely the repeat
.and pastepPoperators have unique behaviors when used after a VISUAL ‘block’ mode edit, that is extremely useful when editing text as blocks. Say we wanted to append semicolon to the end of a paragraph we could simply do<ctrl-v>}A;<Esc>we can then repeat the operation using.which will replicate the change to the same block range under the cursor. Similarly we can use the paste before and after the cursorpandPto paste entire columns, the following will duplicate the first column of a paragraph:<ctrl-v>}ypwhich you can easily undo as an atomic operation withu. -
If you want to preform an {ex} command on visual selection press
:(with selected visuals), vim will automatically prefix your ex command with the visual range:'<,'>so you can execute any command on the selected text, e.g.:'<,'>norm @qwill execute macroqon all visually selected lines. -
A shortcut to the above can be done with the bang
!operator, this will automatically put is in ex command mode with the visual selection already entered, the equivalent of:'<,'>!ready for entering a command, this is useful in many situations, for example to sort a visual block we can just doviB!sortwhich is the equivalentviB:!sort. The same can also be done from NORMAL mode using!iBsort. -
When indenting (or any other operation) in VISUAL mode with
<>you will find that once indented you lose the current selection, to visually reselect the text you can usegv, so to indent while keeping current selection use<gvand>gvrespectively. Personally I never want to lose my selection when indenting hence I use the below mappings in my keymaps:
|
|
Text Objects
|
|
Notes:
-
Text objects can be used with any operator, e.g.
ditwill delete “some text” from<a>some text</a>andyatwill copy the entire tag into the clipboard. For more information Jared Caroll’s: Vim Text Objects: The Definitive Guide. -
gnis a very useful text object, few examples:cgnwill change the next search pattern match,vgnwill visually select all text from the cursor to the next match. For more information read Bennet Hardwick’s blog: 8 Vim tips and tricks for advanced beginners. -
Any text object can also be used with a count. For example, we have the below text (cursor at ^):
|
|
If we run di) we will delete all 3 parameters. However we can also run d2i( to delete inside the parent parenthesis, thus deleting the entire condition and resulting in the text if () {. I found this very useful tip (and others) in Antoyo’s blog.
Search & Replace
|
|
Notes:
-
You can repeat the last substitute interactively with
g& -
For more information on the different
.../gmodifiers read:help s_flags -
For more information on the “very magic” pattern read Vim fandom: Simplifying regular expressions using magic and no-magic.
-
The
gandvex commands are extremely useful, few examples::g/pattern/dor:g/pattern/norm ddwill delete all lines matchingpattern, you can also supply a range to the command::g/pattern/-1dwill delete one line above all lines matchingpattern, same can be achieved with:g/pattern/norm 1jdd -
:y {reg}copies the range to the register {reg}. If {reg} is a capital letter register, this appends to the existing register, i.e. if we dolet @a = '' | %g/regex/y Ait will copy all lines matching regex in the entire file to register a. We can then copy the register to the system clipboard withlet @+ = @a. -
Important note regarding the use of
:svs:g:sis a shortcut forsubstituteandgis a shortcut forglobal, thereforesshould be used when doing search and replace (substitution) andgshould be used when you’d like to execute a command for every match (not necessarily substitution), each has it’s strength and it’s a matter of using the right tool for the job. Example: say we wanted to substitutebarwithblahfor every line containingfoo, we could achieve the same result with both but as you can see thegcommand would be a better fit in this case:
|
|
REGEX Examples
Search examples
|
|
Substitution examples
|
|
Multiple Files
To learn more I recommend watching Drew Neil: Searching Multiple Files with vimgrep
|
|
When just starting to use vim search and replace an entire project at first seems overly complex, plugins can definitely help here (fzf comes to mind) but once you understand how to use the quickfix list it’s actually quite easy.
Vim comes builtin with the vimgrep utility which searches for a regex patter
and populates the quickfix list accordingly. From there, you can manipulate
matches using the cdo|cfdo combo.
Searching the project is as easy as:
|
|
Personally I prefer to use :grep in conjunction with the
rg utility, to do so add the below
to your init.vim:
|
|
And then run the same search:
|
|
From here it’s very easy to search and replace all matches with any substitute command:
|
|
Macros
|
|
Notes:
-
Macros are essentially just a saved series of keystrokes, if you’re recording a macro and make a mistake, don’t start over, instead, undo it and keep going normally, using macro
qas an example (recorded withqq), once you’re finished with the macro, press"qpto paste it to an empty line, remove the mistaken keystrokes and the undo and copy it back into theqregister with"qy$. -
Don’t leave undos in your macro. If you undo in a macro to correct a mistake, always be sure to manually remove the mistake and the undo from the macro. In replay mode, an undo will undo the entire macro up until that point, erasing all of your hard work and bleeding the macro out into the rest of your text.
-
The above was taken from Hillel Wayne’s blog: Vim Macro Tricks.
-
Alternatively, you can resume recording a macro using the capitalized version of the registers, say we started recording into the
qregister withqqwe can “pause” the macro recording withqand later resume recording withqQ(note the capitalizedQ). -
Macros are not limited to the current buffer, if you wish to transform text between windows just add a windows switch command to your macro (e.g.
<ctrl-w>w). This makes it very useful to mass manipulate text between different buffers. -
A neat trick to running macros quickly is to use the
.register which is the last inputed text. Let’s say we want to run a macro that does the simple task of transposing two adjacent charactersxp, what we can do is enter INSERT mode, enter the macro keys, pressufor undo and then execute the macro with@., thus the entire sequence equalsixp<Esc>uand now we can run our macro with@.. Alternatively, if you’d like your macro to contain a<cr>(down one line) you can runO~$~<Esc>ddand then run the macro with2@"(since our text was ‘cut’ into the default register) - this will toggle capitalization of the first and last character in 2 subsequent lines. -
Building on the above, the same
xpmacro can be run using the expression register by running@='xp'and then repeat the macro execution with@@. You can run more complex commands using the full format{count}@='[commands]'. For example, running3@='v2<ctrl-a>w'on the text1 5 8will increment each digit by 2 resulting in3 7 10. This example is equivalent toqqv2<ctrl-a>wq2@q: which records the edit to macroqand then executes it two more times. (note: if you wish to input special characters (<Esc>,<CR>, etc.) in the command line, prefix the special character with<ctrl-v>e.g.<ctrl-v><Esc>.
Recursive Macros
A recursive macro, as the name suggests, is a macro that calls itself, in Vim, the call is usually done at the end of the macro, so a recursive macro will usually end with a call to itself @q followed by q to stop the macro recording. A simple recursive macro that deletes all vimscript comments in an entire buffer would look like this:
|
|
If you wish to test your macro before executing on the entire buffer you can take advantage of appending to a register using a capitalized register letter, let’s re-do our example from above while also testing our macro:
|
|
As you can see from above, recursive macros can be very useful if you wish to run a macro on the entire buffer without having to worry about the number of times required to run the macro, it’s similar to running 9999@q (in a file with less than 9999 lines). Note that this is different than running the ex command :%norm @q, in the latter case the macro would run on the entire buffer regardless if there are some lines with errors (e.g. can’t find the "), this gives us the flexibility to choose between the two approaches, if we want to run until failure we use a recursive macro, if we wish to run on the entire buffer regardless of errors we use the :%norm @{reg} or :0,$norm @{reg} variant.
Note: It is VERY IMPORTANT to clean the destination register (q in our case) by running q{reg}q before we start the recording, the reason for this is when you’re recording the macro for first time you are also running it when you’re adding the recursion call @q, if our register isn’t empty the register commands will be executed and most likely mess up our edit.
Marks
|
|
Files and Windows
|
|
Notes:
-
:bufdoand:windocan be used for multiple file/window operations, for example to search and replace in all open buffers you can run:bufdo %s/old/new/g -
:findandgfare both dependent on the&pathvariable which by default contains.which is the current working directory (:pwd), for said commands to be effective be sure to always open Vim from your project directory or usecdto change Vim’s working directory (best done usingcd %:h). If you would like:findandgfto find files recursively in all folders specified by&pathbe surepathcontains**. Use:set path+=**if you wish to add**to the current&path. Personally, I define my path as:set path=.,,,$PWD/**(search current directory and project directory recursively).
Tabs
|
|
Terminal
Vim:
|
|
Neovim:
|
|
Both:
|
|
Spellcheck
|
|
Misc commands
|
|
|
|
Ctrl-R and the Expression Register
The expression register (=) is used to evaluate expressions and can be accessed using "= from NORMAL and VISUAL modes and <ctrl-r> from INSERT and ex command modes, it is very useful to insert registers and other input into the command line or directly to the document when you don’t want to leave INSERT mode (useful so you can repeat the entire edit with .):
INSERT and ex modes:
|
|
NORMAL and VISUAL modes:
|
|
Notes:
-
For more information on evaluating expressions
:help expression. For even more information read Aaron Bieber’s: Master Vim Registers With Ctrl R and watch Vimcasts: Simple calculations with Vim’s expression register calculations with Vim’s expression register -
When inserting a register with
<ctrl-r>{reg}and then repeating the edit with.you will find out that same text will be entered even if the register contents has changed, to have the actual command enter the.register we need to use<ctrl-r><ctrl-o>{reg}instead. Best shown with an example, say we have the below text and we wish to add parens around the text
|
|
We can modify the first line using ciw(<ctrl-r>+) which will result in “(one)” but when we repeat the action for “two” the result would still be “(one)” as the actual text is saved in the register. To circumvent this we can use ciw(<ctrl-r><ctrl-o>+) instead which inserts the actual command ^R^O+ into the register, that way when we repeat the action with . the result would be as expected “(two)”.
- For more information regarding
<ctrl-r><ctrl-o>read:help i_ctrl-r_ctrl-oand watch Drew Neil’s vimcast: Pasting from INSERT mode
Comparing buffers with vimdiff
|
|
NOTE:
-
The shortcuts
doanddpalso run:diffupdate, so the equivalent ofdpcan be thought of as:diffput {target buffer} | diffupdate -
{targetbuffer}above is automatically resolved as the ‘other buffer’ on a 2-way split, that works for bothdoanddp. However,docannot sensibly decide which buffer to use in a 3-way split (git merge conflict resolution) and therefore cannot be used in this case.dpassumes we always want to ‘push’ changes to the working copy which is always the middle buffer and therefore can be used in a 3-way split from either the left (target) or right (merge) buffers.
Folding
Fold methods (set with set foldmethod=<method>:
|
|
|
|
Fold management when foldmethod is set to manual or marker:
|
|