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:

[register] operator [count] motion

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:

OperatorActionLeaves cursor in
dDelete (cuts to register)NORMAL
yYank (copy to register)NORMAL
cChange (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:

KeyEquivalent toAction
xdlDelete character under the cursor
XdhDelete character before the cursor
Dd$Delete from cursor to end of line
sclDelete character under cursor and enter Insert mode
SccDelete 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:

KeyAction
uUndo the last change
UUndo all changes to the current line (resets the whole line)
Ctrl+RRedo — re-apply an undone change
{n}uUndo the last n changes
Vim's undo tree: Unlike most editors which have a linear undo history, Vim records a full tree of changes. If you undo several steps and then make a new edit, the undone branch is not lost — it can be accessed with :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:

KeyBehaviour
pPut after the cursor. For whole lines, puts below the current line.
PPut before the cursor. For whole lines, puts above the current line.
gpPut after the cursor and move the cursor to the end of the pasted text.
gPPut before the cursor and move the cursor to the end of the pasted text.
{n}pPaste n times (e.g. 3p pastes three copies).
Line paste vs character paste: When you yank or delete an entire line (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

KeyModeSelects
vVISUALCharacter by character — any arbitrary range of text
VV-LINEWhole lines — always selects complete lines regardless of column
Ctrl+VV-BLOCKA 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
Visual Block insert: When you press 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
Text objects — 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 word
  • ci( — change inside parentheses
  • yi" — yank inside double quotes
  • da[ — delete around square brackets (including the brackets)
Text objects are among the most powerful features in Vim and are worth practising until they feel natural.

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

RegisterContents
"The unnamed register — what p pastes by default
0The yank register — always holds the last yanked (not deleted) text. Useful when a delete has overwritten ".
19Delete 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
The yank register (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:

KeyAction
]sJump to the next misspelled word
[sJump to the previous misspelled word
z=Show a list of suggested corrections for the word under the cursor
zgMark word as good (add to personal dictionary)
zwMark 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

Delete operator
d{motion}Delete text covered by motion (e.g. dw, d$, dG)
ddDelete entire current line
{n}ddDelete n lines
DDelete from cursor to end of line (= d$)
xDelete character under cursor
XDelete character before cursor
xpSwap current character with the next (fix transposition typos)
Undo / redo
uUndo last change
UUndo all changes to current line
Ctrl+RRedo (re-apply an undone change)
Yank (copy)
y{motion}Yank text covered by motion (e.g. yw, y$, yG)
yyYank entire current line
{n}yyYank n lines
YYank to end of line (some configs) — or yy depending on settings
Put (paste)
pPut (paste) after cursor / below current line
PPut before cursor / above current line
gpPut after cursor, move cursor to end of pasted text
gPPut before cursor, move cursor to end of pasted text
Change operator
c{motion}Delete motion + enter Insert mode (e.g. cw, c$)
ccChange entire current line
CChange from cursor to end of line (= c$)
sSubstitute character (delete char under cursor + Insert mode)
SSubstitute line (delete entire line + Insert mode = cc)
ciw / cawChange inner/around word (text object)
ci" / ca"Change inside/around double quotes
ci( / ca(Change inside/around parentheses
Visual mode
vEnter character-wise Visual mode
VEnter line-wise Visual mode
Ctrl+VEnter block-wise Visual mode (column selection)
Registers
"x{op}Use named register x for next operation (e.g. "ayy, "ap)
"Ax{op}Append to register x (uppercase letter)
"0pPaste from yank register (last yank, not overwritten by delete)
"+y / "+pYank to / paste from the system clipboard
"_d{motion}Delete to black hole register (truly removes, no paste)
:registersShow contents of all registers
Search and replace
:s/old/newReplace first occurrence on current line
:s/old/new/gReplace all occurrences on current line
:s/old/new/gcReplace all on current line with confirmation
:%s/old/new/gReplace all occurrences in entire file
:5,15s/old/new/gReplace in line range 5–15
:'<,'>s/old/new/gReplace in Visual selection
Spell checking
:set spellEnable spell checking
:set spelllang=en_gbSet spell check language
:set nospellDisable spell checking
]s / [sJump to next / previous misspelled word
z=Show spelling suggestions for word under cursor
zg / zwAdd word to personal dictionary / bad-word list