1 ;;; undo-tree.el --- Treat undo history as a tree -*- lexical-binding: t; -*-
3 ;; Copyright (C) 2009-2012 Free Software Foundation, Inc
5 ;; Author: Toby Cubitt <toby-undo-tree@dr-qubit.org>
7 ;; Keywords: convenience, files, undo, redo, history, tree
8 ;; URL: http://www.dr-qubit.org/emacs.php
9 ;; Repository: http://www.dr-qubit.org/git/undo-tree.git
11 ;; This file is part of Emacs.
13 ;; This file is free software: you can redistribute it and/or modify it under
14 ;; the terms of the GNU General Public License as published by the Free
15 ;; Software Foundation, either version 3 of the License, or (at your option)
18 ;; This program is distributed in the hope that it will be useful, but WITHOUT
19 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 ;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
23 ;; You should have received a copy of the GNU General Public License along
24 ;; with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
29 ;; Emacs has a powerful undo system. Unlike the standard undo/redo system in
30 ;; most software, it allows you to recover *any* past state of a buffer
31 ;; (whereas the standard undo/redo system can lose past states as soon as you
32 ;; redo). However, this power comes at a price: many people find Emacs' undo
33 ;; system confusing and difficult to use, spawning a number of packages that
34 ;; replace it with the less powerful but more intuitive undo/redo system.
36 ;; Both the loss of data with standard undo/redo, and the confusion of Emacs'
37 ;; undo, stem from trying to treat undo history as a linear sequence of
38 ;; changes. It's not. The `undo-tree-mode' provided by this package replaces
39 ;; Emacs' undo system with a system that treats undo history as what it is: a
40 ;; branching tree of changes. This simple idea allows the more intuitive
41 ;; behaviour of the standard undo/redo system to be combined with the power of
42 ;; never losing any history. An added side bonus is that undo history can in
43 ;; some cases be stored more efficiently, allowing more changes to accumulate
44 ;; before Emacs starts discarding history.
46 ;; The only downside to this more advanced yet simpler undo system is that it
47 ;; was inspired by Vim. But, after all, most successful religions steal the
48 ;; best ideas from their competitors!
54 ;; This package has only been tested with Emacs versions 24 and CVS. It should
55 ;; work in Emacs versions 22 and 23 too, but will not work without
56 ;; modifications in earlier versions of Emacs.
58 ;; To install `undo-tree-mode', make sure this file is saved in a directory in
59 ;; your `load-path', and add the line:
61 ;; (require 'undo-tree)
63 ;; to your .emacs file. Byte-compiling undo-tree.el is recommended (e.g. using
64 ;; "M-x byte-compile-file" from within emacs).
66 ;; If you want to replace the standard Emacs' undo system with the
67 ;; `undo-tree-mode' system in all buffers, you can enable it globally by
70 ;; (global-undo-tree-mode)
72 ;; to your .emacs file.
78 ;; If you're the kind of person who likes to jump in the car and drive,
79 ;; without bothering to first figure out whether the button on the left dips
80 ;; the headlights or operates the ejector seat (after all, you'll soon figure
81 ;; it out when you push it), then here's the minimum you need to know:
83 ;; `undo-tree-mode' and `global-undo-tree-mode'
84 ;; Enable undo-tree mode (either in the current buffer or globally).
86 ;; C-_ C-/ (`undo-tree-undo')
89 ;; M-_ C-? (`undo-tree-redo')
92 ;; `undo-tree-switch-branch'
93 ;; Switch undo-tree branch.
94 ;; (What does this mean? Better press the button and see!)
96 ;; C-x u (`undo-tree-visualize')
97 ;; Visualize the undo tree.
98 ;; (Better try pressing this button too!)
100 ;; C-x r u (`undo-tree-save-state-to-register')
101 ;; Save current buffer state to register.
103 ;; C-x r U (`undo-tree-restore-state-from-register')
104 ;; Restore buffer state from register.
108 ;; In the undo-tree visualizer:
110 ;; <up> p C-p (`undo-tree-visualize-undo')
113 ;; <down> n C-n (`undo-tree-visualize-redo')
116 ;; <left> b C-b (`undo-tree-visualize-switch-branch-left')
117 ;; Switch to previous undo-tree branch.
119 ;; <right> f C-f (`undo-tree-visualize-switch-branch-right')
120 ;; Switch to next undo-tree branch.
122 ;; C-<up> M-{ (`undo-tree-visualize-undo-to-x')
123 ;; Undo changes up to last branch point.
125 ;; C-<down> M-} (`undo-tree-visualize-redo-to-x')
126 ;; Redo changes down to next branch point.
128 ;; <down> n C-n (`undo-tree-visualize-redo')
131 ;; <mouse-1> (`undo-tree-visualizer-mouse-set')
132 ;; Set state to node at mouse click.
134 ;; t (`undo-tree-visualizer-toggle-timestamps')
135 ;; Toggle display of time-stamps.
137 ;; d (`undo-tree-visualizer-toggle-diff')
138 ;; Toggle diff display.
140 ;; s (`undo-tree-visualizer-selection-mode')
141 ;; Toggle keyboard selection mode.
143 ;; q (`undo-tree-visualizer-quit')
144 ;; Quit undo-tree-visualizer.
146 ;; C-q (`undo-tree-visualizer-abort')
147 ;; Abort undo-tree-visualizer.
163 ;; In visualizer selection mode:
165 ;; <up> p C-p (`undo-tree-visualizer-select-previous')
166 ;; Select previous node.
168 ;; <down> n C-n (`undo-tree-visualizer-select-next')
171 ;; <left> b C-b (`undo-tree-visualizer-select-left')
172 ;; Select left sibling node.
174 ;; <right> f C-f (`undo-tree-visualizer-select-right')
175 ;; Select right sibling node.
178 ;; Select node 10 above.
181 ;; Select node 10 below.
183 ;; <enter> (`undo-tree-visualizer-set')
184 ;; Set state to selected node and exit selection mode.
186 ;; s (`undo-tree-visualizer-mode')
187 ;; Exit selection mode.
189 ;; t (`undo-tree-visualizer-toggle-timestamps')
190 ;; Toggle display of time-stamps.
192 ;; d (`undo-tree-visualizer-toggle-diff')
193 ;; Toggle diff display.
195 ;; q (`undo-tree-visualizer-quit')
196 ;; Quit undo-tree-visualizer.
198 ;; C-q (`undo-tree-visualizer-abort')
199 ;; Abort undo-tree-visualizer.
209 ;; Persistent undo history:
211 ;; Note: Requires a recent development version of Emacs checked out out from
212 ;; the Emacs bzr repository. All stable versions of Emacs currently
213 ;; break this feature.
215 ;; `undo-tree-auto-save-history' (variable)
216 ;; automatically save and restore undo-tree history along with buffer
217 ;; (disabled by default)
219 ;; `undo-tree-save-history' (command)
220 ;; manually save undo history to file
222 ;; `undo-tree-load-history' (command)
223 ;; manually load undo history from file
227 ;; Compressing undo history:
229 ;; Undo history files cannot grow beyond the maximum undo tree size, which
230 ;; is limited by `undo-limit', `undo-strong-limit' and
231 ;; `undo-outer-limit'. Nevertheless, undo history files can grow quite
232 ;; large. If you want to automatically compress undo history, add the
233 ;; following advice to your .emacs file (replacing ".gz" with the filename
234 ;; extension of your favourite compression algorithm):
236 ;; (defadvice undo-tree-make-history-save-file-name
237 ;; (after undo-tree activate)
238 ;; (setq concat ad-return-value ".gz"))
246 ;; To understand the different undo systems, it's easiest to consider an
247 ;; example. Imagine you make a few edits in a buffer. As you edit, you
248 ;; accumulate a history of changes, which we might visualize as a string of
249 ;; past buffer states, growing downwards:
251 ;; o (initial buffer state)
260 ;; x (current buffer state)
263 ;; Now imagine that you undo the last two changes. We can visualize this as
264 ;; rewinding the current state back two steps:
266 ;; o (initial buffer state)
269 ;; x (current buffer state)
278 ;; However, this isn't a good representation of what Emacs' undo system
279 ;; does. Instead, it treats the undos as *new* changes to the buffer, and adds
280 ;; them to the history:
282 ;; o (initial buffer state)
291 ;; x (buffer state before undo)
300 ;; Actually, since the buffer returns to a previous state after an undo,
301 ;; perhaps a better way to visualize it is to imagine the string of changes
302 ;; turning back on itself:
304 ;; (initial buffer state) o
307 ;; (first edit) o x (second undo)
310 ;; (second edit) o o (first undo)
313 ;; o (buffer state before undo)
315 ;; Treating undos as new changes might seem a strange thing to do. But the
316 ;; advantage becomes clear as soon as we imagine what happens when you edit
317 ;; the buffer again. Since you've undone a couple of changes, new edits will
318 ;; branch off from the buffer state that you've rewound to. Conceptually, it
321 ;; o (initial buffer state)
332 ;; The standard undo/redo system only lets you go backwards and forwards
333 ;; linearly. So as soon as you make that new edit, it discards the old
334 ;; branch. Emacs' undo just keeps adding changes to the end of the string. So
335 ;; the undo history in the two systems now looks like this:
337 ;; Undo/Redo: Emacs' undo
345 ;; . x (new edit) o o |
346 ;; (discarded . | / |
353 ;; Now, what if you change your mind about those undos, and decide you did
354 ;; like those other changes you'd made after all? With the standard undo/redo
355 ;; system, you're lost. There's no way to recover them, because that branch
356 ;; was discarded when you made the new edit.
358 ;; However, in Emacs' undo system, those old buffer states are still there in
359 ;; the undo history. You just have to rewind back through the new edit, and
360 ;; back through the changes made by the undos, until you reach them. Of
361 ;; course, since Emacs treats undos (even undos of undos!) as new changes,
362 ;; you're really weaving backwards and forwards through the history, all the
363 ;; time adding new changes to the end of the string as you go:
368 ;; o o o (undo new edit)
371 ;; o o | | o (undo the undo)
374 ;; (trying to get o | | x (undo the undo)
375 ;; to this state) | /
379 ;; So far, this is still reasonably intuitive to use. It doesn't behave so
380 ;; differently to standard undo/redo, except that by going back far enough you
381 ;; can access changes that would be lost in standard undo/redo.
383 ;; However, imagine that after undoing as just described, you decide you
384 ;; actually want to rewind right back to the initial state. If you're lucky,
385 ;; and haven't invoked any command since the last undo, you can just keep on
386 ;; undoing until you get back to the start:
388 ;; (trying to get o x (got there!)
389 ;; to this state) | |
391 ;; o o o o (keep undoing)
394 ;; o o | | o o (keep undoing)
397 ;; (already undid o | | o (got this far)
398 ;; to this state) | /
402 ;; But if you're unlucky, and you happen to have moved the point (say) after
403 ;; getting to the state labelled "got this far", then you've "broken the undo
404 ;; chain". Hold on to something solid, because things are about to get
405 ;; hairy. If you try to undo now, Emacs thinks you're trying to undo the
406 ;; undos! So to get back to the initial state you now have to rewind through
407 ;; *all* the changes, including the undos you just did:
409 ;; (trying to get o x (finally got there!)
410 ;; to this state) | |
414 ;; | | \ | \ | \ | \ |
415 ;; o o | | o o o | o o
416 ;; | / | | | / | | | /
418 ;; (already undid o | | o<. | | o
419 ;; to this state) | / : | /
423 ;; (got this far, but
424 ;; broke the undo chain)
428 ;; In practice you can just hold down the undo key until you reach the buffer
429 ;; state that you want. But whatever you do, don't move around in the buffer
430 ;; to *check* that you've got back to where you want! Because you'll break the
431 ;; undo chain, and then you'll have to traverse the entire string of undos
432 ;; again, just to get back to the point at which you broke the
433 ;; chain. Undo-in-region and commands such as `undo-only' help to make using
434 ;; Emacs' undo a little easier, but nonetheless it remains confusing for many
438 ;; So what does `undo-tree-mode' do? Remember the diagram we drew to represent
439 ;; the history we've been discussing (make a few edits, undo a couple of them,
440 ;; and edit again)? The diagram that conceptually represented our undo
441 ;; history, before we started discussing specific undo systems? It looked like
444 ;; o (initial buffer state)
450 ;; o x (current state)
455 ;; Well, that's *exactly* what the undo history looks like to
456 ;; `undo-tree-mode'. It doesn't discard the old branch (as standard undo/redo
457 ;; does), nor does it treat undos as new changes to be added to the end of a
458 ;; linear string of buffer states (as Emacs' undo does). It just keeps track
459 ;; of the tree of branching changes that make up the entire undo history.
461 ;; If you undo from this point, you'll rewind back up the tree to the previous
475 ;; If you were to undo again, you'd rewind back to the initial state. If on
476 ;; the other hand you redo the change, you'll end up back at the bottom of the
477 ;; most recent branch:
479 ;; o (undo takes you here)
485 ;; o x (redo takes you here)
490 ;; So far, this is just like the standard undo/redo system. But what if you
491 ;; want to return to a buffer state located on a previous branch of the
492 ;; history? Since `undo-tree-mode' keeps the entire history, you simply need
493 ;; to tell it to switch to a different branch, and then redo the changes you
499 ;; o (start here, but switch
500 ;; |\ to the other branch)
507 ;; Now you're on the other branch, if you undo and redo changes you'll stay on
508 ;; that branch, moving up and down through the buffer states located on that
509 ;; branch. Until you decide to switch branches again, of course.
511 ;; Real undo trees might have multiple branches and sub-branches:
524 ;; Trying to imagine what Emacs' undo would do as you move about such a tree
525 ;; will likely frazzle your brain circuits! But in `undo-tree-mode', you're
526 ;; just moving around this undo history tree. Most of the time, you'll
527 ;; probably only need to stay on the most recent branch, in which case it
528 ;; behaves like standard undo/redo, and is just as simple to understand. But
529 ;; if you ever need to recover a buffer state on a different branch, the
530 ;; possibility of switching between branches and accessing the full undo
531 ;; history is still there.
535 ;; The Undo-Tree Visualizer
536 ;; ========================
538 ;; Actually, it gets better. You don't have to imagine all these tree
539 ;; diagrams, because `undo-tree-mode' includes an undo-tree visualizer which
540 ;; draws them for you! In fact, it draws even better diagrams: it highlights
541 ;; the node representing the current buffer state, it highlights the current
542 ;; branch, and you can toggle the display of time-stamps (by hitting "t") and
543 ;; a diff of the undo changes (by hitting "d"). (There's one other tiny
544 ;; difference: the visualizer puts the most recent branch on the left rather
547 ;; Bring up the undo tree visualizer whenever you want by hitting "C-x u".
549 ;; In the visualizer, the usual keys for moving up and down a buffer instead
550 ;; move up and down the undo history tree (e.g. the up and down arrow keys, or
551 ;; "C-n" and "C-p"). The state of the "parent" buffer (the buffer whose undo
552 ;; history you are visualizing) is updated as you move around the undo tree in
553 ;; the visualizer. If you reach a branch point in the visualizer, the usual
554 ;; keys for moving forward and backward in a buffer instead switch branch
555 ;; (e.g. the left and right arrow keys, or "C-f" and "C-b").
557 ;; Clicking with the mouse on any node in the visualizer will take you
558 ;; directly to that node, resetting the state of the parent buffer to the
559 ;; state represented by that node.
561 ;; You can also select nodes directly using the keyboard, by hitting "s" to
562 ;; toggle selection mode. The usual motion keys now allow you to move around
563 ;; the tree without changing the parent buffer. Hitting <enter> will reset the
564 ;; state of the parent buffer to the state represented by the currently
567 ;; It can be useful to see how long ago the parent buffer was in the state
568 ;; represented by a particular node in the visualizer. Hitting "t" in the
569 ;; visualizer toggles the display of time-stamps for all the nodes. (Note
570 ;; that, because of the way `undo-tree-mode' works, these time-stamps may be
571 ;; somewhat later than the true times, especially if it's been a long time
572 ;; since you last undid any changes.)
574 ;; To get some idea of what changes are represented by a given node in the
575 ;; tree, it can be useful to see a diff of the changes. Hit "d" in the
576 ;; visualizer to toggle a diff display. This normally displays a diff between
577 ;; the current state and the previous one, i.e. it shows you the changes that
578 ;; will be applied if you undo (move up the tree). However, the diff display
579 ;; really comes into its own in the visualizer's selection mode (see above),
580 ;; where it instead shows a diff between the current state and the currently
581 ;; selected state, i.e. it shows you the changes that will be applied if you
582 ;; reset to the selected state.
584 ;; (Note that the diff is generated by the Emacs `diff' command, and is
585 ;; displayed using `diff-mode'. See the corresponding customization groups if
586 ;; you want to customize the diff display.)
588 ;; Finally, hitting "q" will quit the visualizer, leaving the parent buffer in
589 ;; whatever state you ended at. Hitting "C-q" will abort the visualizer,
590 ;; returning the parent buffer to whatever state it was originally in when the
598 ;; Emacs allows a very useful and powerful method of undoing only selected
599 ;; changes: when a region is active, only changes that affect the text within
600 ;; that region will be undone. With the standard Emacs undo system, changes
601 ;; produced by undoing-in-region naturally get added onto the end of the
602 ;; linear undo history:
606 ;; | x (second undo-in-region)
609 ;; | o (first undo-in-region)
615 ;; You can of course redo these undos-in-region as usual, by undoing the
623 ;; | o o (undo the undo-in-region)
627 ;; o x (undo the undo-in-region)
630 ;; In `undo-tree-mode', undo-in-region works similarly: when there's an active
631 ;; region, undoing only undoes changes that affect that region. However, the
632 ;; way these undos-in-region are recorded in the undo history is quite
633 ;; different. In `undo-tree-mode', undo-in-region creates a new branch in the
634 ;; undo history. The new branch consists of an undo step that undoes some of
635 ;; the changes that affect the current region, and another step that undoes
636 ;; the remaining changes needed to rejoin the previous undo history.
638 ;; Previous undo history Undo-in-region
646 ;; o o x (undo-in-region)
651 ;; As long as you don't change the active region after undoing-in-region,
652 ;; continuing to undo-in-region extends the new branch, pulling more changes
653 ;; that affect the current region into an undo step immediately above your
654 ;; current location in the undo tree, and pushing the point at which the new
655 ;; branch is attached further up the tree:
657 ;; First undo-in-region Second undo-in-region
662 ;; o o x (undo-in-region)
670 ;; Redoing takes you back down the undo tree, as usual (as long as you haven't
671 ;; changed the active region after undoing-in-region, it doesn't matter if it
686 ;; What about redo-in-region? Obviously, this only makes sense if you have
687 ;; already undone some changes, so that there are some changes to redo!
688 ;; Redoing-in-region splits off a new branch of the undo history below your
689 ;; current location in the undo tree. This time, the new branch consists of a
690 ;; redo step that redoes some of the redo changes that affect the current
691 ;; region, followed by all the remaining redo changes.
693 ;; Previous undo history Redo-in-region
701 ;; o o x (redo-in-region)
706 ;; As long as you don't change the active region after redoing-in-region,
707 ;; continuing to redo-in-region extends the new branch, pulling more redo
708 ;; changes into a redo step immediately below your current location in the
711 ;; First redo-in-region Second redo-in-region
719 ;; o x (redo-in-region) o o
722 ;; o o o x (redo-in-region)
727 ;; Note that undo-in-region and redo-in-region only ever add new changes to
728 ;; the undo tree, they *never* modify existing undo history. So you can always
729 ;; return to previous buffer states by switching to a previous branch of the
736 (eval-when-compile (require 'cl))
741 ;;; =====================================================================
742 ;;; Compatibility hacks for older Emacsen
744 ;; `characterp' isn't defined in Emacs versions < 23
745 (unless (fboundp 'characterp)
746 (defalias 'characterp 'char-valid-p))
748 ;; `region-active-p' isn't defined in Emacs versions < 23
749 (unless (fboundp 'region-active-p)
750 (defun region-active-p () (and transient-mark-mode mark-active)))
753 ;; `registerv' defstruct isn't defined in Emacs versions < 24
754 (unless (fboundp 'registerv-make)
755 (defmacro registerv-make (data &rest _dummy) data))
757 (unless (fboundp 'registerv-data)
758 (defmacro registerv-data (data) data))
761 ;; `diff-no-select' and `diff-file-local-copy' aren't defined in Emacs
762 ;; versions < 24 (copied and adapted from Emacs 24)
763 (unless (fboundp 'diff-no-select)
764 (defun diff-no-select (old new &optional switches no-async buf)
765 ;; Noninteractive helper for creating and reverting diff buffers
766 (unless (bufferp new) (setq new (expand-file-name new)))
767 (unless (bufferp old) (setq old (expand-file-name old)))
768 (or switches (setq switches diff-switches)) ; If not specified, use default.
769 (unless (listp switches) (setq switches (list switches)))
770 (or buf (setq buf (get-buffer-create "*Diff*")))
771 (let* ((old-alt (diff-file-local-copy old))
772 (new-alt (diff-file-local-copy new))
776 ;; Use explicitly specified switches
778 ,@(mapcar #'shell-quote-argument
780 (when (or old-alt new-alt)
781 (list "-L" (if (stringp old)
782 old (prin1-to-string old))
783 "-L" (if (stringp new)
784 new (prin1-to-string new))))
785 (list (or old-alt old)
788 (thisdir default-directory))
789 (with-current-buffer buf
790 (setq buffer-read-only t)
791 (buffer-disable-undo (current-buffer))
792 (let ((inhibit-read-only t))
794 (buffer-enable-undo (current-buffer))
796 (set (make-local-variable 'revert-buffer-function)
797 (lambda (_ignore-auto _noconfirm)
798 (diff-no-select old new switches no-async (current-buffer))))
799 (setq default-directory thisdir)
800 (let ((inhibit-read-only t))
801 (insert command "\n"))
802 (if (and (not no-async) (fboundp 'start-process))
803 (let ((proc (start-process "Diff" buf shell-file-name
804 shell-command-switch command)))
805 (set-process-filter proc 'diff-process-filter)
806 (set-process-sentinel
807 proc (lambda (proc _msg)
808 (with-current-buffer (process-buffer proc)
809 (diff-sentinel (process-exit-status proc))
810 (if old-alt (delete-file old-alt))
811 (if new-alt (delete-file new-alt))))))
812 ;; Async processes aren't available.
813 (let ((inhibit-read-only t))
815 (call-process shell-file-name nil buf nil
816 shell-command-switch command))
817 (if old-alt (delete-file old-alt))
818 (if new-alt (delete-file new-alt)))))
821 (unless (fboundp 'diff-file-local-copy)
822 (defun diff-file-local-copy (file-or-buf)
823 (if (bufferp file-or-buf)
824 (with-current-buffer file-or-buf
825 (let ((tempfile (make-temp-file "buffer-content-")))
826 (write-region nil nil tempfile nil 'nomessage)
828 (file-local-copy file-or-buf))))
833 ;;; =====================================================================
834 ;;; Global variables and customization options
836 (defvar buffer-undo-tree nil
837 "Tree of undo entries in current buffer.")
838 (make-variable-buffer-local 'buffer-undo-tree)
839 (put 'buffer-undo-tree 'permanent-local t)
842 (defgroup undo-tree nil
846 (defcustom undo-tree-mode-lighter " Undo-Tree"
847 "Lighter displayed in mode line
848 when `undo-tree-mode' is enabled."
853 (defcustom undo-tree-incompatible-major-modes '(term-mode)
854 "List of major-modes in which `undo-tree-mode' should not be enabled.
855 \(See `turn-on-undo-tree-mode'.\)"
857 :type '(repeat symbol))
860 (defcustom undo-tree-enable-undo-in-region t
861 "When non-nil, enable undo-in-region.
863 When undo-in-region is enabled, undoing or redoing when the
864 region is active (in `transient-mark-mode') or with a prefix
865 argument (not in `transient-mark-mode') only undoes changes
866 within the current region."
871 (defcustom undo-tree-auto-save-history nil
872 "When non-nil, `undo-tree-mode' will save undo history to file
873 when a buffer is saved to file.
875 It will automatically load undo history when a buffer is loaded
876 from file, if an undo save file exists.
878 Undo-tree history is saved to a file called
879 \".<buffer-file-name>.~undo-tree\" in the same directory as the
882 WARNING! `undo-tree-auto-save-history' will not work properly in
883 Emacs versions prior to 24.3, so it cannot be enabled via
884 the customization interface in versions earlier than that one. To
885 ignore this warning and enable it regardless, set
886 `undo-tree-auto-save-history' to a non-nil value outside of
889 :type (if (version-list-< (version-to-list emacs-version) '(24 3))
890 '(choice (const :tag "<disabled>" nil))
894 (defcustom undo-tree-history-directory-alist nil
895 "Alist of filename patterns and undo history directory names.
896 Each element looks like (REGEXP . DIRECTORY). Undo history for
897 files with names matching REGEXP will be saved in DIRECTORY.
898 DIRECTORY may be relative or absolute. If it is absolute, so
899 that all matching files are backed up into the same directory,
900 the file names in this directory will be the full name of the
901 file backed up with all directory separators changed to `!' to
902 prevent clashes. This will not work correctly if your filesystem
903 truncates the resulting name.
905 For the common case of all backups going into one directory, the
906 alist should contain a single element pairing \".\" with the
907 appropriate directory name.
909 If this variable is nil, or it fails to match a filename, the
910 backup is made in the original file's directory.
912 On MS-DOS filesystems without long names this variable is always
915 :type '(repeat (cons (regexp :tag "Regexp matching filename")
916 (directory :tag "Undo history directory name"))))
920 (defcustom undo-tree-visualizer-relative-timestamps t
921 "When non-nil, display times relative to current time
922 when displaying time stamps in visualizer.
924 Otherwise, display absolute times."
929 (defcustom undo-tree-visualizer-timestamps nil
930 "When non-nil, display time-stamps by default
931 in undo-tree visualizer.
933 \\<undo-tree-visualizer-map>You can always toggle time-stamps on and off \
934 using \\[undo-tree-visualizer-toggle-timestamps], regardless of the
935 setting of this variable."
940 (defcustom undo-tree-visualizer-diff nil
941 "When non-nil, display diff by default in undo-tree visualizer.
943 \\<undo-tree-visualizer-map>You can always toggle the diff display \
944 using \\[undo-tree-visualizer-toggle-diff], regardless of the
945 setting of this variable."
950 (defcustom undo-tree-visualizer-lazy-drawing 100
951 "When non-nil, use lazy undo-tree drawing in visualizer.
953 Setting this to a number causes the visualizer to switch to lazy
954 drawing when the number of nodes in the tree is larger than this
957 Lazy drawing means that only the visible portion of the tree will
958 be drawn initially , and the tree will be extended later as
959 needed. For the most part, the only visible effect of this is to
960 significantly speed up displaying the visualizer for very large
963 There is one potential negative effect of lazy drawing. Other
964 branches of the tree will only be drawn once the node from which
965 they branch off becomes visible. So it can happen that certain
966 portions of the tree that would be shown with lazy drawing
967 disabled, will not be drawn immediately when it is
968 enabled. However, this effect is quite rare in practice."
970 :type '(choice (const :tag "never" nil)
971 (const :tag "always" t)
972 (integer :tag "> size")))
975 (defface undo-tree-visualizer-default-face
976 '((((class color)) :foreground "gray"))
977 "Face used to draw undo-tree in visualizer."
980 (defface undo-tree-visualizer-current-face
981 '((((class color)) :foreground "red"))
982 "Face used to highlight current undo-tree node in visualizer."
985 (defface undo-tree-visualizer-active-branch-face
986 '((((class color) (background dark))
987 (:foreground "white" :weight bold))
988 (((class color) (background light))
989 (:foreground "black" :weight bold)))
990 "Face used to highlight active undo-tree branch in visualizer."
993 (defface undo-tree-visualizer-register-face
994 '((((class color)) :foreground "yellow"))
995 "Face used to highlight undo-tree nodes saved to a register
999 (defface undo-tree-visualizer-unmodified-face
1000 '((((class color)) :foreground "cyan"))
1001 "Face used to highlight nodes corresponding to unmodified buffers
1006 (defvar undo-tree-visualizer-parent-buffer nil
1007 "Parent buffer in visualizer.")
1008 (make-variable-buffer-local 'undo-tree-visualizer-parent-buffer)
1010 ;; stores modification time of parent buffer's file, if any
1011 (defvar undo-tree-visualizer-parent-mtime nil)
1012 (make-variable-buffer-local 'undo-tree-visualizer-parent-mtime)
1014 ;; stores current horizontal spacing needed for drawing undo-tree
1015 (defvar undo-tree-visualizer-spacing nil)
1016 (make-variable-buffer-local 'undo-tree-visualizer-spacing)
1018 ;; calculate horizontal spacing required for drawing tree with current
1020 (defsubst undo-tree-visualizer-calculate-spacing ()
1021 (if undo-tree-visualizer-timestamps
1022 (if undo-tree-visualizer-relative-timestamps 9 13)
1025 ;; holds node that was current when visualizer was invoked
1026 (defvar undo-tree-visualizer-initial-node nil)
1027 (make-variable-buffer-local 'undo-tree-visualizer-initial-node)
1029 ;; holds currently selected node in visualizer selection mode
1030 (defvar undo-tree-visualizer-selected-node nil)
1031 (make-variable-buffer-local 'undo-tree-visualizer-selected)
1033 ;; used to store nodes at edge of currently drawn portion of tree
1034 (defvar undo-tree-visualizer-needs-extending-down nil)
1035 (make-variable-buffer-local 'undo-tree-visualizer-needs-extending-down)
1036 (defvar undo-tree-visualizer-needs-extending-up nil)
1037 (make-variable-buffer-local 'undo-tree-visualizer-needs-extending-up)
1039 ;; dynamically bound to t when undoing from visualizer, to inhibit
1040 ;; `undo-tree-kill-visualizer' hook function in parent buffer
1041 (defvar undo-tree-inhibit-kill-visualizer nil)
1043 ;; can be let-bound to a face name, used in drawing functions
1044 (defvar undo-tree-insert-face nil)
1046 ;; visualizer buffer names
1047 (defconst undo-tree-visualizer-buffer-name " *undo-tree*")
1048 (defconst undo-tree-diff-buffer-name "*undo-tree Diff*")
1050 ;; prevent debugger being called on "No further redo information"
1051 (add-to-list 'debug-ignored-errors "^No further redo information")
1052 (add-to-list 'debug-ignored-errors "^No further redo information for region")
1054 ;; install history-auto-save hooks
1055 (add-hook 'write-file-functions 'undo-tree-save-history-hook)
1056 (add-hook 'find-file-hook 'undo-tree-load-history-hook)
1061 ;;; =================================================================
1064 (defvar undo-tree-map nil
1065 "Keymap used in undo-tree-mode.")
1067 (unless undo-tree-map
1068 (let ((map (make-sparse-keymap)))
1069 ;; remap `undo' and `undo-only' to `undo-tree-undo'
1070 (define-key map [remap undo] 'undo-tree-undo)
1071 (define-key map [remap undo-only] 'undo-tree-undo)
1072 ;; bind standard undo bindings (since these match redo counterparts)
1073 (define-key map (kbd "C-/") 'undo-tree-undo)
1074 (define-key map "\C-_" 'undo-tree-undo)
1075 ;; redo doesn't exist normally, so define our own keybindings
1076 (define-key map (kbd "C-?") 'undo-tree-redo)
1077 (define-key map (kbd "M-_") 'undo-tree-redo)
1078 ;; just in case something has defined `redo'...
1079 (define-key map [remap redo] 'undo-tree-redo)
1080 ;; we use "C-x u" for the undo-tree visualizer
1081 (define-key map (kbd "\C-x u") 'undo-tree-visualize)
1082 ;; bind register commands
1083 (define-key map (kbd "C-x r u") 'undo-tree-save-state-to-register)
1084 (define-key map (kbd "C-x r U") 'undo-tree-restore-state-from-register)
1086 (setq undo-tree-map map)))
1089 (defvar undo-tree-visualizer-map nil
1090 "Keymap used in undo-tree visualizer.")
1092 (unless undo-tree-visualizer-map
1093 (let ((map (make-sparse-keymap)))
1094 ;; vertical motion keys undo/redo
1095 (define-key map [remap previous-line] 'undo-tree-visualize-undo)
1096 (define-key map [remap next-line] 'undo-tree-visualize-redo)
1097 (define-key map [up] 'undo-tree-visualize-undo)
1098 (define-key map "p" 'undo-tree-visualize-undo)
1099 (define-key map "\C-p" 'undo-tree-visualize-undo)
1100 (define-key map [down] 'undo-tree-visualize-redo)
1101 (define-key map "n" 'undo-tree-visualize-redo)
1102 (define-key map "\C-n" 'undo-tree-visualize-redo)
1103 ;; horizontal motion keys switch branch
1104 (define-key map [remap forward-char]
1105 'undo-tree-visualize-switch-branch-right)
1106 (define-key map [remap backward-char]
1107 'undo-tree-visualize-switch-branch-left)
1108 (define-key map [right] 'undo-tree-visualize-switch-branch-right)
1109 (define-key map "f" 'undo-tree-visualize-switch-branch-right)
1110 (define-key map "\C-f" 'undo-tree-visualize-switch-branch-right)
1111 (define-key map [left] 'undo-tree-visualize-switch-branch-left)
1112 (define-key map "b" 'undo-tree-visualize-switch-branch-left)
1113 (define-key map "\C-b" 'undo-tree-visualize-switch-branch-left)
1114 ;; paragraph motion keys undo/redo to significant points in tree
1115 (define-key map [remap backward-paragraph] 'undo-tree-visualize-undo-to-x)
1116 (define-key map [remap forward-paragraph] 'undo-tree-visualize-redo-to-x)
1117 (define-key map "\M-{" 'undo-tree-visualize-undo-to-x)
1118 (define-key map "\M-}" 'undo-tree-visualize-redo-to-x)
1119 (define-key map [C-down] 'undo-tree-visualize-undo-to-x)
1120 (define-key map [C-up] 'undo-tree-visualize-redo-to-x)
1121 ;; mouse sets buffer state to node at click
1122 (define-key map [mouse-1] 'undo-tree-visualizer-mouse-set)
1123 ;; toggle timestamps
1124 (define-key map "t" 'undo-tree-visualizer-toggle-timestamps)
1126 (define-key map "d" 'undo-tree-visualizer-toggle-diff)
1128 (define-key map "s" 'undo-tree-visualizer-selection-mode)
1129 ;; horizontal scrolling may be needed if the tree is very wide
1130 (define-key map "," 'undo-tree-visualizer-scroll-left)
1131 (define-key map "." 'undo-tree-visualizer-scroll-right)
1132 (define-key map "<" 'undo-tree-visualizer-scroll-left)
1133 (define-key map ">" 'undo-tree-visualizer-scroll-right)
1134 ;; vertical scrolling may be needed if the tree is very tall
1135 (define-key map [next] 'undo-tree-visualizer-scroll-up)
1136 (define-key map [prior] 'undo-tree-visualizer-scroll-down)
1137 ;; quit/abort visualizer
1138 (define-key map "q" 'undo-tree-visualizer-quit)
1139 (define-key map "\C-q" 'undo-tree-visualizer-abort)
1141 (setq undo-tree-visualizer-map map)))
1144 (defvar undo-tree-visualizer-selection-map nil
1145 "Keymap used in undo-tree visualizer selection mode.")
1147 (unless undo-tree-visualizer-selection-map
1148 (let ((map (make-sparse-keymap)))
1149 ;; vertical motion keys move up and down tree
1150 (define-key map [remap previous-line]
1151 'undo-tree-visualizer-select-previous)
1152 (define-key map [remap next-line]
1153 'undo-tree-visualizer-select-next)
1154 (define-key map [up] 'undo-tree-visualizer-select-previous)
1155 (define-key map "p" 'undo-tree-visualizer-select-previous)
1156 (define-key map "\C-p" 'undo-tree-visualizer-select-previous)
1157 (define-key map [down] 'undo-tree-visualizer-select-next)
1158 (define-key map "n" 'undo-tree-visualizer-select-next)
1159 (define-key map "\C-n" 'undo-tree-visualizer-select-next)
1160 ;; vertical scroll keys move up and down quickly
1161 (define-key map [next]
1162 (lambda () (interactive) (undo-tree-visualizer-select-next 10)))
1163 (define-key map [prior]
1164 (lambda () (interactive) (undo-tree-visualizer-select-previous 10)))
1165 ;; horizontal motion keys move to left and right siblings
1166 (define-key map [remap forward-char] 'undo-tree-visualizer-select-right)
1167 (define-key map [remap backward-char] 'undo-tree-visualizer-select-left)
1168 (define-key map [right] 'undo-tree-visualizer-select-right)
1169 (define-key map "f" 'undo-tree-visualizer-select-right)
1170 (define-key map "\C-f" 'undo-tree-visualizer-select-right)
1171 (define-key map [left] 'undo-tree-visualizer-select-left)
1172 (define-key map "b" 'undo-tree-visualizer-select-left)
1173 (define-key map "\C-b" 'undo-tree-visualizer-select-left)
1174 ;; horizontal scroll keys move left or right quickly
1176 (lambda () (interactive) (undo-tree-visualizer-select-left 10)))
1178 (lambda () (interactive) (undo-tree-visualizer-select-right 10)))
1180 (lambda () (interactive) (undo-tree-visualizer-select-left 10)))
1182 (lambda () (interactive) (undo-tree-visualizer-select-right 10)))
1183 ;; mouse or <enter> sets buffer state to node at point/click
1184 (define-key map "\r" 'undo-tree-visualizer-set)
1185 (define-key map [mouse-1] 'undo-tree-visualizer-mouse-set)
1186 ;; toggle timestamps
1187 (define-key map "t" 'undo-tree-visualizer-toggle-timestamps)
1189 (define-key map "d" 'undo-tree-visualizer-selection-toggle-diff)
1190 ;; quit visualizer selection mode
1191 (define-key map "s" 'undo-tree-visualizer-mode)
1193 (define-key map "q" 'undo-tree-visualizer-quit)
1194 (define-key map "\C-q" 'undo-tree-visualizer-abort)
1196 (setq undo-tree-visualizer-selection-map map)))
1201 ;;; =====================================================================
1202 ;;; Undo-tree data structure
1208 (:constructor make-undo-tree
1210 (root (undo-tree-make-node nil nil))
1214 (object-pool (make-hash-table :test 'eq :weakness 'value))))
1217 root current size count object-pool)
1223 (:type vector) ; create unnamed struct
1225 (:constructor undo-tree-make-node
1229 (timestamp (current-time))
1231 (:constructor undo-tree-make-node-backwards
1235 (next (list next-node))
1236 (timestamp (current-time))
1239 previous next undo redo timestamp branch meta-data)
1242 (defmacro undo-tree-node-p (n)
1243 (let ((len (length (undo-tree-make-node nil nil))))
1244 `(and (vectorp ,n) (= (length ,n) ,len))))
1249 (undo-tree-region-data
1250 (:type vector) ; create unnamed struct
1252 (:constructor undo-tree-make-region-data
1253 (&optional undo-beginning undo-end
1254 redo-beginning redo-end))
1255 (:constructor undo-tree-make-undo-region-data
1256 (undo-beginning undo-end))
1257 (:constructor undo-tree-make-redo-region-data
1258 (redo-beginning redo-end))
1260 undo-beginning undo-end redo-beginning redo-end)
1263 (defmacro undo-tree-region-data-p (r)
1264 (let ((len (length (undo-tree-make-region-data))))
1265 `(and (vectorp ,r) (= (length ,r) ,len))))
1267 (defmacro undo-tree-node-clear-region-data (node)
1268 `(setf (undo-tree-node-meta-data ,node)
1271 (plist-put (undo-tree-node-meta-data ,node)
1275 (defmacro undo-tree-node-undo-beginning (node)
1276 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1277 (when (undo-tree-region-data-p r)
1278 (undo-tree-region-data-undo-beginning r))))
1280 (defmacro undo-tree-node-undo-end (node)
1281 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1282 (when (undo-tree-region-data-p r)
1283 (undo-tree-region-data-undo-end r))))
1285 (defmacro undo-tree-node-redo-beginning (node)
1286 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1287 (when (undo-tree-region-data-p r)
1288 (undo-tree-region-data-redo-beginning r))))
1290 (defmacro undo-tree-node-redo-end (node)
1291 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1292 (when (undo-tree-region-data-p r)
1293 (undo-tree-region-data-redo-end r))))
1296 (defsetf undo-tree-node-undo-beginning (node) (val)
1297 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1298 (unless (undo-tree-region-data-p r)
1299 (setf (undo-tree-node-meta-data ,node)
1300 (plist-put (undo-tree-node-meta-data ,node) :region
1301 (setq r (undo-tree-make-region-data)))))
1302 (setf (undo-tree-region-data-undo-beginning r) ,val)))
1304 (defsetf undo-tree-node-undo-end (node) (val)
1305 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1306 (unless (undo-tree-region-data-p r)
1307 (setf (undo-tree-node-meta-data ,node)
1308 (plist-put (undo-tree-node-meta-data ,node) :region
1309 (setq r (undo-tree-make-region-data)))))
1310 (setf (undo-tree-region-data-undo-end r) ,val)))
1312 (defsetf undo-tree-node-redo-beginning (node) (val)
1313 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1314 (unless (undo-tree-region-data-p r)
1315 (setf (undo-tree-node-meta-data ,node)
1316 (plist-put (undo-tree-node-meta-data ,node) :region
1317 (setq r (undo-tree-make-region-data)))))
1318 (setf (undo-tree-region-data-redo-beginning r) ,val)))
1320 (defsetf undo-tree-node-redo-end (node) (val)
1321 `(let ((r (plist-get (undo-tree-node-meta-data ,node) :region)))
1322 (unless (undo-tree-region-data-p r)
1323 (setf (undo-tree-node-meta-data ,node)
1324 (plist-put (undo-tree-node-meta-data ,node) :region
1325 (setq r (undo-tree-make-region-data)))))
1326 (setf (undo-tree-region-data-redo-end r) ,val)))
1331 (undo-tree-visualizer-data
1332 (:type vector) ; create unnamed struct
1334 (:constructor undo-tree-make-visualizer-data
1335 (&optional lwidth cwidth rwidth marker))
1337 lwidth cwidth rwidth marker)
1340 (defmacro undo-tree-visualizer-data-p (v)
1341 (let ((len (length (undo-tree-make-visualizer-data))))
1342 `(and (vectorp ,v) (= (length ,v) ,len))))
1344 (defun undo-tree-node-clear-visualizer-data (node)
1345 (let ((plist (undo-tree-node-meta-data node)))
1346 (if (eq (car plist) :visualizer)
1347 (setf (undo-tree-node-meta-data node) (nthcdr 2 plist))
1348 (while (and plist (not (eq (cadr plist) :visualizer)))
1349 (setq plist (cdr plist)))
1350 (if plist (setcdr plist (nthcdr 3 plist))))))
1352 (defmacro undo-tree-node-lwidth (node)
1353 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1354 (when (undo-tree-visualizer-data-p v)
1355 (undo-tree-visualizer-data-lwidth v))))
1357 (defmacro undo-tree-node-cwidth (node)
1358 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1359 (when (undo-tree-visualizer-data-p v)
1360 (undo-tree-visualizer-data-cwidth v))))
1362 (defmacro undo-tree-node-rwidth (node)
1363 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1364 (when (undo-tree-visualizer-data-p v)
1365 (undo-tree-visualizer-data-rwidth v))))
1367 (defmacro undo-tree-node-marker (node)
1368 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1369 (when (undo-tree-visualizer-data-p v)
1370 (undo-tree-visualizer-data-marker v))))
1373 (defsetf undo-tree-node-lwidth (node) (val)
1374 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1375 (unless (undo-tree-visualizer-data-p v)
1376 (setf (undo-tree-node-meta-data ,node)
1377 (plist-put (undo-tree-node-meta-data ,node) :visualizer
1378 (setq v (undo-tree-make-visualizer-data)))))
1379 (setf (undo-tree-visualizer-data-lwidth v) ,val)))
1381 (defsetf undo-tree-node-cwidth (node) (val)
1382 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1383 (unless (undo-tree-visualizer-data-p v)
1384 (setf (undo-tree-node-meta-data ,node)
1385 (plist-put (undo-tree-node-meta-data ,node) :visualizer
1386 (setq v (undo-tree-make-visualizer-data)))))
1387 (setf (undo-tree-visualizer-data-cwidth v) ,val)))
1389 (defsetf undo-tree-node-rwidth (node) (val)
1390 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1391 (unless (undo-tree-visualizer-data-p v)
1392 (setf (undo-tree-node-meta-data ,node)
1393 (plist-put (undo-tree-node-meta-data ,node) :visualizer
1394 (setq v (undo-tree-make-visualizer-data)))))
1395 (setf (undo-tree-visualizer-data-rwidth v) ,val)))
1397 (defsetf undo-tree-node-marker (node) (val)
1398 `(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
1399 (unless (undo-tree-visualizer-data-p v)
1400 (setf (undo-tree-node-meta-data ,node)
1401 (plist-put (undo-tree-node-meta-data ,node) :visualizer
1402 (setq v (undo-tree-make-visualizer-data)))))
1403 (setf (undo-tree-visualizer-data-marker v) ,val)))
1408 (undo-tree-register-data
1411 (:constructor undo-tree-make-register-data (buffer node)))
1414 (defun undo-tree-register-data-p (data)
1417 (undo-tree-node-p (undo-tree-register-data-node data))))
1419 (defun undo-tree-register-data-print-func (data)
1420 (princ (format "an undo-tree state for buffer %s"
1421 (undo-tree-register-data-buffer data))))
1423 (defmacro undo-tree-node-register (node)
1424 `(plist-get (undo-tree-node-meta-data ,node) :register))
1426 (defsetf undo-tree-node-register (node) (val)
1427 `(setf (undo-tree-node-meta-data ,node)
1428 (plist-put (undo-tree-node-meta-data ,node) :register ,val)))
1433 ;;; =====================================================================
1434 ;;; Basic undo-tree data structure functions
1436 (defun undo-tree-grow (undo)
1437 "Add an UNDO node to current branch of `buffer-undo-tree'."
1438 (let* ((current (undo-tree-current buffer-undo-tree))
1439 (new (undo-tree-make-node current undo)))
1440 (push new (undo-tree-node-next current))
1441 (setf (undo-tree-current buffer-undo-tree) new)))
1444 (defun undo-tree-grow-backwards (node undo &optional redo)
1445 "Add new node *above* undo-tree NODE, and return new node.
1446 Note that this will overwrite NODE's \"previous\" link, so should
1447 only be used on a detached NODE, never on nodes that are already
1448 part of `buffer-undo-tree'."
1449 (let ((new (undo-tree-make-node-backwards node undo redo)))
1450 (setf (undo-tree-node-previous node) new)
1454 (defun undo-tree-splice-node (node splice)
1455 "Splice NODE into undo tree, below node SPLICE.
1456 Note that this will overwrite NODE's \"next\" and \"previous\"
1457 links, so should only be used on a detached NODE, never on nodes
1458 that are already part of `buffer-undo-tree'."
1459 (setf (undo-tree-node-next node) (undo-tree-node-next splice)
1460 (undo-tree-node-branch node) (undo-tree-node-branch splice)
1461 (undo-tree-node-previous node) splice
1462 (undo-tree-node-next splice) (list node)
1463 (undo-tree-node-branch splice) 0)
1464 (dolist (n (undo-tree-node-next node))
1465 (setf (undo-tree-node-previous n) node)))
1468 (defun undo-tree-snip-node (node)
1469 "Snip NODE out of undo tree."
1470 (let* ((parent (undo-tree-node-previous node))
1472 ;; if NODE is only child, replace parent's next links with NODE's
1473 (if (= (length (undo-tree-node-next parent)) 0)
1474 (setf (undo-tree-node-next parent) (undo-tree-node-next node)
1475 (undo-tree-node-branch parent) (undo-tree-node-branch node))
1477 (setq position (undo-tree-position node (undo-tree-node-next parent)))
1479 ;; if active branch used do go via NODE, set parent's branch to active
1481 ((= (undo-tree-node-branch parent) position)
1482 (setf (undo-tree-node-branch parent)
1483 (+ position (undo-tree-node-branch node))))
1484 ;; if active branch didn't go via NODE, update parent's branch to point
1485 ;; to same node as before
1486 ((> (undo-tree-node-branch parent) position)
1487 (incf (undo-tree-node-branch parent)
1488 (1- (length (undo-tree-node-next node))))))
1489 ;; replace NODE in parent's next list with NODE's entire next list
1491 (setf (undo-tree-node-next parent)
1492 (nconc (undo-tree-node-next node)
1493 (cdr (undo-tree-node-next parent))))
1494 (setq p (nthcdr (1- position) (undo-tree-node-next parent)))
1495 (setcdr p (nconc (undo-tree-node-next node) (cddr p)))))
1496 ;; update previous links of NODE's children
1497 (dolist (n (undo-tree-node-next node))
1498 (setf (undo-tree-node-previous n) parent))))
1501 (defun undo-tree-mapc (--undo-tree-mapc-function-- node)
1502 ;; Apply FUNCTION to NODE and to each node below it.
1503 (let ((stack (list node))
1506 (setq n (pop stack))
1507 (funcall --undo-tree-mapc-function-- n)
1508 (setq stack (append (undo-tree-node-next n) stack)))))
1511 (defmacro undo-tree-num-branches ()
1512 "Return number of branches at current undo tree node."
1513 '(length (undo-tree-node-next (undo-tree-current buffer-undo-tree))))
1516 (defun undo-tree-position (node list)
1517 "Find the first occurrence of NODE in LIST.
1518 Return the index of the matching item, or nil of not found.
1519 Comparison is done with `eq'."
1523 (when (eq node (car list)) (throw 'found i))
1525 (setq list (cdr list))))
1529 (defvar *undo-tree-id-counter* 0)
1530 (make-variable-buffer-local '*undo-tree-id-counter*)
1532 (defmacro undo-tree-generate-id ()
1533 ;; Generate a new, unique id (uninterned symbol).
1534 ;; The name is made by appending a number to "undo-tree-id".
1535 ;; (Copied from CL package `gensym'.)
1536 `(let ((num (prog1 *undo-tree-id-counter* (incf *undo-tree-id-counter*))))
1537 (make-symbol (format "undo-tree-id%d" num))))
1540 (defun undo-tree-decircle (undo-tree)
1541 ;; Nullify PREVIOUS links of UNDO-TREE nodes, to make UNDO-TREE data
1542 ;; structure non-circular.
1545 (dolist (n (undo-tree-node-next node))
1546 (setf (undo-tree-node-previous n) nil)))
1547 (undo-tree-root undo-tree)))
1550 (defun undo-tree-recircle (undo-tree)
1551 ;; Recreate PREVIOUS links of UNDO-TREE nodes, to restore circular UNDO-TREE
1555 (dolist (n (undo-tree-node-next node))
1556 (setf (undo-tree-node-previous n) node)))
1557 (undo-tree-root undo-tree)))
1562 ;;; =====================================================================
1563 ;;; Undo list and undo changeset utility functions
1565 (defmacro undo-list-marker-elt-p (elt)
1566 `(markerp (car-safe ,elt)))
1568 (defmacro undo-list-GCd-marker-elt-p (elt)
1569 ;; Return t if ELT is a marker element whose marker has been moved to the
1570 ;; object-pool, so may potentially have been garbage-collected.
1571 ;; Note: Valid marker undo elements should be uniquely identified as cons
1572 ;; cells with a symbol in the car (replacing the marker), and a number in
1573 ;; the cdr. However, to guard against future changes to undo element
1574 ;; formats, we perform an additional redundant check on the symbol name.
1575 `(and (car-safe ,elt)
1576 (symbolp (car ,elt))
1577 (let ((str (symbol-name (car ,elt))))
1578 (and (> (length str) 12)
1579 (string= (substring str 0 12) "undo-tree-id")))
1580 (numberp (cdr-safe ,elt))))
1583 (defun undo-tree-move-GC-elts-to-pool (elt)
1584 ;; Move elements that can be garbage-collected into `buffer-undo-tree'
1585 ;; object pool, substituting a unique id that can be used to retrieve them
1586 ;; later. (Only markers require this treatment currently.)
1587 (when (undo-list-marker-elt-p elt)
1588 (let ((id (undo-tree-generate-id)))
1589 (puthash id (car elt) (undo-tree-object-pool buffer-undo-tree))
1593 (defun undo-tree-restore-GC-elts-from-pool (elt)
1594 ;; Replace object id's in ELT with corresponding objects from
1595 ;; `buffer-undo-tree' object pool and return modified ELT, or return nil if
1596 ;; any object in ELT has been garbage-collected.
1597 (if (undo-list-GCd-marker-elt-p elt)
1598 (when (setcar elt (gethash (car elt)
1599 (undo-tree-object-pool buffer-undo-tree)))
1604 (defun undo-list-clean-GCd-elts (undo-list)
1605 ;; Remove object id's from UNDO-LIST that refer to elements that have been
1606 ;; garbage-collected. UNDO-LIST is modified by side-effect.
1607 (while (undo-list-GCd-marker-elt-p (car undo-list))
1608 (unless (gethash (caar undo-list)
1609 (undo-tree-object-pool buffer-undo-tree))
1610 (setq undo-list (cdr undo-list))))
1611 (let ((p undo-list))
1613 (when (and (undo-list-GCd-marker-elt-p (cadr p))
1614 (null (gethash (car (cadr p))
1615 (undo-tree-object-pool buffer-undo-tree))))
1616 (setcdr p (cddr p)))
1621 (defun undo-list-pop-changeset (&optional discard-pos)
1622 ;; Pop changeset from `buffer-undo-list'. If DISCARD-POS is non-nil, discard
1623 ;; any position entries from changeset.
1625 ;; discard undo boundaries and (if DISCARD-POS is non-nil) position entries
1626 ;; at head of undo list
1627 (while (or (null (car buffer-undo-list))
1628 (and discard-pos (integerp (car buffer-undo-list))))
1629 (setq buffer-undo-list (cdr buffer-undo-list)))
1630 ;; pop elements up to next undo boundary, discarding position entries if
1631 ;; DISCARD-POS is non-nil
1632 (if (eq (car buffer-undo-list) 'undo-tree-canary)
1633 (push nil buffer-undo-list)
1634 (let* ((changeset (list (pop buffer-undo-list)))
1637 (undo-tree-move-GC-elts-to-pool (car p))
1638 (while (and discard-pos (integerp (car buffer-undo-list)))
1639 (setq buffer-undo-list (cdr buffer-undo-list)))
1640 (and (car buffer-undo-list)
1641 (not (eq (car buffer-undo-list) 'undo-tree-canary))))
1642 (setcdr p (list (pop buffer-undo-list)))
1647 (defun undo-tree-copy-list (undo-list)
1648 ;; Return a deep copy of first changeset in `undo-list'. Object id's are
1649 ;; replaced by corresponding objects from `buffer-undo-tree' object-pool.
1652 ;; if first element contains an object id, replace it with object from
1653 ;; pool, discarding element entirely if it's been GC'd
1656 (undo-tree-restore-GC-elts-from-pool (pop undo-list))))
1657 (setq copy (list copy)
1659 ;; copy remaining elements, replacing object id's with objects from
1660 ;; pool, or discarding them entirely if they've been GC'd
1662 (when (setcdr p (undo-tree-restore-GC-elts-from-pool
1663 (undo-copy-list-1 (pop undo-list))))
1664 (setcdr p (list (cdr p)))
1670 (defun undo-list-transfer-to-tree ()
1671 ;; Transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'.
1673 ;; `undo-list-transfer-to-tree' should never be called when undo is disabled
1674 ;; (i.e. `buffer-undo-tree' is t)
1675 (assert (not (eq buffer-undo-tree t)))
1677 ;; if `buffer-undo-tree' is empty, create initial undo-tree
1678 (when (null buffer-undo-tree) (setq buffer-undo-tree (make-undo-tree)))
1679 ;; make sure there's a canary at end of `buffer-undo-list'
1680 (when (null buffer-undo-list)
1681 (setq buffer-undo-list '(nil undo-tree-canary)))
1683 (unless (or (eq (cadr buffer-undo-list) 'undo-tree-canary)
1684 (eq (car buffer-undo-list) 'undo-tree-canary))
1685 ;; create new node from first changeset in `buffer-undo-list', save old
1686 ;; `buffer-undo-tree' current node, and make new node the current node
1687 (let* ((node (undo-tree-make-node nil (undo-list-pop-changeset)))
1688 (splice (undo-tree-current buffer-undo-tree))
1689 (size (undo-list-byte-size (undo-tree-node-undo node)))
1691 (setf (undo-tree-current buffer-undo-tree) node)
1692 ;; grow tree fragment backwards using `buffer-undo-list' changesets
1693 (while (and buffer-undo-list
1694 (not (eq (cadr buffer-undo-list) 'undo-tree-canary)))
1696 (undo-tree-grow-backwards node (undo-list-pop-changeset)))
1697 (incf size (undo-list-byte-size (undo-tree-node-undo node)))
1699 ;; if no undo history has been discarded from `buffer-undo-list' since
1700 ;; last transfer, splice new tree fragment onto end of old
1701 ;; `buffer-undo-tree' current node
1702 (if (or (eq (cadr buffer-undo-list) 'undo-tree-canary)
1703 (eq (car buffer-undo-list) 'undo-tree-canary))
1705 (setf (undo-tree-node-previous node) splice)
1706 (push node (undo-tree-node-next splice))
1707 (setf (undo-tree-node-branch splice) 0)
1708 (incf (undo-tree-size buffer-undo-tree) size)
1709 (incf (undo-tree-count buffer-undo-tree) count))
1710 ;; if undo history has been discarded, replace entire
1711 ;; `buffer-undo-tree' with new tree fragment
1712 (setq node (undo-tree-grow-backwards node nil))
1713 (setf (undo-tree-root buffer-undo-tree) node)
1714 (setq buffer-undo-list '(nil undo-tree-canary))
1715 (setf (undo-tree-size buffer-undo-tree) size)
1716 (setf (undo-tree-count buffer-undo-tree) count)
1717 (setq buffer-undo-list '(nil undo-tree-canary))))
1718 ;; discard undo history if necessary
1719 (undo-tree-discard-history)))
1722 (defun undo-list-byte-size (undo-list)
1723 ;; Return size (in bytes) of UNDO-LIST
1724 (let ((size 0) (p undo-list))
1726 (incf size 8) ; cons cells use up 8 bytes
1727 (when (and (consp (car p)) (stringp (caar p)))
1728 (incf size (string-bytes (caar p))))
1734 (defun undo-list-rebuild-from-tree ()
1735 "Rebuild `buffer-undo-list' from information in `buffer-undo-tree'."
1736 (unless (eq buffer-undo-list t)
1737 (undo-list-transfer-to-tree)
1738 (setq buffer-undo-list nil)
1739 (when buffer-undo-tree
1740 (let ((stack (list (list (undo-tree-root buffer-undo-tree)))))
1741 (push (sort (mapcar 'identity (undo-tree-node-next (caar stack)))
1743 (time-less-p (undo-tree-node-timestamp a)
1744 (undo-tree-node-timestamp b))))
1746 ;; Traverse tree in depth-and-oldest-first order, but add undo records
1747 ;; on the way down, and redo records on the way up.
1748 (while (or (car stack)
1749 (not (eq (car (nth 1 stack))
1750 (undo-tree-current buffer-undo-tree))))
1753 (setq buffer-undo-list
1754 (append (undo-tree-node-undo (caar stack))
1757 (push (sort (mapcar 'identity
1758 (undo-tree-node-next (caar stack)))
1760 (time-less-p (undo-tree-node-timestamp a)
1761 (undo-tree-node-timestamp b))))
1764 (setq buffer-undo-list
1765 (append (undo-tree-node-redo (caar stack))
1768 (pop (car stack))))))))
1773 ;;; =====================================================================
1774 ;;; History discarding utility functions
1776 (defun undo-tree-oldest-leaf (node)
1777 ;; Return oldest leaf node below NODE.
1778 (while (undo-tree-node-next node)
1780 (car (sort (mapcar 'identity (undo-tree-node-next node))
1782 (time-less-p (undo-tree-node-timestamp a)
1783 (undo-tree-node-timestamp b)))))))
1787 (defun undo-tree-discard-node (node)
1788 ;; Discard NODE from `buffer-undo-tree', and return next in line for
1791 ;; don't discard current node
1792 (unless (eq node (undo-tree-current buffer-undo-tree))
1794 ;; discarding root node...
1795 (if (eq node (undo-tree-root buffer-undo-tree))
1797 ;; should always discard branches before root
1798 ((> (length (undo-tree-node-next node)) 1)
1799 (error "Trying to discard undo-tree root which still\
1800 has multiple branches"))
1801 ;; don't discard root if current node is only child
1802 ((eq (car (undo-tree-node-next node))
1803 (undo-tree-current buffer-undo-tree))
1807 ;; clear any register referring to root
1808 (let ((r (undo-tree-node-register node)))
1809 (when (and r (eq (get-register r) node))
1810 (set-register r nil)))
1811 ;; make child of root into new root
1812 (setq node (setf (undo-tree-root buffer-undo-tree)
1813 (car (undo-tree-node-next node))))
1814 ;; update undo-tree size
1815 (decf (undo-tree-size buffer-undo-tree)
1816 (+ (undo-list-byte-size (undo-tree-node-undo node))
1817 (undo-list-byte-size (undo-tree-node-redo node))))
1818 (decf (undo-tree-count buffer-undo-tree))
1819 ;; discard new root's undo data and PREVIOUS link
1820 (setf (undo-tree-node-undo node) nil
1821 (undo-tree-node-redo node) nil
1822 (undo-tree-node-previous node) nil)
1823 ;; if new root has branches, or new root is current node, next node
1824 ;; to discard is oldest leaf, otherwise it's new root
1825 (if (or (> (length (undo-tree-node-next node)) 1)
1826 (eq (car (undo-tree-node-next node))
1827 (undo-tree-current buffer-undo-tree)))
1828 (undo-tree-oldest-leaf node)
1831 ;; discarding leaf node...
1832 (let* ((parent (undo-tree-node-previous node))
1833 (current (nth (undo-tree-node-branch parent)
1834 (undo-tree-node-next parent))))
1835 ;; clear any register referring to the discarded node
1836 (let ((r (undo-tree-node-register node)))
1837 (when (and r (eq (get-register r) node))
1838 (set-register r nil)))
1839 ;; update undo-tree size
1840 (decf (undo-tree-size buffer-undo-tree)
1841 (+ (undo-list-byte-size (undo-tree-node-undo node))
1842 (undo-list-byte-size (undo-tree-node-redo node))))
1843 (decf (undo-tree-count buffer-undo-tree))
1845 (setf (undo-tree-node-next parent)
1846 (delq node (undo-tree-node-next parent))
1847 (undo-tree-node-branch parent)
1848 (undo-tree-position current (undo-tree-node-next parent)))
1849 ;; if parent has branches, or parent is current node, next node to
1850 ;; discard is oldest leaf, otherwise it's the parent itself
1851 (if (or (eq parent (undo-tree-current buffer-undo-tree))
1852 (and (undo-tree-node-next parent)
1853 (or (not (eq parent (undo-tree-root buffer-undo-tree)))
1854 (> (length (undo-tree-node-next parent)) 1))))
1855 (undo-tree-oldest-leaf parent)
1860 (defun undo-tree-discard-history ()
1861 "Discard undo history until we're within memory usage limits
1862 set by `undo-limit', `undo-strong-limit' and `undo-outer-limit'."
1864 (when (> (undo-tree-size buffer-undo-tree) undo-limit)
1865 ;; if there are no branches off root, first node to discard is root;
1866 ;; otherwise it's leaf node at botom of oldest branch
1867 (let ((node (if (> (length (undo-tree-node-next
1868 (undo-tree-root buffer-undo-tree))) 1)
1869 (undo-tree-oldest-leaf (undo-tree-root buffer-undo-tree))
1870 (undo-tree-root buffer-undo-tree))))
1872 ;; discard nodes until memory use is within `undo-strong-limit'
1874 (> (undo-tree-size buffer-undo-tree) undo-strong-limit))
1875 (setq node (undo-tree-discard-node node)))
1877 ;; discard nodes until next node to discard would bring memory use
1878 ;; within `undo-limit'
1880 ;; check first if last discard has brought us within
1881 ;; `undo-limit', in case we can avoid more expensive
1882 ;; `undo-strong-limit' calculation
1883 ;; Note: this assumes undo-strong-limit > undo-limit;
1884 ;; if not, effectively undo-strong-limit = undo-limit
1885 (> (undo-tree-size buffer-undo-tree) undo-limit)
1886 (> (- (undo-tree-size buffer-undo-tree)
1887 ;; if next node to discard is root, the memory we
1888 ;; free-up comes from discarding changesets from its
1890 (if (eq node (undo-tree-root buffer-undo-tree))
1891 (+ (undo-list-byte-size
1892 (undo-tree-node-undo
1893 (car (undo-tree-node-next node))))
1894 (undo-list-byte-size
1895 (undo-tree-node-redo
1896 (car (undo-tree-node-next node)))))
1897 ;; ...otherwise, it comes from discarding changesets
1898 ;; from along with the node itself
1899 (+ (undo-list-byte-size (undo-tree-node-undo node))
1900 (undo-list-byte-size (undo-tree-node-redo node)))
1903 (setq node (undo-tree-discard-node node)))
1905 ;; if we're still over the `undo-outer-limit', discard entire history
1906 (when (> (undo-tree-size buffer-undo-tree) undo-outer-limit)
1907 ;; query first if `undo-ask-before-discard' is set
1908 (if undo-ask-before-discard
1911 "Buffer `%s' undo info is %d bytes long; discard it? "
1912 (buffer-name) (undo-tree-size buffer-undo-tree)))
1913 (setq buffer-undo-tree nil))
1914 ;; otherwise, discard and display warning
1916 '(undo discard-info)
1918 (format "Buffer `%s' undo info was %d bytes long.\n"
1919 (buffer-name) (undo-tree-size buffer-undo-tree))
1920 "The undo info was discarded because it exceeded\
1923 This is normal if you executed a command that made a huge change
1924 to the buffer. In that case, to prevent similar problems in the
1925 future, set `undo-outer-limit' to a value that is large enough to
1926 cover the maximum size of normal changes you expect a single
1927 command to make, but not so large that it might exceed the
1928 maximum memory allotted to Emacs.
1930 If you did not execute any such command, the situation is
1931 probably due to a bug and you should report it.
1933 You can disable the popping up of this buffer by adding the entry
1934 \(undo discard-info) to the user option `warning-suppress-types',
1935 which is defined in the `warnings' library.\n")
1937 (setq buffer-undo-tree nil)))
1943 ;;; =====================================================================
1944 ;;; Visualizer utility functions
1946 (defun undo-tree-compute-widths (node)
1947 "Recursively compute widths for nodes below NODE."
1948 (let ((stack (list node))
1951 ;; try to compute widths for node at top of stack
1952 (if (undo-tree-node-p
1953 (setq res (undo-tree-node-compute-widths (car stack))))
1954 ;; if computation fails, it returns a node whose widths still need
1955 ;; computing, which we push onto the stack
1957 ;; otherwise, store widths and remove it from stack
1958 (setf (undo-tree-node-lwidth (car stack)) (aref res 0)
1959 (undo-tree-node-cwidth (car stack)) (aref res 1)
1960 (undo-tree-node-rwidth (car stack)) (aref res 2))
1964 (defun undo-tree-node-compute-widths (node)
1965 ;; Compute NODE's left-, centre-, and right-subtree widths. Returns widths
1966 ;; (in a vector) if successful. Otherwise, returns a node whose widths need
1967 ;; calculating before NODE's can be calculated.
1968 (let ((num-children (length (undo-tree-node-next node)))
1969 (lwidth 0) (cwidth 0) (rwidth 0) p)
1972 ;; leaf nodes have 0 width
1975 (undo-tree-node-lwidth node) 0
1976 (undo-tree-node-cwidth node) 1
1977 (undo-tree-node-rwidth node) 0))
1979 ;; odd number of children
1980 ((= (mod num-children 2) 1)
1981 (setq p (undo-tree-node-next node))
1982 ;; compute left-width
1983 (dotimes (i (/ num-children 2))
1984 (if (undo-tree-node-lwidth (car p))
1985 (incf lwidth (+ (undo-tree-node-lwidth (car p))
1986 (undo-tree-node-cwidth (car p))
1987 (undo-tree-node-rwidth (car p))))
1988 ;; if child's widths haven't been computed, return that child
1989 (throw 'need-widths (car p)))
1991 (if (undo-tree-node-lwidth (car p))
1992 (incf lwidth (undo-tree-node-lwidth (car p)))
1993 (throw 'need-widths (car p)))
1994 ;; centre-width is inherited from middle child
1995 (setf cwidth (undo-tree-node-cwidth (car p)))
1996 ;; compute right-width
1997 (incf rwidth (undo-tree-node-rwidth (car p)))
1999 (dotimes (i (/ num-children 2))
2000 (if (undo-tree-node-lwidth (car p))
2001 (incf rwidth (+ (undo-tree-node-lwidth (car p))
2002 (undo-tree-node-cwidth (car p))
2003 (undo-tree-node-rwidth (car p))))
2004 (throw 'need-widths (car p)))
2007 ;; even number of children
2009 (setq p (undo-tree-node-next node))
2010 ;; compute left-width
2011 (dotimes (i (/ num-children 2))
2012 (if (undo-tree-node-lwidth (car p))
2013 (incf lwidth (+ (undo-tree-node-lwidth (car p))
2014 (undo-tree-node-cwidth (car p))
2015 (undo-tree-node-rwidth (car p))))
2016 (throw 'need-widths (car p)))
2018 ;; centre-width is 0 when number of children is even
2020 ;; compute right-width
2021 (dotimes (i (/ num-children 2))
2022 (if (undo-tree-node-lwidth (car p))
2023 (incf rwidth (+ (undo-tree-node-lwidth (car p))
2024 (undo-tree-node-cwidth (car p))
2025 (undo-tree-node-rwidth (car p))))
2026 (throw 'need-widths (car p)))
2029 ;; return left-, centre- and right-widths
2030 (vector lwidth cwidth rwidth))))
2033 (defun undo-tree-clear-visualizer-data (tree)
2034 ;; Clear visualizer data below NODE.
2036 (lambda (n) (undo-tree-node-clear-visualizer-data n))
2037 (undo-tree-root tree)))
2040 (defun undo-tree-node-unmodified-p (node &optional mtime)
2041 ;; Return non-nil if NODE corresponds to a buffer state that once upon a
2042 ;; time was unmodified. If a file modification time MTIME is specified,
2043 ;; return non-nil if the corresponding buffer state really is unmodified.
2044 (let (changeset ntime)
2046 (or (undo-tree-node-redo node)
2047 (and (setq changeset (car (undo-tree-node-next node)))
2048 (undo-tree-node-undo changeset)))
2051 (dolist (elt changeset)
2052 (when (and (consp elt) (eq (car elt) t) (consp (cdr elt))
2053 (throw 'found (cdr elt)))))))
2056 ;; high-precision timestamps
2057 (if (listp (cdr ntime))
2059 ;; old-style timestamps
2060 (and (= (car ntime) (car mtime))
2061 (= (cdr ntime) (cadr mtime))))))))
2066 ;;; =====================================================================
2067 ;;; Undo-in-region utility functions
2069 ;; `undo-elt-in-region' uses this as a dynamically-scoped variable
2070 (defvar undo-adjusted-markers nil)
2073 (defun undo-tree-pull-undo-in-region-branch (start end)
2074 ;; Pull out entries from undo changesets to create a new undo-in-region
2075 ;; branch, which undoes changeset entries lying between START and END first,
2076 ;; followed by remaining entries from the changesets, before rejoining the
2077 ;; existing undo tree history. Repeated calls will, if appropriate, extend
2078 ;; the current undo-in-region branch rather than creating a new one.
2080 ;; if we're just reverting the last redo-in-region, we don't need to
2081 ;; manipulate the undo tree at all
2082 (if (undo-tree-reverting-redo-in-region-p start end)
2083 t ; return t to indicate success
2085 ;; We build the `region-changeset' and `delta-list' lists forwards, using
2086 ;; pointers `r' and `d' to the penultimate element of the list. So that we
2087 ;; don't have to treat the first element differently, we prepend a dummy
2088 ;; leading nil to the lists, and have the pointers point to that
2090 ;; Note: using '(nil) instead of (list nil) in the `let*' results in
2091 ;; bizarre errors when the code is byte-compiled, where parts of the
2092 ;; lists appear to survive across different calls to this function.
2093 ;; An obscure byte-compiler bug, perhaps?
2094 (let* ((region-changeset (list nil))
2095 (r region-changeset)
2096 (delta-list (list nil))
2098 (node (undo-tree-current buffer-undo-tree))
2099 (repeated-undo-in-region
2100 (undo-tree-repeated-undo-in-region-p start end))
2101 undo-adjusted-markers ; `undo-elt-in-region' expects this
2102 fragment splice original-fragment original-splice original-current
2103 got-visible-elt undo-list elt)
2105 ;; --- initialisation ---
2107 ;; if this is a repeated undo in the same region, start pulling changes
2108 ;; from NODE at which undo-in-region branch iss attached, and detatch
2109 ;; the branch, using it as initial FRAGMENT of branch being constructed
2110 (repeated-undo-in-region
2111 (setq original-current node
2112 fragment (car (undo-tree-node-next node))
2114 ;; undo up to node at which undo-in-region branch is attached
2115 ;; (recognizable as first node with more than one branch)
2116 (let ((mark-active nil))
2117 (while (= (length (undo-tree-node-next node)) 1)
2120 node (undo-tree-current buffer-undo-tree))))
2121 (when (eq splice node) (setq splice nil))
2122 ;; detatch undo-in-region branch
2123 (setf (undo-tree-node-next node)
2124 (delq fragment (undo-tree-node-next node))
2125 (undo-tree-node-previous fragment) nil
2126 original-fragment fragment
2127 original-splice node))
2129 ;; if this is a new undo-in-region, initial FRAGMENT is a copy of all
2130 ;; nodes below the current one in the active branch
2131 ((undo-tree-node-next node)
2132 (setq fragment (undo-tree-make-node nil nil)
2134 (while (setq node (nth (undo-tree-node-branch node)
2135 (undo-tree-node-next node)))
2136 (push (undo-tree-make-node
2138 (undo-copy-list (undo-tree-node-undo node))
2139 (undo-copy-list (undo-tree-node-redo node)))
2140 (undo-tree-node-next splice))
2141 (setq splice (car (undo-tree-node-next splice))))
2142 (setq fragment (car (undo-tree-node-next fragment))
2144 node (undo-tree-current buffer-undo-tree))))
2147 ;; --- pull undo-in-region elements into branch ---
2148 ;; work backwards up tree, pulling out undo elements within region until
2149 ;; we've got one that undoes a visible change (insertion or deletion)
2151 (while (and (not got-visible-elt) node (undo-tree-node-undo node))
2152 ;; we cons a dummy nil element on the front of the changeset so that
2153 ;; we can conveniently remove the first (real) element from the
2154 ;; changeset if we need to; the leading nil is removed once we're
2155 ;; done with this changeset
2156 (setq undo-list (cons nil (undo-copy-list (undo-tree-node-undo node)))
2157 elt (cadr undo-list))
2160 (setq fragment (undo-tree-grow-backwards fragment undo-list))
2161 (unless splice (setq splice fragment)))
2162 (setq fragment (undo-tree-make-node nil undo-list))
2163 (setq splice fragment))
2167 ;; keep elements within region
2168 ((undo-elt-in-region elt start end)
2169 ;; set flag if kept element is visible (insertion or deletion)
2170 (when (and (consp elt)
2171 (or (stringp (car elt)) (integerp (car elt))))
2172 (setq got-visible-elt t))
2173 ;; adjust buffer positions in elements previously undone before
2174 ;; kept element, as kept element will now be undone first
2175 (undo-tree-adjust-elements-to-elt splice elt)
2176 ;; move kept element to undo-in-region changeset, adjusting its
2177 ;; buffer position as it will now be undone first
2178 (setcdr r (list (undo-tree-apply-deltas elt (cdr delta-list))))
2180 (setcdr undo-list (cddr undo-list)))
2182 ;; discard "was unmodified" elements
2183 ;; FIXME: deal properly with these
2184 ((and (consp elt) (eq (car elt) t))
2185 (setcdr undo-list (cddr undo-list)))
2187 ;; if element crosses region, we can't pull any more elements
2188 ((undo-elt-crosses-region elt start end)
2189 ;; if we've found a visible element, it must be earlier in
2190 ;; current node's changeset; stop pulling elements (null
2191 ;; `undo-list' and non-nil `got-visible-elt' cause loop to exit)
2193 (setq undo-list nil)
2194 ;; if we haven't found a visible element yet, pulling
2195 ;; undo-in-region branch has failed
2196 (setq region-changeset nil)
2199 ;; if rejecting element, add its delta (if any) to the list
2201 (let ((delta (undo-delta elt)))
2202 (when (/= 0 (cdr delta))
2203 (setcdr d (list delta))
2205 (setq undo-list (cdr undo-list))))
2207 ;; process next element of current changeset
2208 (setq elt (cadr undo-list)))
2210 ;; if there are remaining elements in changeset, remove dummy nil
2212 (if (cadr (undo-tree-node-undo fragment))
2213 (pop (undo-tree-node-undo fragment))
2214 ;; otherwise, if we've kept all elements in changeset, discard
2216 (when (eq splice fragment) (setq splice nil))
2217 (setq fragment (car (undo-tree-node-next fragment))))
2218 ;; process changeset from next node up the tree
2219 (setq node (undo-tree-node-previous node))))
2221 ;; pop dummy nil from front of `region-changeset'
2222 (setq region-changeset (cdr region-changeset))
2225 ;; --- integrate branch into tree ---
2226 ;; if no undo-in-region elements were found, restore undo tree
2227 (if (null region-changeset)
2228 (when original-current
2229 (push original-fragment (undo-tree-node-next original-splice))
2230 (setf (undo-tree-node-branch original-splice) 0
2231 (undo-tree-node-previous original-fragment) original-splice)
2232 (let ((mark-active nil))
2233 (while (not (eq (undo-tree-current buffer-undo-tree)
2235 (undo-tree-redo-1)))
2236 nil) ; return nil to indicate failure
2239 ;; need to undo up to node where new branch will be attached, to
2240 ;; ensure redo entries are populated, and then redo back to where we
2242 (let ((mark-active nil)
2243 (current (undo-tree-current buffer-undo-tree)))
2244 (while (not (eq (undo-tree-current buffer-undo-tree) node))
2246 (while (not (eq (undo-tree-current buffer-undo-tree) current))
2247 (undo-tree-redo-1)))
2250 ;; if there's no remaining fragment, just create undo-in-region node
2251 ;; and attach it to parent of last node from which elements were
2254 (setq fragment (undo-tree-make-node node region-changeset))
2255 (push fragment (undo-tree-node-next node))
2256 (setf (undo-tree-node-branch node) 0)
2257 ;; set current node to undo-in-region node
2258 (setf (undo-tree-current buffer-undo-tree) fragment))
2260 ;; if no splice point has been set, add undo-in-region node to top of
2261 ;; fragment and attach it to parent of last node from which elements
2264 (setq fragment (undo-tree-grow-backwards fragment region-changeset))
2265 (push fragment (undo-tree-node-next node))
2266 (setf (undo-tree-node-branch node) 0
2267 (undo-tree-node-previous fragment) node)
2268 ;; set current node to undo-in-region node
2269 (setf (undo-tree-current buffer-undo-tree) fragment))
2271 ;; if fragment contains nodes, attach fragment to parent of last node
2272 ;; from which elements were pulled, and splice in undo-in-region node
2274 (setf (undo-tree-node-previous fragment) node)
2275 (push fragment (undo-tree-node-next node))
2276 (setf (undo-tree-node-branch node) 0)
2277 ;; if this is a repeated undo-in-region, then we've left the current
2278 ;; node at the original splice-point; we need to set the current
2279 ;; node to the equivalent node on the undo-in-region branch and redo
2280 ;; back to where we started
2281 (when repeated-undo-in-region
2282 (setf (undo-tree-current buffer-undo-tree)
2283 (undo-tree-node-previous original-fragment))
2284 (let ((mark-active nil))
2285 (while (not (eq (undo-tree-current buffer-undo-tree) splice))
2286 (undo-tree-redo-1 nil 'preserve-undo))))
2287 ;; splice new undo-in-region node into fragment
2288 (setq node (undo-tree-make-node nil region-changeset))
2289 (undo-tree-splice-node node splice)
2290 ;; set current node to undo-in-region node
2291 (setf (undo-tree-current buffer-undo-tree) node)))
2293 ;; update undo-tree size
2294 (setq node (undo-tree-node-previous fragment))
2296 (and (setq node (car (undo-tree-node-next node)))
2297 (not (eq node original-fragment))
2298 (incf (undo-tree-count buffer-undo-tree))
2299 (incf (undo-tree-size buffer-undo-tree)
2300 (+ (undo-list-byte-size (undo-tree-node-undo node))
2301 (undo-list-byte-size (undo-tree-node-redo node)))))))
2302 t) ; indicate undo-in-region branch was successfully pulled
2307 (defun undo-tree-pull-redo-in-region-branch (start end)
2308 ;; Pull out entries from redo changesets to create a new redo-in-region
2309 ;; branch, which redoes changeset entries lying between START and END first,
2310 ;; followed by remaining entries from the changesets. Repeated calls will,
2311 ;; if appropriate, extend the current redo-in-region branch rather than
2312 ;; creating a new one.
2314 ;; if we're just reverting the last undo-in-region, we don't need to
2315 ;; manipulate the undo tree at all
2316 (if (undo-tree-reverting-undo-in-region-p start end)
2317 t ; return t to indicate success
2319 ;; We build the `region-changeset' and `delta-list' lists forwards, using
2320 ;; pointers `r' and `d' to the penultimate element of the list. So that we
2321 ;; don't have to treat the first element differently, we prepend a dummy
2322 ;; leading nil to the lists, and have the pointers point to that
2324 ;; Note: using '(nil) instead of (list nil) in the `let*' causes bizarre
2325 ;; errors when the code is byte-compiled, where parts of the lists
2326 ;; appear to survive across different calls to this function. An
2327 ;; obscure byte-compiler bug, perhaps?
2328 (let* ((region-changeset (list nil))
2329 (r region-changeset)
2330 (delta-list (list nil))
2332 (node (undo-tree-current buffer-undo-tree))
2333 (repeated-redo-in-region
2334 (undo-tree-repeated-redo-in-region-p start end))
2335 undo-adjusted-markers ; `undo-elt-in-region' expects this
2336 fragment splice got-visible-elt redo-list elt)
2338 ;; --- inisitalisation ---
2340 ;; if this is a repeated redo-in-region, detach fragment below current
2342 (repeated-redo-in-region
2343 (when (setq fragment (car (undo-tree-node-next node)))
2344 (setf (undo-tree-node-previous fragment) nil
2345 (undo-tree-node-next node)
2346 (delq fragment (undo-tree-node-next node)))))
2347 ;; if this is a new redo-in-region, initial fragment is a copy of all
2348 ;; nodes below the current one in the active branch
2349 ((undo-tree-node-next node)
2350 (setq fragment (undo-tree-make-node nil nil)
2352 (while (setq node (nth (undo-tree-node-branch node)
2353 (undo-tree-node-next node)))
2354 (push (undo-tree-make-node
2356 (undo-copy-list (undo-tree-node-redo node)))
2357 (undo-tree-node-next splice))
2358 (setq splice (car (undo-tree-node-next splice))))
2359 (setq fragment (car (undo-tree-node-next fragment)))))
2362 ;; --- pull redo-in-region elements into branch ---
2363 ;; work down fragment, pulling out redo elements within region until
2364 ;; we've got one that redoes a visible change (insertion or deletion)
2365 (setq node fragment)
2367 (while (and (not got-visible-elt) node (undo-tree-node-redo node))
2368 ;; we cons a dummy nil element on the front of the changeset so that
2369 ;; we can conveniently remove the first (real) element from the
2370 ;; changeset if we need to; the leading nil is removed once we're
2371 ;; done with this changeset
2372 (setq redo-list (push nil (undo-tree-node-redo node))
2373 elt (cadr redo-list))
2376 ;; keep elements within region
2377 ((undo-elt-in-region elt start end)
2378 ;; set flag if kept element is visible (insertion or deletion)
2379 (when (and (consp elt)
2380 (or (stringp (car elt)) (integerp (car elt))))
2381 (setq got-visible-elt t))
2382 ;; adjust buffer positions in elements previously redone before
2383 ;; kept element, as kept element will now be redone first
2384 (undo-tree-adjust-elements-to-elt fragment elt t)
2385 ;; move kept element to redo-in-region changeset, adjusting its
2386 ;; buffer position as it will now be redone first
2387 (setcdr r (list (undo-tree-apply-deltas elt (cdr delta-list) -1)))
2389 (setcdr redo-list (cddr redo-list)))
2391 ;; discard "was unmodified" elements
2392 ;; FIXME: deal properly with these
2393 ((and (consp elt) (eq (car elt) t))
2394 (setcdr redo-list (cddr redo-list)))
2396 ;; if element crosses region, we can't pull any more elements
2397 ((undo-elt-crosses-region elt start end)
2398 ;; if we've found a visible element, it must be earlier in
2399 ;; current node's changeset; stop pulling elements (null
2400 ;; `redo-list' and non-nil `got-visible-elt' cause loop to exit)
2402 (setq redo-list nil)
2403 ;; if we haven't found a visible element yet, pulling
2404 ;; redo-in-region branch has failed
2405 (setq region-changeset nil)
2408 ;; if rejecting element, add its delta (if any) to the list
2410 (let ((delta (undo-delta elt)))
2411 (when (/= 0 (cdr delta))
2412 (setcdr d (list delta))
2414 (setq redo-list (cdr redo-list))))
2416 ;; process next element of current changeset
2417 (setq elt (cadr redo-list)))
2419 ;; if there are remaining elements in changeset, remove dummy nil
2421 (if (cadr (undo-tree-node-redo node))
2422 (pop (undo-tree-node-undo node))
2423 ;; otherwise, if we've kept all elements in changeset, discard
2425 (if (eq fragment node)
2426 (setq fragment (car (undo-tree-node-next fragment)))
2427 (undo-tree-snip-node node)))
2428 ;; process changeset from next node in fragment
2429 (setq node (car (undo-tree-node-next node)))))
2431 ;; pop dummy nil from front of `region-changeset'
2432 (setq region-changeset (cdr region-changeset))
2435 ;; --- integrate branch into tree ---
2436 (setq node (undo-tree-current buffer-undo-tree))
2437 ;; if no redo-in-region elements were found, restore undo tree
2438 (if (null (car region-changeset))
2439 (when (and repeated-redo-in-region fragment)
2440 (push fragment (undo-tree-node-next node))
2441 (setf (undo-tree-node-branch node) 0
2442 (undo-tree-node-previous fragment) node)
2443 nil) ; return nil to indicate failure
2445 ;; otherwise, add redo-in-region node to top of fragment, and attach
2446 ;; it below current node
2449 (undo-tree-grow-backwards fragment nil region-changeset)
2450 (undo-tree-make-node nil nil region-changeset)))
2451 (push fragment (undo-tree-node-next node))
2452 (setf (undo-tree-node-branch node) 0
2453 (undo-tree-node-previous fragment) node)
2454 ;; update undo-tree size
2455 (unless repeated-redo-in-region
2456 (setq node fragment)
2457 (while (and (setq node (car (undo-tree-node-next node)))
2458 (incf (undo-tree-count buffer-undo-tree))
2459 (incf (undo-tree-size buffer-undo-tree)
2460 (undo-list-byte-size
2461 (undo-tree-node-redo node))))))
2462 (incf (undo-tree-size buffer-undo-tree)
2463 (undo-list-byte-size (undo-tree-node-redo fragment)))
2464 t) ; indicate redo-in-region branch was successfully pulled
2469 (defun undo-tree-adjust-elements-to-elt (node undo-elt &optional below)
2470 "Adjust buffer positions of undo elements, starting at NODE's
2471 and going up the tree (or down the active branch if BELOW is
2472 non-nil) and through the nodes' undo elements until we reach
2473 UNDO-ELT. UNDO-ELT must appear somewhere in the undo changeset
2474 of either NODE itself or some node above it in the tree."
2475 (let ((delta (list (undo-delta undo-elt)))
2476 (undo-list (undo-tree-node-undo node)))
2477 ;; adjust elements until we reach UNDO-ELT
2478 (while (and (car undo-list)
2479 (not (eq (car undo-list) undo-elt)))
2481 (undo-tree-apply-deltas (car undo-list) delta -1))
2482 ;; move to next undo element in list, or to next node if we've run out
2484 (unless (car (setq undo-list (cdr undo-list)))
2486 (setq node (nth (undo-tree-node-branch node)
2487 (undo-tree-node-next node)))
2488 (setq node (undo-tree-node-previous node)))
2489 (setq undo-list (undo-tree-node-undo node))))))
2493 (defun undo-tree-apply-deltas (undo-elt deltas &optional sgn)
2494 ;; Apply DELTAS in order to UNDO-ELT, multiplying deltas by SGN
2495 ;; (only useful value for SGN is -1).
2496 (let (position offset)
2497 (dolist (delta deltas)
2498 (setq position (car delta)
2499 offset (* (cdr delta) (or sgn 1)))
2502 ((integerp undo-elt)
2503 (when (>= undo-elt position)
2504 (setq undo-elt (- undo-elt offset))))
2505 ;; nil (or any other atom)
2507 ;; (TEXT . POSITION)
2508 ((stringp (car undo-elt))
2509 (let ((text-pos (abs (cdr undo-elt)))
2510 (point-at-end (< (cdr undo-elt) 0)))
2511 (if (>= text-pos position)
2512 (setcdr undo-elt (* (if point-at-end -1 1)
2513 (- text-pos offset))))))
2515 ((integerp (car undo-elt))
2516 (when (>= (car undo-elt) position)
2517 (setcar undo-elt (- (car undo-elt) offset))
2518 (setcdr undo-elt (- (cdr undo-elt) offset))))
2519 ;; (nil PROPERTY VALUE BEG . END)
2520 ((null (car undo-elt))
2521 (let ((tail (nthcdr 3 undo-elt)))
2522 (when (>= (car tail) position)
2523 (setcar tail (- (car tail) offset))
2524 (setcdr tail (- (cdr tail) offset)))))
2530 (defun undo-tree-repeated-undo-in-region-p (start end)
2531 ;; Return non-nil if undo-in-region between START and END is a repeated
2533 (let ((node (undo-tree-current buffer-undo-tree)))
2535 (nth (undo-tree-node-branch node) (undo-tree-node-next node)))
2536 (eq (undo-tree-node-undo-beginning node) start)
2537 (eq (undo-tree-node-undo-end node) end))))
2540 (defun undo-tree-repeated-redo-in-region-p (start end)
2541 ;; Return non-nil if undo-in-region between START and END is a repeated
2543 (let ((node (undo-tree-current buffer-undo-tree)))
2544 (and (eq (undo-tree-node-redo-beginning node) start)
2545 (eq (undo-tree-node-redo-end node) end))))
2548 ;; Return non-nil if undo-in-region between START and END is simply
2549 ;; reverting the last redo-in-region
2550 (defalias 'undo-tree-reverting-undo-in-region-p
2551 'undo-tree-repeated-undo-in-region-p)
2554 ;; Return non-nil if redo-in-region between START and END is simply
2555 ;; reverting the last undo-in-region
2556 (defalias 'undo-tree-reverting-redo-in-region-p
2557 'undo-tree-repeated-redo-in-region-p)
2562 ;;; =====================================================================
2563 ;;; Undo-tree commands
2566 (define-minor-mode undo-tree-mode
2567 "Toggle undo-tree mode.
2568 With no argument, this command toggles the mode.
2569 A positive prefix argument turns the mode on.
2570 A negative prefix argument turns it off.
2572 Undo-tree-mode replaces Emacs' standard undo feature with a more
2573 powerful yet easier to use version, that treats the undo history
2574 as what it is: a tree.
2576 The following keys are available in `undo-tree-mode':
2580 Within the undo-tree visualizer, the following keys are available:
2582 \\{undo-tree-visualizer-map}"
2585 undo-tree-mode-lighter ; lighter
2586 undo-tree-map ; keymap
2588 ;; if disabling `undo-tree-mode', rebuild `buffer-undo-list' from tree so
2589 ;; Emacs undo can work
2590 (if (not undo-tree-mode)
2591 (undo-list-rebuild-from-tree)
2592 (setq buffer-undo-tree nil)))
2595 (defun turn-on-undo-tree-mode (&optional print-message)
2596 "Enable `undo-tree-mode' in the current buffer, when appropriate.
2597 Some major modes implement their own undo system, which should
2598 not normally be overridden by `undo-tree-mode'. This command does
2599 not enable `undo-tree-mode' in such buffers. If you want to force
2600 `undo-tree-mode' to be enabled regardless, use (undo-tree-mode 1)
2603 The heuristic used to detect major modes in which
2604 `undo-tree-mode' should not be used is to check whether either
2605 the `undo' command has been remapped, or the default undo
2606 keybindings (C-/ and C-_) have been overridden somewhere other
2607 than in the global map. In addition, `undo-tree-mode' will not be
2608 enabled if the buffer's `major-mode' appears in
2609 `undo-tree-incompatible-major-modes'."
2611 (if (or (key-binding [remap undo])
2612 (undo-tree-overridden-undo-bindings-p)
2613 (memq major-mode undo-tree-incompatible-major-modes))
2615 (message "Buffer does not support undo-tree-mode;\
2616 undo-tree-mode NOT enabled"))
2617 (undo-tree-mode 1)))
2620 (defun undo-tree-overridden-undo-bindings-p ()
2621 "Returns t if default undo bindings are overridden, nil otherwise.
2622 Checks if either of the default undo key bindings (\"C-/\" or
2623 \"C-_\") are overridden in the current buffer by any keymap other
2624 than the global one. (So global redefinitions of the default undo
2625 key bindings do not count.)"
2626 (let ((binding1 (lookup-key (current-global-map) [?\C-/]))
2627 (binding2 (lookup-key (current-global-map) [?\C-_])))
2628 (global-set-key [?\C-/] 'undo)
2629 (global-set-key [?\C-_] 'undo)
2631 (or (and (key-binding [?\C-/])
2632 (not (eq (key-binding [?\C-/]) 'undo)))
2633 (and (key-binding [?\C-_])
2634 (not (eq (key-binding [?\C-_]) 'undo))))
2635 (global-set-key [?\C-/] binding1)
2636 (global-set-key [?\C-_] binding2))))
2640 (define-globalized-minor-mode global-undo-tree-mode
2641 undo-tree-mode turn-on-undo-tree-mode)
2645 (defun undo-tree-undo (&optional arg)
2647 Repeat this command to undo more changes.
2648 A numeric ARG serves as a repeat count.
2650 In Transient Mark mode when the mark is active, only undo changes
2651 within the current region. Similarly, when not in Transient Mark
2652 mode, just \\[universal-argument] as an argument limits undo to
2653 changes within the current region."
2655 ;; throw error if undo is disabled in buffer
2656 (when (eq buffer-undo-list t) (error "No undo information in this buffer"))
2657 (undo-tree-undo-1 arg)
2658 ;; inform user if at branch point
2659 (when (> (undo-tree-num-branches) 1) (message "Undo branch point!")))
2662 (defun undo-tree-undo-1 (&optional arg preserve-redo preserve-timestamps)
2663 ;; Internal undo function. An active mark in `transient-mark-mode', or
2664 ;; non-nil ARG otherwise, enables undo-in-region. Non-nil PRESERVE-REDO
2665 ;; causes the existing redo record to be preserved, rather than replacing it
2666 ;; with the new one generated by undoing. Non-nil PRESERVE-TIMESTAMPS
2667 ;; disables updating of timestamps in visited undo-tree nodes. (This latter
2668 ;; should *only* be used when temporarily visiting another undo state and
2669 ;; immediately returning to the original state afterwards. Otherwise, it
2670 ;; could cause history-discarding errors.)
2671 (let ((undo-in-progress t)
2672 (undo-in-region (and undo-tree-enable-undo-in-region
2673 (or (region-active-p)
2674 (and arg (not (numberp arg))))))
2676 ;; transfer entries accumulated in `buffer-undo-list' to
2677 ;; `buffer-undo-tree'
2678 (undo-list-transfer-to-tree)
2680 (dotimes (i (or (and (numberp arg) (prefix-numeric-value arg)) 1))
2681 ;; check if at top of undo tree
2682 (unless (undo-tree-node-previous (undo-tree-current buffer-undo-tree))
2683 (error "No further undo information"))
2685 ;; if region is active, or a non-numeric prefix argument was supplied,
2686 ;; try to pull out a new branch of changes affecting the region
2687 (when (and undo-in-region
2688 (not (undo-tree-pull-undo-in-region-branch
2689 (region-beginning) (region-end))))
2690 (error "No further undo information for region"))
2692 ;; remove any GC'd elements from node's undo list
2693 (setq current (undo-tree-current buffer-undo-tree))
2694 (decf (undo-tree-size buffer-undo-tree)
2695 (undo-list-byte-size (undo-tree-node-undo current)))
2696 (setf (undo-tree-node-undo current)
2697 (undo-list-clean-GCd-elts (undo-tree-node-undo current)))
2698 (incf (undo-tree-size buffer-undo-tree)
2699 (undo-list-byte-size (undo-tree-node-undo current)))
2700 ;; undo one record from undo tree
2701 (when undo-in-region
2702 (setq pos (set-marker (make-marker) (point)))
2703 (set-marker-insertion-type pos t))
2704 (primitive-undo 1 (undo-tree-copy-list (undo-tree-node-undo current)))
2707 ;; if preserving old redo record, discard new redo entries that
2708 ;; `primitive-undo' has added to `buffer-undo-list', and remove any GC'd
2709 ;; elements from node's redo list
2712 (undo-list-pop-changeset)
2713 (decf (undo-tree-size buffer-undo-tree)
2714 (undo-list-byte-size (undo-tree-node-redo current)))
2715 (setf (undo-tree-node-redo current)
2716 (undo-list-clean-GCd-elts (undo-tree-node-redo current)))
2717 (incf (undo-tree-size buffer-undo-tree)
2718 (undo-list-byte-size (undo-tree-node-redo current))))
2719 ;; otherwise, record redo entries that `primitive-undo' has added to
2720 ;; `buffer-undo-list' in current node's redo record, replacing
2721 ;; existing entry if one already exists
2722 (decf (undo-tree-size buffer-undo-tree)
2723 (undo-list-byte-size (undo-tree-node-redo current)))
2724 (setf (undo-tree-node-redo current)
2725 (undo-list-pop-changeset 'discard-pos))
2726 (incf (undo-tree-size buffer-undo-tree)
2727 (undo-list-byte-size (undo-tree-node-redo current))))
2729 ;; rewind current node and update timestamp
2730 (setf (undo-tree-current buffer-undo-tree)
2731 (undo-tree-node-previous (undo-tree-current buffer-undo-tree)))
2732 (unless preserve-timestamps
2733 (setf (undo-tree-node-timestamp (undo-tree-current buffer-undo-tree))
2736 ;; if undoing-in-region, record current node, region and direction so we
2737 ;; can tell if undo-in-region is repeated, and re-activate mark if in
2738 ;; `transient-mark-mode'; if not, erase any leftover data
2739 (if (not undo-in-region)
2740 (undo-tree-node-clear-region-data current)
2742 ;; note: we deliberately want to store the region information in the
2743 ;; node *below* the now current one
2744 (setf (undo-tree-node-undo-beginning current) (region-beginning)
2745 (undo-tree-node-undo-end current) (region-end))
2746 (set-marker pos nil)))
2748 ;; undo deactivates mark unless undoing-in-region
2749 (setq deactivate-mark (not undo-in-region))))
2753 (defun undo-tree-redo (&optional arg)
2754 "Redo changes. A numeric ARG serves as a repeat count.
2756 In Transient Mark mode when the mark is active, only redo changes
2757 within the current region. Similarly, when not in Transient Mark
2758 mode, just \\[universal-argument] as an argument limits redo to
2759 changes within the current region."
2761 ;; throw error if undo is disabled in buffer
2762 (when (eq buffer-undo-list t) (error "No undo information in this buffer"))
2763 (undo-tree-redo-1 arg)
2764 ;; inform user if at branch point
2765 (when (> (undo-tree-num-branches) 1) (message "Undo branch point!")))
2768 (defun undo-tree-redo-1 (&optional arg preserve-undo preserve-timestamps)
2769 ;; Internal redo function. An active mark in `transient-mark-mode', or
2770 ;; non-nil ARG otherwise, enables undo-in-region. Non-nil PRESERVE-UNDO
2771 ;; causes the existing redo record to be preserved, rather than replacing it
2772 ;; with the new one generated by undoing. Non-nil PRESERVE-TIMESTAMPS
2773 ;; disables updating of timestamps in visited undo-tree nodes. (This latter
2774 ;; should *only* be used when temporarily visiting another undo state and
2775 ;; immediately returning to the original state afterwards. Otherwise, it
2776 ;; could cause history-discarding errors.)
2777 (let ((undo-in-progress t)
2778 (redo-in-region (and undo-tree-enable-undo-in-region
2779 (or (region-active-p)
2780 (and arg (not (numberp arg))))))
2782 ;; transfer entries accumulated in `buffer-undo-list' to
2783 ;; `buffer-undo-tree'
2784 (undo-list-transfer-to-tree)
2786 (dotimes (i (or (and (numberp arg) (prefix-numeric-value arg)) 1))
2787 ;; check if at bottom of undo tree
2788 (when (null (undo-tree-node-next (undo-tree-current buffer-undo-tree)))
2789 (error "No further redo information"))
2791 ;; if region is active, or a non-numeric prefix argument was supplied,
2792 ;; try to pull out a new branch of changes affecting the region
2793 (when (and redo-in-region
2794 (not (undo-tree-pull-redo-in-region-branch
2795 (region-beginning) (region-end))))
2796 (error "No further redo information for region"))
2798 ;; get next node (but DON'T advance current node in tree yet, in case
2800 (setq current (undo-tree-current buffer-undo-tree)
2801 current (nth (undo-tree-node-branch current)
2802 (undo-tree-node-next current)))
2803 ;; remove any GC'd elements from node's redo list
2804 (decf (undo-tree-size buffer-undo-tree)
2805 (undo-list-byte-size (undo-tree-node-redo current)))
2806 (setf (undo-tree-node-redo current)
2807 (undo-list-clean-GCd-elts (undo-tree-node-redo current)))
2808 (incf (undo-tree-size buffer-undo-tree)
2809 (undo-list-byte-size (undo-tree-node-redo current)))
2810 ;; redo one record from undo tree
2811 (when redo-in-region
2812 (setq pos (set-marker (make-marker) (point)))
2813 (set-marker-insertion-type pos t))
2814 (primitive-undo 1 (undo-tree-copy-list (undo-tree-node-redo current)))
2816 ;; advance current node in tree
2817 (setf (undo-tree-current buffer-undo-tree) current)
2819 ;; if preserving old undo record, discard new undo entries that
2820 ;; `primitive-undo' has added to `buffer-undo-list', and remove any GC'd
2821 ;; elements from node's redo list
2824 (undo-list-pop-changeset)
2825 (decf (undo-tree-size buffer-undo-tree)
2826 (undo-list-byte-size (undo-tree-node-undo current)))
2827 (setf (undo-tree-node-undo current)
2828 (undo-list-clean-GCd-elts (undo-tree-node-undo current)))
2829 (incf (undo-tree-size buffer-undo-tree)
2830 (undo-list-byte-size (undo-tree-node-undo current))))
2831 ;; otherwise, record undo entries that `primitive-undo' has added to
2832 ;; `buffer-undo-list' in current node's undo record, replacing
2833 ;; existing entry if one already exists
2834 (decf (undo-tree-size buffer-undo-tree)
2835 (undo-list-byte-size (undo-tree-node-undo current)))
2836 (setf (undo-tree-node-undo current)
2837 (undo-list-pop-changeset 'discard-pos))
2838 (incf (undo-tree-size buffer-undo-tree)
2839 (undo-list-byte-size (undo-tree-node-undo current))))
2842 (unless preserve-timestamps
2843 (setf (undo-tree-node-timestamp current) (current-time)))
2845 ;; if redoing-in-region, record current node, region and direction so we
2846 ;; can tell if redo-in-region is repeated, and re-activate mark if in
2847 ;; `transient-mark-mode'
2848 (if (not redo-in-region)
2849 (undo-tree-node-clear-region-data current)
2851 (setf (undo-tree-node-redo-beginning current) (region-beginning)
2852 (undo-tree-node-redo-end current) (region-end))
2853 (set-marker pos nil)))
2855 ;; redo deactivates the mark unless redoing-in-region
2856 (setq deactivate-mark (not redo-in-region))))
2860 (defun undo-tree-switch-branch (branch)
2861 "Switch to a different BRANCH of the undo tree.
2862 This will affect which branch to descend when *redoing* changes
2863 using `undo-tree-redo'."
2864 (interactive (list (or (and prefix-arg (prefix-numeric-value prefix-arg))
2865 (and (not (eq buffer-undo-list t))
2866 (or (undo-list-transfer-to-tree) t)
2867 (let ((b (undo-tree-node-branch
2869 buffer-undo-tree))))
2871 ;; switch to other branch if only 2
2872 ((= (undo-tree-num-branches) 2) (- 1 b))
2873 ;; prompt if more than 2
2874 ((> (undo-tree-num-branches) 2)
2876 (format "Branch (0-%d, on %d): "
2877 (1- (undo-tree-num-branches)) b)))
2879 ;; throw error if undo is disabled in buffer
2880 (when (eq buffer-undo-list t) (error "No undo information in this buffer"))
2881 ;; sanity check branch number
2882 (when (<= (undo-tree-num-branches) 1) (error "Not at undo branch point"))
2883 (when (or (< branch 0) (> branch (1- (undo-tree-num-branches))))
2884 (error "Invalid branch number"))
2885 ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'
2886 (undo-list-transfer-to-tree)
2888 (setf (undo-tree-node-branch (undo-tree-current buffer-undo-tree))
2890 (message "Switched to branch %d" branch))
2893 (defun undo-tree-set (node &optional preserve-timestamps)
2894 ;; Set buffer to state corresponding to NODE. Returns intersection point
2895 ;; between path back from current node and path back from selected NODE.
2896 ;; Non-nil PRESERVE-TIMESTAMPS disables updating of timestamps in visited
2897 ;; undo-tree nodes. (This should *only* be used when temporarily visiting
2898 ;; another undo state and immediately returning to the original state
2899 ;; afterwards. Otherwise, it could cause history-discarding errors.)
2900 (let ((path (make-hash-table :test 'eq))
2902 (puthash (undo-tree-root buffer-undo-tree) t path)
2903 ;; build list of nodes leading back from selected node to root, updating
2904 ;; branches as we go to point down to selected node
2907 (when (undo-tree-node-previous n)
2908 (setf (undo-tree-node-branch (undo-tree-node-previous n))
2910 n (undo-tree-node-next (undo-tree-node-previous n))))
2911 (setq n (undo-tree-node-previous n)))))
2912 ;; work backwards from current node until we intersect path back from
2914 (setq n (undo-tree-current buffer-undo-tree))
2915 (while (not (gethash n path))
2916 (setq n (undo-tree-node-previous n)))
2917 ;; ascend tree until intersection node
2918 (while (not (eq (undo-tree-current buffer-undo-tree) n))
2919 (undo-tree-undo-1 nil nil preserve-timestamps))
2920 ;; descend tree until selected node
2921 (while (not (eq (undo-tree-current buffer-undo-tree) node))
2922 (undo-tree-redo-1 nil nil preserve-timestamps))
2923 n)) ; return intersection node
2927 (defun undo-tree-save-state-to-register (register)
2928 "Store current undo-tree state to REGISTER.
2929 The saved state can be restored using
2930 `undo-tree-restore-state-from-register'.
2931 Argument is a character, naming the register."
2932 (interactive "cUndo-tree state to register: ")
2933 ;; throw error if undo is disabled in buffer
2934 (when (eq buffer-undo-list t) (error "No undo information in this buffer"))
2935 ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'
2936 (undo-list-transfer-to-tree)
2937 ;; save current node to REGISTER
2939 register (registerv-make
2940 (undo-tree-make-register-data
2941 (current-buffer) (undo-tree-current buffer-undo-tree))
2942 :print-func 'undo-tree-register-data-print-func))
2943 ;; record REGISTER in current node, for visualizer
2944 (setf (undo-tree-node-register (undo-tree-current buffer-undo-tree))
2949 (defun undo-tree-restore-state-from-register (register)
2950 "Restore undo-tree state from REGISTER.
2951 The state must be saved using `undo-tree-save-state-to-register'.
2952 Argument is a character, naming the register."
2953 (interactive "*cRestore undo-tree state from register: ")
2954 ;; throw error if undo is disabled in buffer, or if register doesn't contain
2955 ;; an undo-tree node
2956 (let ((data (registerv-data (get-register register))))
2958 ((eq buffer-undo-list t)
2959 (error "No undo information in this buffer"))
2960 ((not (undo-tree-register-data-p data))
2961 (error "Register doesn't contain undo-tree state"))
2962 ((not (eq (current-buffer) (undo-tree-register-data-buffer data)))
2963 (error "Register contains undo-tree state for a different buffer")))
2964 ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'
2965 (undo-list-transfer-to-tree)
2966 ;; restore buffer state corresponding to saved node
2967 (undo-tree-set (undo-tree-register-data-node data))))
2972 ;;; =====================================================================
2973 ;;; Persistent storage commands
2975 (defun undo-tree-make-history-save-file-name (file)
2976 "Create the undo history file name for FILE.
2977 Normally this is the file's name with `.' prepended and
2978 `~undo-tree~' appended.
2980 A match for FILE is sought in `undo-tree-history-directory-alist';
2981 see the documentation of that variable. If the directory for the
2982 backup doesn't exist, it is created."
2983 (let* ((backup-directory-alist undo-tree-history-directory-alist)
2984 (name (make-backup-file-name-1 file)))
2985 (concat (file-name-directory name) "." (file-name-nondirectory name)
2989 (defun undo-tree-save-history (&optional filename overwrite)
2990 "Store undo-tree history to file.
2992 If optional argument FILENAME is omitted, default save file is
2993 \".<buffer-file-name>.~undo-tree\" if buffer is visiting a file.
2994 Otherwise, prompt for one.
2996 If OVERWRITE is non-nil, any existing file will be overwritten
2997 without asking for confirmation."
2999 (when (eq buffer-undo-list t) (error "No undo information in this buffer"))
3000 (undo-list-transfer-to-tree)
3001 (when (and buffer-undo-tree (not (eq buffer-undo-tree t)))
3003 (undo-tree-kill-visualizer)
3004 (error (undo-tree-clear-visualizer-data buffer-undo-tree)))
3005 (let ((buff (current-buffer))
3010 (if buffer-file-name
3011 (undo-tree-make-history-save-file-name buffer-file-name)
3012 (expand-file-name (read-file-name "File to save in: ") nil))))
3013 (when (or (not (file-exists-p filename))
3015 (yes-or-no-p (format "Overwrite \"%s\"? " filename)))
3018 ;; transform undo-tree into non-circular structure, and make
3020 (undo-tree-decircle buffer-undo-tree)
3021 (setq tree (copy-undo-tree buffer-undo-tree))
3022 ;; discard undo-tree object pool before saving
3023 (setf (undo-tree-object-pool tree) nil)
3024 ;; print undo-tree to file
3025 ;; NOTE: We use `with-temp-buffer' instead of `with-temp-file'
3026 ;; to allow `auto-compression-mode' to take effect, in
3027 ;; case user has overridden or advised the default
3028 ;; `undo-tree-make-history-save-file-name' to add a
3029 ;; compressed file extension.
3030 (with-auto-compression-mode
3032 (prin1 (sha1 buff) (current-buffer))
3033 (terpri (current-buffer))
3034 (let ((print-circle t)) (prin1 tree (current-buffer)))
3035 (write-region nil nil filename))))
3036 ;; restore circular undo-tree data structure
3037 (undo-tree-recircle buffer-undo-tree))
3042 (defun undo-tree-load-history (&optional filename noerror)
3043 "Load undo-tree history from file.
3045 If optional argument FILENAME is null, default load file is
3046 \".<buffer-file-name>.~undo-tree\" if buffer is visiting a file.
3047 Otherwise, prompt for one.
3049 If optional argument NOERROR is non-nil, return nil instead of
3050 signaling an error if file is not found."
3055 (if buffer-file-name
3056 (undo-tree-make-history-save-file-name buffer-file-name)
3057 (expand-file-name (read-file-name "File to load from: ") nil))))
3059 ;; attempt to read undo-tree from FILENAME
3061 (unless (file-exists-p filename)
3063 (throw 'load-error nil)
3064 (error "File \"%s\" does not exist; could not load undo-tree history"
3066 (let (buff hash tree)
3067 (setq buff (current-buffer))
3068 (with-auto-compression-mode
3070 (insert-file-contents filename)
3071 (goto-char (point-min))
3073 (setq hash (read (current-buffer)))
3076 (funcall (if noerror 'message 'error)
3077 "Error reading undo-tree history from \"%s\"" filename)
3078 (throw 'load-error nil)))
3079 (unless (string= (sha1 buff) hash)
3081 (funcall (if noerror 'message 'error)
3082 "Buffer has been modified; could not load undo-tree history")
3083 (throw 'load-error nil))
3085 (setq tree (read (current-buffer)))
3088 (funcall (if noerror 'message 'error)
3089 "Error reading undo-tree history from \"%s\"" filename)
3090 (throw 'load-error nil)))
3092 ;; initialise empty undo-tree object pool
3093 (setf (undo-tree-object-pool tree)
3094 (make-hash-table :test 'eq :weakness 'value))
3095 ;; restore circular undo-tree data structure
3096 (undo-tree-recircle tree)
3097 (setq buffer-undo-tree tree))))
3101 ;; Versions of save/load functions for use in hooks
3102 (defun undo-tree-save-history-hook ()
3103 (when (and undo-tree-mode undo-tree-auto-save-history
3104 (not (eq buffer-undo-list t)))
3105 (undo-tree-save-history nil t) nil))
3107 (defun undo-tree-load-history-hook ()
3108 (when (and undo-tree-mode undo-tree-auto-save-history
3109 (not (eq buffer-undo-list t)))
3110 (undo-tree-load-history nil t)))
3115 ;;; =====================================================================
3116 ;;; Visualizer drawing functions
3118 (defun undo-tree-visualize ()
3119 "Visualize the current buffer's undo tree."
3122 ;; throw error if undo is disabled in buffer
3123 (when (eq buffer-undo-list t) (error "No undo information in this buffer"))
3124 ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'
3125 (undo-list-transfer-to-tree)
3126 ;; add hook to kill visualizer buffer if original buffer is changed
3127 (add-hook 'before-change-functions 'undo-tree-kill-visualizer nil t)
3128 ;; prepare *undo-tree* buffer, then draw tree in it
3129 (let ((undo-tree buffer-undo-tree)
3130 (buff (current-buffer))
3131 (display-buffer-mark-dedicated 'soft))
3132 (switch-to-buffer-other-window
3133 (get-buffer-create undo-tree-visualizer-buffer-name))
3134 (setq undo-tree-visualizer-parent-buffer buff)
3135 (setq undo-tree-visualizer-parent-mtime
3136 (and (buffer-file-name buff)
3137 (nth 5 (file-attributes (buffer-file-name buff)))))
3138 (setq buffer-undo-tree undo-tree)
3139 (setq undo-tree-visualizer-initial-node (undo-tree-current undo-tree))
3140 (setq undo-tree-visualizer-spacing
3141 (undo-tree-visualizer-calculate-spacing))
3142 (make-local-variable 'undo-tree-visualizer-timestamps)
3143 (make-local-variable 'undo-tree-visualizer-diff)
3144 (set (make-local-variable 'undo-tree-visualizer-lazy-drawing)
3145 (or (eq undo-tree-visualizer-lazy-drawing t)
3146 (and (numberp undo-tree-visualizer-lazy-drawing)
3147 (>= (undo-tree-count undo-tree)
3148 undo-tree-visualizer-lazy-drawing))))
3149 (when undo-tree-visualizer-diff (undo-tree-visualizer-show-diff))
3150 (undo-tree-visualizer-mode)
3151 (let ((inhibit-read-only t)) (undo-tree-draw-tree undo-tree))))
3154 (defun undo-tree-kill-visualizer (&rest _dummy)
3155 ;; Kill visualizer. Added to `before-change-functions' hook of original
3156 ;; buffer when visualizer is invoked.
3157 (unless undo-tree-inhibit-kill-visualizer
3159 (with-current-buffer undo-tree-visualizer-buffer-name
3160 (undo-tree-visualizer-quit)))))
3164 (defun undo-tree-draw-tree (undo-tree)
3165 ;; Draw undo-tree in current buffer starting from NODE (or root if nil).
3166 (let ((node (if undo-tree-visualizer-lazy-drawing
3167 (undo-tree-current undo-tree)
3168 (undo-tree-root undo-tree))))
3170 (undo-tree-clear-visualizer-data undo-tree)
3171 (undo-tree-compute-widths node)
3172 ;; lazy drawing starts vertically centred and displaced horizontally to
3173 ;; the left (window-width/4), since trees will typically grow right
3174 (if undo-tree-visualizer-lazy-drawing
3176 (undo-tree-move-down (/ (window-height) 2))
3177 (undo-tree-move-forward (max 2 (/ (window-width) 4)))) ; left margin
3178 ;; non-lazy drawing starts in centre at top of buffer
3179 (undo-tree-move-down 1) ; top margin
3180 (undo-tree-move-forward
3181 (max (/ (window-width) 2)
3182 (+ (undo-tree-node-char-lwidth node)
3183 ;; add space for left part of left-most time-stamp
3184 (if undo-tree-visualizer-timestamps
3185 (/ (- undo-tree-visualizer-spacing 4) 2)
3188 ;; link starting node to its representation in visualizer
3189 (setf (undo-tree-node-marker node) (make-marker))
3190 (set-marker-insertion-type (undo-tree-node-marker node) nil)
3191 (move-marker (undo-tree-node-marker node) (point))
3193 (let ((undo-tree-insert-face 'undo-tree-visualizer-default-face)
3195 (if (not undo-tree-visualizer-lazy-drawing)
3196 (undo-tree-extend-down node t)
3197 (undo-tree-extend-down node)
3198 (undo-tree-extend-up node)
3199 (setq node-list undo-tree-visualizer-needs-extending-down
3200 undo-tree-visualizer-needs-extending-down nil)
3201 (while node-list (undo-tree-extend-down (pop node-list)))))
3202 ;; highlight active branch
3203 (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face))
3204 (undo-tree-highlight-active-branch
3205 (or undo-tree-visualizer-needs-extending-up
3206 (undo-tree-root undo-tree))))
3207 ;; highlight current node
3208 (undo-tree-draw-node (undo-tree-current undo-tree) 'current)))
3211 (defun undo-tree-extend-down (node &optional bottom)
3212 ;; Extend tree downwards starting from NODE and point. If BOTTOM is t,
3213 ;; extend all the way down to the leaves. If BOTTOM is a node, extend down
3214 ;; as far as that node. If BOTTOM is an integer, extend down as far as that
3215 ;; line. Otherwise, only extend visible portion of tree. NODE is assumed to
3216 ;; already have a node marker. Returns non-nil if anything was actually
3218 (let ((extended nil)
3219 (cur-stack (list node))
3221 ;; don't bother extending if BOTTOM specifies an already-drawn node
3222 (unless (and (undo-tree-node-p bottom) (undo-tree-node-marker bottom))
3223 ;; draw nodes layer by layer
3224 (while (or cur-stack
3225 (prog1 (setq cur-stack next-stack)
3226 (setq next-stack nil)))
3227 (setq node (pop cur-stack))
3228 ;; if node is within range being drawn...
3229 (if (or (eq bottom t)
3230 (and (undo-tree-node-p bottom)
3231 (not (eq (undo-tree-node-previous node) bottom)))
3232 (and (integerp bottom)
3233 (>= bottom (line-number-at-pos
3234 (undo-tree-node-marker node))))
3236 (pos-visible-in-window-p (undo-tree-node-marker node)
3238 ;; ...draw one layer of node's subtree (if not already drawn)
3240 (unless (and (undo-tree-node-next node)
3241 (undo-tree-node-marker
3242 (nth (undo-tree-node-branch node)
3243 (undo-tree-node-next node))))
3244 (goto-char (undo-tree-node-marker node))
3245 (undo-tree-draw-subtree node)
3248 (append (undo-tree-node-next node) next-stack)))
3249 ;; ...otherwise, postpone drawing until later
3250 (push node undo-tree-visualizer-needs-extending-down))))
3254 (defun undo-tree-extend-up (node &optional top)
3255 ;; Extend tree upwards starting from NODE. If TOP is t, extend all the way
3256 ;; to root. If TOP is a node, extend up as far as that node. If TOP is an
3257 ;; integer, extend up as far as that line. Otherwise, only extend visible
3258 ;; portion of tree. NODE is assumed to already have a node marker. Returns
3259 ;; non-nil if anything was actually extended.
3260 (let ((extended nil) parent n)
3261 ;; don't bother extending if TOP specifies an already-drawn node
3262 (unless (and (undo-tree-node-p top) (undo-tree-node-marker top))
3264 (setq parent (undo-tree-node-previous node))
3265 ;; if we haven't reached root...
3267 ;; ...and node is within range being drawn...
3269 (and (undo-tree-node-p top) (not (eq node top)))
3271 (< top (line-number-at-pos
3272 (undo-tree-node-marker node))))
3274 ;; NOTE: check point in case window-start is outdated
3275 (< (min (line-number-at-pos (point))
3276 (line-number-at-pos (window-start)))
3278 (undo-tree-node-marker node)))))
3279 ;; ...and it hasn't already been drawn
3280 (when (not (undo-tree-node-marker parent))
3281 ;; link parent node to its representation in visualizer
3282 (undo-tree-compute-widths parent)
3283 (undo-tree-move-to-parent node)
3284 (setf (undo-tree-node-marker parent) (make-marker))
3285 (set-marker-insertion-type
3286 (undo-tree-node-marker parent) nil)
3287 (move-marker (undo-tree-node-marker parent) (point))
3288 ;; draw subtree beneath parent
3289 (setq undo-tree-visualizer-needs-extending-down
3290 (nconc (delq node (undo-tree-draw-subtree parent))
3291 undo-tree-visualizer-needs-extending-down))
3293 ;; ...otherwise, postpone drawing for later and exit
3294 (setq undo-tree-visualizer-needs-extending-up (when parent node)
3297 ;; if we've reached root, stop extending and add top margin
3298 (setq undo-tree-visualizer-needs-extending-up nil)
3299 (goto-char (undo-tree-node-marker node))
3300 (undo-tree-move-up 1) ; top margin
3301 (delete-region (point-min) (line-beginning-position)))
3303 (setq node parent)))
3307 (defun undo-tree-expand-down (from &optional to)
3308 ;; Expand tree downwards. FROM is the node to start expanding from. Stop
3309 ;; expanding at TO if specified. Otherwise, just expand visible portion of
3310 ;; tree and highlight active branch from FROM.
3311 (when undo-tree-visualizer-needs-extending-down
3312 (let ((inhibit-read-only t)
3314 ;; extend down as far as TO node
3316 (setq extended (undo-tree-extend-down from to))
3317 (goto-char (undo-tree-node-marker to))
3318 (redisplay t)) ; force redisplay to scroll buffer if necessary
3319 ;; extend visible portion of tree downwards
3320 (setq node-list undo-tree-visualizer-needs-extending-down
3321 undo-tree-visualizer-needs-extending-down nil)
3323 (dolist (n node-list)
3324 (when (undo-tree-extend-down n) (setq extended t)))
3325 ;; highlight active branch in newly-extended-down portion, if any
3327 (let ((undo-tree-insert-face
3328 'undo-tree-visualizer-active-branch-face))
3329 (undo-tree-highlight-active-branch from)))))))
3332 (defun undo-tree-expand-up (from &optional to)
3333 ;; Expand tree upwards. FROM is the node to start expanding from, TO is the
3334 ;; node to stop expanding at. If TO node isn't specified, just expand visible
3335 ;; portion of tree and highlight active branch down to FROM.
3336 (when undo-tree-visualizer-needs-extending-up
3337 (let ((inhibit-read-only t)
3339 ;; extend up as far as TO node
3341 (setq extended (undo-tree-extend-up from to))
3342 (goto-char (undo-tree-node-marker to))
3343 ;; simulate auto-scrolling if close to top of buffer
3344 (when (<= (line-number-at-pos (point)) scroll-margin)
3345 (undo-tree-move-up (if (= scroll-conservatively 0)
3346 (/ (window-height) 2) 3))
3347 (when (undo-tree-extend-up to) (setq extended t))
3348 (goto-char (undo-tree-node-marker to))
3349 (unless (= scroll-conservatively 0) (recenter scroll-margin))))
3350 ;; extend visible portion of tree upwards
3351 (and undo-tree-visualizer-needs-extending-up
3352 (undo-tree-extend-up undo-tree-visualizer-needs-extending-up)
3354 ;; extend visible portion of tree downwards
3355 (setq node-list undo-tree-visualizer-needs-extending-down
3356 undo-tree-visualizer-needs-extending-down nil)
3357 (dolist (n node-list) (undo-tree-extend-down n))
3358 ;; highlight active branch in newly-extended-up portion, if any
3360 (let ((undo-tree-insert-face
3361 'undo-tree-visualizer-active-branch-face))
3362 (undo-tree-highlight-active-branch
3363 (or undo-tree-visualizer-needs-extending-up
3364 (undo-tree-root buffer-undo-tree))
3369 (defun undo-tree-highlight-active-branch (node &optional end)
3370 ;; Draw highlighted active branch below NODE in current buffer. Stop
3371 ;; highlighting at END node if specified.
3372 (let ((stack (list node)))
3373 ;; draw active branch
3375 (setq node (pop stack))
3376 (unless (or (eq node end)
3377 (memq node undo-tree-visualizer-needs-extending-down))
3378 (goto-char (undo-tree-node-marker node))
3379 (setq node (undo-tree-draw-subtree node 'active)
3380 stack (nconc stack node))))))
3383 (defun undo-tree-draw-node (node &optional current)
3384 ;; Draw symbol representing NODE in visualizer. If CURRENT is non-nil, node
3386 (goto-char (undo-tree-node-marker node))
3387 (when undo-tree-visualizer-timestamps
3388 (undo-tree-move-backward (/ undo-tree-visualizer-spacing 2)))
3390 (let* ((undo-tree-insert-face (and undo-tree-insert-face
3391 (or (and (consp undo-tree-insert-face)
3392 undo-tree-insert-face)
3393 (list undo-tree-insert-face))))
3394 (register (undo-tree-node-register node))
3395 (unmodified (if undo-tree-visualizer-parent-mtime
3396 (undo-tree-node-unmodified-p
3397 node undo-tree-visualizer-parent-mtime)
3398 (undo-tree-node-unmodified-p node)))
3400 ;; check node's register (if any) still stores appropriate undo-tree state
3401 (unless (and register
3402 (undo-tree-register-data-p
3403 (registerv-data (get-register register)))
3404 (eq node (undo-tree-register-data-node
3405 (registerv-data (get-register register)))))
3406 (setq register nil))
3407 ;; represent node by different symbols, depending on whether it's the
3408 ;; current node, is saved in a register, or corresponds to an unmodified
3412 (undo-tree-visualizer-timestamps
3413 (undo-tree-timestamp-to-string
3414 (undo-tree-node-timestamp node)
3415 undo-tree-visualizer-relative-timestamps
3417 (register (char-to-string register))
3421 undo-tree-insert-face
3424 (current '(undo-tree-visualizer-current-face))
3425 (unmodified '(undo-tree-visualizer-unmodified-face))
3426 (register '(undo-tree-visualizer-register-face)))
3427 undo-tree-insert-face))
3428 ;; draw node and link it to its representation in visualizer
3429 (undo-tree-insert node-string)
3430 (undo-tree-move-backward (if undo-tree-visualizer-timestamps
3431 (1+ (/ undo-tree-visualizer-spacing 2))
3433 (move-marker (undo-tree-node-marker node) (point))
3434 (put-text-property (point) (1+ (point)) 'undo-tree-node node)))
3437 (defun undo-tree-draw-subtree (node &optional active-branch)
3438 ;; Draw subtree rooted at NODE. The subtree will start from point.
3439 ;; If ACTIVE-BRANCH is non-nil, just draw active branch below NODE. Returns
3440 ;; list of nodes below NODE.
3441 (let ((num-children (length (undo-tree-node-next node)))
3442 node-list pos trunk-pos n)
3444 (undo-tree-draw-node node)
3447 ;; if we're at a leaf node, we're done
3448 ((= num-children 0))
3450 ;; if node has only one child, draw it (not strictly necessary to deal
3451 ;; with this case separately, but as it's by far the most common case
3452 ;; this makes the code clearer and more efficient)
3454 (undo-tree-move-down 1)
3455 (undo-tree-insert ?|)
3456 (undo-tree-move-backward 1)
3457 (undo-tree-move-down 1)
3458 (undo-tree-insert ?|)
3459 (undo-tree-move-backward 1)
3460 (undo-tree-move-down 1)
3461 (setq n (car (undo-tree-node-next node)))
3462 ;; link next node to its representation in visualizer
3463 (unless (markerp (undo-tree-node-marker n))
3464 (setf (undo-tree-node-marker n) (make-marker))
3465 (set-marker-insertion-type (undo-tree-node-marker n) nil))
3466 (move-marker (undo-tree-node-marker n) (point))
3467 ;; add next node to list of nodes to draw next
3470 ;; if node has multiple children, draw branches
3472 (undo-tree-move-down 1)
3473 (undo-tree-insert ?|)
3474 (undo-tree-move-backward 1)
3475 (move-marker (setq trunk-pos (make-marker)) (point))
3477 (undo-tree-move-backward
3478 (- (undo-tree-node-char-lwidth node)
3479 (undo-tree-node-char-lwidth
3480 (car (undo-tree-node-next node)))))
3481 (move-marker (setq pos (make-marker)) (point))
3482 (setq n (cons nil (undo-tree-node-next node)))
3483 (dotimes (i (/ num-children 2))
3485 (when (or (null active-branch)
3487 (nth (undo-tree-node-branch node)
3488 (undo-tree-node-next node))))
3489 (undo-tree-move-forward 2)
3490 (undo-tree-insert ?_ (- trunk-pos pos 2))
3492 (undo-tree-move-forward 1)
3493 (undo-tree-move-down 1)
3494 (undo-tree-insert ?/)
3495 (undo-tree-move-backward 2)
3496 (undo-tree-move-down 1)
3497 ;; link node to its representation in visualizer
3498 (unless (markerp (undo-tree-node-marker (car n)))
3499 (setf (undo-tree-node-marker (car n)) (make-marker))
3500 (set-marker-insertion-type (undo-tree-node-marker (car n)) nil))
3501 (move-marker (undo-tree-node-marker (car n)) (point))
3502 ;; add node to list of nodes to draw next
3503 (push (car n) node-list))
3505 (undo-tree-move-forward
3506 (+ (undo-tree-node-char-rwidth (car n))
3507 (undo-tree-node-char-lwidth (cadr n))
3508 undo-tree-visualizer-spacing 1))
3509 (move-marker pos (point)))
3510 ;; middle subtree (only when number of children is odd)
3511 (when (= (mod num-children 2) 1)
3513 (when (or (null active-branch)
3515 (nth (undo-tree-node-branch node)
3516 (undo-tree-node-next node))))
3517 (undo-tree-move-down 1)
3518 (undo-tree-insert ?|)
3519 (undo-tree-move-backward 1)
3520 (undo-tree-move-down 1)
3521 ;; link node to its representation in visualizer
3522 (unless (markerp (undo-tree-node-marker (car n)))
3523 (setf (undo-tree-node-marker (car n)) (make-marker))
3524 (set-marker-insertion-type (undo-tree-node-marker (car n)) nil))
3525 (move-marker (undo-tree-node-marker (car n)) (point))
3526 ;; add node to list of nodes to draw next
3527 (push (car n) node-list))
3529 (undo-tree-move-forward
3530 (+ (undo-tree-node-char-rwidth (car n))
3531 (if (cadr n) (undo-tree-node-char-lwidth (cadr n)) 0)
3532 undo-tree-visualizer-spacing 1))
3533 (move-marker pos (point)))
3535 (move-marker trunk-pos (1+ trunk-pos))
3536 (dotimes (i (/ num-children 2))
3538 (when (or (null active-branch)
3540 (nth (undo-tree-node-branch node)
3541 (undo-tree-node-next node))))
3542 (goto-char trunk-pos)
3543 (undo-tree-insert ?_ (- pos trunk-pos 1))
3545 (undo-tree-move-backward 1)
3546 (undo-tree-move-down 1)
3547 (undo-tree-insert ?\\)
3548 (undo-tree-move-down 1)
3549 ;; link node to its representation in visualizer
3550 (unless (markerp (undo-tree-node-marker (car n)))
3551 (setf (undo-tree-node-marker (car n)) (make-marker))
3552 (set-marker-insertion-type (undo-tree-node-marker (car n)) nil))
3553 (move-marker (undo-tree-node-marker (car n)) (point))
3554 ;; add node to list of nodes to draw next
3555 (push (car n) node-list))
3558 (undo-tree-move-forward
3559 (+ (undo-tree-node-char-rwidth (car n))
3560 (if (cadr n) (undo-tree-node-char-lwidth (cadr n)) 0)
3561 undo-tree-visualizer-spacing 1))
3562 (move-marker pos (point))))
3564 ;; return list of nodes to draw next
3565 (nreverse node-list)))
3568 (defun undo-tree-node-char-lwidth (node)
3569 ;; Return left-width of NODE measured in characters.
3570 (if (= (length (undo-tree-node-next node)) 0) 0
3571 (- (* (+ undo-tree-visualizer-spacing 1) (undo-tree-node-lwidth node))
3572 (if (= (undo-tree-node-cwidth node) 0)
3573 (1+ (/ undo-tree-visualizer-spacing 2)) 0))))
3576 (defun undo-tree-node-char-rwidth (node)
3577 ;; Return right-width of NODE measured in characters.
3578 (if (= (length (undo-tree-node-next node)) 0) 0
3579 (- (* (+ undo-tree-visualizer-spacing 1) (undo-tree-node-rwidth node))
3580 (if (= (undo-tree-node-cwidth node) 0)
3581 (1+ (/ undo-tree-visualizer-spacing 2)) 0))))
3584 (defun undo-tree-insert (str &optional arg)
3585 ;; Insert character or string STR ARG times, overwriting, and using
3586 ;; `undo-tree-insert-face'.
3587 (unless arg (setq arg 1))
3588 (when (characterp str)
3589 (setq str (make-string arg str))
3591 (dotimes (i arg) (insert str))
3592 (setq arg (* arg (length str)))
3593 (undo-tree-move-forward arg)
3594 ;; make sure mark isn't active, otherwise `backward-delete-char' might
3595 ;; delete region instead of single char if transient-mark-mode is enabled
3596 (setq mark-active nil)
3597 (backward-delete-char arg)
3598 (when undo-tree-insert-face
3599 (put-text-property (- (point) arg) (point) 'face undo-tree-insert-face)))
3602 (defun undo-tree-move-down (&optional arg)
3603 ;; Move down, extending buffer if necessary.
3604 (let ((row (line-number-at-pos))
3605 (col (current-column))
3607 (unless arg (setq arg 1))
3609 (setq line (line-number-at-pos))
3610 ;; if buffer doesn't have enough lines, add some
3611 (when (/= line (+ row arg))
3614 (insert (make-string (- line row arg) ?\n))
3615 (forward-line (+ arg (- row line))))
3616 (t (insert (make-string (- arg (- line row)) ?\n)))))
3617 (undo-tree-move-forward col)))
3620 (defun undo-tree-move-up (&optional arg)
3621 ;; Move up, extending buffer if necessary.
3622 (unless arg (setq arg 1))
3623 (undo-tree-move-down (- arg)))
3626 (defun undo-tree-move-forward (&optional arg)
3627 ;; Move forward, extending buffer if necessary.
3628 (unless arg (setq arg 1))
3632 (setq n (- (line-end-position) (point)))
3636 (insert (make-string (- arg n) ? ))))
3639 (setq n (- (point) (line-beginning-position)))
3640 (when (< (- n 2) arg) ; -2 to create left-margin
3641 ;; no space left - shift entire buffer contents right!
3642 (let ((pos (move-marker (make-marker) (point))))
3643 (set-marker-insertion-type pos t)
3644 (goto-char (point-min))
3646 (insert-before-markers (make-string (- arg -2 n) ? ))
3649 (backward-char arg)))))
3652 (defun undo-tree-move-backward (&optional arg)
3653 ;; Move backward, extending buffer if necessary.
3654 (unless arg (setq arg 1))
3655 (undo-tree-move-forward (- arg)))
3658 (defun undo-tree-move-to-parent (node)
3659 ;; Move to position of parent of NODE, extending buffer if necessary.
3660 (let* ((parent (undo-tree-node-previous node))
3661 (n (undo-tree-node-next parent))
3663 (goto-char (undo-tree-node-marker node))
3665 ;; move horizontally
3666 (setq p (undo-tree-position node n))
3668 ;; node in centre subtree: no horizontal movement
3669 ((and (= (mod l 2) 1) (= p (/ l 2))))
3670 ;; node in left subtree: move right
3672 (setq n (nthcdr p n))
3673 (undo-tree-move-forward
3674 (+ (undo-tree-node-char-rwidth (car n))
3675 (/ undo-tree-visualizer-spacing 2) 1))
3676 (dotimes (i (- (/ l 2) p 1))
3678 (undo-tree-move-forward
3679 (+ (undo-tree-node-char-lwidth (car n))
3680 (undo-tree-node-char-rwidth (car n))
3681 undo-tree-visualizer-spacing 1)))
3682 (when (= (mod l 2) 1)
3684 (undo-tree-move-forward
3685 (+ (undo-tree-node-char-lwidth (car n))
3686 (/ undo-tree-visualizer-spacing 2) 1))))
3687 (t ;; node in right subtree: move left
3688 (setq n (nthcdr (/ l 2) n))
3689 (when (= (mod l 2) 1)
3690 (undo-tree-move-backward
3691 (+ (undo-tree-node-char-rwidth (car n))
3692 (/ undo-tree-visualizer-spacing 2) 1))
3694 (dotimes (i (- p (/ l 2) (mod l 2)))
3695 (undo-tree-move-backward
3696 (+ (undo-tree-node-char-lwidth (car n))
3697 (undo-tree-node-char-rwidth (car n))
3698 undo-tree-visualizer-spacing 1))
3700 (undo-tree-move-backward
3701 (+ (undo-tree-node-char-lwidth (car n))
3702 (/ undo-tree-visualizer-spacing 2) 1)))))
3704 (undo-tree-move-up 3)))
3707 (defun undo-tree-timestamp-to-string
3708 (timestamp &optional relative current register)
3709 ;; Convert TIMESTAMP to string (either absolute or RELATVE time), indicating
3710 ;; if it's the CURRENT node and/or has an associated REGISTER.
3713 (let ((time (floor (float-time
3714 (subtract-time (current-time) timestamp))))
3718 (if (> (setq n (/ time 315360000)) 0)
3719 (if (> n 999) "-ages" (format "-%dy" n))
3720 (setq time (% time 315360000))
3722 (if (> (setq n (/ time 86400)) 0)
3724 (setq time (% time 86400))
3726 (if (> (setq n (/ time 3600)) 0)
3728 (setq time (% time 3600))
3730 (if (> (setq n (/ time 60)) 0)
3733 (format "-%ds" (% time 60)))))))
3735 (if current "*" " ")
3737 (if register (concat "[" (char-to-string register) "]")
3739 (setq n (length time))
3741 (concat (make-string (- 9 n) ? ) time)
3744 (concat (if current "*" " ")
3745 (format-time-string "%H:%M:%S" timestamp)
3747 (concat "[" (char-to-string register) "]")
3753 ;;; =====================================================================
3754 ;;; Visualizer commands
3756 (defun undo-tree-visualizer-mode ()
3757 "Major mode used in undo-tree visualizer.
3759 The undo-tree visualizer can only be invoked from a buffer in
3760 which `undo-tree-mode' is enabled. The visualizer displays the
3761 undo history tree graphically, and allows you to browse around
3762 the undo history, undoing or redoing the corresponding changes in
3765 Within the undo-tree visualizer, the following keys are available:
3767 \\{undo-tree-visualizer-map}"
3769 (setq major-mode 'undo-tree-visualizer-mode)
3770 (setq mode-name "undo-tree-visualizer-mode")
3771 (use-local-map undo-tree-visualizer-map)
3772 (setq truncate-lines t)
3773 (setq cursor-type nil)
3774 (setq buffer-read-only t)
3775 (setq undo-tree-visualizer-selected-node nil)
3776 (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff)))
3780 (defun undo-tree-visualize-undo (&optional arg)
3781 "Undo changes. A numeric ARG serves as a repeat count."
3783 (let ((old (undo-tree-current buffer-undo-tree))
3785 ;; unhighlight old current node
3786 (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face)
3787 (inhibit-read-only t))
3788 (undo-tree-draw-node old))
3789 ;; undo in parent buffer
3790 (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer)
3793 (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-undo-1 arg))
3794 (setq current (undo-tree-current buffer-undo-tree))
3795 (switch-to-buffer-other-window undo-tree-visualizer-buffer-name)
3796 ;; when using lazy drawing, extend tree upwards as required
3797 (when undo-tree-visualizer-lazy-drawing
3798 (undo-tree-expand-up old current))
3799 ;; highlight new current node
3800 (let ((inhibit-read-only t)) (undo-tree-draw-node current 'current))
3801 ;; update diff display, if any
3802 (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff)))))
3805 (defun undo-tree-visualize-redo (&optional arg)
3806 "Redo changes. A numeric ARG serves as a repeat count."
3808 (let ((old (undo-tree-current buffer-undo-tree))
3810 ;; unhighlight old current node
3811 (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face)
3812 (inhibit-read-only t))
3813 (undo-tree-draw-node (undo-tree-current buffer-undo-tree)))
3814 ;; redo in parent buffer
3815 (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer)
3818 (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-redo-1 arg))
3819 (setq current (undo-tree-current buffer-undo-tree))
3820 (switch-to-buffer-other-window undo-tree-visualizer-buffer-name)
3821 ;; when using lazy drawing, extend tree downwards as required
3822 (when undo-tree-visualizer-lazy-drawing
3823 (undo-tree-expand-down old current))
3824 ;; highlight new current node
3825 (let ((inhibit-read-only t)) (undo-tree-draw-node current 'current))
3826 ;; update diff display, if any
3827 (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff)))))
3830 (defun undo-tree-visualize-switch-branch-right (arg)
3831 "Switch to next branch of the undo tree.
3832 This will affect which branch to descend when *redoing* changes
3833 using `undo-tree-redo' or `undo-tree-visualizer-redo'."
3835 ;; un-highlight old active branch below current node
3836 (goto-char (undo-tree-node-marker (undo-tree-current buffer-undo-tree)))
3837 (let ((undo-tree-insert-face 'undo-tree-visualizer-default-face)
3838 (inhibit-read-only t))
3839 (undo-tree-highlight-active-branch (undo-tree-current buffer-undo-tree)))
3841 (let ((branch (undo-tree-node-branch (undo-tree-current buffer-undo-tree))))
3842 (setf (undo-tree-node-branch (undo-tree-current buffer-undo-tree))
3844 ((>= (+ branch arg) (undo-tree-num-branches))
3845 (1- (undo-tree-num-branches)))
3846 ((<= (+ branch arg) 0) 0)
3847 (t (+ branch arg))))
3848 (let ((inhibit-read-only t))
3849 ;; highlight new active branch below current node
3850 (goto-char (undo-tree-node-marker (undo-tree-current buffer-undo-tree)))
3851 (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face))
3852 (undo-tree-highlight-active-branch (undo-tree-current buffer-undo-tree)))
3853 ;; re-highlight current node
3854 (undo-tree-draw-node (undo-tree-current buffer-undo-tree) 'current))))
3857 (defun undo-tree-visualize-switch-branch-left (arg)
3858 "Switch to previous branch of the undo tree.
3859 This will affect which branch to descend when *redoing* changes
3860 using `undo-tree-redo' or `undo-tree-visualizer-redo'."
3862 (undo-tree-visualize-switch-branch-right (- arg)))
3865 (defun undo-tree-visualizer-quit ()
3866 "Quit the undo-tree visualizer."
3868 (undo-tree-clear-visualizer-data buffer-undo-tree)
3869 ;; remove kill visualizer hook from parent buffer
3871 (with-current-buffer undo-tree-visualizer-parent-buffer
3872 (remove-hook 'before-change-functions 'undo-tree-kill-visualizer t))
3873 ;; kill diff buffer, if any
3874 (when undo-tree-visualizer-diff (undo-tree-visualizer-hide-diff))
3875 (let ((parent undo-tree-visualizer-parent-buffer)
3877 ;; kill visualizer buffer
3879 ;; switch back to parent buffer
3881 (if (setq window (get-buffer-window parent))
3882 (select-window window)
3883 (switch-to-buffer parent))))))
3886 (defun undo-tree-visualizer-abort ()
3887 "Quit the undo-tree visualizer and return buffer to original state."
3889 (let ((node undo-tree-visualizer-initial-node))
3890 (undo-tree-visualizer-quit)
3891 (undo-tree-set node)))
3894 (defun undo-tree-visualizer-set (&optional pos)
3895 "Set buffer to state corresponding to undo tree node
3896 at POS, or point if POS is nil."
3898 (unless pos (setq pos (point)))
3899 (let ((node (get-text-property pos 'undo-tree-node)))
3901 ;; set parent buffer to state corresponding to node at POS
3902 (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer)
3903 (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-set node))
3904 (switch-to-buffer-other-window undo-tree-visualizer-buffer-name)
3905 ;; re-draw undo tree
3906 (let ((inhibit-read-only t)) (undo-tree-draw-tree buffer-undo-tree))
3907 (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff)))))
3910 (defun undo-tree-visualizer-mouse-set (pos)
3911 "Set buffer to state corresponding to undo tree node
3912 at mouse event POS."
3914 (undo-tree-visualizer-set (event-start (nth 1 pos))))
3917 (defun undo-tree-visualize-undo-to-x (&optional x)
3918 "Undo to last branch point, register, or saved state.
3919 If X is 'branch, undo to last branch point. If X is 'register,
3920 undo to last register. If X is 'saved, undo to last saved state.
3922 Interactively, a single \\[universal-argument] specifies
3923 `branch', a double \\[universal-argument] \[universal-argument]
3924 spcified `saved', and a negative prefix argument specifies
3927 (when (and (called-interactively-p 'any) x)
3928 (setq x (prefix-numeric-value x)
3933 (let ((current (undo-tree-current buffer-undo-tree))
3935 (while (and (undo-tree-node-previous current)
3936 (or (undo-tree-visualize-undo) t)
3937 (setq current (undo-tree-current buffer-undo-tree))
3939 (not (or (and (or (null x) (eq x 'branch))
3940 (> (undo-tree-num-branches) 1))
3942 (and (or (null x) (eq x 'register))
3943 (setq r (undo-tree-node-register current))
3944 (undo-tree-register-data-p
3945 (setq r (registerv-data (get-register r))))
3946 (eq current (undo-tree-register-data-node r)))
3948 (and (or (null x) (eq x 'saved))
3949 (undo-tree-node-unmodified-p current))
3953 (defun undo-tree-visualize-redo-to-x (&optional x)
3954 "Redo to next branch point or register.
3955 If X is the symbol `branch', redo to next branch point ignoring
3956 registers. If X is the symbol 'register', redo to next register,
3957 ignoring branch points.
3959 Interactively, a positive prefix argument specifies `branch', and
3960 a negative prefix argument specifies `register'."
3962 (when (and (called-interactively-p 'any) x)
3963 (setq x (prefix-numeric-value x)
3968 (let ((current (undo-tree-current buffer-undo-tree))
3970 (while (and (undo-tree-node-next current)
3971 (or (undo-tree-visualize-redo) t)
3972 (setq current (undo-tree-current buffer-undo-tree))
3974 (not (or (and (or (null x) (eq x 'branch))
3975 (> (undo-tree-num-branches) 1))
3977 (and (or (null x) (eq x 'register))
3978 (setq r (undo-tree-node-register current))
3979 (undo-tree-register-data-p
3980 (setq r (registerv-data (get-register r))))
3981 (eq current (undo-tree-register-data-node r)))
3983 (and (or (null x) (eq x 'saved))
3984 (undo-tree-node-unmodified-p current))
3988 (defun undo-tree-visualizer-toggle-timestamps ()
3989 "Toggle display of time-stamps."
3991 (setq undo-tree-visualizer-timestamps (not undo-tree-visualizer-timestamps))
3992 (setq undo-tree-visualizer-spacing (undo-tree-visualizer-calculate-spacing))
3994 (let ((inhibit-read-only t)) (undo-tree-draw-tree buffer-undo-tree)))
3997 (defun undo-tree-visualizer-scroll-left (&optional arg)
3999 (scroll-left (or arg 1) t))
4002 (defun undo-tree-visualizer-scroll-right (&optional arg)
4004 (scroll-right (or arg 1) t))
4007 (defun undo-tree-visualizer-scroll-up (&optional arg)
4009 (if (or (and (numberp arg) (< arg 0)) (eq arg '-))
4010 (undo-tree-visualizer-scroll-down arg)
4011 ;; scroll up and expand newly-visible portion of tree
4013 (scroll-up-command arg)
4014 (undo-tree-expand-down
4015 (nth (undo-tree-node-branch (undo-tree-current buffer-undo-tree))
4016 (undo-tree-node-next (undo-tree-current buffer-undo-tree)))))
4017 ;; signal error if at eob
4018 (when (and (not undo-tree-visualizer-needs-extending-down) (eobp))
4022 (defun undo-tree-visualizer-scroll-down (&optional arg)
4024 (if (or (and (numberp arg) (< arg 0)) (eq arg '-))
4025 (undo-tree-visualizer-scroll-up arg)
4026 ;; ensure there's enough room at top of buffer to scroll
4028 (or arg (- (window-height) next-screen-context-lines)))
4029 (window-line (1- (line-number-at-pos (window-start)))))
4030 (when (and undo-tree-visualizer-needs-extending-up
4031 (< window-line scroll-lines))
4032 (let ((inhibit-read-only t))
4033 (goto-char (point-min))
4034 (undo-tree-move-up (- scroll-lines window-line)))))
4035 ;; scroll down and expand newly-visible portion of tree
4037 (scroll-down-command arg)
4038 (undo-tree-expand-up
4039 (undo-tree-node-previous (undo-tree-current buffer-undo-tree))))
4040 ;; signal error if at bob
4041 (when (and (not undo-tree-visualizer-needs-extending-down) (bobp))
4047 ;;; =====================================================================
4048 ;;; Visualizer selection mode
4050 (defun undo-tree-visualizer-selection-mode ()
4051 "Major mode used to select nodes in undo-tree visualizer."
4053 (setq major-mode 'undo-tree-visualizer-selection-mode)
4054 (setq mode-name "undo-tree-visualizer-selection-mode")
4055 (use-local-map undo-tree-visualizer-selection-map)
4056 (setq cursor-type 'box)
4057 (setq undo-tree-visualizer-selected-node
4058 (undo-tree-current buffer-undo-tree))
4059 ;; erase diff (if any), as initially selected node is identical to current
4060 (when undo-tree-visualizer-diff
4061 (let ((buff (get-buffer undo-tree-diff-buffer-name))
4062 (inhibit-read-only t))
4063 (when buff (with-current-buffer buff (erase-buffer))))))
4066 (defun undo-tree-visualizer-select-previous (&optional arg)
4067 "Move to previous node."
4069 (let ((node undo-tree-visualizer-selected-node))
4072 (unless (undo-tree-node-previous node) (throw 'top t))
4073 (setq node (undo-tree-node-previous node))))
4074 ;; when using lazy drawing, extend tree upwards as required
4075 (when undo-tree-visualizer-lazy-drawing
4076 (undo-tree-expand-up undo-tree-visualizer-selected-node node))
4077 ;; update diff display, if any
4078 (when (and undo-tree-visualizer-diff
4079 (not (eq node undo-tree-visualizer-selected-node)))
4080 (undo-tree-visualizer-update-diff node))
4081 ;; move to selected node
4082 (goto-char (undo-tree-node-marker node))
4083 (setq undo-tree-visualizer-selected-node node)))
4086 (defun undo-tree-visualizer-select-next (&optional arg)
4087 "Move to next node."
4089 (let ((node undo-tree-visualizer-selected-node))
4092 (unless (nth (undo-tree-node-branch node) (undo-tree-node-next node))
4095 (nth (undo-tree-node-branch node) (undo-tree-node-next node)))))
4096 ;; when using lazy drawing, extend tree upwards as required
4097 (when undo-tree-visualizer-lazy-drawing
4098 (undo-tree-expand-down undo-tree-visualizer-selected-node node))
4099 ;; update diff display, if any
4100 (when (and undo-tree-visualizer-diff
4101 (not (eq node undo-tree-visualizer-selected-node)))
4102 (undo-tree-visualizer-update-diff node))
4103 ;; move to selected node
4104 (goto-char (undo-tree-node-marker node))
4105 (setq undo-tree-visualizer-selected-node node)))
4108 (defun undo-tree-visualizer-select-right (&optional arg)
4109 "Move right to a sibling node."
4111 (let ((node undo-tree-visualizer-selected-node)
4113 (goto-char (undo-tree-node-marker undo-tree-visualizer-selected-node))
4114 (setq end (line-end-position))
4117 (while (or (null node) (eq node undo-tree-visualizer-selected-node))
4119 (setq node (get-text-property (point) 'undo-tree-node))
4120 (when (= (point) end) (throw 'end t)))))
4121 (goto-char (undo-tree-node-marker
4122 (or node undo-tree-visualizer-selected-node)))
4123 (when (and undo-tree-visualizer-diff node
4124 (not (eq node undo-tree-visualizer-selected-node)))
4125 (undo-tree-visualizer-update-diff node))
4126 (when node (setq undo-tree-visualizer-selected-node node))))
4129 (defun undo-tree-visualizer-select-left (&optional arg)
4130 "Move left to a sibling node."
4132 (let ((node (get-text-property (point) 'undo-tree-node))
4134 (goto-char (undo-tree-node-marker undo-tree-visualizer-selected-node))
4135 (setq beg (line-beginning-position))
4138 (while (or (null node) (eq node undo-tree-visualizer-selected-node))
4140 (setq node (get-text-property (point) 'undo-tree-node))
4141 (when (= (point) beg) (throw 'beg t)))))
4142 (goto-char (undo-tree-node-marker
4143 (or node undo-tree-visualizer-selected-node)))
4144 (when (and undo-tree-visualizer-diff node
4145 (not (eq node undo-tree-visualizer-selected-node)))
4146 (undo-tree-visualizer-update-diff node))
4147 (when node (setq undo-tree-visualizer-selected-node node))))
4151 ;;; =====================================================================
4152 ;;; Visualizer diff display
4154 (defun undo-tree-visualizer-toggle-diff ()
4155 "Toggle diff display in undo-tree visualizer."
4157 (if undo-tree-visualizer-diff
4158 (undo-tree-visualizer-hide-diff)
4159 (undo-tree-visualizer-show-diff)))
4162 (defun undo-tree-visualizer-selection-toggle-diff ()
4163 "Toggle diff display in undo-tree visualizer selection mode."
4165 (if undo-tree-visualizer-diff
4166 (undo-tree-visualizer-hide-diff)
4167 (let ((node (get-text-property (point) 'undo-tree-node)))
4168 (when node (undo-tree-visualizer-show-diff node)))))
4171 (defun undo-tree-visualizer-show-diff (&optional node)
4172 ;; show visualizer diff display
4173 (setq undo-tree-visualizer-diff t)
4174 (let ((buff (with-current-buffer undo-tree-visualizer-parent-buffer
4175 (undo-tree-diff node)))
4176 (display-buffer-mark-dedicated 'soft)
4178 (setq win (split-window))
4179 (set-window-buffer win buff)
4180 (shrink-window-if-larger-than-buffer win)))
4183 (defun undo-tree-visualizer-hide-diff ()
4184 ;; hide visualizer diff display
4185 (setq undo-tree-visualizer-diff nil)
4186 (let ((win (get-buffer-window undo-tree-diff-buffer-name)))
4187 (when win (with-selected-window win (kill-buffer-and-window)))))
4190 (defun undo-tree-diff (&optional node)
4191 ;; Create diff between current state and NODE (or previous state, if NODE is
4192 ;; null). Returns buffer containing diff.
4195 (let ((undo-tree-inhibit-kill-visualizer t)
4196 (current (undo-tree-current buffer-undo-tree)))
4197 (undo-tree-set (or node (undo-tree-node-previous current) current)
4198 'preserve-timestamps)
4199 (setq tmpfile (diff-file-local-copy (current-buffer)))
4200 (undo-tree-set current 'preserve-timestamps))
4201 (setq buff (diff-no-select
4202 (current-buffer) tmpfile nil 'noasync
4203 (get-buffer-create undo-tree-diff-buffer-name)))
4204 ;; delete process messages and useless headers from diff buffer
4205 (with-current-buffer buff
4206 (goto-char (point-min))
4207 (delete-region (point) (1+ (line-end-position 3)))
4208 (goto-char (point-max))
4210 (delete-region (point) (point-max))
4211 (setq cursor-type nil)
4212 (setq buffer-read-only t))
4216 (defun undo-tree-visualizer-update-diff (&optional node)
4217 ;; update visualizer diff display to show diff between current state and
4218 ;; NODE (or previous state, if NODE is null)
4219 (with-current-buffer undo-tree-visualizer-parent-buffer
4220 (undo-tree-diff node))
4221 (let ((win (get-buffer-window undo-tree-diff-buffer-name)))
4224 (shrink-window-if-larger-than-buffer win))))
4228 (provide 'undo-tree)
4230 ;;; undo-tree.el ends here