• Stars
    star
    113
  • Rank 310,115 (Top 7 %)
  • Language
    Emacs Lisp
  • License
    GNU General Publi...
  • Created over 5 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Navigate the emacs undo history by staging undo's in a temporary buffer

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:

  1. If you get lost, you can cancel the whole series of undo’s, without modifying the original buffer or undo history.
  2. 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.
  3. 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):

./assets/undo-propose.gif

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-propose
  • undo-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.