How to design undo & redo in text editor?

You can model your actions as commands, that you keep in two stacks. One for undo, another for redo. You can compose your commands to create more high-level commands, like when you want to undo the actions of a macro, for example; or if you want to group individual keystrokes of a single word, or phrase, in one action.

Each action in your editor (or a redo action) generates a new undo command that goes into the undo stack (and also clears the redo stack). Each undo action generates the corresponding redo command that goes into the redo stack.

You can also, as mentioned in the comments by derekerdmann, combine both undo and redo commands into one type of command, that knows how to undo and redo its action.


If you don't want anything fancy, you can just add an UndoManager. Your Document will fire an UndoableEdit every time you add or remove text. To undo and redo each change, simply call those methods in UndoManager.

The downside of this is UndoManager adds a new edit each time the user types something in, so typing "apple" will leave you with 5 edits, undoable one at a time. For my text editor, I wrote a wrapper for edits that stores the time it was made in addition to text change and offset, as well as an UndoableEditListener that concatenates new edits to previous ones if there is only a short period of time between them (0.5 seconds works well for me).

This works well for general editting, but causes problems when a massive replace is done. If you had a document with 5000 instances of "apple" and you wanted to replace this with "orange", you'd end up with 5000 edits all storing "apple", "orange" and an offset. To lower the amount of memory used, I've treated this as a separate case to ordinary edits and am instead storing "apple", "orange" and an array of 5000 offsets. I haven't gotten around to applying this yet, but I know that it'll cause some headaches when multiple strings match the search condition (eg. case insensitive search, regex search).


There are basically two good ways to go about it:

  • the "Command" design pattern

  • using only OO over immutable objects, where everything is just immutable objects made of immutable objects made themselves of immutable objects (this is less common but wonderfully elegant when done correctly)

The advantage of using OO over immutable objects over the naive command or the naive undo/redo is that you don't need to think much about it: no need to "undo" the effect of an action and no need to "replay" all the commands. All you need is a pointer to a huge list of immutable objects.

Because objects are immutable all the "states" can be incredibly lightweight because you can cache/reuse most objects in any state.

"OO over immutable objects" is a pure jewel. Probably not gonna become mainstream before another 10 years that said ; )

P.S: doing OO over immutable objects also amazingly simplifies concurrent programming.