Vim


  • Description: Vim modal editor — modes, motions, operators, text objects, search/substitute, windows/tabs, buffers, registers, marks, ex commands, configuration
  • My Notion Note ID: K2B-1-3
  • Created: 2023-04-10
  • Updated: 2026-05-15
  • License: Reuse is very welcome. Please credit Yu Zhang and link back to the original on yuzhang.io

Table of Contents


1. Overview

  • Origin. Bram Moolenaar, 1991. Clone of Bill Joy's vi (ex work started 1976; first shipped as vi in 2BSD, 1979).
  • Name. 1991 release "Vi IMitation" → renamed "Vi IMproved" in 1992 (v1.22) once feature set surpassed original.
  • License. Charityware — donate to ICCF Holland (children in Uganda).
  • Maintainer. Bram passed 2023 → Christian Brabandt + contributors, github.com/vim/vim.
  • Ubiquity. Every Unix-like system (BSD, Linux, macOS). POSIX mandates vi; vim (or vim.tiny) satisfies it. Core motions portable across every SSH'd server.
  • Modality. Keystrokes mean different things per mode — Normal d = delete operator, Insert d = letter d. Trades discoverability for keystroke efficiency → edits become composable phrases (diw = "delete inner word") instead of mouse selections.
  • Neovim. Fork since 2014. Lua scripting, async jobs, built-in LSP. ~99% config-compatible — everything here applies to both unless noted.

2. Modes

:help vim-modes lists seven basic modes. Mode transitions are the first thing to internalize.

Mode Enter From Normal Purpose
Normal <Esc> from any mode Navigation, operators, the default
Insert i, a, o, I, A, O, s, S, c{motion} Type text
Visual (char) v Select characters
Visual (line) V Select whole lines
Visual (block) <C-v> Rectangular selection
Select gh (or mouse drag with :set selectmode=mouse) Visual mode that replaces selection on any printable key — used by snippet plugins, rare otherwise
Command-line :, /, ? Ex commands and search
Ex Q, gQ Multi-line ex prompt (:visual to leave)
Replace R Overwrite text
Terminal-Job :terminal (Neovim, Vim 8+) Embedded shell

The three Visual variants are sub-flavours of one mode; counting Visual once gives the canonical seven (Normal, Visual, Select, Insert, Command-line, Ex, Terminal-Job).

  • Return to Normal. <Esc> or <C-[> (canonical, easier reach).
  • Why modal. Alphabet stays free as commands. Modeless editors (Emacs, VS Code) burn Ctrl/Alt/Cmd on every action; Vim reserves them for orthogonal axes (windows, completion). Cost: learning curve. Payoff: common edits collapse to 2-3 keystrokes.

3. Motions

Motions move the cursor. Count-prefixable: 5j → down 5 lines; 3w → forward 3 words.

3.1 Character and Line Motions

Keys Action
h j k l Left, down, up, right
0 Start of line (column 0)
^ First non-blank character
$ End of line
g_ Last non-blank character
gg First line of file
G Last line of file
{count}G Go to line {count}
{count}gg Same as above

3.2 Word Motions

Keys Action
w / W Next word / WORD start
b / B Previous word / WORD start
e / E End of word / WORD
ge / gE End of previous word / WORD

Lowercase splits on punctuation; uppercase WORD treats whitespace as the only separator. foo.bar = two words, one WORD.

3.3 Paragraph, Sentence, Section

Keys Action
{ / } Previous / next blank-line-separated paragraph
( / ) Previous / next sentence
[[ / ]] Previous / next section (or { in column 0)

3.4 Find Within Line

Keys Action
f{char} Forward to {char}
F{char} Backward to {char}
t{char} Forward till before {char}
T{char} Backward till after {char}
; Repeat last f/t/F/T in same direction
, Repeat last f/t/F/T in opposite direction

3.5 Search-Based Motions

Keys Action
/pattern<CR> Forward search
?pattern<CR> Backward search
n / N Next / previous match
* / # Search forward / backward for word under cursor
% Jump to matching () [] {}

4. Operators and Text Objects

Verb-noun grammar — Vim's central abstraction. Operator = verb; motion or text object = noun. d3w = delete (d) three words (3w).

4.1 Operators

Key Action
d Delete
c Change (delete and enter Insert mode)
y Yank (copy)
> / < Indent right / left
= Auto-indent (formatprg)
gu / gU Lowercase / uppercase
g~ Toggle case
gq Format text
! Filter through external command

Doubled operator → current line: dd deletes line, yy yanks line, >> indents one line.

4.2 Text Objects

Pair with operators. Two flavors: i (inner, excludes delimiters) and a (around, includes delimiters).

Object Inner Around
word iw aw
WORD iW aW
sentence is as
paragraph ip ap
"..." i" a"
'...' i' a'
`...` i` a`
(...) i( or ib a( or ab
[...] i[ a[
{...} i{ or iB a{ or aB
<...> i< a<
XML/HTML tag it at

Examples:

diw      " delete inner word
daw      " delete a word (with surrounding whitespace)
ci"      " change text inside quotes
ca(      " change parens and content
dap      " delete a paragraph
yit      " yank inside HTML tag

Grammar composes uniformly. d/c/y + a handful of motions + text objects → large combinatorial vocabulary.


5. Editing Essentials

5.1 Insert Variants

Key Action
i Insert before cursor
I Insert at first non-blank of line
a Append after cursor
A Append at end of line
o Open new line below
O Open new line above
s Substitute character (delete + insert)
S Substitute line

5.2 Undo and Repeat

Key Action
u Undo
<C-r> Redo
U Undo all changes on line
. Repeat last change

. ("dot") — most underused key. Replays last text-modifying action including its count. After cw{new}<Esc>, . repeats the change on the next word cw lands on.

5.3 Copy, Paste, Join, Case

Key Action
yy Yank line
p / P Paste after / before cursor
J Join line below with current (single space)
gJ Join without inserting space
~ Toggle case of character
gU{motion} Uppercase
gu{motion} Lowercase
gUU / guu Upper/lower entire line

5.4 Indent and Format

Key Action
>> / << Indent / dedent line
=G Auto-indent to end of file
gg=G Auto-indent entire file
gqap Format paragraph to textwidth

6. Search and Substitute

/pattern<CR> → forward; ?pattern<CR> → backward. n/N repeat in original / opposite direction. 'incsearch' highlights matches as you type; 'hlsearch' keeps all matches highlighted until :noh.

6.2 Substitute

:s general form:

:[range]s/{pattern}/{replacement}/{flags}
Form Effect
:s/old/new/ First occurrence on current line
:s/old/new/g All occurrences on current line
:%s/old/new/g All occurrences in whole file (% = entire buffer)
:%s/old/new/gc Same, with confirmation per match
:5,20s/old/new/g Lines 5 through 20
:.,+10s/old/new/g Current line through 10 below
:'<,'>s/old/new/g Last visual selection (auto-inserted after : in Visual mode)

Flags: g = global within line, c = confirm, i = ignore case, I = match case, n = count matches without replacing.

6.3 Regex Flavor

Default "magic" mode: . * ^ $ \| \( \) \{ \} \+ \?. \v "very magic" → PCRE-like, every metacharacter except letters/digits/_ is special.

:%s/\v(\w+)\s+(\w+)/\2 \1/g    " swap two adjacent words
:%s/\v<TODO>/DONE/g            " word boundaries with < and >

Capture groups: \(...\) (magic) or (...) (very magic). Back-references in replacement: \1\9. Entire match: \0 or &.

6.4 Global Command

:g/pattern/cmd → run cmd on every matching line. :v/pattern/cmd → on non-matching lines.

:g/^$/d              " delete blank lines
:g/TODO/p            " print all lines with TODO
:v/^#/d              " delete lines not starting with #

7. Windows, Tabs, Buffers

Three display layers, often confused:

  • Buffer. File loaded into memory. Independent of any window.
  • Window. Viewport onto a buffer. Multiple windows can share one buffer.
  • Tab. Collection of windows. Workspace layout — not a document tab (vs. browser tabs).

7.1 Buffers

Command Action
:e {file} Edit file in current window (load into buffer)
:ls or :buffers List buffers
:b {n} or :b {name} Switch to buffer n or matching name
:bn / :bp Next / previous buffer
:bd Delete (unload) buffer
:bufdo {cmd} Run command across all buffers

7.2 Windows

Command Action
:sp {file} Horizontal split
:vsp {file} Vertical split
<C-w>s / <C-w>v Split current window
<C-w>h/j/k/l Move to window in direction
<C-w>w Cycle windows
<C-w>c or :close Close current window
<C-w>o or :only Close all other windows
<C-w>= Equalize sizes
<C-w>_ / ` `
<C-w>r Rotate windows

7.3 Tabs

Command Action
:tabnew {file} New tab
:tabclose Close current tab
gt / gT Next / previous tab
{n}gt Go to tab n
:tabmove {n} Reorder tab
:tabdo {cmd} Run command in every tab

Vim tabs ≠ browser tabs — a tab holds a whole window layout. For a file picker, use a buffer-based plugin (fzf.vim, telescope.nvim), not tabs.


8. Registers and Marks

8.1 Registers

Named clipboards. Prefix any yank/delete/paste with "{reg}:

"ayy     " yank line into register a
"ap      " paste from register a
"+y      " yank to system clipboard
"+p      " paste from system clipboard
Register Contents
"" Unnamed (last delete or yank)
"0 Last yank only
"1"9 Numbered: rotating history of line-or-bigger deletes, plus deletes by search/section motions (/, ?, n, N, %, (, ), {, }) regardless of size
"- Small-delete register (deletes shorter than one line; populated in addition to "1 when the deleting motion is one that fills "1 anyway)
"a"z Named, lowercase overwrites, uppercase appends
"+ System clipboard (X11 CLIPBOARD selection)
"* Primary selection (X11) / clipboard on macOS/Windows
"_ Black hole — discards content
"% Current file name
"# Alternate file name
". Last inserted text
": Last ex command
"/ Last search pattern
"= Expression register (evaluate vim expression)

View all with :reg.

Black hole "_. Use for deletions that shouldn't clobber the unnamed register. "_dd deletes a line without overwriting your last yank.

8.2 Marks

Named cursor position. Set with m{a-zA-Z}; jump with `{mark} (exact position) or '{mark} (line, first non-blank).

Mark Scope
mamz Per-file (lowercase)
mAmZ Global, including file name (uppercase)
`` Position before last jump
`. Last change
`^ Last insert
`[ / `] Start / end of last change or yank
`< / `> Start / end of last visual selection

:marks lists all. Global marks (mA) survive across files and sessions if 'shada' (Neovim) / 'viminfo' (Vim) is configured.


9. Ex Commands and Ranges

Commands typed after : — inherited from ed/ex, the line editors that predate vi.

9.1 Ranges

Range prefixes most ex commands. Forms:

Range Meaning
:5 Line 5
:. Current line
:$ Last line
:% Whole file (alias for 1,$)
:1,10 Lines 1 through 10
:.,+5 Current line and 5 following
:.,$ Current to end
:'a,'b From mark a to mark b
:'<,'> Last visual selection
:/foo/,/bar/ From line matching foo to line matching bar

9.2 Common Ex Commands

Command Action
:w Write (save)
:w {file} Write to another file
:q Quit (fails if unsaved)
:q! Force quit, discard changes
:wq or :x Write and quit (:x writes only if modified)
ZZ Same as :x (Normal mode)
ZQ Same as :q! (Normal mode)
:e! Reload current file, discard changes
:r {file} Insert file below cursor
:r !cmd Insert output of shell command
:!cmd Run shell command, show output
:[range]!cmd Filter range through command
:set {option} Set option
:set {option}? Query option value
:help {topic} Open help (e.g., :help :s)

9.3 Filtering Through Shell

:%!sort -u           " sort whole file, dedupe
:5,20!python -m json.tool   " pretty-print JSON in lines 5-20
:r !date             " insert current date

10. Configuration

Vim → ~/.vimrc. Neovim → ~/.config/nvim/init.vim or init.lua.

10.1 Minimal Sane Defaults

" ~/.vimrc
set nocompatible              " disable vi compatibility
syntax on                     " syntax highlighting
filetype plugin indent on     " filetype detection and indent files

set number                    " absolute line numbers
set relativenumber            " relative numbers for motion counts
set cursorline                " highlight current line

set expandtab                 " spaces, not tabs
set tabstop=4                 " a tab is 4 spaces
set shiftwidth=4              " indent step is 4 spaces
set softtabstop=4             " <BS> deletes 4 spaces
set smartindent

set ignorecase                " case-insensitive search
set smartcase                 " ...unless query has caps
set incsearch                 " show matches as you type
set hlsearch                  " highlight all matches

set hidden                    " allow buffer switching without saving
set mouse=a                   " enable mouse in all modes
set clipboard=unnamedplus     " yank to system clipboard

set undofile                  " persistent undo
set undodir=~/.vim/undo

set scrolloff=8               " keep 8 lines visible above/below cursor
set sidescrolloff=8

let mapleader = " "           " space as leader key
nnoremap <leader>w :w<CR>
nnoremap <leader>q :q<CR>
nnoremap <leader><space> :noh<CR>

10.2 Plugin Managers

Manager Style Notes
vim-plug Vimscript Single file, simple syntax — Plug 'tpope/vim-surround'
Vundle Vimscript Older, still works
packer.nvim Lua Neovim-only, declarative
lazy.nvim Lua Current default for Neovim
Native packages Built-in ~/.vim/pack/{group}/start/{plugin} — no manager needed

Near-essentials (work in both Vim and Neovim):

  • tpope/vim-surround — operate on surrounding pairs: cs"'"foo" becomes 'foo'.
  • tpope/vim-commentarygcc comments a line, gc{motion} for a range.
  • tpope/vim-repeat — makes . repeat plugin actions.
  • junegunn/fzf.vim — fuzzy file/buffer/line picker.

11. Pitfalls

  • Caps Lock as Escape on macOS. Touch Bar removed physical Escape on some models; corner reach is awkward regardless. Remap Caps Lock → Escape in System Settings → Keyboard → Modifier Keys. Or use <C-[> (identical to <Esc>).
  • :wq vs :x vs ZZ. :wq writes unconditionally (bumps mtime even if unchanged → confuses build tools); :x/ZZ write only when modified. Prefer :x for files watched by make/incremental builds.
  • Stuck in command-line history. q: (instead of :q) opens the command-line window — looks broken. Type :q<CR> inside it to close.
  • Recursive :e %:p:h. %:p:h → current file's directory; :e %:p:h opens it in netrw. Useful, but :e . from $HOME → giant tree. Prefer :Explore or a file plugin.
  • Leader key conflicts. Many plugins map <leader>{key}. Setting mapleader after sourcing plugins → plugins captured the old leader. Set mapleader at top of config, before plugin loading.
  • hlsearch lingering. Matches stay highlighted after the search. :noh clears for current view; next search restores highlighting. Common binding: <leader><space>:noh.
  • Accidental macro recording. q in Normal mode starts recording into the register named by the next keypress. Tell: recording @a at the bottom. Press q again to stop.
  • Caps Lock typing. With Caps Lock on, j/k/l/h become J/K/L/HJ joins lines, K opens man page, D deletes to end of line. Many a confused dd starts here.
  • :q! chain on :qa. Multiple modified buffers → :qa refuses. :qa! discards everything. Check :ls first to see what's modified.

12. References