emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] master ebd8979: New undo-tree package release.


From: Toby Cubitt
Subject: [elpa] master ebd8979: New undo-tree package release.
Date: Mon, 6 Jan 2020 11:36:50 -0500 (EST)

branch: master
commit ebd8979eecca8f554b40db624ba649d513d737f3
Author: Toby S. Cubitt <address@hidden>
Commit: Toby S. Cubitt <address@hidden>

    New undo-tree package release.
---
 packages/undo-tree/undo-tree.el | 595 ++++++++++++++++++++++++++++------------
 1 file changed, 412 insertions(+), 183 deletions(-)

diff --git a/packages/undo-tree/undo-tree.el b/packages/undo-tree/undo-tree.el
index cb8a230..defe1d2 100644
--- a/packages/undo-tree/undo-tree.el
+++ b/packages/undo-tree/undo-tree.el
@@ -1,9 +1,10 @@
 ;;; undo-tree.el --- Treat undo history as a tree  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 2009-2013  Free Software Foundation, Inc
+;; Copyright (C) 2009-2020  Free Software Foundation, Inc
 
 ;; Author: Toby Cubitt <address@hidden>
-;; Version: 0.6.5
+;; Maintainer: Toby Cubitt <address@hidden>
+;; Version: 0.7
 ;; Keywords: convenience, files, undo, redo, history, tree
 ;; URL: http://www.dr-qubit.org/emacs.php
 ;; Repository: http://www.dr-qubit.org/git/undo-tree.git
@@ -410,7 +411,7 @@
 ;;                       o  o     o     o     o     o
 ;;                       |  |\    |\    |\    |\    |
 ;;                       |  | \   | \   | \   | \   |
-;;                       o  o  |  |  o  o  o  |  o  o
+;;                       o  o  |  |  o  o  |  |  o  o
 ;;                       | /   |  |  | /   |  |  | /
 ;;                       |/    |  |  |/    |  |  |/
 ;;      (already undid   o     |  |  o<.   |  |  o
@@ -586,7 +587,7 @@
 ;; Finally, hitting "q" will quit the visualizer, leaving the parent buffer in
 ;; whatever state you ended at. Hitting "C-q" will abort the visualizer,
 ;; returning the parent buffer to whatever state it was originally in when the
-;; visualizer was .
+;; visualizer was invoked.
 ;;
 ;;
 ;;
@@ -625,24 +626,37 @@
 ;;                       o     x  (undo the undo-in-region)
 ;;
 ;;
-;; In `undo-tree-mode', undo-in-region works similarly: when there's an active
-;; region, undoing only undoes changes that affect that region. However, the
-;; way these undos-in-region are recorded in the undo history is quite
-;; different. In `undo-tree-mode', undo-in-region creates a new branch in the
-;; undo history. The new branch consists of an undo step that undoes some of
-;; the changes that affect the current region, and another step that undoes
-;; the remaining changes needed to rejoin the previous undo history.
+;; In `undo-tree-mode', undo-in-region works much the same way: when there's
+;; an active region, undoing only undoes changes that affect that region. In
+;; `undo-tree-mode', redoing when there's an active region similarly only
+;; redoes changes that affect that region.
+;;
+;; However, the way these undo- and redo-in-region changes are recorded in the
+;; undo history is quite different. The good news is, you don't need to
+;; understand this to use undo- and redo-in-region in `undo-tree-mode' - just
+;; go ahead and use them! They'll probably work as you expect. But if you're
+;; masochistic enough to want to understand conceptually what's happening to
+;; the undo tree as you undo- and redo-in-region, then read on...
+;;
+;;
+;; Undo-in-region creates a new branch in the undo history. The new branch
+;; consists of an undo step that undoes some of the changes that affect the
+;; current region, and another step that undoes the remaining changes needed
+;; to rejoin the previous undo history.
 ;;
 ;;      Previous undo history                Undo-in-region
 ;;
 ;;               o                                o
 ;;               |                                |
 ;;               |                                |
+;;               |                                |
 ;;               o                                o
-;;               |                                |\
+;;               |                                |
+;;               |                                |
+;;               |                                |
+;;               o                                o_
 ;;               |                                | \
-;;               o                                o  x  (undo-in-region)
-;;               |                                |  |
+;;               |                                |  x  (undo-in-region)
 ;;               |                                |  |
 ;;               x                                o  o
 ;;
@@ -655,48 +669,57 @@
 ;;      First undo-in-region                 Second undo-in-region
 ;;
 ;;               o                                o
-;;               |                                |\
+;;               |                                |
+;;               |                                |
+;;               |                                |
+;;               o                                o_
 ;;               |                                | \
-;;               o                                o  x  (undo-in-region)
-;;               |\                               |  |
+;;               |                                |  x  (undo-in-region)
+;;               |                                |  |
+;;               o_                               o  |
 ;;               | \                              |  |
-;;               o  x                             o  o
-;;               |  |                             |  |
-;;               |  |                             |  |
-;;               o  o                             o  o
+;;              |  x                             |  o
+;;              |  |                             |  |
+;;              o  o                             o  o
 ;;
 ;; Redoing takes you back down the undo tree, as usual (as long as you haven't
 ;; changed the active region after undoing-in-region, it doesn't matter if it
 ;; is still active):
 ;;
 ;;                       o
-;;                      |\
+;;                      |
+;;                      |
+;;                      |
+;;                      o_
 ;;                      | \
-;;                      o  o
-;;                      |  |
+;;                      |  o
 ;;                      |  |
-;;                      o  o  (redo)
+;;                      o  |
 ;;                      |  |
+;;                      |  o  (redo)
 ;;                      |  |
 ;;                      o  x  (redo)
 ;;
 ;;
-;; What about redo-in-region? Obviously, this only makes sense if you have
-;; already undone some changes, so that there are some changes to redo!
-;; Redoing-in-region splits off a new branch of the undo history below your
-;; current location in the undo tree. This time, the new branch consists of a
-;; redo step that redoes some of the redo changes that affect the current
-;; region, followed by all the remaining redo changes.
+;; What about redo-in-region? Obviously, redo-in-region only makes sense if
+;; you have already undone some changes, so that there are some changes to
+;; redo! Redoing-in-region splits off a new branch of the undo history below
+;; your current location in the undo tree. This time, the new branch consists
+;; of a first redo step that redoes some of the redo changes that affect the
+;; current region, followed by *all* the remaining redo changes.
 ;;
 ;;      Previous undo history                Redo-in-region
 ;;
 ;;               o                                o
 ;;               |                                |
 ;;               |                                |
-;;               x                                o
-;;               |                                |\
+;;               |                                |
+;;               x                                o_
 ;;               |                                | \
-;;               o                                o  x  (redo-in-region)
+;;               |                                |  x  (redo-in-region)
+;;               |                                |  |
+;;               o                                o  |
+;;               |                                |  |
 ;;               |                                |  |
 ;;               |                                |  |
 ;;               o                                o  o
@@ -708,19 +731,19 @@
 ;;
 ;;      First redo-in-region                 Second redo-in-region
 ;;
-;;          o                                     o
-;;          |                                     |
-;;          |                                     |
-;;          o                                     o
-;;          |\                                    |\
-;;          | \                                   | \
-;;          o  x  (redo-in-region)                o  o
-;;          |  |                                  |  |
-;;          |  |                                  |  |
-;;          o  o                                  o  x  (redo-in-region)
-;;                                                   |
-;;                                                   |
-;;                                                   o
+;;               o                                 o
+;;               |                                 |
+;;               |                                 |
+;;               |                                 |
+;;               o_                                o_
+;;               | \                               | \
+;;               |  x                              |  o
+;;               |  |                              |  |
+;;               o  |                              o  |
+;;               |  |                              |  |
+;;               |  |                              |  x  (redo-in-region)
+;;               |  |                              |  |
+;;               o  o                              o  o
 ;;
 ;; Note that undo-in-region and redo-in-region only ever add new changes to
 ;; the undo tree, they *never* modify existing undo history. So you can always
@@ -851,6 +874,45 @@
   "Tree undo/redo."
   :group 'undo)
 
+
+(defcustom undo-tree-limit 80000000
+  "Value of `undo-limit' used in `undo-tree-mode'.
+
+If `undo-limit' is larger than `undo-tree-limit', the larger of
+the two values will be used.
+
+See also `undo-tree-strong-limit' and `undo-tree-outer-limit'.
+
+Setting this to nil prevents `undo-tree-mode' ever discarding
+undo history. (As far as possible. In principle, it is still
+possible for Emacs to discard undo history behind
+`undo-tree-mode's back.) USE THIS SETTING AT YOUR OWN RISK! Emacs
+may crash if undo history exceeds Emacs' available memory. This
+is particularly risky if `undo-tree-auto-save-history' is
+enabled, as in that case undo history is preserved even between
+Emacs sessions."
+  :group 'undo-tree
+  :type '(choice integer (const nil)))
+
+
+(defcustom undo-tree-strong-limit 120000000
+  "Value of `undo-strong-limit' used in `undo-tree-mode'.
+
+If `undo-strong-limit' is larger than `undo-tree-strong-limit'
+the larger of the two values will be used."
+  :group 'undo-tree
+  :type 'integer)
+
+
+(defcustom undo-tree-outer-limit 360000000
+  "Value of `undo-outer-limit' used in `undo-tree-mode'.
+
+If `undo-outer-limit' is larger than `undo-tree-outer-limit' the
+larger of the two values will be used."
+  :group 'undo-tree
+  :type 'integer)
+
+
 (defcustom undo-tree-mode-lighter " Undo-Tree"
   "Lighter displayed in mode line
 when `undo-tree-mode' is enabled."
@@ -865,7 +927,7 @@ when `undo-tree-mode' is enabled."
   :type '(repeat symbol))
 
 
-(defcustom undo-tree-enable-undo-in-region t
+(defcustom undo-tree-enable-undo-in-region nil
   "When non-nil, enable undo-in-region.
 
 When undo-in-region is enabled, undoing or redoing when the
@@ -982,6 +1044,26 @@ enabled. However, this effect is quite rare in practice."
                 (integer :tag "> size")))
 
 
+(defvar undo-tree-pre-save-element-functions '()
+  "Special hook to modify undo-tree elements prior to saving.
+Each function on this hook is called in turn on each undo element
+in the tree by `undo-tree-save-history' prior to writing the undo
+history to file. It should return either nil, which removes that
+undo element from the saved history, or a replacement element to
+use instead (which should be identical to the original element if
+that element should be saved unchanged).")
+
+
+(defvar undo-tree-post-load-element-functions '()
+  "Special hook to modify undo-tree undo elements after loading.
+Each function on this hook is called in turn on each undo element
+in the tree by `undo-tree-load-history' after loading the undo
+history from file. It should return either nil, which removes that
+undo element from the loaded history, or a replacement element to
+use instead (which should be identical to the original element if
+that element should be loaded unchanged).")
+
+
 (defface undo-tree-visualizer-default-face
   '((((class color)) :foreground "gray"))
   "Face used to draw undo-tree in visualizer."
@@ -1065,8 +1147,9 @@ in visualizer."
 (defconst undo-tree-diff-buffer-name "*undo-tree Diff*")
 
 ;; install history-auto-save hooks
-(add-hook 'write-file-functions 'undo-tree-save-history-hook)
-(add-hook 'find-file-hook 'undo-tree-load-history-hook)
+(add-hook 'write-file-functions 'undo-tree-save-history-from-hook)
+(add-hook 'kill-buffer-hook 'undo-tree-save-history-from-hook)
+(add-hook 'find-file-hook 'undo-tree-load-history-from-hook)
 
 
 
@@ -1217,6 +1300,7 @@ in visualizer."
                             :enable (and undo-tree-mode
                                          (not buffer-read-only)
                                          (not (eq t buffer-undo-list))
+                                         (not (eq nil buffer-undo-tree))
                                          (undo-tree-node-previous
                                           (undo-tree-current 
buffer-undo-tree)))
                             :help "Undo last operation"))
@@ -1225,6 +1309,7 @@ in visualizer."
                             :enable (and undo-tree-mode
                                          (not buffer-read-only)
                                          (not (eq t buffer-undo-list))
+                                         (not (eq nil buffer-undo-tree))
                                          (undo-tree-node-next
                                           (undo-tree-current 
buffer-undo-tree)))
                             :help "Redo last operation")
@@ -1255,10 +1340,11 @@ in visualizer."
                   (size 0)
                  (count 0)
                  (object-pool (make-hash-table :test 'eq :weakness 'value))))
-   ;;(:copier nil)
-   )
+   (:copier nil))
   root current size count object-pool)
 
+(defun copy-undo-tree (tree)
+  (copy-tree tree 'copy-vectors))
 
 
 (defstruct
@@ -1661,30 +1747,29 @@ Comparison is done with `eq'."
   undo-list)
 
 
-(defun undo-list-pop-changeset (&optional discard-pos)
-  ;; Pop changeset from `buffer-undo-list'. If DISCARD-POS is non-nil, discard
-  ;; any position entries from changeset.
+(defun undo-list-found-canary-p (undo-list)
+  (or (eq (car undo-list) 'undo-tree-canary)
+      (and (null (car undo-list))
+          (eq (cadr undo-list) 'undo-tree-canary))))
 
-  ;; discard undo boundaries and (if DISCARD-POS is non-nil) position entries
-  ;; at head of undo list
-  (while (or (null (car buffer-undo-list))
-            (and discard-pos (integerp (car buffer-undo-list))))
-    (setq buffer-undo-list (cdr buffer-undo-list)))
-  ;; pop elements up to next undo boundary, discarding position entries if
-  ;; DISCARD-POS is non-nil
-  (if (eq (car buffer-undo-list) 'undo-tree-canary)
-      (push nil buffer-undo-list)
-    (let* ((changeset (list (pop buffer-undo-list)))
-           (p changeset))
-      (while (progn
-              (undo-tree-move-GC-elts-to-pool (car p))
-              (while (and discard-pos (integerp (car buffer-undo-list)))
-                (setq buffer-undo-list (cdr buffer-undo-list)))
-              (and (car buffer-undo-list)
-                   (not (eq (car buffer-undo-list) 'undo-tree-canary))))
-        (setcdr p (list (pop buffer-undo-list)))
-       (setq p (cdr p)))
-      changeset)))
+
+(defmacro undo-list-pop-changeset (undo-list &optional discard-pos)
+  ;; Pop changeset from `undo-list'. If DISCARD-POS is non-nil, discard
+  ;; any position entries from changeset.
+  `(when (and ,undo-list (not (undo-list-found-canary-p ,undo-list)))
+     (let (changeset)
+       ;; discard initial undo boundary(ies)
+       (while (null (car ,undo-list)) (setq ,undo-list (cdr ,undo-list)))
+       ;; pop elements up to next undo boundary, discarding position entries
+       ;; if DISCARD-POS is non-nil
+       (while (null changeset)
+        (while (and ,undo-list (car ,undo-list)
+                    (not (undo-list-found-canary-p ,undo-list)))
+          (if (and ,discard-pos (integerp (car ,undo-list)))
+              (setq ,undo-list (cdr ,undo-list))
+            (push (pop ,undo-list) changeset)
+            (undo-tree-move-GC-elts-to-pool (car changeset)))))
+       (nreverse changeset))))
 
 
 (defun undo-tree-copy-list (undo-list)
@@ -1709,9 +1794,14 @@ Comparison is done with `eq'."
       copy)))
 
 
+(defvar undo-tree-gc-flag nil)
+
+(defun undo-tree-post-gc ()
+  (setq undo-tree-gc-flag t))
+
 
 (defun undo-list-transfer-to-tree ()
-  ;; Transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'.
+  ;; Transfer entries accumulated in `undo-list' to `buffer-undo-tree'.
 
   ;; `undo-list-transfer-to-tree' should never be called when undo is disabled
   ;; (i.e. `buffer-undo-tree' is t)
@@ -1719,57 +1809,66 @@ Comparison is done with `eq'."
 
   ;; if `buffer-undo-tree' is empty, create initial undo-tree
   (when (null buffer-undo-tree) (setq buffer-undo-tree (make-undo-tree)))
-  ;; make sure there's a canary at end of `buffer-undo-list'
-  (when (null buffer-undo-list)
-    (setq buffer-undo-list '(nil undo-tree-canary)))
 
-  (unless (or (eq (cadr buffer-undo-list) 'undo-tree-canary)
-             (eq (car buffer-undo-list) 'undo-tree-canary))
-    ;; create new node from first changeset in `buffer-undo-list', save old
+  ;; garbage-collect then repeatedly try to deep-copy `buffer-undo-list' until
+  ;; we succeed without GC running, in an attempt to mitigate race conditions
+  ;; with garbage collector corrupting undo history (is this even a thing?!)
+  (unless (or (null buffer-undo-list)
+             (undo-list-found-canary-p buffer-undo-list))
+    (garbage-collect))
+  (let (undo-list changeset)
+    (setq undo-tree-gc-flag t)
+    (while undo-tree-gc-flag
+      (setq undo-tree-gc-flag nil
+           undo-list (copy-tree buffer-undo-list)))
+    (setq buffer-undo-list '(nil undo-tree-canary))
+
+    ;; create new node from first changeset in `undo-list', save old
     ;; `buffer-undo-tree' current node, and make new node the current node
-    (let* ((node (undo-tree-make-node nil (undo-list-pop-changeset)))
-          (splice (undo-tree-current buffer-undo-tree))
-          (size (undo-list-byte-size (undo-tree-node-undo node)))
-          (count 1))
-      (setf (undo-tree-current buffer-undo-tree) node)
-      ;; grow tree fragment backwards using `buffer-undo-list' changesets
-      (while (and buffer-undo-list
-                 (not (eq (cadr buffer-undo-list) 'undo-tree-canary)))
-       (setq node
-             (undo-tree-grow-backwards node (undo-list-pop-changeset)))
-       (incf size (undo-list-byte-size (undo-tree-node-undo node)))
-       (incf count))
-      ;; if no undo history has been discarded from `buffer-undo-list' since
-      ;; last transfer, splice new tree fragment onto end of old
-      ;; `buffer-undo-tree' current node
-      (if (or (eq (cadr buffer-undo-list) 'undo-tree-canary)
-             (eq (car buffer-undo-list) 'undo-tree-canary))
-         (progn
-           (setf (undo-tree-node-previous node) splice)
-           (push node (undo-tree-node-next splice))
-           (setf (undo-tree-node-branch splice) 0)
-           (incf (undo-tree-size buffer-undo-tree) size)
-           (incf (undo-tree-count buffer-undo-tree) count))
-       ;; if undo history has been discarded, replace entire
-       ;; `buffer-undo-tree' with new tree fragment
-       (setq node (undo-tree-grow-backwards node nil))
-       (setf (undo-tree-root buffer-undo-tree) node)
-       (setq buffer-undo-list '(nil undo-tree-canary))
-       (setf (undo-tree-size buffer-undo-tree) size)
-       (setf (undo-tree-count buffer-undo-tree) count)
-       (setq buffer-undo-list '(nil undo-tree-canary))))
-    ;; discard undo history if necessary
-    (undo-tree-discard-history)))
+    (when (setq changeset (undo-list-pop-changeset undo-list))
+      (let* ((node (undo-tree-make-node nil changeset))
+            (splice (undo-tree-current buffer-undo-tree))
+            (size (undo-list-byte-size (undo-tree-node-undo node)))
+            (count 1))
+       (setf (undo-tree-current buffer-undo-tree) node)
+       ;; grow tree fragment backwards using `undo-list' changesets
+       (while (setq changeset (undo-list-pop-changeset undo-list))
+         (setq node (undo-tree-grow-backwards node changeset))
+         (incf size (undo-list-byte-size (undo-tree-node-undo node)))
+         (incf count))
+
+       ;; if no undo history has been discarded from `undo-list' since last
+       ;; transfer, splice new tree fragment onto end of old
+       ;; `buffer-undo-tree' current node
+       (if (undo-list-found-canary-p undo-list)
+           (progn
+             (setf (undo-tree-node-previous node) splice)
+             (push node (undo-tree-node-next splice))
+             (setf (undo-tree-node-branch splice) 0)
+             (incf (undo-tree-size buffer-undo-tree) size)
+             (incf (undo-tree-count buffer-undo-tree) count))
+
+         ;; if undo history has been discarded, replace entire
+         ;; `buffer-undo-tree' with new tree fragment
+         (unless (= (undo-tree-size buffer-undo-tree) 0)
+           (message "Undo history discarded by Emacs (see `undo-limit') - 
rebuilding undo-tree"))
+         (setq node (undo-tree-grow-backwards node nil))
+         (setf (undo-tree-root buffer-undo-tree) node)
+         (setf (undo-tree-size buffer-undo-tree) size)
+         (setf (undo-tree-count buffer-undo-tree) count)
+         (setq undo-list '(nil undo-tree-canary))))))
+
+  ;; discard undo history if necessary
+  (undo-tree-discard-history))
 
 
 (defun undo-list-byte-size (undo-list)
   ;; Return size (in bytes) of UNDO-LIST
-  (let ((size 0) (p undo-list))
-    (while p
+  (let ((size 0))
+    (dolist (elt undo-list)
       (incf size 8)  ; cons cells use up 8 bytes
-      (when (and (consp (car p)) (stringp (caar p)))
-        (incf size (string-bytes (caar p))))
-      (setq p (cdr p)))
+      (when (stringp (car-safe elt))
+        (incf size (string-bytes (car elt)))))
     size))
 
 
@@ -1944,6 +2043,7 @@ set by `undo-limit', `undo-strong-limit' and 
`undo-outer-limit'."
                          ))
                      undo-limit))
         (setq node (undo-tree-discard-node node)))
+      (message "Undo history discarded by undo-tree (see `undo-tree-limit')")
 
       ;; if we're still over the `undo-outer-limit', discard entire history
       (when (> (undo-tree-size buffer-undo-tree) undo-outer-limit)
@@ -2023,7 +2123,7 @@ which is defined in the `warnings' library.\n")
        ((= (mod num-children 2) 1)
         (setq p (undo-tree-node-next node))
         ;; compute left-width
-        (dotimes (i (/ num-children 2))
+        (dotimes (_ (/ num-children 2))
           (if (undo-tree-node-lwidth (car p))
               (incf lwidth (+ (undo-tree-node-lwidth (car p))
                               (undo-tree-node-cwidth (car p))
@@ -2039,7 +2139,7 @@ which is defined in the `warnings' library.\n")
         ;; compute right-width
         (incf rwidth (undo-tree-node-rwidth (car p)))
         (setq p (cdr p))
-        (dotimes (i (/ num-children 2))
+        (dotimes (_ (/ num-children 2))
           (if (undo-tree-node-lwidth (car p))
               (incf rwidth (+ (undo-tree-node-lwidth (car p))
                               (undo-tree-node-cwidth (car p))
@@ -2051,7 +2151,7 @@ which is defined in the `warnings' library.\n")
        (t
         (setq p (undo-tree-node-next node))
         ;; compute left-width
-        (dotimes (i (/ num-children 2))
+        (dotimes (_ (/ num-children 2))
           (if (undo-tree-node-lwidth (car p))
               (incf lwidth (+ (undo-tree-node-lwidth (car p))
                               (undo-tree-node-cwidth (car p))
@@ -2061,7 +2161,7 @@ which is defined in the `warnings' library.\n")
         ;; centre-width is 0 when number of children is even
         (setq cwidth 0)
         ;; compute right-width
-        (dotimes (i (/ num-children 2))
+        (dotimes (_ (/ num-children 2))
           (if (undo-tree-node-lwidth (car p))
               (incf rwidth (+ (undo-tree-node-lwidth (car p))
                               (undo-tree-node-cwidth (car p))
@@ -2605,6 +2705,8 @@ of either NODE itself or some node above it in the tree."
 ;;; =====================================================================
 ;;;                        Undo-tree commands
 
+(defvar undo-tree-timer nil)
+
 ;;;###autoload
 (define-minor-mode undo-tree-mode
   "Toggle undo-tree mode.
@@ -2628,11 +2730,34 @@ Within the undo-tree visualizer, the following keys are 
available:
   undo-tree-mode-lighter    ; lighter
   undo-tree-map             ; keymap
 
-  ;; if disabling `undo-tree-mode', rebuild `buffer-undo-list' from tree so
-  ;; Emacs undo can work
-  (when (not undo-tree-mode)
+  (cond
+   (undo-tree-mode  ; enabling `undo-tree-mode'
+    (set (make-local-variable 'undo-limit)
+        (if undo-tree-limit
+            (max undo-limit undo-tree-limit)
+          most-positive-fixnum))
+    (set (make-local-variable 'undo-strong-limit)
+        (if undo-tree-limit
+            (max undo-strong-limit undo-tree-strong-limit)
+          most-positive-fixnum))
+    (set (make-local-variable 'undo-outer-limit)
+        (if undo-tree-limit
+            (max undo-outer-limit undo-tree-outer-limit)
+          most-positive-fixnum))
+    (when (null undo-tree-limit)
+      (setq undo-tree-timer
+           (run-with-idle-timer 5 'repeat #'undo-list-transfer-to-tree)))
+    (add-hook 'post-gc-hook #'undo-tree-post-gc nil))
+
+   (t  ; disabling `undo-tree-mode'
+    ;; rebuild `buffer-undo-list' from tree so Emacs undo can work
     (undo-list-rebuild-from-tree)
-    (setq buffer-undo-tree nil)))
+    (setq buffer-undo-tree nil)
+    (remove-hook 'post-gc-hook #'undo-tree-post-gc 'local)
+    (when (timerp undo-tree-timer) (cancel-timer undo-tree-timer))
+    (kill-local-variable 'undo-limit)
+    (kill-local-variable 'undo-strong-limit)
+    (kill-local-variable 'undo-outer-limit))))
 
 
 (defun turn-on-undo-tree-mode (&optional print-message)
@@ -2695,6 +2820,8 @@ within the current region. Similarly, when not in 
Transient Mark
 mode, just \\[universal-argument] as an argument limits undo to
 changes within the current region."
   (interactive "*P")
+  (unless undo-tree-mode
+    (user-error "Undo-tree mode not enabled in buffer"))
   ;; throw error if undo is disabled in buffer
   (when (eq buffer-undo-list t)
     (user-error "No undo information in this buffer"))
@@ -2721,7 +2848,7 @@ changes within the current region."
     ;; `buffer-undo-tree'
     (undo-list-transfer-to-tree)
 
-    (dotimes (i (or (and (numberp arg) (prefix-numeric-value arg)) 1))
+    (dotimes (_ (or (and (numberp arg) (prefix-numeric-value arg)) 1))
       ;; check if at top of undo tree
       (unless (undo-tree-node-previous (undo-tree-current buffer-undo-tree))
        (user-error "No further undo information"))
@@ -2753,7 +2880,7 @@ changes within the current region."
       ;; elements from node's redo list
       (if preserve-redo
          (progn
-           (undo-list-pop-changeset)
+           (undo-list-pop-changeset buffer-undo-list)
            (decf (undo-tree-size buffer-undo-tree)
                  (undo-list-byte-size (undo-tree-node-redo current)))
            (setf (undo-tree-node-redo current)
@@ -2766,7 +2893,7 @@ changes within the current region."
        (decf (undo-tree-size buffer-undo-tree)
              (undo-list-byte-size (undo-tree-node-redo current)))
        (setf (undo-tree-node-redo current)
-             (undo-list-pop-changeset 'discard-pos))
+             (undo-list-pop-changeset buffer-undo-list 'discard-pos))
        (incf (undo-tree-size buffer-undo-tree)
              (undo-list-byte-size (undo-tree-node-redo current))))
 
@@ -2802,6 +2929,8 @@ within the current region. Similarly, when not in 
Transient Mark
 mode, just \\[universal-argument] as an argument limits redo to
 changes within the current region."
   (interactive "*P")
+  (unless undo-tree-mode
+    (user-error "Undo-tree mode not enabled in buffer"))
   ;; throw error if undo is disabled in buffer
   (when (eq buffer-undo-list t)
     (user-error "No undo information in this buffer"))
@@ -2828,7 +2957,7 @@ changes within the current region."
     ;; `buffer-undo-tree'
     (undo-list-transfer-to-tree)
 
-    (dotimes (i (or (and (numberp arg) (prefix-numeric-value arg)) 1))
+    (dotimes (_ (or (and (numberp arg) (prefix-numeric-value arg)) 1))
       ;; check if at bottom of undo tree
       (when (null (undo-tree-node-next (undo-tree-current buffer-undo-tree)))
        (user-error "No further redo information"))
@@ -2866,7 +2995,7 @@ changes within the current region."
       ;; elements from node's redo list
       (if preserve-undo
          (progn
-           (undo-list-pop-changeset)
+           (undo-list-pop-changeset buffer-undo-list)
            (decf (undo-tree-size buffer-undo-tree)
                  (undo-list-byte-size (undo-tree-node-undo current)))
            (setf (undo-tree-node-undo current)
@@ -2879,7 +3008,7 @@ changes within the current region."
        (decf (undo-tree-size buffer-undo-tree)
              (undo-list-byte-size (undo-tree-node-undo current)))
        (setf (undo-tree-node-undo current)
-             (undo-list-pop-changeset 'discard-pos))
+             (undo-list-pop-changeset buffer-undo-list 'discard-pos))
        (incf (undo-tree-size buffer-undo-tree)
              (undo-list-byte-size (undo-tree-node-undo current))))
 
@@ -2908,7 +3037,7 @@ This will affect which branch to descend when *redoing* 
changes
 using `undo-tree-redo'."
   (interactive (list (or (and prefix-arg (prefix-numeric-value prefix-arg))
                          (and (not (eq buffer-undo-list t))
-                             (or (undo-list-transfer-to-tree) t)
+                             (undo-list-transfer-to-tree)
                              (let ((b (undo-tree-node-branch
                                        (undo-tree-current
                                         buffer-undo-tree))))
@@ -2921,6 +3050,8 @@ using `undo-tree-redo'."
                                   (format "Branch (0-%d, on %d): "
                                           (1- (undo-tree-num-branches)) b)))
                                 ))))))
+  (unless undo-tree-mode
+    (user-error "Undo-tree mode not enabled in buffer"))
   ;; throw error if undo is disabled in buffer
   (when (eq buffer-undo-list t)
     (user-error "No undo information in this buffer"))
@@ -2977,6 +3108,8 @@ The saved state can be restored using
 `undo-tree-restore-state-from-register'.
 Argument is a character, naming the register."
   (interactive "cUndo-tree state to register: ")
+  (unless undo-tree-mode
+    (user-error "Undo-tree mode not enabled in buffer"))
   ;; throw error if undo is disabled in buffer
   (when (eq buffer-undo-list t)
     (user-error "No undo information in this buffer"))
@@ -2999,6 +3132,8 @@ Argument is a character, naming the register."
 The state must be saved using `undo-tree-save-state-to-register'.
 Argument is a character, naming the register."
   (interactive "*cRestore undo-tree state from register: ")
+  (unless undo-tree-mode
+    (user-error "Undo-tree mode not enabled in buffer"))
   ;; throw error if undo is disabled in buffer, or if register doesn't contain
   ;; an undo-tree node
   (let ((data (registerv-data (get-register register))))
@@ -3044,13 +3179,16 @@ Otherwise, prompt for one.
 If OVERWRITE is non-nil, any existing file will be overwritten
 without asking for confirmation."
   (interactive)
+  (unless undo-tree-mode
+    (user-error "Undo-tree mode not enabled in buffer"))
   (when (eq buffer-undo-list t)
     (user-error "No undo information in this buffer"))
   (undo-list-transfer-to-tree)
   (when (and buffer-undo-tree (not (eq buffer-undo-tree t)))
-    (condition-case nil
-       (undo-tree-kill-visualizer)
-      (error (undo-tree-clear-visualizer-data buffer-undo-tree)))
+    (undo-tree-kill-visualizer)
+    ;; should be cleared already by killing the visualizer, but writes
+    ;; unreasable data if not for some reason, so just in case...
+    (undo-tree-clear-visualizer-data buffer-undo-tree)
     (let ((buff (current-buffer))
          tree)
       ;; get filename
@@ -3062,42 +3200,57 @@ without asking for confirmation."
       (when (or (not (file-exists-p filename))
                overwrite
                (yes-or-no-p (format "Overwrite \"%s\"? " filename)))
-       (unwind-protect
-           (progn
-             ;; transform undo-tree into non-circular structure, and make
-             ;; temporary copy
-             (undo-tree-decircle buffer-undo-tree)
-             (setq tree (copy-undo-tree buffer-undo-tree))
-             ;; discard undo-tree object pool before saving
-             (setf (undo-tree-object-pool tree) nil)
-             ;; print undo-tree to file
-             ;; NOTE: We use `with-temp-buffer' instead of `with-temp-file'
-             ;;       to allow `auto-compression-mode' to take effect, in
-             ;;       case user has overridden or advised the default
-             ;;       `undo-tree-make-history-save-file-name' to add a
-             ;;       compressed file extension.
-             (with-auto-compression-mode
-               (with-temp-buffer
-                 (prin1 (sha1 buff) (current-buffer))
-                 (terpri (current-buffer))
-                 (let ((print-circle t)) (prin1 tree (current-buffer)))
-                 (write-region nil nil filename))))
-         ;; restore circular undo-tree data structure
-         (undo-tree-recircle buffer-undo-tree))
-       ))))
+       ;; transform undo-tree into non-circular structure, and make tmp copy
+       (setq tree (copy-undo-tree buffer-undo-tree))
+       (undo-tree-decircle tree)
+       ;; discard undo-tree object pool before saving
+       (setf (undo-tree-object-pool tree) nil)
+       ;; run pre-save transformer functions
+       (when undo-tree-pre-save-element-functions
+         (undo-tree-mapc
+          (lambda (node)
+            (let ((changeset (undo-tree-node-undo node)))
+              (run-hook-wrapped
+               'undo-tree-pre-save-element-functions
+               (lambda (fun)
+                 (setq changeset (delq nil (mapcar fun changeset)))))
+               (setf (undo-tree-node-undo node) changeset))
+            (let ((changeset (undo-tree-node-redo node)))
+              (run-hook-wrapped
+               'undo-tree-pre-save-element-functions
+               (lambda (fun)
+                 (setq changeset (delq nil (mapcar fun changeset)))))
+              (setf (undo-tree-node-redo node) changeset)))
+          (undo-tree-root tree)))
+       ;; print undo-tree to file
+       ;; NOTE: We use `with-temp-buffer' instead of `with-temp-file' to
+       ;;       allow `auto-compression-mode' to take effect, in case user
+       ;;       has overridden or advised the default
+       ;;       `undo-tree-make-history-save-file-name' to add a compressed
+       ;;       file extension.
+       (with-auto-compression-mode
+         (with-temp-buffer
+           (prin1 (sha1 buff) (current-buffer))
+           (terpri (current-buffer))
+           (let ((print-circle t)) (prin1 tree (current-buffer)))
+           (write-region nil nil filename)))))))
 
 
 
 (defun undo-tree-load-history (&optional filename noerror)
-  "Load undo-tree history from file.
+  "Load undo-tree history from file, for the current buffer.
 
 If optional argument FILENAME is null, default load file is
 \".<buffer-file-name>.~undo-tree\" if buffer is visiting a file.
 Otherwise, prompt for one.
 
 If optional argument NOERROR is non-nil, return nil instead of
-signaling an error if file is not found."
+signaling an error if file is not found.
+
+Note this will overwrite any existing undo history."
   (interactive)
+  (unless undo-tree-mode
+    (user-error "Undo-tree mode not enabled in buffer"))
   ;; get filename
   (unless filename
     (setq filename
@@ -3122,7 +3275,7 @@ signaling an error if file is not found."
              (setq hash (read (current-buffer)))
            (error
             (kill-buffer nil)
-            (funcall (if noerror 'message 'user-error)
+            (funcall (if noerror #'message #'user-error)
                      "Error reading undo-tree history from \"%s\"" filename)
             (throw 'load-error nil)))
          (unless (string= (sha1 buff) hash)
@@ -3134,30 +3287,62 @@ signaling an error if file is not found."
              (setq tree (read (current-buffer)))
            (error
             (kill-buffer nil)
-            (funcall (if noerror 'message 'error)
+            (funcall (if noerror #'message #'error)
                      "Error reading undo-tree history from \"%s\"" filename)
             (throw 'load-error nil)))
          (kill-buffer nil)))
-      ;; initialise empty undo-tree object pool
+       ;; run post-load transformer functions
+       (when undo-tree-post-load-element-functions
+         (undo-tree-mapc
+          (lambda (node)
+            (let ((changeset (undo-tree-node-undo node)))
+              (run-hook-wrapped
+               'undo-tree-post-load-element-functions
+               (lambda (fun)
+                 (setq changeset (delq nil (mapcar fun changeset)))))
+               (setf (undo-tree-node-undo node) changeset))
+            (let ((changeset (undo-tree-node-redo node)))
+              (run-hook-wrapped
+               'undo-tree-post-load-element-functions
+               (lambda (fun)
+                 (setq changeset (delq nil (mapcar fun changeset)))))
+              (setf (undo-tree-node-redo node) changeset)))
+          (undo-tree-root tree)))      ;; initialise empty undo-tree object 
pool
       (setf (undo-tree-object-pool tree)
            (make-hash-table :test 'eq :weakness 'value))
       ;; restore circular undo-tree data structure
       (undo-tree-recircle tree)
-      (setq buffer-undo-tree tree))))
+      ;; create undo-tree object pool
+      (setf (undo-tree-object-pool tree)
+           (make-hash-table :test 'eq :weakness 'value))
+      (setq buffer-undo-tree tree
+           buffer-undo-list '(nil undo-tree-canary)))))
 
 
 
 ;; Versions of save/load functions for use in hooks
-(defun undo-tree-save-history-hook ()
+(defun undo-tree-save-history-from-hook ()
   (when (and undo-tree-mode undo-tree-auto-save-history
-            (not (eq buffer-undo-list t)))
-    (undo-tree-save-history nil t) nil))
+            (not (eq buffer-undo-list t))
+            buffer-file-name)
+    (undo-tree-save-history nil 'overwrite) nil))
 
-(defun undo-tree-load-history-hook ()
+(define-obsolete-function-alias
+  'undo-tree-save-history-hook 'undo-tree-save-history-from-hook
+  "`undo-tree-save-history-hook' is obsolete since undo-tree
+ version 0.6.6. Use `undo-tree-save-history-from-hook' instead.")
+
+
+(defun undo-tree-load-history-from-hook ()
   (when (and undo-tree-mode undo-tree-auto-save-history
             (not (eq buffer-undo-list t))
             (not revert-buffer-in-progress-p))
-    (undo-tree-load-history nil t)))
+    (undo-tree-load-history nil 'noerror)))
+
+(define-obsolete-function-alias
+  'undo-tree-load-history-hook 'undo-tree-load-history-from-hook
+  "`undo-tree-load-history-hook' is obsolete since undo-tree
+ version 0.6.6. Use `undo-tree-load-history-from-hook' instead.")
 
 
 
@@ -3168,6 +3353,8 @@ signaling an error if file is not found."
 (defun undo-tree-visualize ()
   "Visualize the current buffer's undo tree."
   (interactive "*")
+  (unless undo-tree-mode
+    (user-error "Undo-tree mode not enabled in buffer"))
   (deactivate-mark)
   ;; throw error if undo is disabled in buffer
   (when (eq buffer-undo-list t)
@@ -3535,7 +3722,7 @@ signaling an error if file is not found."
            (car (undo-tree-node-next node)))))
       (move-marker (setq pos (make-marker)) (point))
       (setq n (cons nil (undo-tree-node-next node)))
-      (dotimes (i (/ num-children 2))
+      (dotimes (_ (/ num-children 2))
         (setq n (cdr n))
         (when (or (null active-branch)
                   (eq (car n)
@@ -3588,7 +3775,7 @@ signaling an error if file is not found."
         (move-marker pos (point)))
       ;; right subtrees
       (move-marker trunk-pos (1+ trunk-pos))
-      (dotimes (i (/ num-children 2))
+      (dotimes (_ (/ num-children 2))
         (setq n (cdr n))
         (when (or (null active-branch)
                   (eq (car n)
@@ -3643,7 +3830,7 @@ signaling an error if file is not found."
   (when (characterp str)
     (setq str (make-string arg str))
     (setq arg 1))
-  (dotimes (i arg) (insert str))
+  (dotimes (_ arg) (insert str))
   (setq arg (* arg (length str)))
   (undo-tree-move-forward arg)
   ;; make sure mark isn't active, otherwise `backward-delete-char' might
@@ -3728,7 +3915,7 @@ signaling an error if file is not found."
        (undo-tree-move-forward
         (+ (undo-tree-node-char-rwidth (car n))
            (/ undo-tree-visualizer-spacing 2) 1))
-       (dotimes (i (- (/ l 2) p 1))
+       (dotimes (_ (- (/ l 2) p 1))
          (setq n (cdr n))
          (undo-tree-move-forward
           (+ (undo-tree-node-char-lwidth (car n))
@@ -3746,7 +3933,7 @@ signaling an error if file is not found."
           (+ (undo-tree-node-char-rwidth (car n))
              (/ undo-tree-visualizer-spacing 2) 1))
          (setq n (cdr n)))
-       (dotimes (i (- p (/ l 2) (mod l 2)))
+       (dotimes (_ (- p (/ l 2) (mod l 2)))
          (undo-tree-move-backward
           (+ (undo-tree-node-char-lwidth (car n))
              (undo-tree-node-char-rwidth (car n))
@@ -3766,7 +3953,7 @@ signaling an error if file is not found."
   (if relative
       ;; relative time
       (let ((time (floor (float-time
-                         (subtract-time (current-time) timestamp))))
+                         (time-subtract (current-time) timestamp))))
            n)
        (setq time
              ;; years
@@ -3832,6 +4019,8 @@ Within the undo-tree visualizer, the following keys are 
available:
 (defun undo-tree-visualize-undo (&optional arg)
   "Undo changes. A numeric ARG serves as a repeat count."
   (interactive "p")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (let ((old (undo-tree-current buffer-undo-tree))
        current)
     ;; unhighlight old current node
@@ -3857,6 +4046,8 @@ Within the undo-tree visualizer, the following keys are 
available:
 (defun undo-tree-visualize-redo (&optional arg)
   "Redo changes. A numeric ARG serves as a repeat count."
   (interactive "p")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (let ((old (undo-tree-current buffer-undo-tree))
        current)
     ;; unhighlight old current node
@@ -3884,6 +4075,8 @@ Within the undo-tree visualizer, the following keys are 
available:
 This will affect which branch to descend when *redoing* changes
 using `undo-tree-redo' or `undo-tree-visualizer-redo'."
   (interactive "p")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   ;; un-highlight old active branch below current node
   (goto-char (undo-tree-node-marker (undo-tree-current buffer-undo-tree)))
   (let ((undo-tree-insert-face 'undo-tree-visualizer-default-face)
@@ -3917,6 +4110,8 @@ using `undo-tree-redo' or `undo-tree-visualizer-redo'."
 (defun undo-tree-visualizer-quit ()
   "Quit the undo-tree visualizer."
   (interactive)
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (undo-tree-clear-visualizer-data buffer-undo-tree)
   ;; remove kill visualizer hook from parent buffer
   (unwind-protect
@@ -3938,6 +4133,8 @@ using `undo-tree-redo' or `undo-tree-visualizer-redo'."
 (defun undo-tree-visualizer-abort ()
   "Quit the undo-tree visualizer and return buffer to original state."
   (interactive)
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (let ((node undo-tree-visualizer-initial-node))
     (undo-tree-visualizer-quit)
     (undo-tree-set node)))
@@ -3947,6 +4144,8 @@ using `undo-tree-redo' or `undo-tree-visualizer-redo'."
   "Set buffer to state corresponding to undo tree node
 at POS, or point if POS is nil."
   (interactive)
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (unless pos (setq pos (point)))
   (let ((node (get-text-property pos 'undo-tree-node)))
     (when node
@@ -3963,13 +4162,15 @@ at POS, or point if POS is nil."
   "Set buffer to state corresponding to undo tree node
 at mouse event POS."
   (interactive "@e")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (undo-tree-visualizer-set (event-start (nth 1 pos))))
 
 
 (defun undo-tree-visualize-undo-to-x (&optional x)
   "Undo to last branch point, register, or saved state.
 If X is the symbol `branch', undo to last branch point. If X is
-the symbol `register', undo to last register. If X is the sumbol
+the symbol `register', undo to last register. If X is the symbol
 `saved', undo to last saved state. If X is null, undo to first of
 these that's encountered.
 
@@ -3978,6 +4179,8 @@ Interactively, a single \\[universal-argument] specifies
 specifies `saved', and a negative prefix argument specifies
 `register'."
   (interactive "P")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (when (and (called-interactively-p 'any) x)
     (setq x (prefix-numeric-value x)
          x (cond
@@ -4030,6 +4233,8 @@ Interactively, a single \\[universal-argument] specifies
 specifies `saved', and a negative prefix argument specifies
 `register'."
   (interactive "P")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (when (and (called-interactively-p 'any) x)
     (setq x (prefix-numeric-value x)
          x (cond
@@ -4073,6 +4278,8 @@ specifies `saved', and a negative prefix argument 
specifies
 (defun undo-tree-visualizer-toggle-timestamps ()
   "Toggle display of time-stamps."
   (interactive)
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (setq undo-tree-visualizer-timestamps (not undo-tree-visualizer-timestamps))
   (setq undo-tree-visualizer-spacing (undo-tree-visualizer-calculate-spacing))
   ;; redraw tree
@@ -4081,16 +4288,22 @@ specifies `saved', and a negative prefix argument 
specifies
 
 (defun undo-tree-visualizer-scroll-left (&optional arg)
   (interactive "p")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (scroll-left (or arg 1) t))
 
 
 (defun undo-tree-visualizer-scroll-right (&optional arg)
   (interactive "p")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (scroll-right (or arg 1) t))
 
 
 (defun undo-tree-visualizer-scroll-up (&optional arg)
   (interactive "P")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (if (or (and (numberp arg) (< arg 0)) (eq arg '-))
       (undo-tree-visualizer-scroll-down arg)
     ;; scroll up and expand newly-visible portion of tree
@@ -4106,6 +4319,8 @@ specifies `saved', and a negative prefix argument 
specifies
 
 (defun undo-tree-visualizer-scroll-down (&optional arg)
   (interactive "P")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (if (or (and (numberp arg) (< arg 0)) (eq arg '-))
       (undo-tree-visualizer-scroll-up arg)
     ;; ensure there's enough room at top of buffer to scroll
@@ -4159,9 +4374,11 @@ specifies `saved', and a negative prefix argument 
specifies
 (defun undo-tree-visualizer-select-previous (&optional arg)
   "Move to previous node."
   (interactive "p")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (let ((node undo-tree-visualizer-selected-node))
     (catch 'top
-      (dotimes (i (or arg 1))
+      (dotimes (_ (or arg 1))
        (unless (undo-tree-node-previous node) (throw 'top t))
        (setq node (undo-tree-node-previous node))))
     ;; when using lazy drawing, extend tree upwards as required
@@ -4179,9 +4396,11 @@ specifies `saved', and a negative prefix argument 
specifies
 (defun undo-tree-visualizer-select-next (&optional arg)
   "Move to next node."
   (interactive "p")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (let ((node undo-tree-visualizer-selected-node))
     (catch 'bottom
-      (dotimes (i (or arg 1))
+      (dotimes (_ (or arg 1))
        (unless (nth (undo-tree-node-branch node) (undo-tree-node-next node))
          (throw 'bottom t))
        (setq node
@@ -4201,12 +4420,14 @@ specifies `saved', and a negative prefix argument 
specifies
 (defun undo-tree-visualizer-select-right (&optional arg)
   "Move right to a sibling node."
   (interactive "p")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (let ((node undo-tree-visualizer-selected-node)
        end)
     (goto-char (undo-tree-node-marker undo-tree-visualizer-selected-node))
     (setq end (line-end-position))
     (catch 'end
-      (dotimes (i arg)
+      (dotimes (_ arg)
        (while (or (null node) (eq node undo-tree-visualizer-selected-node))
          (forward-char)
          (setq node (get-text-property (point) 'undo-tree-node))
@@ -4222,12 +4443,14 @@ specifies `saved', and a negative prefix argument 
specifies
 (defun undo-tree-visualizer-select-left (&optional arg)
   "Move left to a sibling node."
   (interactive "p")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (let ((node (get-text-property (point) 'undo-tree-node))
        beg)
     (goto-char (undo-tree-node-marker undo-tree-visualizer-selected-node))
     (setq beg (line-beginning-position))
     (catch 'beg
-      (dotimes (i arg)
+      (dotimes (_ arg)
        (while (or (null node) (eq node undo-tree-visualizer-selected-node))
          (backward-char)
          (setq node (get-text-property (point) 'undo-tree-node))
@@ -4261,6 +4484,8 @@ specifies `saved', and a negative prefix argument 
specifies
 (defun undo-tree-visualizer-mouse-select (pos)
   "Select undo tree node at mouse event POS."
   (interactive "@e")
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (undo-tree-visualizer-select (event-start (nth 1 pos))))
 
 
@@ -4272,6 +4497,8 @@ specifies `saved', and a negative prefix argument 
specifies
 (defun undo-tree-visualizer-toggle-diff ()
   "Toggle diff display in undo-tree visualizer."
   (interactive)
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (if undo-tree-visualizer-diff
       (undo-tree-visualizer-hide-diff)
     (undo-tree-visualizer-show-diff)))
@@ -4280,6 +4507,8 @@ specifies `saved', and a negative prefix argument 
specifies
 (defun undo-tree-visualizer-selection-toggle-diff ()
   "Toggle diff display in undo-tree visualizer selection mode."
   (interactive)
+  (unless (eq major-mode 'undo-tree-visualizer-mode)
+    (user-error "Undo-tree mode not enabled in buffer"))
   (if undo-tree-visualizer-diff
       (undo-tree-visualizer-hide-diff)
     (let ((node (get-text-property (point) 'undo-tree-node)))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]