Undo you too far and you want it back. Today you add redo, which re-applies an undone edit by keeping a second stack of the states you undid past.
Redo an undone edit by moving state between an undo stack and a redo stack.
Redo makes undo reversible. The trick is a second stack. When you undo, instead of throwing the current state away, you push it onto a redo stack first - that saved state is precisely what redo will restore. So undo moves a state from the undo stack to the redo stack (restoring the older one), and redo moves a state from the redo stack back to the undo stack (restoring the newer one). The two stacks are mirror images, and a state slides between them as you step back and forth.
That symmetry is why redoing after an undo lands you exactly where you started -
"abcd" with the cursor at column 4 - and why redoing again, with the redo stack
empty, safely does nothing. Undo and redo now let you scrub freely along a straight
line of edits. But that line branches the moment you make a new edit after undoing,
and deciding what happens to the redo stack then is the next, subtle lesson.
// Undo now saves the CURRENT state to the redo stack before restoring:// e.redo = append(e.redo, e.Snapshot()); e.Restore(popFromUndo)// Redo is the symmetric move:func (e *Editor) Redo() {if len(e.redo) == 0 { return }last := e.redo[len(e.redo)-1]; e.redo = e.redo[:len(e.redo)-1]e.undo = append(e.undo, e.Snapshot()) // so you can undo the redoe.Restore(last)}