ADR 0077: Replace mode (R)¶
Status¶
Accepted
Context¶
r replaces one character (ADR 0076).
R keeps replacing until Escape, which is a mode rather than a single
change and so needed more than another call into that.
Decision¶
A flag on Insert, not a fourth mode¶
m_vimReplacing sits alongside VimMode::Insert, the same call
ADR 0056 made for linewise
Visual. Everything that matters — the caret shape, the gate that stops
Normal-mode keys reaching the buffer, the dot capture, Escape's step
back a column — already keys off "are we inserting". Only two paths
differ: typing, and Backspace.
The status bar says REPLACE rather than INSERT, because the
difference between them is exactly what a mode indicator is for.
Verified against vim, case by case¶
vim is installed here, so each rule was checked by running the same keys
through vim -u NONE -N and diffing the buffer:
| keys | buffer | result |
|---|---|---|
Rxy<Esc> |
abcdef |
xycdef, cursor col 2 |
Rxyz<BS><Esc> |
abcdef |
xycdef — Backspace restores c |
Rxy<BS><BS><Esc> |
abcdef |
abcdef — fully restored |
4lRxyz<Esc> |
abcdef |
abcdxyz — appends past the line end |
3Rab<Esc> |
abcdefgh |
abababgh — the count repeats the text |
2Rxy<Esc> |
abcdefgh |
xyxyefgh |
R on an empty line |
appends |
All of them match, as do . repeats of a session with and without a
count.
Backspace restores rather than deletes¶
This is the rule that shapes the data. Each typed character records what
it overwrote, so Backspace can put it back; an empty record means that
character was appended past the end of the line and there is nothing to
restore, so Backspace just removes it. Without the record, undoing a
mistyped R would eat the line instead of repairing it.
The count's extra passes run before the cursor steps back¶
Escape does two things on the way out, and their order is load-bearing.
3Rab first replays ab twice more from where typing stopped, then
steps the cursor back a column. Doing it the other way round starts each
extra pass one character early and produces aababfgh instead of
abababgh. Found by diffing against vim, not by reading the code.
. replays through the overwriting path¶
The dot machinery captures the typed text
(ADR 0075) and re-inserts it on
replay. For R that would insert rather than overwrite, so the replay
checks the flag and routes through the same per-character replace the
live session uses.
Consequences¶
Undo granularity is per typed character, not per session: Rxy<Esc>u
restores one character where vim restores the line. This is not new
— plain Insert already behaves this way (ixy<Esc>u leaves xabcdef
here against vim's abcdef), and R inherits it rather than
introducing it. Making an insert or replace session a single undo group
is a real improvement and a separate change, since it would alter i,
a, o and c as much as R.
Visual-mode r, which replaces every character in a selection, is still
not implemented — the same gap Visual-mode operators have in
ADR 0075.
R does not write a register, for the same reason r does not.