yi-0.8.1: The Haskell-Scriptable Editor

Safe HaskellNone



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.

From Berlage:

   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 Source

A new empty URList. 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

addChangeU :: Change -> URList -> URList Source

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.

setSavedFilePointU :: URList -> URList Source

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.

isAtSavedFilePointU :: URList -> Bool Source

undoIsAtSavedFilePoint. 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 the save.

undoU :: Mark -> URList -> BufferImpl syntax -> (BufferImpl syntax, (URList, [Update])) Source

This undoes one interaction step.

redoU :: Mark -> URList -> BufferImpl syntax -> (BufferImpl syntax, (URList, [Update])) Source

This redoes one iteraction step.

data URList Source

A URList consists of an undo and a redo list.