pub const MAX_UNDO_STEPS: usize = 1000;Expand description
Whole-content undo history, stored as rope snapshots.
A snapshot is a Rope rather than a String because ropey clones are O(1)
and copy-on-write: two snapshots share every node they have in common, so a
deep undo stack over a large file costs the edits, not one full copy of the
text per step. to_string() would allocate and copy the whole buffer on
every keystroke.
Whole-content snapshots stay the right call at this size — they are correct for any edit shape, and with structural sharing they are no longer expensive enough to justify per-edit deltas.
Runs have no clock. VS Code and Zed break undo groups on an idle timer.
A timer means the buffer needs a clock, which means tests need to inject one,
which means the rule is only ever exercised through a fake. The rule here is
structural instead: consecutive edits of the same EditKind coalesce, and
anything that is not an edit — a motion, a click, a save — calls boundary.
That is deterministic and it matches what a user means by “undo what I just
typed”: the run ends when they moved.
ponytail: pausing mid-word for ten minutes without moving still coalesces. If that ever bites, a timer goes beside this rule, not instead of it. How many undo steps are kept.
vim’s undolevels default, and there is no reason to be cleverer until
someone measures a session where it bites. Structural sharing makes each
snapshot cheap but not free — every one pins the rope nodes it replaced, so
an uncapped stack is an uncapped retention of every version of the file for
as long as the editor is open.