[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals/undo-tree c638cbd 051/195: General code tidying and reo
From: |
Stefan Monnier |
Subject: |
[elpa] externals/undo-tree c638cbd 051/195: General code tidying and reorganisation. |
Date: |
Sat, 28 Nov 2020 13:41:19 -0500 (EST) |
branch: externals/undo-tree
commit c638cbd3f5d18520f9644080209e8a531c2d2cdc
Author: Toby S. Cubitt <toby-undo-tree@dr-qubit.org>
Commit: Toby S. Cubitt <toby-undo-tree@dr-qubit.org>
General code tidying and reorganisation.
---
undo-tree.el | 477 +++++++++++++++++++++++++++++++----------------------------
1 file changed, 249 insertions(+), 228 deletions(-)
diff --git a/undo-tree.el b/undo-tree.el
index 4cbe560..9d0f5b1 100644
--- a/undo-tree.el
+++ b/undo-tree.el
@@ -196,9 +196,9 @@
;; x (second undo)
;;
;;
-;; Actually, since the buffer returns to a previous state after an undo, a
-;; better way to visualize it is to imagine the string of changes turning back
-;; on itself:
+;; Actually, since the buffer returns to a previous state after an undo,
+;; perhaps a better way to visualize it is to imagine the string of changes
+;; turning back on itself:
;;
;; (initial buffer state) o
;; |
@@ -251,7 +251,7 @@
;;
;; Now, what if you change your mind about those undos, and decide you did
;; like those other changes you'd made after all? With the standard undo/redo
-;; system, you're stuck. There's no way to recover them, because that branch
+;; system, you're lost. There's no way to recover them, because that branch
;; was discarded when you made the new edit.
;;
;; However, in Emacs' undo system, those old buffer states are still there in
@@ -298,11 +298,12 @@
;; |/
;; o
;;
-;; But if you're unlucky, you happen to have moved the point (say) after
-;; getting to the point labelled "got this far". In that case, you've "broken
-;; the undo chain". If you try to undo now, Emacs thinks you're trying to undo
-;; the undos! So to get back to the initial state you now have to rewind
-;; through *all* the changes, including the undos you just did:
+;; But if you're unlucky, and you happen to have moved the point (say) after
+;; getting to the point labelled "got this far", then you've "broken the undo
+;; chain". Hold on to something solid, because things are about to get
+;; hairy. If you try to undo now, Emacs thinks you're trying to undo the
+;; undos! So to get back to the initial state you now have to rewind through
+;; *all* the changes, including the undos you just did:
;;
;; (trying to get o x (finally got there!)
;; to this state) | |
@@ -325,11 +326,12 @@
;;
;; In practice you can just hold down the undo key until you reach the buffer
;; state that you want. But whatever you do, don't move around in the buffer
-;; to check you've got back to where you want! Because you'll break the undo
-;; chain, and then you'll have to traverse the entire string of undos again to
-;; get back to the point at which you broke the chain. Undo in region and
-;; commands such as `undo-only' help to make using Emacs' undo a little
-;; easier, but nonetheless it remains confusing for many people.
+;; to *check* that you've got back to where you want! Because you'll break the
+;; undo chain, and then you'll have to traverse the entire string of undos
+;; again, just to get back to the point at which you broke the
+;; chain. Undo-in-region and commands such as `undo-only' help to make using
+;; Emacs' undo a little easier, but nonetheless it remains confusing for many
+;; people.
;;
;;
;; So what does `undo-tree-mode' do? Remember the diagram we drew to represent
@@ -401,9 +403,9 @@
;; |
;; (redo) x
;;
-;; Now you're on the other branch, and if you undo and redo changes you'll
-;; stay on that branch, moving up and down through the buffer states located
-;; on that branch. Until you decide to switch branches again, of course.
+;; Now you're on the other branch, if you undo and redo changes you'll stay on
+;; that branch, moving up and down through the buffer states located on that
+;; branch. Until you decide to switch branches again, of course.
;;
;; Real undo trees might have multiple branches and sub-branches:
;;
@@ -422,8 +424,8 @@
;; will likely frazzle your brain circuits! But in `undo-tree-mode', you're
;; just moving around this undo history tree. Most of the time, you'll
;; probably only need to stay on the most recent branch, in which case it
-;; behaves like standard undo/redo, so is just as simple to understand. But if
-;; you ever need to recover a buffer state on a different branch, the
+;; behaves like standard undo/redo, and is just as simple to understand. But
+;; if you ever need to recover a buffer state on a different branch, the
;; possibility of switching between branches and accessing the full undo
;; history is still there.
;;
@@ -436,20 +438,20 @@
;; diagrams, because `undo-tree-mode' includes an undo-tree visualizer which
;; draws them for you! In fact, it draws even better diagrams: it highlights
;; the node representing the current buffer state, it highlights the current
-;; branch, and you can toggle the display of time-stamps for each buffer
-;; state. (There's one other tiny difference: the visualizer puts the most
-;; recent branch on the left rather than the right.)
+;; branch, and (by hitting "t") you can toggle the display of
+;; time-stamps. (There's one other tiny difference: the visualizer puts the
+;; most recent branch on the left rather than the right.)
;;
;; In the visualizer, the usual keys for moving up and down a buffer instead
;; move up and down the undo history tree (e.g. the up and down arrow keys, or
;; "C-n" and "C-p"). The state of the "parent" buffer (the buffer whose undo
;; history you are visualizing) is updated as you move around the undo tree in
;; the visualizer. If you reach a branch point in the visualizer, the usual
-;; keys for moving forward and backward in a buffer instead switch which
-;; branch to follow (e.g. the left and right arrow keys, or "C-f" and "C-b").
-;; Clicking with the mouse on any node in the visualizer will take you
-;; directly to that node, resetting the state of the parent buffer to the
-;; state represented by that node.
+;; keys for moving forward and backward in a buffer instead switch branch
+;; (e.g. the left and right arrow keys, or "C-f" and "C-b"). And clicking with
+;; the mouse on any node in the visualizer will take you directly to that
+;; node, resetting the state of the parent buffer to the state represented by
+;; that node.
;;
;; It can be useful to see how long ago the parent buffer was in the state
;; represented by a particular node in the visualizer. Hitting "t" in the
@@ -459,7 +461,7 @@
;; since you last undid any changes.)
;;
;; Finally, hitting "q" will quit the visualizer, leaving the parent buffer in
-;; whatever state you were last on.
+;; whatever state you ended at.
;;
;;
;;
@@ -499,6 +501,7 @@
;; visualizer's parent buffer, or switch to the parent buffer if no window
;; is displaying it
;; * fixed bug in `undo-tree-switch-branch'
+;; * general code tidying and reorganisation
;;
;; Version 0.1.6
;; * added `undo-tree-mode-lighter' customization option to allow the
@@ -506,14 +509,14 @@
;; * bug-fix in `undo-tree-discard-node'
;; * added `undo-tree-save-state-to-register' and
;; `undo-tree-restore-state-from-register' commands and keybindings for
-;; saving/restoring buffer states using registers
+;; saving/restoring undo-tree states using registers
;;
;; Version 0.1.5
;; * modified `undo-tree-visualize' to mark the visualizer window as
-;; soft-dedicated and changed `undo-tree-visualizer-quit' to use
-;; `kill-buffer', so that visualizer window is deleted along with buffer if
-;; visualizer buffer was displayed in a new window, but not if it was
-;; displayed in an existing window.
+;; soft-dedicated, and changed `undo-tree-visualizer-quit' to use
+;; `kill-buffer', so that the visualizer window is deleted along with its
+;; buffer if the visualizer buffer was displayed in a new window, but not if
+;; it was displayed in an existing window.
;;
;; Version 0.1.4
;; * modified `undo-tree-undo' and `undo-tree-redo' to always replace
@@ -840,103 +843,9 @@ part of `buffer-undo-tree'."
new))
-(defun undo-tree-compute-widths (undo-tree)
- "Recursively compute widths for all UNDO-TREE's nodes."
- (let ((stack (list (undo-tree-root undo-tree)))
- res)
- (while stack
- ;; try to compute widths for node at top of stack
- (if (undo-tree-node-p
- (setq res (undo-tree-node-compute-widths (car stack))))
- ;; if computation fails, it returns a node whose widths still need
- ;; computing, which we push onto the stack
- (push res stack)
- ;; otherwise, store widths and remove it from stack
- (setf (undo-tree-node-lwidth (car stack)) (aref res 0)
- (undo-tree-node-cwidth (car stack)) (aref res 1)
- (undo-tree-node-rwidth (car stack)) (aref res 2))
- (pop stack)))))
-
-
-(defun undo-tree-node-compute-widths (node)
- ;; Compute NODE's left-, centre-, and right-subtree widths. Returns widths
- ;; (in a vector) if successful. Otherwise, returns a node whose widths need
- ;; calculating before NODE's can be calculated.
- (let ((num-children (length (undo-tree-node-next node)))
- (lwidth 0) (cwidth 0) (rwidth 0)
- p w)
- (catch 'need-widths
- (cond
- ;; leaf nodes have 0 width
- ((= 0 num-children)
- (setf cwidth 1
- (undo-tree-node-lwidth node) 0
- (undo-tree-node-cwidth node) 1
- (undo-tree-node-rwidth node) 0))
-
- ;; odd number of children
- ((= (mod num-children 2) 1)
- (setq p (undo-tree-node-next node))
- ;; compute left-width
- (dotimes (i (/ num-children 2))
- (if (undo-tree-node-lwidth (car p))
- (incf lwidth (+ (undo-tree-node-lwidth (car p))
- (undo-tree-node-cwidth (car p))
- (undo-tree-node-rwidth (car p))))
- ;; if child's widths haven't been computed, return that child
- (throw 'need-widths (car p)))
- (setq p (cdr p)))
- (if (undo-tree-node-lwidth (car p))
- (incf lwidth (undo-tree-node-lwidth (car p)))
- (throw 'need-widths (car p)))
- ;; centre-width is inherited from middle child
- (setf cwidth (undo-tree-node-cwidth (car p)))
- ;; compute right-width
- (incf rwidth (undo-tree-node-rwidth (car p)))
- (setq p (cdr p))
- (dotimes (i (/ num-children 2))
- (if (undo-tree-node-lwidth (car p))
- (incf rwidth (+ (undo-tree-node-lwidth (car p))
- (undo-tree-node-cwidth (car p))
- (undo-tree-node-rwidth (car p))))
- (throw 'need-widths (car p)))
- (setq p (cdr p))))
-
- ;; even number of children
- (t
- (setq p (undo-tree-node-next node))
- ;; compute left-width
- (dotimes (i (/ num-children 2))
- (if (undo-tree-node-lwidth (car p))
- (incf lwidth (+ (undo-tree-node-lwidth (car p))
- (undo-tree-node-cwidth (car p))
- (undo-tree-node-rwidth (car p))))
- (throw 'need-widths (car p)))
- (setq p (cdr p)))
- ;; centre-width is 0 when number of children is even
- (setq cwidth 0)
- ;; compute right-width
- (dotimes (i (/ num-children 2))
- (if (undo-tree-node-lwidth (car p))
- (incf rwidth (+ (undo-tree-node-lwidth (car p))
- (undo-tree-node-cwidth (car p))
- (undo-tree-node-rwidth (car p))))
- (throw 'need-widths (car p)))
- (setq p (cdr p)))))
-
- ;; return left-, centre- and right-widths
- (vector lwidth cwidth rwidth))))
-
-
-(defun undo-tree-clear-visualizer-data (undo-tree)
- ;; Clear visualizer data from UNDO-TREE.
- (let ((stack (list (undo-tree-root undo-tree)))
- node)
- (while stack
- (setq node (pop stack))
- (setf (undo-tree-node-visualizer node) nil)
- (dolist (n (undo-tree-node-next node))
- (push n stack)))))
+(defmacro undo-tree-num-branches ()
+ "Return number of branches at current undo tree node."
+ '(length (undo-tree-node-next (undo-tree-current buffer-undo-tree))))
(defun undo-tree-position (node list)
@@ -952,10 +861,102 @@ Comparison is done with 'eq."
nil)))
-(defmacro undo-tree-num-branches ()
- ;; Return number of branches at current undo tree node.
- '(length (undo-tree-node-next (undo-tree-current buffer-undo-tree))))
+(defvar *undo-tree-id-counter* 0)
+(defmacro undo-tree-generate-id ()
+ ;; Generate a new, unique id (uninterned symbol).
+ ;; The name is made by appending a number to "undo-tree-id".
+ ;; (Copied from CL package `gensym'.)
+ `(let ((num (prog1 *undo-tree-id-counter* (incf *undo-tree-id-counter*))))
+ (make-symbol (format "undo-tree-id%d" num))))
+
+
+
+
+;;; =====================================================================
+;;; Utility functions for handling `buffer-undo-list'
+
+(defun undo-list-pop-changeset ()
+ ;; Pop changeset from `buffer-undo-list'.
+ ;; discard undo boundaries and marker adjustment entries at head of list
+ (while (or (null (car buffer-undo-list))
+ (and (consp (car buffer-undo-list))
+ (markerp (caar buffer-undo-list))))
+ (setq buffer-undo-list (cdr buffer-undo-list)))
+ ;; pop elements up to next undo boundary
+ (unless (eq (car buffer-undo-list) 'undo-tree-canary)
+ (let* ((changeset (cons (pop buffer-undo-list) nil))
+ (p changeset))
+ (while (car buffer-undo-list)
+ (setcdr p (cons (pop buffer-undo-list) nil))
+ ;; discard marker adjustment entries (see Commentary, above)
+ (if (and (consp (cadr p)) (markerp (car (cadr p))))
+ (setcdr p nil)
+ (setq p (cdr p))))
+ changeset)))
+
+
+
+(defun undo-list-transfer-to-tree ()
+ ;; Transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'.
+ ;; if `buffer-undo-tree' is empty, create initial undo-tree and make sure
+ ;; there's a canary at end of `buffer-undo-list'
+ (when (null buffer-undo-tree)
+ (setq buffer-undo-tree (make-undo-tree))
+ (let ((elt (last buffer-undo-list)))
+ (unless (eq (car elt) 'undo-tree-canary)
+ (setcdr elt '(nil undo-tree-canary)))))
+
+ ;; if `buffer-undo-list' is empty, add a canary
+ (if (null buffer-undo-list)
+ (setq buffer-undo-list '(nil undo-tree-canary))
+ (unless (eq (cadr buffer-undo-list) 'undo-tree-canary)
+ ;; create new node from first changeset in `buffer-undo-list', save old
+ ;; `buffer-undo-tree' current node, and make new node the current node
+ (let* ((node (make-undo-tree-node nil (undo-list-pop-changeset)))
+ (splice (undo-tree-current buffer-undo-tree))
+ (size (undo-list-byte-size (undo-tree-node-undo node))))
+ (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))))
+ ;; 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 (eq (cadr 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))
+ ;; 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)))
+ ;; 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
+ (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)))
+ size))
+
+
+
+
+;;; =====================================================================
+;;; History discarding functions
(defun undo-tree-oldest-leaf (node)
;; Return oldest leaf node below NODE.
@@ -974,9 +975,6 @@ Comparison is done with 'eq."
;; don't discard current node
(unless (eq node (undo-tree-current buffer-undo-tree))
- (decf (undo-tree-size buffer-undo-tree)
- (+ (undo-list-byte-size (undo-tree-node-undo node))
- (undo-list-byte-size (undo-tree-node-redo node))))
;; discarding root node...
(if (eq node (undo-tree-root buffer-undo-tree))
@@ -989,7 +987,12 @@ Comparison is done with 'eq."
((eq (car (undo-tree-node-next node))
(undo-tree-current buffer-undo-tree))
nil)
+ ;; discard root
(t
+ ;; update undo-tree size
+ (decf (undo-tree-size buffer-undo-tree)
+ (+ (undo-list-byte-size (undo-tree-node-undo node))
+ (undo-list-byte-size (undo-tree-node-redo node))))
;; make child of root into new root
(setf node (setf (undo-tree-root buffer-undo-tree)
(car (undo-tree-node-next node)))
@@ -1007,12 +1010,16 @@ Comparison is done with 'eq."
(let* ((parent (undo-tree-node-previous node))
(current (nth (undo-tree-node-branch parent)
(undo-tree-node-next parent))))
+ ;; update undo-tree size
+ (decf (undo-tree-size buffer-undo-tree)
+ (+ (undo-list-byte-size (undo-tree-node-undo node))
+ (undo-list-byte-size (undo-tree-node-redo node))))
(setf (undo-tree-node-next parent)
- (delq node (undo-tree-node-next parent))
+ (delq node (undo-tree-node-next parent))
(undo-tree-node-branch parent)
- (undo-tree-position current (undo-tree-node-next parent)))
+ (undo-tree-position current (undo-tree-node-next parent)))
;; if parent has branches, or parent is current node, next node to
- ;; discard is oldest lead, otherwise it's parent
+ ;; discard is oldest leaf, otherwise it's parent
(if (or (eq parent (undo-tree-current buffer-undo-tree))
(and (undo-tree-node-next parent)
(or (not (eq parent (undo-tree-root buffer-undo-tree)))
@@ -1050,7 +1057,7 @@ set by `undo-limit', `undo-strong-limit' and
`undo-outer-limit'."
;; if we're still over the `undo-outer-limit', discard entire history
(when (> (undo-tree-size buffer-undo-tree) undo-outer-limit)
- ;; query first `undo-ask-before-discard' is set
+ ;; query first if `undo-ask-before-discard' is set
(if undo-ask-before-discard
(when (yes-or-no-p
(format
@@ -1087,73 +1094,105 @@ which is defined in the `warnings' library.\n")
;;; =====================================================================
-;;; Utility functions for handling `buffer-undo-list'
+;;; Visualizer-related functions
-(defun undo-list-pop-changeset ()
- ;; Pop changeset from `buffer-undo-list'.
- ;; discard undo boundaries and marker adjustment entries at head of list
- (while (or (null (car buffer-undo-list))
- (and (consp (car buffer-undo-list))
- (markerp (caar buffer-undo-list))))
- (setq buffer-undo-list (cdr buffer-undo-list)))
- ;; pop elements up to next undo boundary
- (unless (eq (car buffer-undo-list) 'undo-tree-canary)
- (let* ((changeset (cons (pop buffer-undo-list) nil))
- (p changeset))
- (while (car buffer-undo-list)
- (setcdr p (cons (pop buffer-undo-list) nil))
- ;; discard marker adjustment entries (see Commentary, above)
- (if (and (consp (cadr p)) (markerp (car (cadr p))))
- (setcdr p nil)
- (setq p (cdr p))))
- changeset)))
+(defun undo-tree-compute-widths (undo-tree)
+ "Recursively compute widths for all UNDO-TREE's nodes."
+ (let ((stack (list (undo-tree-root undo-tree)))
+ res)
+ (while stack
+ ;; try to compute widths for node at top of stack
+ (if (undo-tree-node-p
+ (setq res (undo-tree-node-compute-widths (car stack))))
+ ;; if computation fails, it returns a node whose widths still need
+ ;; computing, which we push onto the stack
+ (push res stack)
+ ;; otherwise, store widths and remove it from stack
+ (setf (undo-tree-node-lwidth (car stack)) (aref res 0)
+ (undo-tree-node-cwidth (car stack)) (aref res 1)
+ (undo-tree-node-rwidth (car stack)) (aref res 2))
+ (pop stack)))))
-(defun undo-list-transfer-to-tree ()
- ;; Transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'.
- (if (null buffer-undo-list)
- (setq buffer-undo-list '(nil undo-tree-canary))
- (when (not (eq (cadr buffer-undo-list) 'undo-tree-canary))
- ;; create new node from first changeset in `buffer-undo-list', save old
- ;; `buffer-undo-tree' current node, and make new node the current node
- (let* ((node (make-undo-tree-node nil (undo-list-pop-changeset)))
- (splice (undo-tree-current buffer-undo-tree))
- (size (undo-list-byte-size (undo-tree-node-undo node))))
- (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))))
- ;; 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 (eq (cadr 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))
- ;; 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)))
- ;; discard undo history if necessary
- (undo-tree-discard-history))))
+(defun undo-tree-node-compute-widths (node)
+ ;; Compute NODE's left-, centre-, and right-subtree widths. Returns widths
+ ;; (in a vector) if successful. Otherwise, returns a node whose widths need
+ ;; calculating before NODE's can be calculated.
+ (let ((num-children (length (undo-tree-node-next node)))
+ (lwidth 0) (cwidth 0) (rwidth 0)
+ p w)
+ (catch 'need-widths
+ (cond
+ ;; leaf nodes have 0 width
+ ((= 0 num-children)
+ (setf cwidth 1
+ (undo-tree-node-lwidth node) 0
+ (undo-tree-node-cwidth node) 1
+ (undo-tree-node-rwidth node) 0))
+ ;; odd number of children
+ ((= (mod num-children 2) 1)
+ (setq p (undo-tree-node-next node))
+ ;; compute left-width
+ (dotimes (i (/ num-children 2))
+ (if (undo-tree-node-lwidth (car p))
+ (incf lwidth (+ (undo-tree-node-lwidth (car p))
+ (undo-tree-node-cwidth (car p))
+ (undo-tree-node-rwidth (car p))))
+ ;; if child's widths haven't been computed, return that child
+ (throw 'need-widths (car p)))
+ (setq p (cdr p)))
+ (if (undo-tree-node-lwidth (car p))
+ (incf lwidth (undo-tree-node-lwidth (car p)))
+ (throw 'need-widths (car p)))
+ ;; centre-width is inherited from middle child
+ (setf cwidth (undo-tree-node-cwidth (car p)))
+ ;; compute right-width
+ (incf rwidth (undo-tree-node-rwidth (car p)))
+ (setq p (cdr p))
+ (dotimes (i (/ num-children 2))
+ (if (undo-tree-node-lwidth (car p))
+ (incf rwidth (+ (undo-tree-node-lwidth (car p))
+ (undo-tree-node-cwidth (car p))
+ (undo-tree-node-rwidth (car p))))
+ (throw 'need-widths (car p)))
+ (setq p (cdr p))))
-(defun undo-list-byte-size (undo-list)
- ;; Return size (in bytes) of UNDO-LIST
- (let ((size 0) (p undo-list))
- (while p
- (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)))
- size))
+ ;; even number of children
+ (t
+ (setq p (undo-tree-node-next node))
+ ;; compute left-width
+ (dotimes (i (/ num-children 2))
+ (if (undo-tree-node-lwidth (car p))
+ (incf lwidth (+ (undo-tree-node-lwidth (car p))
+ (undo-tree-node-cwidth (car p))
+ (undo-tree-node-rwidth (car p))))
+ (throw 'need-widths (car p)))
+ (setq p (cdr p)))
+ ;; centre-width is 0 when number of children is even
+ (setq cwidth 0)
+ ;; compute right-width
+ (dotimes (i (/ num-children 2))
+ (if (undo-tree-node-lwidth (car p))
+ (incf rwidth (+ (undo-tree-node-lwidth (car p))
+ (undo-tree-node-cwidth (car p))
+ (undo-tree-node-rwidth (car p))))
+ (throw 'need-widths (car p)))
+ (setq p (cdr p)))))
+
+ ;; return left-, centre- and right-widths
+ (vector lwidth cwidth rwidth))))
+
+
+(defun undo-tree-clear-visualizer-data (undo-tree)
+ ;; Clear visualizer data from UNDO-TREE.
+ (let ((stack (list (undo-tree-root undo-tree)))
+ node)
+ (while stack
+ (setq node (pop stack))
+ (setf (undo-tree-node-visualizer node) nil)
+ (dolist (n (undo-tree-node-next node))
+ (push n stack)))))
@@ -1274,12 +1313,12 @@ Within the undo-tree visualizer, the following keys are
available:
;; pop undo entries that `primitive-undo' has added to
;; `buffer-undo-list' and record them in current node's undo record,
;; replacing existing entry if one already exists
- (when (undo-tree-node-undo current)
- (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))
- (incf (undo-tree-size buffer-undo-tree)
- (undo-list-byte-size (undo-tree-node-undo current))))))
+ (when (undo-tree-node-undo current)
+ (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))
+ (incf (undo-tree-size buffer-undo-tree)
+ (undo-list-byte-size (undo-tree-node-undo current))))))
;; inform user if at branch point
(when (> (undo-tree-num-branches) 1) (message "Undo branch point!"))))
@@ -1292,11 +1331,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 buffer-undo-tree
- (progn
- (setq buffer-undo-tree (make-undo-tree))
- (undo-list-transfer-to-tree)
- t))
+ (or (undo-list-transfer-to-tree) t)
(> (undo-tree-num-branches) 1)
(read-number
(format "Branch (0-%d): "
@@ -1307,12 +1342,7 @@ using `undo-tree-redo'."
(when (<= (undo-tree-num-branches) 1) (error "Not at undo branch point"))
(when (or (< branch 0) (> branch (1- (undo-tree-num-branches))))
(error "Invalid branch number"))
-
- ;; if `buffer-undo-tree' is empty, create initial undo-tree
- (when (null buffer-undo-tree)
- (setq buffer-undo-tree (make-undo-tree)))
- ;; transfer entries accumulated in `buffer-undo-list' to
- ;; `buffer-undo-tree'
+ ;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'
(undo-list-transfer-to-tree)
;; switch branch
(setf (undo-tree-node-branch (undo-tree-current buffer-undo-tree))
@@ -1357,9 +1387,6 @@ Argument is a character, naming the register."
(interactive "cUndo-tree state to register: ")
;; throw error if undo is disabled in buffer
(when (eq buffer-undo-list t) (error "No undo information in this buffer"))
- ;; if `buffer-undo-tree' is empty, create initial undo-tree
- (when (null buffer-undo-tree)
- (setq buffer-undo-tree (make-undo-tree)))
;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'
(undo-list-transfer-to-tree)
;; save current node to REGISTER
@@ -1380,9 +1407,6 @@ Argument is a character, naming the register."
(error "No undo information in this buffer"))
((not (undo-tree-node-p node))
(error "Register doesn't contain undo-tree state")))
- ;; if `buffer-undo-tree' is empty, create initial undo-tree
- (when (null buffer-undo-tree)
- (setq buffer-undo-tree (make-undo-tree)))
;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'
(undo-list-transfer-to-tree)
;; restore buffer state corresponding to saved node
@@ -1399,9 +1423,6 @@ Argument is a character, naming the register."
(interactive)
;; throw error if undo is disabled in buffer
(when (eq buffer-undo-list t) (error "No undo information in this buffer"))
- ;; if `buffer-undo-tree' is empty, create initial undo-tree
- (when (null buffer-undo-tree)
- (setq buffer-undo-tree (make-undo-tree)))
;; transfer entries accumulated in `buffer-undo-list' to `buffer-undo-tree'
(undo-list-transfer-to-tree)
;; add hook to kill visualizer buffer if original buffer is changed
- [elpa] externals/undo-tree cfc036a 133/195: Fix undo-tree-redo to avoid corrupting undo-tree state if redoing fails., (continued)
- [elpa] externals/undo-tree cfc036a 133/195: Fix undo-tree-redo to avoid corrupting undo-tree state if redoing fails., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree bdfd73f 132/195: Ignore bogus buffer modification entries in undo changesets., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree 6e0775d 139/195: Use define-derived-mode and define-minor-mode for undo-tree visualizer., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree d6fa2e7 152/195: Reinstate accidentally deleted file header., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree 8afead1 162/195: Add Maintainer line to package headers., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree e9a9102 164/195: Throw error if interactive commands called outside undo-tree-mode., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree ffd18cd 175/195: Refactor undo-list-transfer-to-tree again in attempt to mitigate GC races., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree 941bfe5 190/195: Don't attempt to save undo history if history file is unwritable., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree 5a1ba84 017/195: Added standard Elisp package headers, including an extensive Commentary., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree 62e6097 044/195: Added undo-tree-save/restore-state-to/from-register commands and keybindings, Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree c638cbd 051/195: General code tidying and reorganisation.,
Stefan Monnier <=
- [elpa] externals/undo-tree caa3bd0 082/195: Added new customization option to allow undo-in-region to be disabled., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree 8972e4d 069/195: Use get-buffer-create when creating the visualizer buffer in undo-tree-visualize., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree d7c1b2c 118/195: "De-circle" undo-tree when saving to file, restore when loading., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree 121cab9 136/195: Trivial typo fixes in comments., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree 18754c1 114/195: Use with-temp-buffer instead of with-temp-file when saving undo history., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree c9f78c3 137/195: Use new user-error instead of error for expected undo errors., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree 1114679 135/195: Fix bugs in binding of undo-tree-insert-face., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree 5d19d4e 155/195: Bump version number and copyright year., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree ffb346a 157/195: Install undo-tree undo/redo Edit menu bar items., Stefan Monnier, 2020/11/28
- [elpa] externals/undo-tree 19baf49 158/195: Fix undo/redo-in-region tree diagrams in Commentary., Stefan Monnier, 2020/11/28