A Vim Journey: Putting It All Together
When I started this series, I had been using Vim for years without getting much beyond basic editing. Learning the command structure gave all those cryptic combinations somewhere to fit.
We have covered quite a few commands since then. Enough that finding one again can mean scrolling through three posts 😅. This part brings the useful ones together, grouped by what you want to do.
If something here feels unfamiliar, the earlier posts have the explanations and examples:
- Part 1: Modes and the language of editing
- Part 2: Visual selections and bulk edits
- Part 3: Registers, clipboard, buffers and windows
There is also the Vim cheatsheet for a separate reference.
Start With the Edit You Want
Suppose your cursor is inside this string:
const message = "Hello, World!";
You want to replace the greeting. You could move to one end and delete character by character. Or you could tell Vim: change inside the quotes.
ci"
Type the replacement, then press Esc.
The same pieces work elsewhere: di" deletes the contents, and yi" copies them. Swap i" for iw to work on a word, or i( to work inside parentheses.
The useful question is: what action, on which text? Once you know those two things, you can often assemble the command rather than look up a new shortcut.
A motion describes where to move, such as w or $. A text object describes a piece of text, such as iw or i". Both can give an operator its target, but text objects like iw aren’t standalone Normal-mode movement commands. The motion and text-object reference explains the distinction.
The Everyday Editing Cheatsheet
Unless noted otherwise, start in Normal mode. Press Esc to leave Insert or Visual mode. Type sequences one key after another; Ctrl-r means hold Control while pressing r. Commands beginning with : need Enter.
| What you want | Keys |
|---|---|
| Insert before the cursor | i |
| Append at the end of the line | A |
| Open a new line below | o |
| Change the word under the cursor | ciw |
| Change inside double quotes | ci" |
| Change inside parentheses | ci( |
| Delete the current line | dd |
| Delete three lines, starting with this one | 3dd |
| Delete from the cursor to the end of the line | d$ |
| Copy the current line | yy |
| Put copied text after the cursor or below the line | p |
| Put it before the cursor or above the line | P |
| Undo / redo | u / Ctrl-r |
| Repeat the last change | . |
For p and P, the placement depends on whether the register contains characterwise or linewise text. Copy a whole line with yy, and putting it gives you another line.
The dot command is worth remembering early. Change one quoted string with ci", type the new value, and press Esc. Move inside another quoted string and press . to apply that change again. Check the result before repeating it everywhere.
Get to the Right Place
| Where you want to go | Keys |
|---|---|
| Next word start / previous word start | w / b |
| End of a word | e |
| Start of the line / first nonblank character / end | 0 / ^ / $ |
| First line / last line | gg / G |
Next = on this line | f= |
Just before the next = on this line | t= |
| Repeat the last character search / reverse it | ; / , |
| Search forward for text | /text, then Enter |
| Repeat the search / reverse its direction | n / N |
A count is useful when you know how far to go: 3w moves three words forward. When the target is already visible, searching for it can save you from counting.
When You Want to See the Selection First
There is nothing wrong with selecting text before editing it. Seeing the highlighted area can be reassuring when you aren’t sure what a command will include.
| Selection | Keys |
|---|---|
| Characters | v, then move |
| Whole lines | V, then move |
| Rectangular block | Ctrl-v, then move |
| Inside quotes | vi" |
| Inner paragraph | vip |
| Previous Visual selection | gv |
After selecting, use d, c, or y. Use > or < to indent or dedent.
For three lines, press V2j: the starting line plus two below it. For the block-insert example from part 2, start at the first character of the first line, type Ctrl-v, 2j, then I. Type your prefix and press Esc; it appears on all three selected lines.
When the Same Edit Applies to Many Lines
Start with a small range when trying a bulk edit. Add confirmation to substitutions when you want to inspect each replacement.
| Task | Command |
|---|---|
Replace all foo matches on the current line | :s/foo/bar/g |
| Replace throughout the file, asking each time | :%s/foo/bar/gc |
| Replace on lines 5 through 10 | :5,10s/foo/bar/g |
| Sort lines 5 through 10 | :5,10sort |
| Append a semicolon to lines 5 through 10 | :5,10normal! A; |
Delete every line containing TODO | :g/TODO/d |
In a substitution, % means the whole file; g means every match on each addressed line. The search pattern is a regular expression, so the examples above aren’t a general literal-text replacement recipe.
From Visual mode, pressing : fills in :'<,'>. For example, select some lines and enter :'<,'>s/foo/bar/gc.
That range addresses whole lines. Selecting a few characters or a rectangular block does not limit this substitution to only the highlighted columns.
The ! in :normal! means to ignore mappings when executing the Normal-mode keys. It doesn’t mean the same thing as the force flag in :q!. Read the command before borrowing its punctuation. See the Normal-command reference for the details.
When a Delete Replaces Your Copied Text
This was the opening problem in part 3: yank a line, delete another one, then p puts the deleted line instead.
| Task | Keys |
|---|---|
| Put the latest yank made without choosing another register | "0p |
| Delete a line without updating the usual registers | "_dd |
Keep a line in register a | "ayy |
Put from register a | "ap |
| Inspect registers | :registers |
| Copy a line to the system clipboard | "+yy |
| Copy a Visual selection to the system clipboard | Select first, then "+y |
| Put from the system clipboard | "+p |
The clipboard commands need working clipboard integration. In Vim, check :help clipboard; in Neovim, start with :checkhealth. Over SSH, the remote editor may not have access to your local clipboard. Part 3 covers those setup differences. The register reference explains where each operation stores text.
When You Need Another File
Keep the three terms straight: a buffer holds text, a window displays a buffer, and a tab page holds a window layout.
| Task | Command or keys |
|---|---|
| Open a file in this window | :edit utils.js |
| List buffers | :ls |
| Switch to an existing buffer by a unique name fragment | :buffer utils |
| Return to this window’s alternate buffer | :buffer # |
| Open a file beside the current one | :vsplit utils.js |
| Open it above or below | :split utils.js |
| Move between windows | Ctrl-w, then h, j, k, or l |
| Equalize window sizes | Ctrl-w, then = |
| Close the current split | :close |
| Save the current buffer | :w |
| Create another tab layout | :tabnew |
| Next / previous tab page | gt / gT |
If switching files produces an unsaved-change warning, save first. :set hidden lets modified buffers stay in memory without being displayed, but it doesn’t save them. Don’t add ! to a warning just to make it go away. The multiple-files tutorial explains the save and switch workflow.
Try One Small Workflow
Put this in a disposable practice file:
const title = "Old title";
const subtitle = "Old subtitle";
console.log(title);
Then try:
- Move inside the first string. Use
ci", typeNew title, and pressEsc. - Move to the
subtitleline and yank it withyy. - Delete the log line with
dd. - Press
"0pto put the subtitle you yanked, rather than the log you just deleted. - Undo that paste with
u. - Save with
:w.
You have used the command language, a register, and undo in one ordinary edit. Repeat it until you can explain why each key is there, then try a different change.
Keep the Reference and Get Back to Editing
You don’t need to remember this whole page. Pick the command that solves today’s annoyance. Look it up again tomorrow if you forget it.
That was the point of this series: getting comfortable enough with Vim that a simple edit doesn’t turn into a fight with the editor. There is plenty left to learn, but there is also plenty here to use already.
When you need the exact behavior, Vim’s own help is worth opening: :help text-objects, :help registers, :help :substitute, and :help windows. For an online reference, see the Vim user manual.