undo-propose
New maintainer wanted
Please let me know if you’d be interested in maintaining this
package. I’m no longer using it, as I found the built-in
revert-buffer
suffices for my need of checkpointing undo’s.
Introduction
undo-propose.el
is a package that allows you to stage undo’s in a
temporary buffer before committing them.
Emacs’ undo system is powerful, but difficult to navigate, due to the fact that Emacs treats previous undo’s as ordinary changes that can themselves be undone. One can get lost when moving through a chain of undo’s, undo’s of undo’s, and so forth, as the same edit will be traversed multiple times backwards and forwards. On top of that, trying to find an old edit can add many undo’s to the edit history, making the undo ring longer and more difficult to navigate later on.
undo-propose
addresses this by letting you stage undo’s inside a
temporary buffer. This has a few benefits:
- If you get lost, you can cancel the whole series of undo’s, without modifying the original buffer or undo history.
- You can search through your undo history for old snippets, copy and paste them back in manually, then discard the rest of the undo’s.
- When finished undo’ing, you can choose to squash the undo’s and add them as a single edit event. This makes the undo history shorter; to go back, you only have to undo 1 step, rather than redo’ing each undo individually.
Screenshot
Example of searching the undo history (right) for an old paragraph, and pasting it back into the original buffer (left):
Installation
undo-propose
is available on MELPA.
Usage
To use undo-propose, call M-x undo-propose
in the buffer you are
editing. This will send you to a new temporary buffer, which is
read-only except for allowing undo
commands. In this buffer, call
undo
as you normally would, until you have reached your desired
place in the undo history. When you are finished, type C-c C-c
to
commit the changes (both in the buffer and undo-ring) back to the
parent. Alternatively, type C-c C-s
to copy the buffer but not the
individual undo events (squashing them into a single edit event in the
undo history). To cancel, type C-c C-k
. You can also ediff the
proposed chain of undo’s by typing C-c C-d
.
Configuration
Adding commands (e.g. redo)
The undo-propose
buffer is read-only, so most commands won’t work.
However, undo
and undo-only
are specially wrapped so that they
will work in the buffer. You can use the macro undo-propose-wrap
to
make additional commands useable in undo-propose
. For example, to
add redo, call (undo-propose-wrap redo)
.
Hooks
undo-propose-entry-hook
is run after staring undo-proposeundo-propose-done-hook
is run after committing or squash committing an undo-propose
Window
By default, undo-propose
opens the temporary buffer in a new
window.
To configure window behavior, you can set display-buffer-alist
(Emacs manual).
For example, to revert to the previous default behavior of opening the buffer in the current window:
(add-to-list 'display-buffer-alist
'("\\*Undo Propose" (display-buffer-same-window)))
Markers
Currently undo-propose
does not correctly update markers in the
parent buffer after undo’ing. As a workaround, you can add markers to
undo-propose-marker-list
to ensure they are updated after undo’ing.
Example configurations
Simple configuration
(require 'undo-propose)
(global-set-key (kbd "C-c u") 'undo-propose)
Opinionated evil configuration
(with-eval-after-load 'evil
(global-undo-tree-mode -1)
(evil-define-key 'normal 'global "u" 'undo-only))
(use-package undo-propose
:commands undo-propose
:init
(evil-define-key 'normal 'global (kbd "C-r") 'undo-propose))
Note that undo-propose
(C-r
in this configuration) just calls
undo
if you’re already in an undo-propose-mode
buffer.
Related packages
undo-propose is inspired by undo-tree and git-timemachine.
See undo-tree for a more powerful undo navigation system. Unfortunately, many users experience corruption issues, leading to lost work (for example, see emacs-evil/evil#1074 and http://ergoemacs.org/emacs/emacs_best_redo_mode.html).
In contrast, undo-propose is much smaller, and meant to complement native emacs’ undo rather than replace it. It tries to minimize direct interaction with undo internals, in order to reduce the likelihood of bugs that corrupt the undo history.
References
Changes
4.0.0
Switched to using the display-buffer
framework to configure window
display. This obsoletes the option undo-propose-pop-to-buffer
. The
new default window behavior has also changed to pop up a new window,
as if the obsolete option undo-propose-pop-to-buffer
were set to
t
.
3.0.0
undo-propose-commit-buffer-only
was renamed to
undo-propose-squash-commit
, and its keybinding C-c C-b
was moved
to C-c C-s
2.0.0
C-c C-c
in the undo-propose buffer now commits to the undo-history
(undo-propose-commit
). To copy the buffer but not the undo-history
(squashing the undo’s), use C-c C-b
(undo-propose-commit-buffer-only
). The old function
undo-propose-finish
is now obsolete; use
undo-propose-commit-buffer-only
instead.