CHANGING TEXT
Learning Vim
Chapter 4 — Changing Text
The Operator + Motion Grammar
In Chapter 3 we built a vocabulary of movement commands. Now we pair those movements with operators — commands that act on text — and unlock the composable editing system that makes Vim so powerful.
Almost every editing command in Vim follows one simple grammar:
The register and count are optional. The operator and motion are required.
For example: d3w means delete (operator) 3 words (count + motion). The operator and every motion from Chapter 3 can combine freely. Once you have learned the operators in this chapter you effectively have hundreds of editing commands without memorising hundreds of individual keystrokes.
The three core operators are:
| Operator | Action | Leaves cursor in |
|---|---|---|
d | Delete (cuts to register) | NORMAL |
y | Yank (copy to register) | NORMAL |
c | Change (delete + enter Insert mode) | INSERT |
Deleting Text
The d operator
The d operator deletes the text covered by whatever motion follows it. Critically, deleted text is not just removed — it is placed into a register (Vim's internal clipboard), from where it can be pasted back with p. Think of it as "cut" rather than "delete".
dw # delete from cursor to start of next word de # delete from cursor to end of current word (leaves trailing space) db # delete from cursor back to start of current word d$ # delete from cursor to end of line d0 # delete from cursor back to start of line d^ # delete from cursor back to first non-whitespace char dG # delete from current line to end of file dgg # delete from current line to start of file d} # delete to end of paragraph d/word # delete from cursor up to (but not including) the next "word" 3dw # delete 3 words (count before motion) d3w # same — count can go before or after the operator
Doubled operators — whole-line shortcuts
Doubling any operator applies it to the entire current line. This is one of the most-used patterns in Vim:
dd # delete the entire current line 5dd # delete 5 lines starting from the current line yy # yank (copy) the entire current line 3yy # yank 3 lines cc # change the entire current line (clears it and enters Insert mode)
Shorthand delete commands
A few delete operations are so common they have single-key shortcuts:
| Key | Equivalent to | Action |
|---|---|---|
x | dl | Delete character under the cursor |
X | dh | Delete character before the cursor |
D | d$ | Delete from cursor to end of line |
s | cl | Delete character under cursor and enter Insert mode |
S | cc | Delete entire line and enter Insert mode |
Before and after — common delete operations
Cursor position shown as the affected region:
| Command | Before | After |
|---|---|---|
dw |
The quick brown fox | The brown fox |
dd |
This entire line is gone | (line removed) |
d$ |
Hello, World! | Hello, |
x |
Heloo there | Helo there |
xp |
Hello (swap e and l) | Hlelo → actually: Hlelo… use xp at e → Hello ✓ |
The xp trick — swapping two characters
A classic Vim idiom for fixing a transposition typo (e.g. "teh" instead of "the") is xp: x deletes the character under the cursor into the unnamed register, and p immediately pastes it after the new cursor position — effectively swapping it with the next character.
# Fix "teh" → "the": place cursor on 'e' x # deletes 'e', cursor moves to 'h' → "th" p # pastes 'e' after 'h' → "the" ✓
Undo and redo
Every deletion (and every edit) can be undone. Vim maintains a full undo history for the session:
| Key | Action |
|---|---|
u | Undo the last change |
U | Undo all changes to the current line (resets the whole line) |
Ctrl+R | Redo — re-apply an undone change |
{n}u | Undo the last n changes |
:undolist and navigated with g- and g+. This is an advanced feature but worth knowing exists.
Yanking and Pasting
The y operator — yank (copy)
"Yank" is Vim's word for copy. The y operator works exactly like d in terms of motions — the difference is that yanking does not remove the text, it only copies it into a register.
yw # yank from cursor to start of next word ye # yank to end of current word y$ # yank to end of line y0 # yank from cursor to start of line yy # yank entire line (most common) 3yy # yank 3 lines yG # yank from current line to end of file y} # yank to end of paragraph
The p command — put (paste)
After deleting or yanking, p puts the text back. The exact position depends on what was copied:
| Key | Behaviour |
|---|---|
p | Put after the cursor. For whole lines, puts below the current line. |
P | Put before the cursor. For whole lines, puts above the current line. |
gp | Put after the cursor and move the cursor to the end of the pasted text. |
gP | Put before the cursor and move the cursor to the end of the pasted text. |
{n}p | Paste n times (e.g. 3p pastes three copies). |
yy, dd), Vim marks the register as a linewise register. Pasting a linewise register with p inserts a new line below the current one, regardless of cursor column — very convenient for duplicating or rearranging lines. Character-wise yanks paste inline at the cursor.
Practical workflow — duplicate a line
yy # yank the current line p # paste it below — now you have two identical lines # Or, to duplicate a line and move it somewhere else: yy # yank 15j # move 15 lines down p # paste below the new location
Visual Mode for Selection-Based Editing
Sometimes the operator + motion model does not map neatly to what you want to select. Visual mode lets you select text first, then apply an operator to the selection.
The three visual modes
| Key | Mode | Selects |
|---|---|---|
v | VISUAL | Character by character — any arbitrary range of text |
V | V-LINE | Whole lines — always selects complete lines regardless of column |
Ctrl+V | V-BLOCK | A rectangular block defined by rows and columns |
Once in any visual mode, use any motion command from Chapter 3 to extend the selection. Then press an operator to act on the highlighted region:
# Select three lines and delete them: V # enter Visual Line mode (current line selected) 2j # extend selection 2 lines down (3 lines total highlighted) d # delete all selected lines # Select a word and replace it: viw # visual select "inner word" (entire word under cursor) c # change — deletes selected text and enters Insert mode # now type the replacement word, then Esc # Select a paragraph and yank it: V # Visual Line mode } # extend to end of paragraph y # yank the selection
Visual Block mode — column editing
Visual Block (Ctrl+V) is unique — it selects a rectangular region of the screen, letting you edit multiple lines simultaneously. This is invaluable for tasks like adding a comment character to a block of lines, aligning columns, or deleting a column of whitespace.
# Delete the first 4 characters (indentation) from 5 lines: Ctrl+V # enter Visual Block 4j # extend down 4 lines (5 lines total selected) 3l # extend right to cover 4 columns d # delete the selected block # Add a "#" comment to the start of 4 lines simultaneously: Ctrl+V # Visual Block 3j # select 4 lines I # Insert at start of block (capital I) # # type the characters to insert Esc # the text is applied to all selected lines
I in Visual Block mode, you only see the text being typed on the first line. After pressing Esc, Vim applies the same insertion to every line in the block. This looks like nothing is happening until you press Esc — do not be alarmed.
The Change Operator
The c operator is a shortcut for the extremely common pattern of delete something, then type something new. It works exactly like d but drops you into Insert mode immediately after the deletion, ready to type the replacement.
cw # change word: delete to start of next word, enter Insert mode ce # change to end of word (more precise — does not eat trailing space) c$ # change to end of line (also written C) c0 # change from cursor to start of line cc # change entire line ciw # change inner word (deletes entire word, even from middle) ci" # change inside quotes: deletes content between " " and enters Insert ci( # change inside parentheses: deletes content between ( ) c/text # change from cursor up to next occurrence of "text" 3cw # change 3 words
iw, i", i( and friends: The i in ciw stands for inner — it selects the word without surrounding whitespace. Its partner a (for around) includes the surrounding whitespace or delimiters. Text objects work with any operator:
diw— delete inner wordci(— change inside parenthesesyi"— yank inside double quotesda[— delete around square brackets (including the brackets)
Registers — Vim's Multiple Clipboards
Every time you delete or yank text, it goes into a register. By default it goes into the unnamed register ("), which is what p pastes from. But Vim has 26 named registers — one for each letter of the alphabet — letting you store multiple pieces of text simultaneously.
Why named registers matter
The problem with relying solely on the unnamed register is that any subsequent delete or yank overwrites it. If you yank some text, then accidentally delete a word before pasting, your yanked text is gone. Named registers solve this:
# Copy a function signature to register 'a': "ayy # yank current line into register a # Do other edits (the unnamed register may get overwritten)... dd # delete a line (overwrites unnamed register) # Paste the function signature from register 'a' — still safe: "ap # paste from register a
Register syntax
# General syntax: "x before any operator or paste command "ayy # yank line into register a "bdw # delete word into register b "cp # paste from register c "Ayy # APPEND to register a (uppercase = append, lowercase = overwrite) # View all register contents: :registers # (or :reg for short)
Special registers
| Register | Contents |
|---|---|
" | The unnamed register — what p pastes by default |
0 | The yank register — always holds the last yanked (not deleted) text. Useful when a delete has overwritten ". |
1–9 | Delete history — 1 is the most recent deletion, 2 the one before that, etc. |
+ | The system clipboard — use "+y to copy to and "+p to paste from the OS clipboard |
* | The primary selection (Linux/X11 middle-click clipboard) |
_ | The black hole register — delete here and the text is truly gone, not stored anywhere |
/ | The last search pattern |
% | The current filename |
0) is your safety net: If you yank a line (yy), then accidentally delete something before pasting, "0p will always paste your last yank — even though the unnamed register was overwritten. Make "0p a habit when you have a specific yank you want to preserve.
Search and Replace
Vim's substitute command is one of its most powerful features. It uses the same regular expression engine as the / search and can replace text across a range of lines or the entire file.
The substitute command
:s/old/new # replace FIRST occurrence of 'old' on the current line :s/old/new/g # replace ALL occurrences on the current line (global flag) :s/old/new/gc # replace all on line, ask for confirmation on each :s/old/new/gi # replace all, case-insensitive
Specifying a range
:%s/old/new/g # replace all in the ENTIRE FILE (% = all lines) :5,15s/old/new/g # replace all between lines 5 and 15 :.,+5s/old/new/g # replace all from current line (.) to 5 lines below :'<,'>s/old/new/g # replace in Visual selection (range is set automatically)
Useful substitute patterns
# Replace and use the matched text in the replacement (\0 or &): :%s/error/**&**/g # wrap every "error" in ** ** # Delete all blank lines: :%s/^$//g # Remove trailing whitespace from every line: :%s/\s\+$//g # Confirmation flags — responses when using /gc: # y = yes (replace this one) # n = no (skip this one) # a = all (replace all remaining without asking) # q = quit (stop substituting) # l = last (replace this one, then quit)
Spell Checking
Vim has a built-in spell checker that is disabled by default. It is useful for documentation, commit messages, or any prose writing done in Vim.
:set spell # enable spell checking :set spelllang=en_gb # set language (en_us, en_gb, fr, de, etc.) :set nospell # disable spell checking
When spell checking is on, misspelled words are highlighted. Use these keys to navigate and fix them:
| Key | Action |
|---|---|
]s | Jump to the next misspelled word |
[s | Jump to the previous misspelled word |
z= | Show a list of suggested corrections for the word under the cursor |
zg | Mark word as good (add to personal dictionary) |
zw | Mark word as wrong (add to personal bad-word list) |
1z= | Accept the first suggestion without showing the list |
Commands Introduced in This Chapter
Chapter 4 — Command Reference
dw, d$, dG)d$)yw, y$, yG)yy depending on settingscw, c$)c$)cc)"ayy, "ap)