An implementation of restricted, linear undo, as described in:
T. Berlage, "A selective undo mechanism for graphical user interfaces based on command objects", ACM Transactions on Computer-Human Interaction 1(3), pp. 269-294, 1994.
Implementation based on a proposal by sjw.
All buffer-mutating commands are stored (in abstract form) in an Undo list. The most recent item in this list is the action that will be undone next. When it is undone, it is removed from the Undo list, and its inverse is added to the Redo list. The last command put into the Redo list can be redone, and again prepended to the Undo list. New commands are added to the Undo list without affecting the Redo list.
Now, the above assumes that commands can be _redone_ in a state other than that in which it was orginally done. This is not the case in our text editor: a user may delete, for example, between an undo and a redo. Berlage addresses this in S2.3. A Yi example:
Delete some characters Undo partialy Move prior in the file, and delete another _chunk_ Redo some things == corruption.
Berlage describes the stable execution property:
A command is always redone in the same state that it was originally executed in, and is always undone in the state that was reached after the original execution.
The only case where the linear undo model violates the stable execution property is when _a new command is submitted while the redo list is not empty_. The _restricted linear undo model_ ... clears the redo list in this case.
Also some discussion of this in: The Text Editor Sam, Rob Pike, pg 19.
- emptyU :: URList
- addChangeU :: Change -> URList -> URList
- setSavedFilePointU :: URList -> URList
- isAtSavedFilePointU :: URList -> Bool
- undoU :: Mark -> URList -> BufferImpl syntax -> (BufferImpl syntax, (URList, [Update]))
- redoU :: Mark -> URList -> BufferImpl syntax -> (BufferImpl syntax, (URList, [Update]))
- data URList
- data Change
A new empty
Notice we must have a saved file point as this is when we assume we are
opening the file so it is currently the same as the one on disk
Add an action to the undo list. According to the restricted, linear undo model, if we add a command whilst the redo list is not empty, we will lose our redoable changes.
Add a saved file point so that we can tell that the buffer has not been modified since the previous saved file point. Notice that we must be sure to remove the previous saved file points since they are now worthless.
True if the undo list is at a SavedFilePoint indicating
that the buffer has not been modified since we last saved the file.
Note: that an empty undo list does NOT mean that the buffer is not modified since
the last save. Because we may have saved the file and then undone actions done before
This undoes one interaction step.
This redoes one iteraction step.