2010-11-15

undo

One of the advantages that text-editors have over daily life is the ease of undoing things. Emacs in particular has a powerful undo-system to return to the previous state of things.

Undo can be activated by pressing C-x u or C-_; if you are more comfortable with using C-z for undo (as is the standard in many non-Emacs environments), you can of course add that key binding as well, by putting in your .emacs:

(global-set-key (kbd "C-z") 'undo)

This overrides the default of C-z triggering suspend-frame, which is not a great loss for most people.

Emacs-undo has some nice features - for example, if you have selected some text ('marked a region'), the undo operation only applies to that area. At the same time, however, the undo-model can be confusing: in emacs, undo is treated like any other command, which means that undo can be applied even to… undo, which is different from what most other editors do. Let me give an example – if it's confusing or tedious then, well, that's what it is…

Suppose I type

hello
world

now I press C-_, and I get

hello

Now I type foo

hello
foo

And press C-_ C-_; and I get back:

hello
world

This is because we're 'undoing the undo' of adding the word 'world', and thus, it reappears! When you try this in most other editors, it would result in

hello

because those editors completely forget about 'world' after it is undone.

So, emacs' model is strictly more powerful - but some (many? )people find it a bit confusing, esp. when a series of 'undos' is interrupted by a 'do'.

If you prefer the model that many other editors use, you might be interested in redo-mode, in particular in RedoPlus. Using that package, undo (or rather, redo) follows a different model. In that model, redo is 'special': it's not registered as a buffer change, and as such it's conceptually different from the redo=undo-undo model that emacs uses by default. As seen above, you actually lose some information in the process.

Yet another way to tackle the undo-problem is implemented by UndoTree: the states of your buffer are seen as nodes in a tree, and you can freely move to specific nodes. UndoTree is as powerful as the emacs system, yet easier to understand. It can even visualize the tree of changes - and you can then by clicking on a node go back to the corresponding buffer state.

Now, when using UndoTree, let's look at our example again:

We started with:

hello
world

then did C-_ (which removed 'world') and typed 'foo' to get:

hello
foo

Now press C-u again, and 'foo' disappear. Now we press C-x u (undo-tree-visualize) and we get a buffer with:

  |
  o
  |
  |
  x
  | 
 / \
o   o

and we can now visually move to any of the nodes, and our buffer is instantly brought back. Cool! The two branches correspond to the states 'world' and 'foo'. I have been undo-tree-mode for the last few weeks, and it works very well: usually I don't even notice it, but when I need the extra power, it's there.

I am told that UndoTree is inspired by the way the vim-text editor does this. Anyway, there is another very powerful feature in the vim undo-system that would be nice to have in emacs to: time-based undo. In vim you can e.g. say something like:

:earlier 5m

to go to the state of your buffer 5 minutes ago. That would be a nice addition for undo-tree-mode!

Update Tavis Rudd notes that pressing t in undo-tree-visualizer-mode (i.e.. what you see when your press C-x u) will give you timestamps instead of o and x:

                  |
                  | 
             18:54:20
                  |
                  |
             18:54:20
          ________|___ 
         /            \
     18:54:15       18:53:37
        |              |
        |              |
     18:54:15       18:53:37
     ___|___           |
    /       \          |
18:54:10  18:53:43  18:53:36

8 comments:

bruno said...
This comment has been removed by the author.
bruno said...

After many years of emacs usage, I was pointed at the ever so great 'C-/' shortcut to undo. It took a day to readjust my muscle memory from 'C-_' to the new 'C-/' ... but there is no going back now.

Tavis Rudd (openid only - no blog) said...

Regarding time based undo, type 't' in the undo-tree-visualizer-mode buffer and it'll show timestamps rather than o's and x's.

Rene Saarsoo said...

Thanks, just installed UndoTree and it really rocks. Now both my editor and version control support branching. I feel enlightened.

phayes said...

@bruno

“Many years”, eh? That's a depressing but all too common story with Emacs users, and one reason why one should try to make good use of Emacs' self-documenting nature - even for the seemingly simple things...

'C-h F undo RET' will show you that in fact 'C-/' is the primary binding for the 'undo' command. The others are aliases - 'C-x u' “for beginners”; 'C-_' “for some text-only terminals”.

Paul Hobbs said...

Also, undo in a region will undo only changes done to that region (!!). So very useful!

skm said...

As usual, thank you for shedding some light into another dark corner in emacs.
I wanted to undo without using 3 keys (or two mouse clicks for menu, undo). even C-_ is three keys counting the shift key.
C-/ is two, and easy to repeat when you want to undelete several deletions, like a whole word or line after using the del key.
Thanks!

Anonymous said...

Undo-tree is a really great piece of code, customizable, ergonomic, really great. The only problem I have with it is undo-in-region, that works quite erratically ; I recommend disabvling it