└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # iBhagwan's (n)vim cheatsheet 2 | 3 | \*\*This cheatsheet was inspired by [Hackjutsu's Vim cheatsheet](https://github.com/hackjutsu/vim-cheatsheet) and Laurent Gregoire's excellent [Vim Quick Reference Card](http://tnerual.eriogerg.free.fr/vimqrc.html). 4 | 5 | I've been using vi for over 20 years but always limited it's use for basically only editing \*nix system config files, recently I (re-)discovered (n)vim as the magical editor that it is and decided to make it my main editor for coding, writing markdown and the likes so down the rabbit hole I went. The more I researched the more I fell in love with the software, the below is the accumulation of all my notes and findings. 6 | 7 | The cheatsheet assumes at least minimal understanding of motions and operators, to better understand motions, operators and how it all comes together in what is referred to as "the vim language" I highly recommend reading [Jim Denis's stackoverflow answer: Your problem with Vim is that you don't grok vi](https://gist.github.com/nifl/1178878). 8 | 9 | Note that everything below works with vanilla vim/nvim and does not require the use of any plugins. I am not opposed to plugins and even use a few which I find extremely helpful but as a philosophy I try to use as much built-in functionality (with minimal keymap changes) as I can before turning to plugins. As you can see below there is **so much** you can do with vanilla Vim that I decided to leave plugins out of the scope of this document. If you'd like to take a look at my custom mappings and plugins, refer to my nvim lua configuration at [nvim-lua](https://github.com/ibhagwan/nvim-lua). 10 | 11 | If you'd like to take your Vim to the next level, I highly recommend watching all of [Drew Neil's VimCasts](http://vimcasts.org/episodes/page/8/) they are absolutely wonderful and will blow your mind. When you're ready to jump in the water and test your skills [Vimgolf](http://www.vimgolf.com) is fantastic exercise which will cement all your Vim knowledge and add new tricks to your arsenal. Download [Vimgolf client from here](https://github.com/igrigorik/vimgolf) or it's [lesser known python client by Daniel Stein](https://github.com/dstein64/vimgolf) if you wish to avoid the ruby dependencies. 12 | 13 | **Thanks to [/u/-romainl-](https://www.reddit.com/user/-romainl-/) for [his great feedback](https://www.reddit.com/r/vim/comments/gha79v/i_wrote_an_advanced_comprehensive_cheatsheet_for/fq7qeop?utm_source=share&utm_medium=web2x) correcting previous inaccuracies.** 14 | 15 | 16 | ### Table of contents: 17 | 18 | - [Saving & Exiting Vim](#saving-exiting-vim) 19 | - [Navigation](#navigation) 20 | + [Movement](#movement) 21 | + [Scrolling](#scrolling) 22 | - [Editing](#Editing) 23 | + [Insert & Exit](#insert-exit) 24 | + [Undo & Repeat](#undo-repeat) 25 | + [Basic Editing](#basic-editing) 26 | + [INSERT mode](#insert-mode) 27 | + [Cut, copy & paste](#cut-copy-and-paste) 28 | - [VISUAL mode](#visual-mode) 29 | + [Selections](#selections) 30 | + [Operators](#operators) 31 | - [Text Objects](#text-objects) 32 | - [Search & Replace](#search-replace) 33 | + [REGEX Examples](#regex-examples) 34 | + [Multiple Files](#multiple-files) 35 | - [Macros](#macros) 36 | + [Recursive Macros](#recursive-macros) 37 | - [Marks](#marks) 38 | - [Files and Windows](#files-and-windows) 39 | - [Tabs](#tabs) 40 | - [Terminal](#term) 41 | - [Spellcheck](#spellcheck) 42 | - [Misc Commands](#misc-commands) 43 | - [Ctrl-R and the Expression Register](#ctrl-r-and-the-expression-register) 44 | - [Comparing buffers with vimdiff](#comparing-buffers-with-vimdiff) 45 | - [Folding](#folding) 46 | 47 | ## Saving & Exiting Vim 48 | ```vim 49 | :w " write the current file 50 | :w {file} " write to {file} 51 | :wq {file} " write to {file} and quit 52 | :saveas {file} " write to {file} 53 | :update {file} " write only if buffer was modified 54 | :w !sudo tee % " write the current file using sudo 55 | :wq :x ZZ " write the current file and quit 56 | :q " quit (fails if there are unsaved changes) 57 | :q! ZQ " quit and throw away unsaved changes 58 | :cq " quit Vim with exit code 59 | ``` 60 | 61 | **NOTE:** the `:cq` command is useful in situations when we need to exit-cancel, for example when running `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. 62 | 63 | ## Navigation 64 | ### Movement 65 | ```vim 66 | k " up 67 | h l " left, right 68 | j " down 69 | ``` 70 | ```vim 71 | + - " first non-blank char line above, below 72 | H M L " [H]igh, [M]iddle, [L]ow line of the window 73 | {n}H {n}L " line {n} from the top, bottom of the window 74 | b w " beginning of word left, right (punctuation considered words) 75 | B W " beginning of WORD left, right (spaces separate words) 76 | e ge " end of word left, right (punctuation considered words) 77 | E gE " end of WORD left, right (spaces separate words) 78 | 0 g0 " start of the line, visual-line 79 | ^ g^ " first non-blank character of the line, visual-line 80 | $ g$ " last character of the line, visual-line (include ) 81 | _ g_ " first, last non-blank character of the line (not including ) 82 | {n}_ " down {n-1} lines on first non-blank character 83 | gm " middle of the line 84 | {n}gg {n}G " goto line {n}, default first, last line of buffer 85 | :{n} " goto line {n}, (ex mode) 86 | {n}% " jump to buf % (e.g. 50% jump to middle of buffer) 87 | {n}| " jump to screen column {n} of current line 88 | f{c} F{c} " next, previous occurrence of character {c} 89 | t{c} T{c} " before ([t]ill) next, previous occurrence of {c} 90 | ; , " repeat last fFtT in the same, opposite direction 91 | ( ) " previous, next sentence (jumps after the next '.' or EOL) 92 | { } " previous, next paragraph (jumps to next empty line) 93 | % " jump to matching parenthesis ([{}]) 94 | [[ ]] " backward, forward start section 95 | [] ][ " backward, forward end of section 96 | [( ]) " backward, forward unclosed (, ) 97 | [{ ]} " backward, forward unclosed {, } 98 | ``` 99 | **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 `` 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: 100 | 101 | ``` 102 | nnoremap (v:count == 0 ? 'g' : '') 103 | vnoremap (v:count == 0 ? 'g' : '') 104 | nnoremap (v:count == 0 ? 'g' : '') 105 | vnoremap (v:count == 0 ? 'g' : '') 106 | ``` 107 | 108 | ### Scrolling 109 | ```vim 110 | zz or z. " center screen on cursor 111 | zb or z- " scroll the screen so the cursor is at the (b)ottom 112 | zt or z " scroll the screen so the cursor is at the (t)op 113 | zh zl " scroll one character to the left, right 114 | zH zL " scroll half screen to the left, right 115 | " move back one full screen 116 | " move forward one full screen 117 | " move forward 1/2 a screen 118 | " move back 1/2 a screen 119 | " scroll the screen up 120 | " scroll the screen down 121 | " jump to previous location in :jumps 122 | " jump to next location in :jumps 123 | `` " jump to last jump location 124 | `. " jump to last edit location 125 | '. " jump to start of line of last edit 126 | g; g, " cycle backwards, forwards in `:changes` (edit locations) 127 | ``` 128 | 129 | ## Editing 130 | ### Insert & Exit 131 | ```vim 132 | " exit insert mode 133 | " exit insert mode 134 | i a " insert before, after the cursor 135 | I A " insert at beginning, end of line 136 | gi gI " insert at last insert location, first column 137 | o O " open a new line below, above the current line 138 | R " enter REPLACE mode, cursor overwrites everything 139 | gR " like R but without affecting layout 140 | ``` 141 | 142 | ### Undo & Repeat 143 | ```vim 144 | u U " undo last command, restore last changed line 145 | " redo 146 | . " repeat last edit 147 | {n}. " repeat last edit {n} times 148 | ``` 149 | 150 | ### Basic Editing 151 | ```vim 152 | x X " delete a single character under, before cursor 153 | {n}x {n}X " repeat x, X {n} times 154 | r{c} " replace character under cursor with {c} 155 | gr{c} " like r, without affecting layout 156 | ~ " switch case a single character 157 | g~{m} " switch case of motion {m} (i.e. `g~iw~` for word) 158 | gu{m} gU{m} " lower, upper case of motion {m} 159 | J gJ " join current line with next, without space 160 | dd D " delete (cut) entire line, to end of line 161 | dw " delete (cut) to the next word 162 | cc C " change (replace) entire line, to end of line 163 | cw " change (replace) to the end of the current word 164 | caw " change (replace) the current word (including spaces) 165 | ciw " change (replace) the current word (not including spaces) 166 | ce " change (replace) forwards to the end of a word 167 | cb " change (replace) backwards to the start of a word 168 | c0 " change (replace) to the start of the line 169 | c$ " change (replace) to the end of the line 170 | c/pattern " change (replace) to first occurrence of 'pattern' 171 | s " delete character and substitute text (equal to `cl`) 172 | S " delete line and substitute text (equal to `cc`) 173 | xp " transpose two letters (delete and paste) 174 | ylxp " transpose two letters (yank, delete and paste) 175 | vyxp " transpose two letters (yank, delete and paste) 176 | >> " indent current line right 177 | << " indent current line left 178 | == " re-indent line (using 'equalprg' if specified) 179 | =% " indent current block of code 180 | gg=G " re-indent entire buffer 181 | " find number in current line and increment by 1 182 | " find number in current line and decrement by 1 183 | {num} " find number in current line and increment by {num} 184 | {count}: " will translate {count} to :{range} in ex mode 185 | ``` 186 | **Notes:** 187 | - All (c)hange commands end with the editor in INSERT mode 188 | 189 | - All double-char commands (i.e. `dd`, `cc`, `yy`, etc) can be thought of as a shortcut to `0{operator}$`, the breakdown is as follows: 190 | ```vim 191 | 0 " go to the start of the line 192 | {operator} " {operator} of your choice 193 | $ " go the end of the line 194 | ``` 195 | 196 | - 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. `d1j` will delete 2 lines down (cursor line + 1 down) and `y2w` will yank 2 words forward. In similar fashion the VISUAL mode operator `v` can be used, e.g. `vi}` will visually select everything inside the curly braces. 197 | 198 | ### INSERT mode 199 | ```vim 200 | " delete a word backwards 201 | " undo edit on current line, on empty lines 202 | " shift left one shift width 203 | " put text from the above line column 204 | " put text from the below line column 205 | {reg} " put register {reg} 206 | u " break the (u)ndo chain 207 | {c} " insert char {c} literally 208 | {n} " insert char by decimal value 209 | u{n} " insert unicode char by decimal value 210 | " insert previously inserted text (equal to `.`) 211 | " same as + exit INSERT mode 212 | " auto-complete after cursor 213 | " auto-complete before cursor 214 | {cmd} " execute one NORMAL mode command (see below note) 215 | " like , does not work on all keyboards 216 | ^x^e ^x^y " scroll up, down 217 | ``` 218 | **Note:** Any NORMAL mode motion can be run from INSERT mode by using `{op}` or `` (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 `` or `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 `: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) 219 | 220 | ### Cut, copy and paste 221 | ```vim 222 | p P " (p)ut or (p)aste clipboard after, before cursor 223 | ]p [P " like p, P with indent adjusted 224 | gp gP " like p, P leaving cursor after new text 225 | yy " yank (copy) a line 226 | {n}yy " yank (copy) {n} lines 227 | yl " yank a single character (l = to the right) 228 | vy " yank a single character (using VISUAL mode) 229 | yw " yank (copy) to the next word 230 | yiw " yank (copy) (i)nner word (entire word) 231 | yaw " yank (copy) (a) word (entire word, including spaces 232 | y$ " yank (copy) to end of line 233 | dd " delete (cut) a line 234 | {n}dd " delete (cut) {n} lines 235 | dw " delete (cut) to the next word 236 | D " delete (cut) to the end of the line 237 | d$ " delete (cut) to the end of the line 238 | d^ " delete (cut) to the first non-blank character of the line 239 | d0 " delete (cut) to the beginning of the line 240 | d/pattern " delete (cut) to first occurrence of 'pattern' 241 | x X " delete (cut) character under, before the cursor 242 | "+p " paste the `+` register (the clipboard) 243 | "0p " paste the yank `0` register 244 | "{reg}p " paste {reg} (:registers) 245 | "{reg}yy " yank current line into {reg} (:registers) 246 | "_dd " delete line into the 'blackhole' register (no clipboard) 247 | 248 | ``` 249 | **Copy paste using ex mode:** 250 | ```vim 251 | :{range}y " yank {range} into the default register 252 | :{range}m{line} " move {range} below {line} 253 | :{range}co{line} " copy {range} to below {line} 254 | :{range}t{line} " shortcut to the `:co[opy]` command above 255 | :-2co . " copy line 2 above cursor to line below cursor 256 | :+2t 0 " copy line 2 below cursor to start of file 257 | :.,$t $ " copy all lines from the cursor to end of file to end of file 258 | :1,3co 5 " copy lines 1-3 to below line 5 259 | ``` 260 | 261 | **Notes:** 262 | - To paste a register directly from INSERT or ex mode use `` followed by a register name. 263 | 264 | - By default the `Y` command is mapped to `yy` (yank line) which isn't consisnt with the behaviors of `C` and `D` (from cursor to end of line), a very useful mapping for both NORMAL and VISUAL mode is: 265 | 266 | ```vim 267 | nnoremap Y y$ 268 | xnoremap Y y$gv 269 | ``` 270 | 271 | - By default all modification operators `d c x` copy the modified text to the unnamed `"` register (unless `set clipboard` was set) which can be confusing at first. For example, let's say we want to overwrite a word with yanked text, we would naturally do `ciwp` or `ciw"` only to find out the same word would be pasted (and not our yanked text), to work around that we can tell the `c` operator to copy the text into the 'blackhole' register instead: `"_ciw`. Alternatively we can also use the yank register `0` which contains the content of the last yank operation using `"0p` or `"0P` (to paste before the cursor). A few useful mappings for my leader key (by default `\`, personally I use `\`) are below, so if I want to change a word without it polluting my registers I would run `bciw`, similarly if I wish to delete a line I would run `dd`: 272 | 273 | ```vim 274 | nnoremap b "_ 275 | nnoremap d "_d 276 | nnoremap D "_D 277 | nnoremap dd "_dd 278 | xnoremap b "_ 279 | xnoremap D "_D 280 | xnoremap D "_D 281 | xnoremap x "_x 282 | ``` 283 | 284 | - 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 `"1p` and then run `u.`, the undo+repeat advances the 'pasted register' so it will perform `"2p`, `"3p` and so forth. 285 | 286 | ## VISUAL mode 287 | ### Selections 288 | ```vim 289 | " exit visual mode 290 | " exit visual mode 291 | v " start VISUAL mode in 'character' mode 292 | V " start VISUAL mode in 'line' mode 293 | " start VISUAL mode in 'block' mode 294 | o " move to other end of marked area 295 | O " move to other corner of block 296 | $ " select to end of line (include newline) 297 | g_ " select to end of line (exclude newline) 298 | aw " select a word 299 | ab " select a block with () 300 | aB " select a block with {} 301 | ib " select inner block with () 302 | iB " select inner block with {} 303 | gv " NORMAL mode: reselect last visual selection 304 | ``` 305 | 306 | **Notes:** 307 | - The above are just some of the available commands as any text object or motion can be used, e.g. `viw` will visually select current word or `vat` will select an entire tag: `some text` 308 | 309 | - 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 because `j` is a linewise motion. If you instead pressed `d2j`, 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](https://www.hillelwayne.com/post/intermediate-vim/). 310 | 311 | - VISUAL mode has a nice feature to expand selection based on blocks, say we wanted to select the inside of an `if` condition in C, we do so with `vi(` or `vi)`, if we wanted to expand the selection to the outer block we can just run `i{` or `i}` (without having to cancel the selection and press `v` again). 312 | 313 | ### Operators 314 | ```vim 315 | ~ " switch case 316 | d " delete 317 | c " change 318 | y " yank 319 | > " indent right 320 | < " indent left 321 | ! " filter through external command 322 | = " re-indent line (using 'equalprg' if specified) 323 | gq " format lines to 'textwidth' length (cursor moves to end) 324 | gw " format lines to 'textwidth' length (cursor stays in place) 325 | gu " make selection lower-case 326 | gU " make selection UPPER-case 327 | v " increment digit under the cursor 328 | {num} " increment current selection by {num} (lines separately increment) 329 | {num} " decrement current selection by {num} (lines separately decrement) 330 | {num}g " increment current selection by {num} (lines serially increment) 331 | ``` 332 | 333 | **Notes:** 334 | - Some operators, namely the repeat `.` and paste `pP` operators 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 `}A;` 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 cursor `p` and `P` to paste entire columns, the following will duplicate the first column of a paragraph: `}yp` which you can easily undo as an atomic operation with `u`. 335 | 336 | - 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 @q` will execute macro `q` on all visually selected lines. 337 | 338 | - 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 do `viB!sort` which is the equivalent `viB:!sort`. The same can also be done from NORMAL mode using `!iBsort`. 339 | 340 | - 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 use `gv`, so to indent while keeping current selection use `gv` respectively. Personally I never want to lose my selection when indenting hence I use the below mappings in [my keymaps](https://github.com/ibhagwan/nvim-lua/blob/main/lua/keymaps.lua): 341 | 342 | ```vim 343 | vmap < >gv 345 | ``` 346 | ## Text Objects 347 | ```vim 348 | aw " a word (includes surrounding white space 349 | iw " inner word (does not include surrounding white space) 350 | as " a sentence 351 | is " inner sentence 352 | ap " a paragraph 353 | ip " inner paragraph 354 | a" " a double quoted string 355 | i" " inner double quoted string 356 | a' " a single quoted string 357 | i' " inner single quoted string 358 | a` " a back quoted string 359 | i` " inner back quoted string 360 | a) or ab " a parenthesized block 361 | i) or ib " inner parenthesized block 362 | a] " a bracketed block 363 | i] " inner bracketed block 364 | a} or aB " a brace block 365 | i} or iB " inner brace block 366 | at " a tag block e.g. 367 | it " inner tag block e.g. 368 | a> " a single tag 369 | i> " inner single tag 370 | gn " next occurrence of search pattern 371 | ``` 372 | **Notes:** 373 | - Text objects can be used with any operator, e.g. `dit` will delete "some text" from `some text` and `yat` will copy the entire tag into the clipboard. For more information [Jared Caroll's: Vim Text Objects: The Definitive Guide](https://blog.carbonfive.com/vim-text-objects-the-definitive-guide/). 374 | 375 | - `gn` is a very useful text object, few examples: `cgn` will change the next search pattern match, `vgn` will 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](https://bennetthardwick.com/blog/2019-01-06-beginner-advanced-vim-tips-and-tricks/). 376 | 377 | - Any text object can also be used with a count. For example, we have the below text (cursor at ^): 378 | ```vim 379 | if (function(param1, param2, param3)) { 380 | ^ 381 | ``` 382 | 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](https://blog.antoyo.xyz/vim-tips). 383 | 384 | ## Search & Replace 385 | ```vim 386 | # * " search word under cursor backward, forward 387 | g# or g* " like #, * but also find partial matches 388 | /pattern " search for pattern 389 | /pattern " go to next match without exiting search mode `/` 390 | /pattern " go to prev match without exiting search mode `/` 391 | /pattern/{-+n} " put cursor {-+n}th line below/above the match 392 | /pattern/e{-+n} " put cursor {-+n}th char before/after match (e)nd 393 | /pattern/b{-+n} " put cursor {-+n}th char before/after match (b)egin 394 | ?pattern " search backward for pattern 395 | / " repeat search in same direction 396 | ? " repeat search in opposite direction 397 | // " put last search pattern into search mode 398 | / " put word under cursor into search mode 399 | / " put WORD under cursor into search mode 400 | /\v{pattern} " Search forwards using Vim's 'very magic' pattern 401 | " special characters can be used without esc seq 402 | n N " repeat search in same, opposite direction 403 | & or :&& " repeat last substitute in the same line 404 | g& " repeat last substitute on all lines 405 | :noh " remove highlighting of search matches 406 | :s/old/new/ " replace first occurrence of old with new 407 | :s/old/new/i " replace first occurrence of old with new (case insensitive) 408 | :s/old/new/g " replace all old with new throughout line ('globally') 409 | :%s/old/new " replace first occurrence of old with new throughout file 410 | :%s/old/new/g " replace all old with new throughout file ('globally') 411 | :%s/old/new/gc " replace all old with new throughout file with confirmations 412 | :%s/old/'&'/g " surround all occurrences of old with ' (i.e. 'old') 413 | :s/\%Vold/new/ " replace all occurrences of old with new in visual selection 414 | :{range} s/old/new/ " replace all old with in {range} (e.g. `:10,20s/...`) 415 | :{num},$ s/old/new/ " replace all old with new from line {num} to last line 416 | :g/regex/{ex} " run :{ex} for every line matching regex 417 | :g!/regex/{ex} " run :{ex} for every line NOT matching regex 418 | :v/regex/{ex} " same as above, shortcut to `:g!` 419 | :g/regex/y {reg} " copy all matching lines to register {reg} 420 | " capitalize {reg} to append to {reg} 421 | :g/regex/m $ " move all matching lines to end of file 422 | :g/regex/-1j " for every matching line, go up one line and join 423 | :%s/\s\+$//e " remove all trailing whitespaces throughout buffer 424 | :g/^/m0 " reverse order of all lines in current buffer 425 | :v/./d " delete all empty lines (same as `:g!/./d`) 426 | /\%>10l\%<20l{regex} " search for regex between lines 10-20 (excluding ln 20) 427 | /\v%>10l%<20l{regex} " same as above using 'very magic' 428 | /\%u{xxxx} " search for unicode character `u+{xxxx}` (e.g. `u+0061` for `a`) 429 | ``` 430 | 431 | **Notes:** 432 | 433 | - You can repeat the last substitute interactively with `g&` 434 | 435 | - For more information on the different `.../g` modifiers read `:help s_flags` 436 | 437 | - For more information on the "very magic" pattern read [Vim fandom: Simplifying regular expressions using magic and no-magic](https://vim.fandom.com/wiki/Simplifying_regular_expressions_using_magic_and_no-magic). 438 | 439 | - The `g` and `v` ex commands are extremely useful, few examples: `:g/pattern/d` or `:g/pattern/norm dd` will delete all lines matching `pattern`, you can also supply a range to the command: `:g/pattern/-1d` will delete one line above all lines matching `pattern`, same can be achieved with `:g/pattern/norm 1jdd` 440 | 441 | - `: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 do `let @a = '' | %g/regex/y A` it will copy all lines matching regex in the entire file to register a. We can then copy the register to the system clipboard with `let @+ = @a`. 442 | 443 | - Important note regarding the use of `:s` vs `:g`: `s` is a shortcut for `substitute` and `g` is a shortcut for `global`, therefore `s` should be used when doing search and replace (substitution) and `g` should 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 substitute `bar` with `blah` for every line containing `foo`, we could achieve the same result with both but as you can see the `g` command would be a better fit in this case: 444 | 445 | ```vim 446 | g/foo/s/bar/blah/g 447 | 448 | :%s/foo/\=substitute(getline('.'), 'bar','blah','g') 449 | ``` 450 | 451 | ### REGEX Examples 452 | ### Search examples 453 | ```vim 454 | /^fred.*joe.*bill " line beginning with fred, followed by joe then bill 455 | /^[A-J] " line beginning A-J 456 | /^[A-J][a-z]\+\s " line beginning A-J then one or more lowercase characters then space or tab 457 | /fred\_.\{-}joe " fred then anything then joe (over multiple lines) 458 | /fred\_s\{-}joe " fred then any whitespace (including newlines) then joe 459 | /fred\|joe " fred OR joe 460 | ``` 461 | 462 | ### Substitution examples 463 | ```vim 464 | :%s/fred/joe/igc " general substitute command 465 | :%s/\r//g " delete DOS Carriage Returns (^M) 466 | :'a,'bg/fred/s/dick/joe/gc " VERY USEFUL 467 | :s/\(.*\):\(.*\)/\2 : \1/ " reverse fields separated by : 468 | " non-greedy matching \{-} " `:help /\{-}` 469 | :%s/^.\{-}pdf/new.pdf/ " to first pdf) 470 | :s/fred/a/g " substitute 'fred' with contents of register 'a' 471 | :%s/^\(.*\)\n\1/\1$/ " delete duplicate lines 472 | " running multiple commands 473 | :%s/suck\|buck/loopy/gc " ORing 474 | :s/__date__/\=strftime("%c")/ " insert datestring 475 | :%s/\f\+\.gif\>/\r&\r/g | v/\.gif$/d | %s/gif/jpg/ 476 | ``` 477 | 478 | ### Multiple Files 479 | 480 | > To learn more I recommend watching 481 | > [Drew Neil: Searching Multiple Files with vimgrep](http://vimcasts.org/episodes/search-multiple-files-with-vimgrep/) 482 | 483 | ```vim 484 | :vimgrep /pattern/ {file} " search for a pattern using vimgrep 485 | :grep /pattern/ {file} " search for a pattern using an external program 486 | :copen " open the 'quickfix` window containing all matches 487 | :cn " jump to the next match 488 | :cp " jump to the previous match 489 | :cdo " execute a command for each quickfix entry 490 | :cfdo " execute a command for each quickfix file 491 | ``` 492 | 493 | When just starting to use vim search and replace an entire project at first 494 | seems overly complex, plugins can definitely help here (fzf comes to mind) but 495 | once you understand how to use the quickfix list it's actually quite easy. 496 | 497 | Vim comes builtin with the `vimgrep` utility which searches for a regex patter 498 | and populates the quickfix list accordingly. From there, you can manipulate 499 | matches using the `cdo|cfdo` combo. 500 | 501 | Searching the project is as easy as: 502 | ```vim 503 | " search the current file 504 | :vimgrep /foo/ % 505 | " search the entire project 506 | :vimgrep /foo/ **/* 507 | ``` 508 | 509 | Personally I prefer to use `:grep` in conjunction with the 510 | [`rg`](https://github.com/BurntSushi/ripgrep) utility, to do so add the below 511 | to your `init.vim`: 512 | ```vim 513 | set grepprg=rg\ --vimgrep\ --no-heading\ --smart-case\ --hidden 514 | set grepformat=%f:%l:%c:%m 515 | ``` 516 | 517 | And then run the same search: 518 | ```vim 519 | " search the current file 520 | :grep 'foo' % 521 | " search the entire project 522 | :grep 'foo' 523 | " or if you prefer to use the location-list 524 | :lgrep 'foo' 525 | ``` 526 | 527 | From here it's very easy to search and replace all matches with 528 | [any substitute command](#search-replace): 529 | ```vim 530 | " if you want to run the command once for each entry use `cdo` 531 | " otherwise the below should suffice as `%s` searches the entire file 532 | :cfdo %s/foo/bar/g 533 | " save all changes 534 | :wall 535 | ``` 536 | 537 | ## Macros 538 | ```vim 539 | q{a-z} " start recording macro to register {a-z} 540 | q{A-Z} " append recording macro to register {a-z} 541 | q " stop macro recording 542 | @{a-z} " execute macro {a-z} 543 | {count}@{a-z} " execute macro {a-z} on {count} lines 544 | @@ " repeat execution of last macro 545 | :@{reg} " execute {reg} as an ex command 546 | @: " repeat execution of last ex command e.g. `:s/...` 547 | @. " execute last inserted text as macro 548 | @='[cmds]' " execute commands through the expression register 549 | :'<,'>normal @q " execute macro `q` on visual selection 550 | "{a-z}p " paste macro {a-z} (register) 551 | "{a-z}y$ " yank into macro {a-z} to end of line 552 | ``` 553 | 554 | **Notes:** 555 | - 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 `q` as an example (recorded with `qq`), once you’re finished with the macro, press `"qp` to paste it to an empty line, remove the mistaken keystrokes and the undo and copy it back into the `q` register with `"qy$`. 556 | 557 | - 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. 558 | 559 | - The above was taken from [Hillel Wayne's blog: Vim Macro Tricks](https://www.hillelwayne.com/vim-macro-trickz/). 560 | 561 | - Alternatively, you can resume recording a macro using the capitalized version of the registers, say we started recording into the `q` register with `qq` we can "pause" the macro recording with `q` and later resume recording with `qQ` (note the capitalized `Q`). 562 | 563 | - 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. `w`). This makes it very useful to mass manipulate text between different buffers. 564 | 565 | - 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 characters `xp`, what we can do is enter INSERT mode, enter the macro keys, press `u` for undo and then execute the macro with `@.`, thus the entire sequence equals `ixpu` and now we can run our macro with `@.`. Alternatively, if you'd like your macro to contain a `` (down one line) you can run `O~$~dd` and then run the macro with `2@"` (since our text was 'cut' into the default register) - this will toggle capitalization of the first and last character in 2 subsequent lines. 566 | 567 | - Building on the above, the same `xp` macro 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, running `3@='v2w'` on the text `1 5 8` will increment each digit by 2 resulting in `3 7 10`. This example is equivalent to `qqv2wq2@q`: which records the edit to macro `q` and then executes it two more times. (note: if you wish to input special characters (``, ``, etc.) in the command line, prefix the special character with `` e.g. ``. 568 | 569 | 570 | ### Recursive Macros 571 | 572 | 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: 573 | ```vim 574 | qqq " empty the q register, VERY IMPORTANT, read below why 575 | qqf"D+@qq " execute on one line and record our recursive macro 576 | @q " execute until fail 577 | ``` 578 | 579 | 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: 580 | ```vim 581 | qqq " empty the q register, VERY IMPORTANT, read below why 582 | qqf"D+q " execute on one line and record our macro 583 | @q " execute one time and check the results 584 | qQ@qq " execute one more time and add the recursion call 585 | @q " execute until fail 586 | ``` 587 | 588 | 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. 589 | 590 | **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. 591 | 592 | ## Marks 593 | ```vim 594 | :marks " list current marks 595 | m{a-z,A-Z} " set mark at cursor position 596 | " {a-z} = local file marks 597 | " {A=Z} = cross file marks 598 | '{a-z,A-Z} " goto first non-blank character in mark {a-z,A-Z} 599 | `{a-z,A-Z} " goto exact cursor position of mark {a-z,A-Z} 600 | ``` 601 | 602 | ## Files and Windows 603 | ```vim 604 | :e {file} " edit a file in a new buffer 605 | :find {file} " find and open file in &path (set path?) 606 | gf " find and open the file under the cursor 607 | gF " find and open the file under the cursor with line number 608 | :cd %:h " change pwd to folder of current buffer (all buffers) 609 | :lcd %:h " change pwd to folder of current buffer (local buffer) 610 | :ls " list all open buffers 611 | :bnext or :bn " go to the next buffer 612 | :bprev or :bp " go to the previous buffer 613 | :bd " delete a buffer (close a file) 614 | :sp {file} " open a file in a new buffer and split window 615 | :vsp {file} " open a file in a new buffer and vertically split window 616 | :windo {ex} " run :{ex} on all windows (e.g. :windo q - quits all windows) 617 | :bufdo {ex} " same as above for buffers 618 | :on " make current window the 'only' window (close all others) 619 | :hide or :q " hide (close) current window 620 | :new " new window in a horizontal split 621 | :vnew " new window in a vertical split 622 | o " same as `:on` above 623 | w " jump to next window 624 | r " swap windows 625 | q " quit a window 626 | s " split window horizontally 627 | v " split window vertically 628 | h " move cursor to the left window (vertical split) 629 | l " move cursor to the right window (vertical split) 630 | j " move cursor to the window below (horizontal split) 631 | k " move cursor to the window above (horizontal split) 632 | " jump to previous buffer 633 | " display filename of current buffer (file) 634 | 1 " display full path of current buffer (file) 635 | 2 " display buf # and full path of current buffer (file) 636 | ``` 637 | 638 | **Notes:** 639 | - `:bufdo` and `:windo` can 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` 640 | 641 | - `:find` and `gf` are both dependent on the `&path` variable 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 use `cd` to change Vim's working directory (best done using `cd %:h`). If you would like `:find` and `gf` to find files recursively in all folders specified by `&path` be sure `path` contains `**`. 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). 642 | 643 | 644 | ## Tabs 645 | ```vim 646 | :tabnew or :tabnew {file} " open a file in a new tab 647 | T " move the current split window into its own tab 648 | gt or :tabnext or :tabn " goto to the next tab 649 | gT or :tabprev or :tabp " goto to the previous tab 650 | {num}gt " goto to tab {num} 651 | :tabmove {num} " move current tab to the {num}th position (indexed from 0) 652 | :tabclose or :tabc " close the current tab and all its windows 653 | :tabonly or :tabo " close all tabs except for the current one 654 | :tabdo {ex} " run :{ex} on all tabs (e.g. :tabdo q - closes all opened tabs) 655 | ``` 656 | 657 | ## Terminal 658 | ### Vim: 659 | ```vim 660 | :term " open terminal window inside vim (default shell) 661 | :term zsh " open terminal window inside vim (zsh) 662 | :vert term zsh " opens a new terminal in a horizontal split (zsh) 663 | ``` 664 | ### Neovim: 665 | ```vim 666 | :term " open terminal window inside vim 667 | :split term://zsh " opens a new terminal in a horizontal split 668 | :vsplit term://zsh " opens a new terminal in a vertical split 669 | :new term://bash " alternates for above commands 670 | :vnew term://bash " alternates for above commands 671 | " go back to NORMAL mode 672 | ``` 673 | ### Both: 674 | ```vim 675 | " suspend vim to background, `fg` in term to resume 676 | :sus[pend][!] or st[op][!] " suspend vim (equal to ctrl-z) if `!` is specified 677 | " vim will write changes to all buffers before suspend 678 | ``` 679 | 680 | ## Spellcheck 681 | ```vim 682 | :set spell " enable spellcheck for current buffer 683 | :set nospell " disable spellcheck for current buffer 684 | :set spelllang={lang} " set spellcheck lang, i.e. `en_us` 685 | [s " find previous misspelled word 686 | ]s " find next misspelled word 687 | z= " see spellcheck suggestions 688 | {num}z= " automatically accept (change) suggestion {num} 689 | zg " add current word to dictionary 690 | zw " add current word to dictionary as a 'bad' word 691 | zug " undo `zg` 692 | zuw " undo `zw` 693 | ``` 694 | 695 | ## Misc commands 696 | ```vim 697 | K " lookup keyword under cursor with `man` 698 | ga " display dec/hex/oct values of character under cursor 699 | g8 " display hex value of utf-8 character under cursor 700 | g? " rot13 a character (cycle 13 alphanumeric chars backwards) 701 | ggg?G " rot13 entire buffer 702 | g< " view last command (:!) output 703 | " redraw window, clear status message (error messages, search, etc) 704 | " display filename and position 705 | g " display cursor, line and column position 706 | ``` 707 | ```vim 708 | :help {keyword} " view help for {keyword} 709 | :help {keyword} " list help of matching {keyword} 710 | :helpgrep {keyword} " help search for {keyword}, open results with :cwindow 711 | :read {file} " read {file} below the cursor 712 | :!{cmd} " execute shell command {cmd} 713 | :!% " execute current file 714 | :!%:p " execute current file (use full path) 715 | :.!{cmd or !!{cmd} " filter current line through {cmd} 716 | !!date " replace current line with output of `date` 717 | :read !{cmd} " read output of {cmd} below cursor 718 | : or q: " enter command line window, or :q to exit 719 | q/ or q? " same as above but for searches 720 | :echo &{opt} " echo Vim option to command line (expand values) 721 | :set {opt}? " echo Vim option to commend line (no expand) 722 | :source " 'source': execute a file as a series of commands 723 | :source $MYVIMRC " source your $MYVIMRC 724 | :retab " retab current buffer according to `expandtab` and `shiftwidth` 725 | :earlier {time} " revert a file to earlier time, e.g. `earlier 1m` 726 | :later {time} " revert a file to later time 727 | :visual :edit " leave :Ex mode 728 | : " go to start of line in command line mode 729 | : " go to end of line in command line mode 730 | ``` 731 | 732 | ## Ctrl-R and the Expression Register 733 | 734 | The expression register (`=`) is used to evaluate expressions and can be accessed using `"=` from NORMAL and VISUAL modes and `` 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 `.`): 735 | 736 | ### INSERT and ex modes: 737 | ```vim 738 | :registers {reg} " display registers {reg} and their values 739 | :display "0 " display value of registers `"` and `0' 740 | :{line}put " put clipboard register under {line} 741 | :put{reg} " put value of {reg} in the line below 742 | :put={expr} " put value of {expr} in the line below 743 | :let @{reg}={expr} " manually assign value to {reg} 744 | :let @*=expand('%') " expand current file path into `*` (clipboard) 745 | {reg} " put register {reg} 746 | ={expr} " put the value of {expr} 747 | =[1,2,3] " put 123 748 | % " put file path of current buffer 749 | - " put last deleted text 750 | : " put word under cursor 751 | : " put WORD under cursor (includes punctuation) 752 | : " put current cursor line 753 | : " put file path under cursor (does not expand ~) 754 | : " put file path under cursor (expands ~) 755 | ``` 756 | 757 | ### NORMAL and VISUAL modes: 758 | ```vim 759 | "={expr} " evaluate {expr} into the expression register 760 | "={expr}p " evaluate {expr} and paste (also saved in the register) 761 | "={expr}P " save as above, paste before the cursor 762 | ``` 763 | 764 | **Notes:** 765 | - For more information on evaluating expressions `:help expression`. For even more information read [Aaron Bieber's: Master Vim Registers With Ctrl R](https://blog.aaronbieber.com/2013/12/03/master-vim-registers-with-ctrl-r.html) and watch [Vimcasts: Simple calculations with Vim's expression register calculations with Vim's expression register](http://vimcasts.org/episodes/simple-calculations-with-vims-expression-register/) 766 | 767 | - When inserting a register with `{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 `{reg}` instead. Best shown with an example, say we have the below text and we wish to add parens around the text 768 | 769 | ```vim 770 | one " we want to change this to => (one) 771 | two " we want to change this to => (two) 772 | ``` 773 | 774 | We can modify the first line using `ciw(+)` 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(+)` 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)". 775 | 776 | - For more information regarding `` read `:help i_ctrl-r_ctrl-o` and watch [Drew Neil's vimcast: Pasting from INSERT mode](http://vimcasts.org/episodes/pasting-from-insert-mode/) 777 | 778 | ## Comparing buffers with vimdiff 779 | ```vim 780 | :windo diffthis " Edit current windows in diff mode 781 | :windo diffoff " Exit diff mode 782 | :diffput {bufspec} " Put diff into {bufspec} from current buffer 783 | :diffget {bufspec} " Pull diff from {bufspec} into current buffer 784 | do " diff (o)btain, NORMAL mode for `:diffget` 785 | dp " diff (p)ut, NORMAL mode for `:diffput` 786 | [c " jump to previous (c)hange 787 | ]c " jump to next (c)hange 788 | :windo set scrollbind " bind all current windows scrolling 789 | :windo set noscrollbind " unbind all current windows scrolling 790 | ``` 791 | 792 | **NOTE:** 793 | 794 | - The shortcuts `do` and `dp` also run `:diffupdate`, so the equivalent of `dp` can be thought of as `:diffput {target buffer} | diffupdate` 795 | 796 | - `{targetbuffer}` above is automatically resolved as the 'other buffer' on a 2-way split, that works for both `do` and `dp`. However, `do` cannot sensibly decide which buffer to use in a 3-way split (git merge conflict resolution) and therefore cannot be used in this case. `dp` assumes 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. 797 | 798 | ## Folding 799 | Fold methods (set with `set foldmethod=`: 800 | 801 | ```vim 802 | manual " folds must be defined by commands (i.e. `zf`) 803 | indent " folds are defined by lines of equal indent 804 | expr " folds are defined by `foldexpr` 805 | marker " folds are defined by `{{{` and `}}}` 806 | syntax " folds are defined by syntax highlighting 807 | diff " folds are defined by non-modified text 808 | ``` 809 | 810 | ```vim 811 | zo " open fold under cursor 812 | zO " open folds under cursor recursively 813 | zc " close fold under cursor 814 | zC " close folds under cursor recursively 815 | za " toggle fold under cursor 816 | zA " toggle folds under cursor recursively 817 | zM " close all folds, set `foldlevel` to 0 818 | zR " open all folds, set `foldlevel` to highest level 819 | zn " sets `nofoldenable`, disable folding 820 | zN " set `foldenable`, restore all previous folds 821 | zi " toggle between `foldenable` and `nofoldenable` 822 | ``` 823 | 824 | Fold management when `foldmethod` is set to `manual` or `marker`: 825 | 826 | ```vim 827 | zf{motion} " create a fold from current line to motion 828 | {visual}zf " create a fold around visual selection 829 | {count}zF " create a fold for {count} lines 830 | :{range}fo[ld] " create a fold for {range} (e.g. `:.,+3fo`) 831 | zd " delete surrounding fold at the cursor 832 | zD " recursively delete surrounding fold 833 | zE " delete all folds in current window 834 | ``` 835 | --------------------------------------------------------------------------------