Learn Vim, one habit at a time
Short lessons that you play in a real Vim editor. Each one follows the same rhythm: learn the idea, try it, try it with a twist, then a boss round scored against par.
Between lessons: practice drills, the Vim cheat sheet, and a daily hole of Vim golf.
Still deciding? Is Vim worth learning, the best way to learn it, and Vim or Neovim.
In Normal mode your keyboard is a remote full of commands; in Insert mode it types. i switches to typing, Esc back to the remote, x is your first button, and u takes back a mistake.
Finish a lesson and its commands start appearing here, scheduled for review just before you'd forget them. Chapter 1 adds these:
Foundations
FreeModes, movement and the six ways to start typing. Everything else builds on these.
In Normal mode your keyboard is a remote full of commands; in Insert mode it types. i switches to typing, Esc back to the remote, x is your first button, and u takes back a mistake.
h j k l keep your fingers on the home row. Counts like 5j multiply any motion, the gutter tells you the count, and you walk the kitchen file to fix a ticket that prints twice.
w b e hop between words. Their uppercase cousins W B E leap over punctuation.
i a I A o O each start typing in a different place, so you rarely need to move first.
0 ^ $ jump to the line ends; f and t jump straight to any character, and ; repeats.
Everything from track one on one file against the clock: inspect it, repair the Formatter's damage, finish it with o O A I and ship. Then take it home: open, save and quit in a real terminal.
The Vim Way
FreeThink in repeatable changes: the dot command and its formula, combos, search-and-stamp renames, a way back from every repeat, undo, and number counters.
. repeats your last change, like a rubber stamp: ink it once with a change, then stamp it anywhere.
The dot formula: make one change you can stamp, then slide and stamp: ; . along a line, j . down a run. s swaps one character.
A I C S o O are combos: a motion and a change in one key, so . repeats them from anywhere on the line.
* lines up every copy of the word under the cursor; fix one, then n . the rest, or let cgn bring each match to you.
; and n each have a partner that goes back the other way, , and N, so overshoot freely. A change doesn't travel; u takes it back.
u and Ctrl-r skip back and forward a whole change at a time. Ctrl-a and Ctrl-x click numbers up and down like a tally counter, and gCtrl-a numbers a column.
The whole of track two against the clock: counted stamps along a search, cgn and . for the misspellings, then combos and the dot formula on the board.
Operators
ProVerb plus noun: delete, change, yank and friends, combined with every motion you know.
Commands are sentences: a verb (d delete, c change, y yank) and a noun, which is any motion you know. dw, ct,, d$.
Word-sized sentences: dw takes the space, de doesn't, db reaches back; cw is the idiom; daw and ciw work from anywhere in the word.
Say the verb twice for the whole line (dd cc yy), D and C for the rest of it, and J joins lines.
y puts a copy in the jar, p and P pour it out after or before. Deletes fill the jar too, so xp and ddp swap letters and lines.
Say the number: 3dd, d3w (or 3dw), 3p, 5.. Two numbers multiply.
Verbs that change the shape, not the words: >> and << shift, = tidies by the braces, and gU gu g~ change case with any noun.
The whole of track three against the clock: cut and change, copy and reorder, then fix the shape, on the new kitchen display.
Vertical movement
ProRelative and absolute jumps, paragraphs, scrolling and the screen: finding your way around a 300-line file.
The gutter is a ruler measuring from your line: read the distance and jump, 13j, 7k, even on a long file.
Line numbers are page numbers: gg and G for the covers, 42G or :42↵ to turn to a line you were told. Then follow a stack trace and fix what it points at.
Blank lines are paragraph breaks: } and { jump to the next and previous one, and d} cuts a whole function from the break above it.
Turn pages without a scroll wheel: Ctrl-d and Ctrl-u half a page, Ctrl-f and Ctrl-b a whole one, and zz zt zb slide the page around your line.
H, M and L jump to the top, middle and bottom of the page you can see (three lines in, with file beyond the edge); a count measures from the edge, 6H.
The whole of track four against the clock: tour legacy.js with every vertical motion, then cut its last three dead functions with d}.
Search
ProSearch forwards and back, search the word under the cursor, use a search as a motion, land a step from the match, and write patterns.
Search is a metal detector: / or ?, a few letters and ↵ jump to the next match, then n and N walk to the next and previous one.
Aim the detector at your feet: * and # search for the word under the cursor, whole words only; g* and g# match it inside longer words too.
A search is a noun: d/ digs from the cursor up to the next match and keeps the match; c/ and y? work the same way.
Stand a step from the match: /lat/e lands on its end, /lat/e+3 three past it, /lat/s+2 from its start, /lat/+1 on the line below, and n keeps the stance.
Tune the detector finer: . is any character, \d a digit, \< and \> word edges, \c any case, and \zs puts the cursor on the part of the match you want.
The whole of track five against the clock: find each swapped stop with /lat: \zs- and n, put both numbers back (retype them, or swap them with dt,, P and dE), then sweep once more and find nothing.
Text objects
ProWords, quotes, brackets, tags and paragraphs as nouns: you don't select text, you name it.
Text objects name a thing from anywhere inside it: i is the filling, a the whole burrito, foil and all. ci" keeps the quotes, da( takes the brackets.
iw and aw are a word and a word in its foil; iW and aW are the kangaroo's WORD, everything between spaces, so ciW replaces a whole dotted path.
i" is a string's filling, a" the string in its foil; from before the quotes ci" takes the first string on the line, and i' and i` work the same way.
Brackets nest like packaging: i( opens the layer around the cursor, 2i( the next one out; i[, i{ and i< are their own wrappings, and di{ empties a body.
Tags are the labels on each end of the foil: it is the text between them, at the element with both tags, and 2it reaches the next element out.
In prose the foil is white space: ip and is are a paragraph and a sentence, ap and as add the blank line or space after, so dap and das cut cleanly; ( and ) hop sentences.
Ink the stamp with an object: after ci" or ciw, . changes the next string or word from anywhere inside it, so j. and n. finish the job.
The whole of track six against the clock: the Spanish menu in JSON, HTML and Markdown, with every object from ciw to dap and the stamp on top.
Visual mode
ProCharacters, lines and blocks: select when you need to see it, and know when an operator is better.
Visual mode is a highlighter: v marks from the cursor, any motion drags it, and then a verb acts on what you see: d, c, y, >, or U u ~ for case.
The highlighter's wide edge: V marks whole lines from anywhere on them, j and } grow it, and d y > J act on every line; p puts them back whole.
A highlight has two ends: o jumps to the other one so it can move, gv brings the last highlight back, and vip marks a whole paragraph in one stroke.
Ctrl-v highlights a rectangle; I types in front of it and A after it, once, and Esc writes it on every line.
In a block, $ reaches the end of every line, so $A appends to ragged rows; c changes the block on every line and r fills it with one character.
A highlight is a strip of a fixed length, so . repeats it by the character; daw means a word, so . repeats a word. Say it with an operator when the thing changes size; highlight shapes.
The whole of track seven against the clock: rows with V, a column with Ctrl-v and I, ragged ends with $A, a highlight rescued with o, and an operator for the last doubled word.
Insert mode power
ProFix typos, run one Normal command, paste, complete and calculate without leaving Insert mode, and type over text with Replace mode.
The typing keyboard has buttons of its own: Ctrl-h rubs out a character, Ctrl-w a word, Ctrl-u everything typed on the line, and you keep typing.
Ctrl-o lends you the remote for one press: one Normal-mode command, like zz, D or 0, and you're typing again where it left you.
In Insert mode Ctrl-r pours a jar where you're typing: Ctrl-r" the last yank or delete, and Ctrl-r= the calculator, which types the answer to a sum; Ctrl-n finishes a word from the file.
Type over instead of in between: r replaces one character, R keeps typing over (⌫ gives the old ones back), r↵ splits a line. Then demo day, live.
Registers
ProVim has a whole shelf of jars: the everyday and yank jars, jars you label yourself, the bin, the clipboard and a history of deletes.
The jar you know is one of a shelf: p pours the everyday jar that every yank and delete refills, and "0p the yank jar that only yanks fill.
Jars a to z are yours: "ayy fills jar a, "ap pours it, and a capital label, "Ayy, adds to the jar instead of refilling it.
"_dd throws a line in the bin without touching any jar; "+y and "+p reach the system clipboard in your editor.
Every line you delete goes into jar 1 and shuffles the row along to 9: "2p puts back the delete before last, and "1p then u. walks back through them.
Macros
ProRecord a change once, replay it five hundred times, and write macros that work on every line.
A macro is a recipe card in a jar: qa writes down every key you press until q, and @a cooks from it again; end on the next line and 4@a does four more.
Write cards that work on every line: start from a known place (0, I, A), move by what's always there (f, not 5x), end on the next line, and let a failing step stop a too-big count.
A card can be added to with qA, or laid out with :put␣a↵, corrected like any text, and put back with 0"ay$.
Instead of a count, give the card a list of lines: :2,$normal␣@a↵ cooks it on a range, from a highlight : fills in the highlighted lines, and :g/pattern/normal␣@a↵ only on lines that match.
A card can count: copy the number from the line above, put it on this line and Ctrl-a it. Then the great reformat: 500 orders around the totals, and a numbered pick list.
Ex & substitution
ProRanges, :s and its flags, :g, :normal, copy, move and sort: edit a whole file in one line.
Monday's :2,$normal @a was an order slip: which lines (., $, %, .,+3, ribbons, a highlight), what to do, and ↵ sends it: :.,+2d↵, :%s/rider/courier/g↵.
The slip's small print: g every match on the line, c ask at each one (y or n), i any case; in the replacement & is the match, \1 a circled group, \u a capital, \= works it out. Then five files, five decisions.
The kitchen keeps the last slip: :&&↵ sends it again on this line with its flags, g& to every line (with your last search as the pattern, so :%&&↵ after a search); and * then :%s//new/g renames the word you pointed at.
A slip that picks its lines by what they say: :g/pattern/ every line that matches, :v/pattern/ every line that doesn't, then any order: :g/console\.log/d↵, :v/courier/d↵, m$ (move below the last line).
:normal takes any Normal-mode keys for every line on the slip: :%normal␣A;↵, :g/./normal␣A;↵ to skip the gaps, a highlight with I// , or only the lines :g picks. Then you choose the tool.
Orders that rearrange the lines: :t copies them to below a line you name (and leaves the jars alone), :m moves them, and :sort lines them up (u drops duplicates, n by number, a range keeps the heading out).
The whole of track twelve before midnight: the rename with the handbook link kept, the ids moved up by 1000 with \=submatch(0)+1000, and the docs cleaned with :g and a ranged :sort u. Then the release.
Real-world refactors
ProSix long boss levels on real code in TypeScript, JavaScript, Python, JSON, CSV and Markdown, scored against par.
Launch week, Monday: orders become tickets in the kitchen module. * and cgn where you choose each one (and pass by the one that must stay), a ranged :s inside one function, :%s with \<\> for whole words.
Launch week, Tuesday: the payments module goes async, on a branch. The dot formula for the same small edit at every function (n.), :%s with a group where the change has a pattern, and a list of what's left before it merges.
Launch week, Wednesday: magic numbers into one CONFIG. Ranged slips that skip the config line, patterns that match a number only where it stands on its own, and qaq then :g/note:/d A to move lines into an emptied jar.
Launch week, Thursday: the mobile payload reshaped for the new API. One slip that asks at each match for camelCase keys (a value must stay), dd and a stray comma for the structure, % to check the shape, ci" and cgn for values.
Launch week, Friday: the export reshaped. One slip with five circled columns, tested on one row first, another for cents, and a block with $A for a new column.
Launch day: comment markers are a column (Ctrl-v and I to add them, a block and d to cut them), and gqip rewraps a paragraph.
Plugins & your editor
ProSurround and commentary, VS Code Vim and IdeaVim, and your first Neovim config.
A wrapping station for track 6's foil: ys wraps a noun (ysiw"), cs swaps the wrapping (cs'"), ds takes it off; opening brackets wrap loosely, closing ones tightly.
A light switch for lines: gc flips them between code and comment, gcc this line, gcip a paragraph, gc2j three lines; the marker comes from the file's language (TypeScript, Python, HTML), and a mixed range all goes off.
The moves are yours in every editor: what carries over to VS Code Vim, vscode-neovim, IdeaVim and Zed, what to set up first, and a five-minute check to run in your own editor.
The season finale: a config of your own, init.lua with a few options that matter, a j k mapping you write yourself, Space as your leader key, and the result to copy into your editor.