The current undo manager has served us well for a long time, but it's starting to show its age.

Current situation

The Good:

  • it works pretty nicely for us

The Bad (also know as Design Issues)

  • not extensible for other kind of actions (e.g. apply tags)
  • it connects to insert-text (thus is broken if someone does something in a signal callback that gets executed after the one in the undomanager)

The Ugly (also known as Implementation Issues)

Update: this part has been fixed with the new implementation based on GQueues.

  • Performance issues. The code was based on a single GList, but it was badly used, with a gint index to store the current location in the list instead of a GList node. So doing a single undo or redo step was a O(n) operation, now it's O(1).
  • Handling of action merging was pretty convoluted.

Proposed changes

What follows is a series of ideas to address the aforementioned issues. Some of the ideas may be good, some may be crack. Also note that while coming up with super generic UndoManager design that addresses all the issues would be nice, it's not required: we can get away with something that's just better of what we have now, especially as long as it stays private to gtksourceview.

object split

Currently we have an undomanager object that gets attached to the buffer. This is rather nice and allows to attach the undo manager to other objects without too much hassle. However it poses certain problems:

  • the object is specific to textBuffer
  • connecting to 'insert-text' is not correct (see above). doing that in the default handler buffer->insert_text is more correct because it would run after all the connected callbacks. The proposal is to have a GtkSourceUndoStack object which handles a fairly generic UndoStack given a set of possible actions, and add the text parts in GtkSourceBuffer.


Currently we can only handle insert and delete. We need a way to at least handle 'apply tag'. There are other actions that while being an insertion or deletion would be nice to be able to distinguish, e.g. paste, search and replace.

Each action could have a pointer to an ActionClass that would be an object containing a vtable specifying how that kind of action can be undone/redone/merged with the current top of the stack.

Further enhancements

There are also other enhancements that would be nice to have.

  • Get a description of the action that is about to be undone to use in the menu item/tooltip, this could be done adding a get_description callback to the ActionClass. API needs to be thought out better, since it's not as trivial as it seems (Undo and Redo have different descriptions, not in all languages you can do "Redo" + "action foo" + "(what I typed)", description should be ellipsized and menu and tooltips have different length). Fortunately as long as the api stays private we can refine this in steps.

  • Add functions that return the list of actions that can be undoed and redoed (as strings):
    • For example: "Insert 'Ciao'", "New paragraph", "Insert 'How'", "Insert 'are', "Delete 'How are'", "Insert "A very long tex...."
    • Give a look at gnumeric and LibreOffice Writer

  • Do we need to implement undo/redo toolbutton widgets? I think we should.
  • Persistent history: store the list of actions on disk???

Projects/GtkSourceView/UndoManagerRework (last edited 2014-09-11 12:27:05 by SébastienWilmet)