ADR 0137: A count before an insert¶
Status¶
Accepted
Context¶
ADR 0136 noted in
passing that 3ob opened one line where vim opens three, and recorded it
as a separate gap. Looking at it properly, the gap was wider than that:
none of i, a, I, A, o and O read their count. All six
ignored it.
Decision¶
A count repeats the whole insert when it ends. Derived from vim rather than assumed, which mattered — three of the rules are not what "repeat it N times" would suggest on its own:
| keys | result |
|---|---|
3iab |
ababab at the point |
3aab / 3Aab / 3Iab |
the same, at that command's position |
3oab |
three new lines, each ab |
2ia<CR>b |
a⏎ba⏎b — the bytes repeat, not the keystrokes |
o and O open a line per repeat; the rest repeat inline. That is the
only difference between them, so one mechanism covers all six.
The indent is taken back per line, not per session¶
ADR 0136 removed the auto-indent from the line you left without typing on. With a count there are several such lines, and vim strips every one:
3o<Esc>on an indented line leaves three empty lines, not three four-space ones.o<CR><CR><Esc>does the same, with no count involved at all — so the single-line version was already incomplete.2ox<CR><Esc>keeps the indent on the lines holdingxand drops it on the blank ones.
So the tracked "line auto-indent wrote to" becomes a span, and leaving Insert walks it bottom-up, stripping the lines that are still only whitespace. Bottom-up because removing one line's indent shifts the offsets of every line after it.
Consequences¶
Fifteen conformance cases, every expectation vim's own. Twelve fail without the repeat.
The last one to pass was . after 3o, and it found a second hole:
vimRepeatChange() leaves Insert "the way Escape does" and had grown a
pass for the Replace count but not this one. Its replay also cannot use
the capture buffer — the text comes from m_dotInserted and capture is
suppressed during a replay — so the repeat takes the text as an argument
rather than reading it from where it usually lives.
What a count still does not reach: s, S, C and c with a motion
all enter Insert too, and none of them repeat. They were out of scope
here because each has its own deletion semantics to get right first, and
guessing at them is how the four failures above would have happened
quietly.