TIP 104: Generalization of the Tk Undo Subsystem

EuroTcl/OpenACS 11 - 12 JULY 2024, VIENNA
Author:         Ludwig Callewaert <[email protected]>
Author:         Larry W. Virden. <[email protected]>
State:          Final
Type:           Project
Vote:           Done
Created:        19-Jun-2002
Discussions-To: news:comp.lang.tcl
Tcl-Version:    8.4
Tk-Ticket:      554763


This TIP proposes a reimplementation of the Tk Text widget undo feature. The text widget interface is not affected. No functional changes are made at the Tcl level. The purpose of the reimplementation is to move the undo feature from a text only implementation to a general implementation also usable by other widgets. This opens the door to undoing also tag, mark and other operations, and allows for an exposure of the undo stack at the Tcl level. These new features are however not part of this TIP.


As stated in the abstract, the current implementation of the text widget undo feature only allows for text changes to be undone. The usefulness of the undo feature would increase tremendously if other operations could be undone (tags, marks, embedded windows, ...). This was already part of the [26] discussions. This TIP deals with the generalization of the undo stack to cope with these requirements.


As the undo functionality is no longer text widget specific, it has been put in a separate file generic/tkUndo.c along with its header file generic/tkUndo.h. The TkUndoRedoStack is a structure containing the undo and redo stacks. These undo and redo stacks are linked lists of TkUndoAtom structures. There are two types of these atoms: the separator (similar to the previous implementation) and the command. When the type is command, both an apply and a revert action need to be provided. The apply action is for the redo. The revert action is for the undo. Both are pointers to a Tcl_Obj, so they can (and should) contain a Tcl script.

The following functions all operating on a TkUndoRedoStack stack are provided to implement the undo/redo functionality.

  1. TkUndoInitStack(interp): returns a pointer to an initialized TkUndoRedoStack and stores interp in that stack for script evaluation.

  2. TkUndoClearStacks(stack): clears both the undo and the redo stacks.

  3. TkUndoFreeStack(stack): clears both undo and redo stacks and frees any memory allocated to stack.

  4. TkUndoInsertUndoSeparator(stack): inserts a separator on the undo stack. Note that there is currently no need for a TkUndoInsertRedoSeparator function, as the redo stack is managed by the internals of TkUndo.

  5. TkUndoPushAction(stack, actionScript, revertScript): pushes an action of the undo stack (an atom of type command). actionScript and revertScript are Tcl_DString pointers that provide the script to redo and undo the action respectively. The redo stack is cleared.

  6. TkUndoRevert(stack): undo a compound action. Compound means all revert script of action between two separators on the undo stack are evaluated in the stack's interpreter and the actions are moved to the redo stack. Returns TCL_ERROR when unsuccessful (stack empty for instance), and TCL_OK otherwise.

  7. TkUndoApply(stack): redo a compound action. The apply script of all actions between two separators on the redo stack is evaluated in the stack's interpreter. The actions are moved to the undo stack. Returns TCL_ERROR when unsuccessful (stack empty for instance), and TCL_OK otherwise.

  8. TkUndoSetDepth(stack, maxDepth): sets the maximum number of compound actions stored on the stack to maxDepth. By default, stacks are unlimited, and a value of maxDepth <= 0 resets the stack to be unlimited.

  9. The option -maxundo is added to the text widget to access the stack limit feature of the text widget's undo stack from the script level.

These functions are sufficient to implement the current undo functionality of the text widget, and they have been used for this purpose.

Reference Implementation

See patch #554763 on SourceForge: _ https://sourceforge.net/tracker/?func=detail&atid=312997&aid=554763&group\_id=12997 _


This document has been placed in the public domain.