The (very) basics of Vim

NOTE: Specific examples given for options, flags, commands variations, etc., are not comprehensive.

Intro

Vim is hard at first. It's a different paradigm. But once you get comfortable, usually after a few days, you'll wonder how you ever lived without it.

My advice in learning Vim, like any new skill, process, or language, is to learn bit by bit. Put a few commands on a sticky note on your monitor. Start with motion commands and basic editing. When you get comfortable with those, put a few more commands on another sticky note. Keep the old one as a reference as long as you need it.

The Buffer

A "buffer" is a block of text you edit using Vim, and several buffers can be open at once.

When you open a file in MS Word, the operating system locks the file so no one else can edit it. This gives you the feeling that the text on your screen and the file itself are one and the same, e.g., "I'm editing the file."

What the computer actually does is read the contents of the file into memory. This temporary version of the file in memory is called a buffer. Your editing program edits the buffer, not the file on disk. When you hit Save, it writes the buffer to disk over the top of the old file.

Vim does not lock files when you open them, so there's no illusion that you're editing the file. You're always editing a buffer. When you Write a buffer, it creates a new file on disk or it overwrites an existing file (usually the file you loaded the buffer from).

This is why Vim's documentation only refers to editing buffers, not files.

Normal Mode

Vim has two main "modes," one for typing ("Insert mode") and one for everything else ("Normal mode"), including moving the cursor around the screen, copy/pasting, doing search and replace, etc. Normal mode is the default mode and where you spend most of your time.

In Insert mode, your keyboard behaves like in other editors: Pushing a letter or number key puts that character into the buffer while meta keys like Ctrl and Alt add extra functionality.

In Normal mode, each key on your keyboard is mapped to a different command. Some keys move the cursor, some delete words, etc.

The power of Vim lies in these commands and how they work together to help you accomplish more editing with fewer keystrokes and less effort.

Moving around the buffer

Basic motion commands move the cursor...

  • j - down
  • k - up
  • h - left
  • l - right

Moving quickly between words

  • w - forward beginning of next "word"
  • e - end of current word (or end next word if currently at end of word)
  • b - to beginning of word (or beginning previous word if currently at beginning of a word)

These commands are good for quickly scrolling through lines as they are much faster than h and l.

  • % - If the cursor is inside parentheses (or quotes, brackets, etc.), move to opening paren. If the cursor is on a parenthesis, move to its partner. If not between parens, do nothing. (Can do weird stuff with unmatched parens.)
  • } - Move forward a paragraph (or a function or a section, depending on the type of file you're editing).
  • { - Move back a paragraph.

Jumping within a line

  • 0 - Move to beginning of line
  • ^ - Move to first non-space character in line (same as "0" if the line starts with a non-space character)
  • $ - Move to end of line

Note: ^ and $ are Regular Expression shortcuts for beginning and end of a string, respectively

Moving to a specific point in the buffer

  • [#]gg - go to line [#] (Example 20gg goes to line 20)
  • gg - go to beginning of buffer
  • G - go to end of buffer
  • [#]| - go to column [#] on current line, e.g. 10| goes to column 10.
  • '' - jump to wherever you were before the last jump. This is useful after using commands like gg to get back to wherever you were when you used gg to jump to the beginning of the buffer. Using '' repeatedly will jump you back and forth.

Searching the buffer

  • f<char> - Find <char>. Puts cursor on next instance of <char> in the current line. Example: fa will jump to the next "a".
  • F - Like f but backwards search
  • t<char> - "To" <char>. Just like f, but put cursor right before the character you're searching instead of on it.
  • T - t but backwards search
  • ; - move to next instance of your most recent f or t This will not take you past the end of the current line.
  • /<RegEx><Enter> - Search buffer. Go to next instance of <RegEx> in the current buffer. This uses full Regular Expression matching (with a bit of Vim-specific syntax).
    • /Hello takes you to the next "Hello"
    • /^Hello takes you to the next "Hello" that is at the beginning of a line.
    • /\sHello takes you to the next "Hello" that has a space (or tab) right in front of it.
  • ? - Same as / but search backward in the buffer instead of forward
  • n(N) - next (previous) instance of the most recent / or ? search
  • * - Do a / search for the word under cursor. This is very useful for finding all instances of the variable your cursor is on.

Composing Commands

Most motion and editing commands can take a number before them to execute that number of times.

  • 4j - Move cursor down 4 lines
  • 10w - Move cursor forward 10 "words"
  • d4w - Delete from here to beginning of 4th word forward
  • <G - Indent everything from cursor to end of buffer

Editing the text in Normal Mode (and more composing commands)

Most composing of actual text will be done in Insert Mode, explained below. However, there are a number of commands that are meant to quickly edit the text without leaving Normal Mode.

Many of these commands require a motion command (signified here as [m]) to specify the extent over which to execute the edit. Several common conventions for many (but not all) commands:

  • double-tap: execute command for entire line cursor is currently on
  • shift + command: execute command from cursor to end of current line

More generally, the composability of editing commands and motion is what makes Vim particularly powerful. If you know 5 editing commands and 5 motion commands, you actually know (at least) 25 commands.

  • d[m] - delete from cursor location to wherever [m] takes the cursor. Examples:
    • dw delete from here (location of cursor) to beginning of next word (includes character under the cursor)
    • dtT deletes "to" (up to but not including) the next instance of "T" on this line
    • df) deletes to ("finds") the next instance of ")" on this line
    • d/the deletes everything between the cursor and the next instance of "the" in the buffer.
  • dd delete this entire line
  • D delete from here to end of line
  • 4dd delete this line and next 3 (4 total)

Yank (copy)

  • y[m] yank (copy). Same basic behavior as d (delete).
    • yw yank from here to beginning of next word
    • y$ yank from here to end of line
  • yy - yank the current line

Note: To make it consistent with D, it's common to add an analagous mapping for Y in your vimrc like so: nnoremap Y y$

Paste

  • p - paste after cursor location. Example: To copy the current line, use yyp, which yanks the current line and then pastes it.
  • P - paste before cursor location

Indent

  • >[m] - Indent through modtion m.
    • >> - Indent current line.
  • <[m] - Un-indent, opposite of >.

Special Motion Commands

  • daw - "Delete a word"; delete the word under the cursor plus any trailing space.
  • diw - "Delete inner word"; delete the word under the cursor, leave spaces.
  • [e]ip - [edit command] the inner paragraph. Where "edit" can be d for delete, c for change, etc.
  • [e]ap - [edit command] a paragraph (like i but including space around paragraph.
  • [e]i( - [edit command] inside parentheses
  • [e]a( - [edit command] a parentheses pair (like i but including the parens

Undo/Redo

  • u - undo (like Ctrl+Z in Word)
  • c-r - redo (like Ctrl+Y in Word)

Saving and quitting

Some important (or longer) commands begin with :. After typing :, you will a colon appear in the bottom left of the screen, followed by any subsequent characters you type. Many commands only require the first few letters. For example, for :q[uit] below, any of

  • :q,
  • :qu,
  • :qui, or
  • :quit

will work.

  • :q[uit] - quit (the current window of) Vim. ("Window" here is internal to Vim, not the OS-level window.)
  • :q! - force quit (if the current buffer has been changed since the last save)
  • :e[dit] {filename} - read file {filename} into a new buffer. If {filename} doesn't exist, create a buffer (not a file) associated with that filename. Vim doesn't "open" files like MS Word does. Instead, it reads the contents of a file into RAM and then you edit the "buffer" in RAM. Other programs may access and change the underlying file you originally opened (Vim will notice this and issue a warning).
  • :bw[ipeout] or :bd[elete] - Close the current buffer but keep the current Vim window open.
  • :w[rite] {filename} - write the current buffer to {filename}. If no filename passed (i.e., :w) and the buffer already has an associated filename (the one used with :e {filename}), that associated filename will be used. A simple :w is like MS Word "save" and :w {new_filename} is "save a copy as {new_filename} but keep the current buffer.
  • :w! - force write (e.g., even if the underlying file has been been changed by another program and this write will overwrite those changes)
  • :save {filename} - Save as (and change current buffer to {filename})
  • :save! {filename} - Save as and overwrite {filename} if it exists.

These commands can be combined, e.g., :wq - write the buffer and quit :wq! - force write and quit

Misc. Other Commands

Change letter case

  • ~ - toggle the case of this character
  • [#]~ - toggle case of [#] next character(s)
  • g~[m] - toggle case with motion [m]
  • gU[m] - make uppercase between current cursor and where motion command m takes the cursor
  • gu[m] - make lowercase

Combine lines

  • J - Take the next line and move it to the end of this line.

Format line/wrap text

  • gq[m] - Format the text between here and [m] (usually just breaks overly long lines to smaller lines, by default 80 characters).
  • gqq - Format the current line
  • gqap - Format this ("a") paragraph

Scrolling

  • c-e - scroll forward, keeping cursor in place
  • e-y - scroll backward, keeping cursor in place
  • c-u - move cursor Up full page
  • c-d - move cursor Down full page
  • c-f - Forward half-page
  • c-b - Back half-page

Note: c-u or C-u in Vim mappings is short for Ctrl+u. m-u is for "meta", which will be the Alt key on Windows machines. Be aware that meta bindings will not always work on Unix systems, especially old ones.

  • H - Move cursor to highest line on screen (home)
  • M - Move cursor to middle line on screen
  • L - Move cursor to lowest line on screen

Insert Mode

Most commands are executed in Normal Mode. If you actually want to add to the text (type a "j" instead of moving down one line) you need to enter Insert Mode. There are several ways to do this.

  • i - Enter Insert mode before the current character
  • a - Enter insert mode After the current character
  • <Esc> - Exit Insert Mode (go back to Normal Mode).

Note: Because <Esc> is a little out of the way, it's common to remap a more convenient keybinding to also exit Insert Mode. For example, adding inoremap jk <Esc> to your vimrc will allow you to use a quick jk instead of <Esc>.

  • I - Enter insert mode at the beginning of the current line's text (same as doing ^ then i)
  • A - Enter insert mode After the end of the current line (like $ then a). "Append" is another good mnemonic.
  • o - Add a new line after the current line and enter insert mode (like doing A<Enter>)
  • O - Add a new line before the current line and enter insert mode

The "change" commands delete the desired text and immediately enters insert mode.

  • c[m] - Change text from here to [m]. This includes "advanced" movements. - ci( - Change everything between the current parentheses.
  • cc - Change this whole line.
  • C - Change from here to end of line.

"Replace" commands:

  • r - replace the current character with the next character typed (only one character allowed)
  • R - Replace characters until you hit <Esc> (like replace/overwrite mode in Word)

Visual "Mode"

  • v[m] - Go into visual (highlight) mode to select characters, then use usual motion commands like j or k to add to selection as the cursor moves.
  • V - Visual mode, but grab whole lines at a time instead of characters.
  • c-v - Visual mode, but select vertically (by columns) instead of horizontally
  • ggvG - Highlight whole file, i.e., go to beginning of file (gg), enter visual mode (v), go to end of file (G).

Once a selection has been made, you can use an edit command on that selection and it will (usually) behave as you'd expect.

Other stuff

Registers (for yank and paste)

"<char>y - yank to register <char>. This allows you to have multiple things in your clipboard. Note the Vim clipboard is separate from the OS clipboard. To move between the two (copy/paste between Vim and another program) use the * register, so:

  • y$ - yanks to end of line, puts in default register
  • "ay$ - yank to end of line but store in register "a" instead of default
  • "*yG - yank to end of file but stores in OS register
  • p - pastes what's in the default register (after the cursor, like a)
  • P - paste before cursor (like command i)
  • "*p - paste what's in the OS register (i.e., if you already yanked to * or you did a Ctrl+C copy in another program)

NOTE: deleting text puts that text into the default register, so if you yy, move to another line, then dd, you'll lose whatever whatever you yanked with yy. There is a plugin to override this behavior (I think by Tim Pope).

Search and Replace

:<range>s/<RegEx>/<str>/<flags> - substitute first instance of <RegEx> in each line in <range> with <str>. <flags> change default behavior.

  • <range>:
    • default range is this line only
    • % - global (whole file)
    • <a>,<b> - between lines/markers/etc
    • . - current line
    • $ - last line in file (so :.,$s is "from here to end of file")
    • There are other <range> things, most common is just %.
  • <flags>
    • g - global/all instances of <RegEx> on line (not just first instance on line)
    • c - confirm (will highlight next instance of <RegEx> and ask you to press "y" to execute change
    • i - case insensitive

Specific substitution: Use \zs and \ze to demark a sub-RegEx within the matched RegEx that should be substituted. Example:

:%s/Year \zs2019\ze is over/2020/g

This changes all instances of "Year 2019 is over" to "Year 2020 is over", but not "2019 was great!" to "2020 was great!".

Advanced motion(ish) commands

There are "motion" commands that can be used with delete, yank, etc., that can be used to target specific text objects. dw will delete from cursor to beginning of next word, so will not delete the entire current word under the cursor unless the cursor happens to be at the beginning of the word. So bdw will delete the whole word and the space(s) after it (unless the cursor is already at the beginning of the word).

A shortcut around this is these motion-like object commands.

  • daw - Delete "a" "word". Deletes the current word and space(s) after it.
  • diw - Delete "inner" "word". Deletes current word but not trailing space(s).
  • dap - Delete a paragraph. A "paragraph" to Vim is a group of consecutive lines of text.
  • yaw - Yanks a word.
  • yiw - Yanks inner word.
  • ya( - Yank a parenthetical. If the cursor is between (), yank everything between those parens and the parens themselves. Else do Nothing.
  • yi( - Yank inner parenthetical. Like ya(, but excluding the parens.
  • ya) - ya(
  • ya[ - Same as ya( but for brackets [].
  • ya" - Same but for ".
  • da( - Deletes a parenthetical.
  • di( - Deletes within parenthetical.
  • g~i( - Toggles the case of the inner parenthetical.
  • ciw - Change inner word
  • ci[ - Change inner (within) brackets (delete text within brackets and enter Insert Mode).

Repeating Commands

Macros

Macros let you record a series of commands and replay them with a single command. Hit q then some letter, for example a, to begin recording macro "a". Do your series of commands, then hit q to stop recording. Replay the macro with @ followed by the macro name, e.g., @a. Using [#]@a repeats a [#] times, e.g., 5@a to replay the macro 5 times in a row.

Repeating Commands with the . Key

The command . repeats last edit command you executed, including insert, replace, indent, etc. This is one of the most useful features in Vim. Some examples:

  • A;<Esc>j.
    • Enter insert mode at end of line (A),
    • type a semi-colon (;),
    • exit Insert Mode; (<Esc>),
    • move down one line (j),
    • add a semi-colon to the end of this new line without leaving Normal Mode (. which equals A;<Esc>).
  • >>...
    • Indent this line >>,
    • then indent it another three times (...).

Marks

Lower case are local, upper case are global (across files). Jumping to a mark is a standard motion command for deleting, yanking, etc.

  • ma - sets mark on current cursor location (line and column), WLOG, called "a"
  • 'a - jump to line of "a" (first non-blank character of line)
  • \`a - jump to position of "a" (line and col)
  • :marks - lists all current marks
  • :delmarks <args> - delete specific marks
  • :delmarks! - delete all lowercase in buffer
  • ]', [' - jump to next (previous) line with a lowercase mark
  • \`] \`[

Special Marks

  • ' - The line you were on before making a "jump". So if you're on line 57 and jump to beginning of file using gg:, hitting '' will take you right back to line 57.
  • '. - Jump to last edit in current buffer (the mark name is .)

Spellcheck

Turn on with :set spell, turn off with :set nospell.

  • z= - Suggest correctly spelled words
  • ]s, [s - Move to next/previous mispelled word (use S for "bad words only")
  • zq - Add word under cursor as good word to first name in 'spellfile'
  • zw - Mark as bad word
  • zu[q,w] - Undo marking

Predictive completion (while in Insert Mode)

  • c-p - predictive completion (word)
  • c-x c-l - predictive completion (line)

This takes what you've already typed (either word or line) and uses the text in the rest of any open buffers to predict what will come next. If there's only one possibility, it will be filled in. If there are several possibilities, it will list the possible choices.

Vim autocomplete is pretty nice, but there are better automated predictive text solutions (specifically, the package YouCompleteMe). However, I've found they're a bit too demanding for most laptops and only useful on desktop computers.

Global command by line

  • :g/<RegEx>/<edit command> - perform the edit command on every line that matches RegEx
  • :g!/... or :v/... - the same but for lines that don't match

Examples:

  • :g/DEL THIS/d deletes every line that contains "DEL THIS"
  • :g/ $/d deletes every line that ends with a space.