Vim's Dot Command: Repeat Edits Without Macros
Vim's dot command (.) repeats the last normal-mode change — insert, delete, change — with counts, across buffers. It's the lightweight alternative to macros for single-edit repetition, and the foundation for repeatable custom operators via vim-repeat.
26 Jun 2026, 18:29 UTC

The Problem: One Edit, Many Places
You've just changed foo_bar to fooBar on line 12 using cwfooBar<Esc>. Now you need the same change on lines 18, 33, and 47. Most people reach for a macro (qa…q) or a global substitute. But Vim has a lighter tool built into normal mode: the dot command (.). It repeats the last change — insert, delete, change, substitute — exactly as typed, including any count prefix. No recording, no playback, no register juggling.
What Counts as a "Change"
Vim defines a change as any normal-mode command that modifies the buffer: cw, dd, >ip, s, r, even . itself. Motions (j, /foo, gg) and Ex commands (:s/foo/bar/) are not changes. This distinction matters: if you delete three lines with 3dd, pressing . deletes three more lines. The count travels with the change.
Try it: open a file, type ihello<Esc>, move down a line, press .. You'll see "hello" inserted again. That's the insert-mode change repeating. For a normal-mode change like cwfoo<Esc>, the dot register holds the change command, not the inserted text.
Cross-Buffer Repetition
The dot register is global. Make a change in fileA.txt, switch to fileB.txt with :edit fileB.txt or Ctrl-^, press . — the same change applies. This lets you reformat a constant across a handful of files without writing a macro or an argdo command.
Caveat: because the register is global, a change in any buffer overwrites the repeatable change for all buffers. If you delete a line in a scratch buffer, your carefully crafted cw from the main file is gone.
Visual Mode: Linewise vs Blockwise
In Visual line mode (V), select three lines, press cwfoo<Esc>. The change applies to the first line of the selection. Pressing . then repeats that change on the next line (or the next target you navigate to), not on all selected lines at once. In Visual block mode (Ctrl-v), . repeats the change on the entire block per press. For per-line repetition inside a block selection, use :'<,'>normal . instead.
Worked Example: Bulk Indent Adjustment
Suppose you have a Python block where indentation drifted:
def process(items): for item in items: print(item) # two spaces if item.active: save(item) # two spaces return resultGoal: add two spaces to the two under-indented lines. Steps:
- Go to line 3 (
print(item)), press^to reach first non-blank, then>>to indent by one shiftwidth. That's one change.- Move to line 5 (
save(item)), press.. The same indent change applies.- Done. Two keystrokes per line after the first, no macro needed.
This works because
>>is a single change command. The dot command repeats it identically wherever you move next.Limitations Worth Knowing
- Ex commands don't repeat.
:s/foo/bar/won't work with.. Use@:for the last Ex command or a macro for sequences. - Macro playback is atomic. If the last change was
@q,.repeats the entire macro as one change, not its internal steps. - Insert mode repeat is separate. In Insert mode,
Ctrl-@(orCtrl-rthen.) inserts the last inserted text — a separate register from normal-mode.. - Persistent undo doesn't preserve the dot register. With
set undofile, undo history survives restarts, but the repeatable change is session state. After quitting and reopening Vim,.will not repeat the last change from the previous session.
Put It in Your Fingers
Next time you're about to record a macro for a single repeated edit, pause. Can you express it as one normal-mode change (cw, dd, >ip, r)? If yes, do it once, then move and press .. You'll edit faster and keep your macro registers free for actual multi-step sequences.
Verify: make a change like cwfoo<Esc>, move to another line, press . — watch it repeat. That's the feedback loop that builds intuition.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.