[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[ELPA-diffs] /srv/bzr/emacs/elpa r320: Update undo-tree to version 0.6.3
From: |
Toby S. Cubitt |
Subject: |
[ELPA-diffs] /srv/bzr/emacs/elpa r320: Update undo-tree to version 0.6.3 |
Date: |
Wed, 05 Dec 2012 17:33:11 +0100 |
User-agent: |
Bazaar (2.5.0) |
------------------------------------------------------------
revno: 320
committer: Toby S. Cubitt <address@hidden>
branch nick: elpa
timestamp: Wed 2012-12-05 17:33:11 +0100
message:
Update undo-tree to version 0.6.3
* undo-tree.el: Implement lazy tree drawing to significantly speed up
visualization of large trees + various more minor improvements.
modified:
packages/undo-tree/undo-tree.el
=== modified file 'packages/undo-tree/undo-tree.el'
--- a/packages/undo-tree/undo-tree.el 2012-09-25 15:22:47 +0000
+++ b/packages/undo-tree/undo-tree.el 2012-12-05 16:33:11 +0000
@@ -1,9 +1,9 @@
-;;; undo-tree.el --- Treat undo history as a tree
+;;; undo-tree.el --- Treat undo history as a tree -*- lexical-binding: t; -*-
;; Copyright (C) 2009-2012 Free Software Foundation, Inc
;; Author: Toby Cubitt <address@hidden>
-;; Version: 0.5.5
+;; Version: 0.6.3
;; 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
@@ -51,8 +51,9 @@
;; Installation
;; ============
;;
-;; This package has only been tested with Emacs versions 22, 23 and CVS. It
-;; will not work without modifications in earlier versions of Emacs.
+;; This package has only been tested with Emacs versions 24 and CVS. It should
+;; work in Emacs versions 22 and 23 too, but will not work without
+;; modifications in earlier versions of Emacs.
;;
;; To install `undo-tree-mode', make sure this file is saved in a directory in
;; your `load-path', and add the line:
@@ -118,6 +119,15 @@
;; <right> f C-f (`undo-tree-visualize-switch-branch-right')
;; Switch to next undo-tree branch.
;;
+;; C-<up> M-{ (`undo-tree-visualize-undo-to-x')
+;; Undo changes up to last branch point.
+;;
+;; C-<down> M-} (`undo-tree-visualize-redo-to-x')
+;; Redo changes down to next branch point.
+;;
+;; <down> n C-n (`undo-tree-visualize-redo')
+;; Redo changes.
+;;
;; <mouse-1> (`undo-tree-visualizer-mouse-set')
;; Set state to node at mouse click.
;;
@@ -727,7 +737,7 @@
(require 'diff)
-
+
;;; =====================================================================
;;; Compatibility hacks for older Emacsen
@@ -742,7 +752,7 @@
;; `registerv' defstruct isn't defined in Emacs versions < 24
(unless (fboundp 'registerv-make)
- (defmacro registerv-make (data &rest dummy) data))
+ (defmacro registerv-make (data &rest _dummy) data))
(unless (fboundp 'registerv-data)
(defmacro registerv-data (data) data))
@@ -819,7 +829,7 @@
-
+
;;; =====================================================================
;;; Global variables and customization options
@@ -840,6 +850,24 @@
:type 'string)
+(defcustom undo-tree-incompatible-major-modes '(term-mode)
+ "List of major-modes in which `undo-tree-mode' should not be enabled.
+\(See `turn-on-undo-tree-mode'.\)"
+ :group 'undo-tree
+ :type '(repeat symbol))
+
+
+(defcustom undo-tree-enable-undo-in-region t
+ "When non-nil, enable undo-in-region.
+
+When undo-in-region is enabled, undoing or redoing when the
+region is active (in `transient-mark-mode') or with a prefix
+argument (not in `transient-mark-mode') only undoes changes
+within the current region."
+ :group 'undo-tree
+ :type 'boolean)
+
+
(defcustom undo-tree-auto-save-history nil
"When non-nil, `undo-tree-mode' will save undo history to file
when a buffer is saved to file.
@@ -852,13 +880,13 @@
file itself.
WARNING! `undo-tree-auto-save-history' will not work properly in
-Emacs versions prior to 24.1.50.1, so it cannot be enabled via
+Emacs versions prior to 24.3, so it cannot be enabled via
the customization interface in versions earlier than that one. To
ignore this warning and enable it regardless, set
`undo-tree-auto-save-history' to a non-nil value outside of
customize."
:group 'undo-tree
- :type (if (version-list-< (version-to-list emacs-version) '(24 1 50 1))
+ :type (if (version-list-< (version-to-list emacs-version) '(24 3))
'(choice (const :tag "<disabled>" nil))
'boolean))
@@ -888,6 +916,7 @@
(directory :tag "Undo history directory name"))))
+
(defcustom undo-tree-visualizer-relative-timestamps t
"When non-nil, display times relative to current time
when displaying time stamps in visualizer.
@@ -906,7 +935,6 @@
setting of this variable."
:group 'undo-tree
:type 'boolean)
-(make-variable-buffer-local 'undo-tree-visualizer-timestamps)
(defcustom undo-tree-visualizer-diff nil
@@ -917,25 +945,31 @@
setting of this variable."
:group 'undo-tree
:type 'boolean)
-(make-variable-buffer-local 'undo-tree-visualizer-diff)
-
-
-(defcustom undo-tree-incompatible-major-modes '(term-mode)
- "List of major-modes in which `undo-tree-mode' should not be enabled.
-\(See `turn-on-undo-tree-mode'.\)"
- :group 'undo-tree
- :type '(repeat symbol))
-
-
-(defcustom undo-tree-enable-undo-in-region t
- "When non-nil, enable undo-in-region.
-
-When undo-in-region is enabled, undoing or redoing when the
-region is active (in `transient-mark-mode') or with a prefix
-argument (not in `transient-mark-mode') only undoes changes
-within the current region."
- :group 'undo-tree
- :type 'boolean)
+
+
+(defcustom undo-tree-visualizer-lazy-drawing 100
+ "When non-nil, use lazy undo-tree drawing in visualizer.
+
+Setting this to a number causes the visualizer to switch to lazy
+drawing when the number of nodes in the tree is larger than this
+value.
+
+Lazy drawing means that only the visible portion of the tree will
+be drawn initially , and the tree will be extended later as
+needed. For the most part, the only visible effect of this is to
+significantly speed up displaying the visualizer for very large
+trees.
+
+There is one potential negative effect of lazy drawing. Other
+branches of the tree will only be drawn once the node from which
+they branch off becomes visible. So it can happen that certain
+portions of the tree that would be shown with lazy drawing
+disabled, will not be drawn immediately when it is
+enabled. However, this effect is quite rare in practice."
+ :group 'undo-tree
+ :type '(choice (const :tag "never" nil)
+ (const :tag "always" t)
+ (integer :tag "> size")))
(defface undo-tree-visualizer-default-face
@@ -962,16 +996,26 @@
in visualizer."
:group 'undo-tree)
+(defface undo-tree-visualizer-unmodified-face
+ '((((class color)) :foreground "cyan"))
+ "Face used to highlight nodes corresponding to unmodified buffers
+in visualizer."
+ :group 'undo-tree)
+
(defvar undo-tree-visualizer-parent-buffer nil
"Parent buffer in visualizer.")
(make-variable-buffer-local 'undo-tree-visualizer-parent-buffer)
+;; stores modification time of parent buffer's file, if any
+(defvar undo-tree-visualizer-parent-mtime nil)
+(make-variable-buffer-local 'undo-tree-visualizer-parent-mtime)
+
;; stores current horizontal spacing needed for drawing undo-tree
(defvar undo-tree-visualizer-spacing nil)
(make-variable-buffer-local 'undo-tree-visualizer-spacing)
-;; calculate horizontal spacing required for drawing undo-tree with current
+;; calculate horizontal spacing required for drawing tree with current
;; settings
(defsubst undo-tree-visualizer-calculate-spacing ()
(if undo-tree-visualizer-timestamps
@@ -986,31 +1030,36 @@
(defvar undo-tree-visualizer-selected-node nil)
(make-variable-buffer-local 'undo-tree-visualizer-selected)
+;; used to store nodes at edge of currently drawn portion of tree
+(defvar undo-tree-visualizer-needs-extending-down nil)
+(make-variable-buffer-local 'undo-tree-visualizer-needs-extending-down)
+(defvar undo-tree-visualizer-needs-extending-up nil)
+(make-variable-buffer-local 'undo-tree-visualizer-needs-extending-up)
+
;; dynamically bound to t when undoing from visualizer, to inhibit
;; `undo-tree-kill-visualizer' hook function in parent buffer
(defvar undo-tree-inhibit-kill-visualizer nil)
+;; can be let-bound to a face name, used in drawing functions
+(defvar undo-tree-insert-face nil)
+;; visualizer buffer names
(defconst undo-tree-visualizer-buffer-name " *undo-tree*")
(defconst undo-tree-diff-buffer-name "*undo-tree Diff*")
;; prevent debugger being called on "No further redo information"
(add-to-list 'debug-ignored-errors "^No further redo information")
-
-
-
-
-;;; =================================================================
-;;; Install history-auto-save hooks
-
+(add-to-list 'debug-ignored-errors "^No further redo information for region")
+
+;; 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)
-
+
;;; =================================================================
-;;; Setup default keymaps
+;;; Default keymaps
(defvar undo-tree-map nil
"Keymap used in undo-tree-mode.")
@@ -1062,6 +1111,13 @@
(define-key map [left] 'undo-tree-visualize-switch-branch-left)
(define-key map "b" 'undo-tree-visualize-switch-branch-left)
(define-key map "\C-b" 'undo-tree-visualize-switch-branch-left)
+ ;; paragraph motion keys undo/redo to significant points in tree
+ (define-key map [remap backward-paragraph] 'undo-tree-visualize-undo-to-x)
+ (define-key map [remap forward-paragraph] 'undo-tree-visualize-redo-to-x)
+ (define-key map "\M-{" 'undo-tree-visualize-undo-to-x)
+ (define-key map "\M-}" 'undo-tree-visualize-redo-to-x)
+ (define-key map [C-down] 'undo-tree-visualize-undo-to-x)
+ (define-key map [C-up] 'undo-tree-visualize-redo-to-x)
;; mouse sets buffer state to node at click
(define-key map [mouse-1] 'undo-tree-visualizer-mouse-set)
;; toggle timestamps
@@ -1076,8 +1132,8 @@
(define-key map "<" 'undo-tree-visualizer-scroll-left)
(define-key map ">" 'undo-tree-visualizer-scroll-right)
;; vertical scrolling may be needed if the tree is very tall
- (define-key map [next] 'scroll-up)
- (define-key map [prior] 'scroll-down)
+ (define-key map [next] 'undo-tree-visualizer-scroll-up)
+ (define-key map [prior] 'undo-tree-visualizer-scroll-down)
;; quit/abort visualizer
(define-key map "q" 'undo-tree-visualizer-quit)
(define-key map "\C-q" 'undo-tree-visualizer-abort)
@@ -1141,7 +1197,7 @@
-
+
;;; =====================================================================
;;; Undo-tree data structure
@@ -1154,10 +1210,11 @@
(root (undo-tree-make-node nil nil))
(current root)
(size 0)
+ (count 0)
(object-pool (make-hash-table :test 'eq :weakness 'value))))
;;(:copier nil)
)
- root current size object-pool)
+ root current size count object-pool)
@@ -1284,13 +1341,13 @@
(let ((len (length (undo-tree-make-visualizer-data))))
`(and (vectorp ,v) (= (length ,v) ,len))))
-(defmacro undo-tree-node-clear-visualizer-data (node)
- `(setf (undo-tree-node-meta-data ,node)
- (delq nil
- (delq :visualizer
- (plist-put (undo-tree-node-meta-data ,node)
- :visualizer nil)))))
-
+(defun undo-tree-node-clear-visualizer-data (node)
+ (let ((plist (undo-tree-node-meta-data node)))
+ (if (eq (car plist) :visualizer)
+ (setf (undo-tree-node-meta-data node) (nthcdr 2 plist))
+ (while (and plist (not (eq (cadr plist) :visualizer)))
+ (setq plist (cdr plist)))
+ (if plist (setcdr plist (nthcdr 3 plist))))))
(defmacro undo-tree-node-lwidth (node)
`(let ((v (plist-get (undo-tree-node-meta-data ,node) :visualizer)))
@@ -1372,7 +1429,7 @@
-
+
;;; =====================================================================
;;; Basic undo-tree data structure functions
@@ -1441,14 +1498,14 @@
(setf (undo-tree-node-previous n) parent))))
-(defun undo-tree-mapc (--undo-tree-mapc-function-- undo-tree)
- ;; Apply FUNCTION to each node in UNDO-TREE.
- (let ((stack (list (undo-tree-root undo-tree)))
- node)
+(defun undo-tree-mapc (--undo-tree-mapc-function-- node)
+ ;; Apply FUNCTION to NODE and to each node below it.
+ (let ((stack (list node))
+ n)
(while stack
- (setq node (pop stack))
- (funcall --undo-tree-mapc-function-- node)
- (setq stack (append (undo-tree-node-next node) stack)))))
+ (setq n (pop stack))
+ (funcall --undo-tree-mapc-function-- n)
+ (setq stack (append (undo-tree-node-next n) stack)))))
(defmacro undo-tree-num-branches ()
@@ -1480,30 +1537,30 @@
(make-symbol (format "undo-tree-id%d" num))))
-(defun undo-tree-decircle (tree)
- ;; Nullify PREVIOUS links of undo-tree-nodes, to make undo-tree data
+(defun undo-tree-decircle (undo-tree)
+ ;; Nullify PREVIOUS links of UNDO-TREE nodes, to make UNDO-TREE data
;; structure non-circular.
(undo-tree-mapc
(lambda (node)
(dolist (n (undo-tree-node-next node))
(setf (undo-tree-node-previous n) nil)))
- tree))
-
-
-(defun undo-tree-recircle (tree)
- ;; Recreate PREVIOUS links of undo-tree-nodes, to restore circular undo-tree
+ (undo-tree-root undo-tree)))
+
+
+(defun undo-tree-recircle (undo-tree)
+ ;; Recreate PREVIOUS links of UNDO-TREE nodes, to restore circular UNDO-TREE
;; data structure.
(undo-tree-mapc
(lambda (node)
(dolist (n (undo-tree-node-next node))
(setf (undo-tree-node-previous n) node)))
- tree))
-
-
-
-
+ (undo-tree-root undo-tree)))
+
+
+
+
;;; =====================================================================
-;;; Utility functions for handling `buffer-undo-list' and changesets
+;;; Undo list and undo changeset utility functions
(defmacro undo-list-marker-elt-p (elt)
`(markerp (car-safe ,elt)))
@@ -1629,14 +1686,16 @@
;; `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))))
+ (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 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
@@ -1646,13 +1705,15 @@
(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-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)))
@@ -1708,9 +1769,9 @@
-
+
;;; =====================================================================
-;;; History discarding functions
+;;; History discarding utility functions
(defun undo-tree-oldest-leaf (node)
;; Return oldest leaf node below NODE.
@@ -1754,6 +1815,7 @@
(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))))
+ (decf (undo-tree-count buffer-undo-tree))
;; discard new root's undo data and PREVIOUS link
(setf (undo-tree-node-undo node) nil
(undo-tree-node-redo node) nil
@@ -1778,12 +1840,14 @@
(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))))
+ (decf (undo-tree-count buffer-undo-tree))
+ ;; discard leaf
(setf (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)))
;; if parent has branches, or parent is current node, next node to
- ;; discard is oldest leaf, otherwise it's parent
+ ;; discard is oldest leaf, otherwise it's the parent itself
(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)))
@@ -1875,13 +1939,13 @@
-
+
;;; =====================================================================
-;;; Visualizer-related functions
+;;; Visualizer utility functions
-(defun undo-tree-compute-widths (undo-tree)
- "Recursively compute widths for all UNDO-TREE's nodes."
- (let ((stack (list (undo-tree-root undo-tree)))
+(defun undo-tree-compute-widths (node)
+ "Recursively compute widths for nodes below NODE."
+ (let ((stack (list node))
res)
(while stack
;; try to compute widths for node at top of stack
@@ -1902,8 +1966,7 @@
;; (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)
+ (lwidth 0) (cwidth 0) (rwidth 0) p)
(catch 'need-widths
(cond
;; leaf nodes have 0 width
@@ -1967,17 +2030,45 @@
(vector lwidth cwidth rwidth))))
-(defun undo-tree-clear-visualizer-data (undo-tree)
- ;; Clear visualizer data from UNDO-TREE.
+(defun undo-tree-clear-visualizer-data (tree)
+ ;; Clear visualizer data below NODE.
(undo-tree-mapc
- (lambda (node) (undo-tree-node-clear-visualizer-data node))
- undo-tree))
-
-
-
-
+ (lambda (n) (undo-tree-node-clear-visualizer-data n))
+ (undo-tree-root tree)))
+
+
+(defun undo-tree-node-unmodified-p (node &optional mtime)
+ ;; Return non-nil if NODE corresponds to a buffer state that once upon a
+ ;; time was unmodified. If a file modification time MTIME is specified,
+ ;; return non-nil if the corresponding buffer state really is unmodified.
+ (let (changeset ntime)
+ (setq changeset
+ (or (undo-tree-node-redo node)
+ (and (setq changeset (car (undo-tree-node-next node)))
+ (undo-tree-node-undo changeset)))
+ ntime
+ (catch 'found
+ (dolist (elt changeset)
+ (when (and (consp elt) (eq (car elt) t) (consp (cdr elt))
+ (throw 'found (cdr elt)))))))
+ (and ntime
+ (or (null mtime)
+ ;; high-precision timestamps
+ (if (listp (cdr ntime))
+ (equal ntime mtime)
+ ;; old-style timestamps
+ (and (= (car ntime) (car mtime))
+ (= (cdr ntime) (cadr mtime))))))))
+
+
+
+
;;; =====================================================================
-;;; Undo-in-region functions
+;;; Undo-in-region utility functions
+
+;; `undo-elt-in-region' uses this as a dynamically-scoped variable
+(defvar undo-adjusted-markers nil)
+
(defun undo-tree-pull-undo-in-region-branch (start end)
;; Pull out entries from undo changesets to create a new undo-in-region
@@ -2128,7 +2219,7 @@
(setq node (undo-tree-node-previous node))))
;; pop dummy nil from front of `region-changeset'
- (pop region-changeset)
+ (setq region-changeset (cdr region-changeset))
;; --- integrate branch into tree ---
@@ -2204,12 +2295,10 @@
(while (progn
(and (setq node (car (undo-tree-node-next node)))
(not (eq node original-fragment))
+ (incf (undo-tree-count buffer-undo-tree))
(incf (undo-tree-size buffer-undo-tree)
- (undo-list-byte-size (undo-tree-node-undo node)))
- (when (undo-tree-node-redo node)
- (incf (undo-tree-size buffer-undo-tree)
- (undo-list-byte-size (undo-tree-node-redo node))))
- )))
+ (+ (undo-list-byte-size (undo-tree-node-undo node))
+ (undo-list-byte-size (undo-tree-node-redo
node)))))))
t) ; indicate undo-in-region branch was successfully pulled
)))
@@ -2340,7 +2429,7 @@
(setq node (car (undo-tree-node-next node)))))
;; pop dummy nil from front of `region-changeset'
- (pop region-changeset)
+ (setq region-changeset (cdr region-changeset))
;; --- integrate branch into tree ---
@@ -2365,14 +2454,14 @@
;; update undo-tree size
(unless repeated-redo-in-region
(setq node fragment)
- (while (progn
- (and (setq node (car (undo-tree-node-next node)))
- (incf (undo-tree-size buffer-undo-tree)
- (undo-list-byte-size
- (undo-tree-node-redo node)))))))
+ (while (and (setq node (car (undo-tree-node-next node)))
+ (incf (undo-tree-count buffer-undo-tree))
+ (incf (undo-tree-size buffer-undo-tree)
+ (undo-list-byte-size
+ (undo-tree-node-redo node))))))
(incf (undo-tree-size buffer-undo-tree)
(undo-list-byte-size (undo-tree-node-redo fragment)))
- t) ; indicate undo-in-region branch was successfully pulled
+ t) ; indicate redo-in-region branch was successfully pulled
)))
@@ -2469,7 +2558,7 @@
-
+
;;; =====================================================================
;;; Undo-tree commands
@@ -2630,9 +2719,8 @@
;; otherwise, record redo entries that `primitive-undo' has added to
;; `buffer-undo-list' in current node's redo record, replacing
;; existing entry if one already exists
- (when (undo-tree-node-redo current)
- (decf (undo-tree-size buffer-undo-tree)
- (undo-list-byte-size (undo-tree-node-redo current))))
+ (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))
(incf (undo-tree-size buffer-undo-tree)
@@ -2707,11 +2795,11 @@
(region-beginning) (region-end))))
(error "No further redo information for region"))
- ;; advance current node
+ ;; get next node (but DON'T advance current node in tree yet, in case
+ ;; redoing fails)
(setq current (undo-tree-current buffer-undo-tree)
- current (setf (undo-tree-current buffer-undo-tree)
- (nth (undo-tree-node-branch current)
- (undo-tree-node-next current))))
+ current (nth (undo-tree-node-branch current)
+ (undo-tree-node-next current)))
;; remove any GC'd elements from node's redo list
(decf (undo-tree-size buffer-undo-tree)
(undo-list-byte-size (undo-tree-node-redo current)))
@@ -2725,6 +2813,8 @@
(set-marker-insertion-type pos t))
(primitive-undo 1 (undo-tree-copy-list (undo-tree-node-redo current)))
(undo-boundary)
+ ;; advance current node in tree
+ (setf (undo-tree-current buffer-undo-tree) current)
;; if preserving old undo record, discard new undo entries that
;; `primitive-undo' has added to `buffer-undo-list', and remove any GC'd
@@ -2741,9 +2831,8 @@
;; otherwise, record undo entries that `primitive-undo' has added to
;; `buffer-undo-list' 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))))
+ (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))
(incf (undo-tree-size buffer-undo-tree)
@@ -2827,10 +2916,10 @@
(setq n (undo-tree-node-previous n)))
;; ascend tree until intersection node
(while (not (eq (undo-tree-current buffer-undo-tree) n))
- (undo-tree-undo-1))
+ (undo-tree-undo-1 nil nil preserve-timestamps))
;; descend tree until selected node
(while (not (eq (undo-tree-current buffer-undo-tree) node))
- (undo-tree-redo-1))
+ (undo-tree-redo-1 nil nil preserve-timestamps))
n)) ; return intersection node
@@ -2879,9 +2968,9 @@
-
+
;;; =====================================================================
-;;; Persistent storage
+;;; Persistent storage commands
(defun undo-tree-make-history-save-file-name (file)
"Create the undo history file name for FILE.
@@ -2894,7 +2983,7 @@
(let* ((backup-directory-alist undo-tree-history-directory-alist)
(name (make-backup-file-name-1 file)))
(concat (file-name-directory name) "." (file-name-nondirectory name)
- ".~undo-tree~")))
+ "~undo-tree~")))
(defun undo-tree-save-history (&optional filename overwrite)
@@ -2974,7 +3063,7 @@
(throw 'load-error nil)
(error "File \"%s\" does not exist; could not load undo-tree history"
filename)))
- (let (buff tmp hash tree)
+ (let (buff hash tree)
(setq buff (current-buffer))
(with-auto-compression-mode
(with-temp-buffer
@@ -3022,9 +3111,9 @@
-
+
;;; =====================================================================
-;;; Undo-tree visualizer
+;;; Visualizer drawing functions
(defun undo-tree-visualize ()
"Visualize the current buffer's undo tree."
@@ -3043,16 +3132,26 @@
(switch-to-buffer-other-window
(get-buffer-create undo-tree-visualizer-buffer-name))
(setq undo-tree-visualizer-parent-buffer buff)
+ (setq undo-tree-visualizer-parent-mtime
+ (and (buffer-file-name buff)
+ (nth 5 (file-attributes (buffer-file-name buff)))))
(setq buffer-undo-tree undo-tree)
(setq undo-tree-visualizer-initial-node (undo-tree-current undo-tree))
(setq undo-tree-visualizer-spacing
(undo-tree-visualizer-calculate-spacing))
+ (make-local-variable 'undo-tree-visualizer-timestamps)
+ (make-local-variable 'undo-tree-visualizer-diff)
+ (set (make-local-variable 'undo-tree-visualizer-lazy-drawing)
+ (or (eq undo-tree-visualizer-lazy-drawing t)
+ (and (numberp undo-tree-visualizer-lazy-drawing)
+ (>= (undo-tree-count undo-tree)
+ undo-tree-visualizer-lazy-drawing))))
(when undo-tree-visualizer-diff (undo-tree-visualizer-show-diff))
(undo-tree-visualizer-mode)
(let ((inhibit-read-only t)) (undo-tree-draw-tree undo-tree))))
-(defun undo-tree-kill-visualizer (&rest dummy)
+(defun undo-tree-kill-visualizer (&rest _dummy)
;; Kill visualizer. Added to `before-change-functions' hook of original
;; buffer when visualizer is invoked.
(unless undo-tree-inhibit-kill-visualizer
@@ -3063,113 +3162,282 @@
(defun undo-tree-draw-tree (undo-tree)
- ;; Draw UNDO-TREE in current buffer.
- (erase-buffer)
- (undo-tree-move-down 1) ; top margin
- (undo-tree-clear-visualizer-data undo-tree)
- (undo-tree-compute-widths undo-tree)
- (undo-tree-move-forward
- (max (/ (window-width) 2)
- (+ (undo-tree-node-char-lwidth (undo-tree-root undo-tree))
- ;; add space for left part of left-most time-stamp
- (if undo-tree-visualizer-timestamps
- (/ (- undo-tree-visualizer-spacing 4) 2)
- 0)
- 2))) ; left margin
- ;; draw undo-tree
- (let ((undo-tree-insert-face 'undo-tree-visualizer-default-face)
- (stack (list (undo-tree-root undo-tree)))
- (n (undo-tree-root undo-tree)))
- ;; link root node to its representation in visualizer
- (unless (markerp (undo-tree-node-marker n))
- (setf (undo-tree-node-marker n) (make-marker))
- (set-marker-insertion-type (undo-tree-node-marker n) nil))
- (move-marker (undo-tree-node-marker n) (point))
- ;; draw nodes from stack until stack is empty
- (while stack
- (setq n (pop stack))
- (goto-char (undo-tree-node-marker n))
- (setq n (undo-tree-draw-subtree n nil))
- (setq stack (append stack n))))
- ;; highlight active branch
- (goto-char (undo-tree-node-marker (undo-tree-root undo-tree)))
- (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face))
- (undo-tree-highlight-active-branch (undo-tree-root undo-tree)))
- ;; highlight current node
- (undo-tree-draw-node (undo-tree-current undo-tree) 'current))
-
-
-(defun undo-tree-highlight-active-branch (node)
- ;; Draw highlighted active branch below NODE in current buffer.
+ ;; Draw undo-tree in current buffer starting from NODE (or root if nil).
+ (let ((node (if undo-tree-visualizer-lazy-drawing
+ (undo-tree-current undo-tree)
+ (undo-tree-root undo-tree))))
+ (erase-buffer)
+ (undo-tree-clear-visualizer-data undo-tree)
+ (undo-tree-compute-widths node)
+ ;; lazy drawing starts vertically centred and displaced horizontally to
+ ;; the left (window-width/4), since trees will typically grow right
+ (if undo-tree-visualizer-lazy-drawing
+ (progn
+ (undo-tree-move-down (/ (window-height) 2))
+ (undo-tree-move-forward (max 2 (/ (window-width) 4)))) ; left margin
+ ;; non-lazy drawing starts in centre at top of buffer
+ (undo-tree-move-down 1) ; top margin
+ (undo-tree-move-forward
+ (max (/ (window-width) 2)
+ (+ (undo-tree-node-char-lwidth node)
+ ;; add space for left part of left-most time-stamp
+ (if undo-tree-visualizer-timestamps
+ (/ (- undo-tree-visualizer-spacing 4) 2)
+ 0)
+ 2)))) ; left margin
+ ;; link starting node to its representation in visualizer
+ (setf (undo-tree-node-marker node) (make-marker))
+ (set-marker-insertion-type (undo-tree-node-marker node) nil)
+ (move-marker (undo-tree-node-marker node) (point))
+ ;; draw undo-tree
+ (let ((undo-tree-insert-face 'undo-tree-visualizer-default-face)
+ node-list)
+ (if (not undo-tree-visualizer-lazy-drawing)
+ (undo-tree-extend-down node t)
+ (undo-tree-extend-down node)
+ (undo-tree-extend-up node)
+ (setq node-list undo-tree-visualizer-needs-extending-down
+ undo-tree-visualizer-needs-extending-down nil)
+ (while node-list (undo-tree-extend-down (pop node-list)))))
+ ;; highlight active branch
+ (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face))
+ (undo-tree-highlight-active-branch
+ (or undo-tree-visualizer-needs-extending-up
+ (undo-tree-root undo-tree))))
+ ;; highlight current node
+ (undo-tree-draw-node (undo-tree-current undo-tree) 'current)))
+
+
+(defun undo-tree-extend-down (node &optional bottom)
+ ;; Extend tree downwards starting from NODE and point. If BOTTOM is t,
+ ;; extend all the way down to the leaves. If BOTTOM is a node, extend down
+ ;; as far as that node. If BOTTOM is an integer, extend down as far as that
+ ;; line. Otherwise, only extend visible portion of tree. NODE is assumed to
+ ;; already have a node marker. Returns non-nil if anything was actually
+ ;; extended.
+ (let ((extended nil)
+ (cur-stack (list node))
+ next-stack)
+ ;; don't bother extending if BOTTOM specifies an already-drawn node
+ (unless (and (undo-tree-node-p bottom) (undo-tree-node-marker bottom))
+ ;; draw nodes layer by layer
+ (while (or cur-stack
+ (prog1 (setq cur-stack next-stack)
+ (setq next-stack nil)))
+ (setq node (pop cur-stack))
+ ;; if node is within range being drawn...
+ (if (or (eq bottom t)
+ (and (undo-tree-node-p bottom)
+ (not (eq (undo-tree-node-previous node) bottom)))
+ (and (integerp bottom)
+ (>= bottom (line-number-at-pos
+ (undo-tree-node-marker node))))
+ (and (null bottom)
+ (pos-visible-in-window-p (undo-tree-node-marker node)
+ nil t)))
+ ;; ...draw one layer of node's subtree (if not already drawn)
+ (progn
+ (unless (and (undo-tree-node-next node)
+ (undo-tree-node-marker
+ (nth (undo-tree-node-branch node)
+ (undo-tree-node-next node))))
+ (goto-char (undo-tree-node-marker node))
+ (undo-tree-draw-subtree node)
+ (setq extended t))
+ (setq next-stack
+ (append (undo-tree-node-next node) next-stack)))
+ ;; ...otherwise, postpone drawing until later
+ (push node undo-tree-visualizer-needs-extending-down))))
+ extended))
+
+
+(defun undo-tree-extend-up (node &optional top)
+ ;; Extend tree upwards starting from NODE. If TOP is t, extend all the way
+ ;; to root. If TOP is a node, extend up as far as that node. If TOP is an
+ ;; integer, extend up as far as that line. Otherwise, only extend visible
+ ;; portion of tree. NODE is assumed to already have a node marker. Returns
+ ;; non-nil if anything was actually extended.
+ (let ((extended nil) parent n)
+ ;; don't bother extending if TOP specifies an already-drawn node
+ (unless (and (undo-tree-node-p top) (undo-tree-node-marker top))
+ (while node
+ (setq parent (undo-tree-node-previous node))
+ ;; if we haven't reached root...
+ (if parent
+ ;; ...and node is within range being drawn...
+ (if (or (eq top t)
+ (and (undo-tree-node-p top) (not (eq node top)))
+ (and (integerp top)
+ (< top (line-number-at-pos
+ (undo-tree-node-marker node))))
+ (and (null top)
+ ;; NOTE: check point in case window-start is outdated
+ (< (min (line-number-at-pos (point))
+ (line-number-at-pos (window-start)))
+ (line-number-at-pos
+ (undo-tree-node-marker node)))))
+ ;; ...and it hasn't already been drawn
+ (when (not (undo-tree-node-marker parent))
+ ;; link parent node to its representation in visualizer
+ (undo-tree-compute-widths parent)
+ (undo-tree-move-to-parent node)
+ (setf (undo-tree-node-marker parent) (make-marker))
+ (set-marker-insertion-type
+ (undo-tree-node-marker parent) nil)
+ (move-marker (undo-tree-node-marker parent) (point))
+ ;; draw subtree beneath parent
+ (setq undo-tree-visualizer-needs-extending-down
+ (nconc (delq node (undo-tree-draw-subtree parent))
+ undo-tree-visualizer-needs-extending-down))
+ (setq extended t))
+ ;; ...otherwise, postpone drawing for later and exit
+ (setq undo-tree-visualizer-needs-extending-up (when parent node)
+ parent nil))
+
+ ;; if we've reached root, stop extending and add top margin
+ (setq undo-tree-visualizer-needs-extending-up nil)
+ (goto-char (undo-tree-node-marker node))
+ (undo-tree-move-up 1) ; top margin
+ (delete-region (point-min) (line-beginning-position)))
+ ;; next iteration
+ (setq node parent)))
+ extended))
+
+
+(defun undo-tree-expand-down (from &optional to)
+ ;; Expand tree downwards. FROM is the node to start expanding from. Stop
+ ;; expanding at TO if specified. Otherwise, just expand visible portion of
+ ;; tree and highlight active branch from FROM.
+ (when undo-tree-visualizer-needs-extending-down
+ (let ((inhibit-read-only t)
+ node-list extended)
+ ;; extend down as far as TO node
+ (when to
+ (setq extended (undo-tree-extend-down from to))
+ (goto-char (undo-tree-node-marker to))
+ (redisplay t)) ; force redisplay to scroll buffer if necessary
+ ;; extend visible portion of tree downwards
+ (setq node-list undo-tree-visualizer-needs-extending-down
+ undo-tree-visualizer-needs-extending-down nil)
+ (when node-list
+ (dolist (n node-list)
+ (when (undo-tree-extend-down n) (setq extended t)))
+ ;; highlight active branch in newly-extended-down portion, if any
+ (when extended
+ (let ((undo-tree-insert-face
+ 'undo-tree-visualizer-active-branch-face))
+ (undo-tree-highlight-active-branch from)))))))
+
+
+(defun undo-tree-expand-up (from &optional to)
+ ;; Expand tree upwards. FROM is the node to start expanding from, TO is the
+ ;; node to stop expanding at. If TO node isn't specified, just expand visible
+ ;; portion of tree and highlight active branch down to FROM.
+ (when undo-tree-visualizer-needs-extending-up
+ (let ((inhibit-read-only t)
+ extended node-list)
+ ;; extend up as far as TO node
+ (when to
+ (setq extended (undo-tree-extend-up from to))
+ (goto-char (undo-tree-node-marker to))
+ ;; simulate auto-scrolling if close to top of buffer
+ (when (<= (line-number-at-pos (point)) scroll-margin)
+ (undo-tree-move-up (if (= scroll-conservatively 0)
+ (/ (window-height) 2) 3))
+ (when (undo-tree-extend-up to) (setq extended t))
+ (goto-char (undo-tree-node-marker to))
+ (unless (= scroll-conservatively 0) (recenter scroll-margin))))
+ ;; extend visible portion of tree upwards
+ (and undo-tree-visualizer-needs-extending-up
+ (undo-tree-extend-up undo-tree-visualizer-needs-extending-up)
+ (setq extended t))
+ ;; extend visible portion of tree downwards
+ (setq node-list undo-tree-visualizer-needs-extending-down
+ undo-tree-visualizer-needs-extending-down nil)
+ (dolist (n node-list) (undo-tree-extend-down n))
+ ;; highlight active branch in newly-extended-up portion, if any
+ (when extended
+ (let ((undo-tree-insert-face
+ 'undo-tree-visualizer-active-branch-face))
+ (undo-tree-highlight-active-branch
+ (or undo-tree-visualizer-needs-extending-up
+ (undo-tree-root buffer-undo-tree))
+ from))))))
+
+
+
+(defun undo-tree-highlight-active-branch (node &optional end)
+ ;; Draw highlighted active branch below NODE in current buffer. Stop
+ ;; highlighting at END node if specified.
(let ((stack (list node)))
- ;; link node to its representation in visualizer
- (unless (markerp (undo-tree-node-marker node))
- (setf (undo-tree-node-marker node) (make-marker))
- (set-marker-insertion-type (undo-tree-node-marker node) nil))
- (move-marker (undo-tree-node-marker node) (point))
;; draw active branch
(while stack
(setq node (pop stack))
- (goto-char (undo-tree-node-marker node))
- (setq node (undo-tree-draw-subtree node 'active))
- (setq stack (append stack node)))))
+ (unless (or (eq node end)
+ (memq node undo-tree-visualizer-needs-extending-down))
+ (goto-char (undo-tree-node-marker node))
+ (setq node (undo-tree-draw-subtree node 'active)
+ stack (nconc stack node))))))
(defun undo-tree-draw-node (node &optional current)
- ;; Draw symbol representing NODE in visualizer.
+ ;; Draw symbol representing NODE in visualizer. If CURRENT is non-nil, node
+ ;; is current node.
(goto-char (undo-tree-node-marker node))
(when undo-tree-visualizer-timestamps
- (backward-char (/ undo-tree-visualizer-spacing 2)))
+ (undo-tree-move-backward (/ undo-tree-visualizer-spacing 2)))
- (let ((register (undo-tree-node-register node))
+ (let* ((undo-tree-insert-face (and undo-tree-insert-face
+ (or (and (consp undo-tree-insert-face)
+ undo-tree-insert-face)
+ (list undo-tree-insert-face))))
+ (register (undo-tree-node-register node))
+ (unmodified (if undo-tree-visualizer-parent-mtime
+ (undo-tree-node-unmodified-p
+ node undo-tree-visualizer-parent-mtime)
+ (undo-tree-node-unmodified-p node)))
node-string)
+ ;; check node's register (if any) still stores appropriate undo-tree state
(unless (and register
+ (undo-tree-register-data-p
+ (registerv-data (get-register register)))
(eq node (undo-tree-register-data-node
(registerv-data (get-register register)))))
(setq register nil))
- ;; represent node by differentl symbols, depending on whether it's the
- ;; current node or is saved in a register
+ ;; represent node by different symbols, depending on whether it's the
+ ;; current node, is saved in a register, or corresponds to an unmodified
+ ;; buffer
(setq node-string
- (cond
- (undo-tree-visualizer-timestamps
- (undo-tree-timestamp-to-string
- (undo-tree-node-timestamp node)
- undo-tree-visualizer-relative-timestamps
- current register))
- (current "x")
- (register (char-to-string register))
- (t "o")))
-
- (cond
- (current
- (let ((undo-tree-insert-face
- (cons 'undo-tree-visualizer-current-face
- (and (boundp 'undo-tree-insert-face)
- (or (and (consp undo-tree-insert-face)
- undo-tree-insert-face)
- (list undo-tree-insert-face))))))
- (undo-tree-insert node-string)))
- (register
- (let ((undo-tree-insert-face
- (cons 'undo-tree-visualizer-register-face
- (and (boundp 'undo-tree-insert-face)
- (or (and (consp undo-tree-insert-face)
- undo-tree-insert-face)
- (list undo-tree-insert-face))))))
- (undo-tree-insert node-string)))
- (t (undo-tree-insert node-string)))
-
- (backward-char (if undo-tree-visualizer-timestamps
- (1+ (/ undo-tree-visualizer-spacing 2))
- 1))
+ (cond
+ (undo-tree-visualizer-timestamps
+ (undo-tree-timestamp-to-string
+ (undo-tree-node-timestamp node)
+ undo-tree-visualizer-relative-timestamps
+ current register))
+ (register (char-to-string register))
+ (unmodified "s")
+ (current "x")
+ (t "o"))
+ undo-tree-insert-face
+ (nconc
+ (cond
+ (current '(undo-tree-visualizer-current-face))
+ (unmodified '(undo-tree-visualizer-unmodified-face))
+ (register '(undo-tree-visualizer-register-face)))
+ undo-tree-insert-face))
+ ;; draw node and link it to its representation in visualizer
+ (undo-tree-insert node-string)
+ (undo-tree-move-backward (if undo-tree-visualizer-timestamps
+ (1+ (/ undo-tree-visualizer-spacing 2))
+ 1))
(move-marker (undo-tree-node-marker node) (point))
(put-text-property (point) (1+ (point)) 'undo-tree-node node)))
(defun undo-tree-draw-subtree (node &optional active-branch)
;; Draw subtree rooted at NODE. The subtree will start from point.
- ;; If ACTIVE-BRANCH is non-nil, just draw active branch below NODE.
- ;; If TIMESTAP is non-nil, draw time-stamps instead of "o" at nodes.
+ ;; If ACTIVE-BRANCH is non-nil, just draw active branch below NODE. Returns
+ ;; list of nodes below NODE.
(let ((num-children (length (undo-tree-node-next node)))
node-list pos trunk-pos n)
;; draw node itself
@@ -3185,10 +3453,10 @@
((= num-children 1)
(undo-tree-move-down 1)
(undo-tree-insert ?|)
- (backward-char 1)
+ (undo-tree-move-backward 1)
(undo-tree-move-down 1)
(undo-tree-insert ?|)
- (backward-char 1)
+ (undo-tree-move-backward 1)
(undo-tree-move-down 1)
(setq n (car (undo-tree-node-next node)))
;; link next node to its representation in visualizer
@@ -3199,18 +3467,18 @@
;; add next node to list of nodes to draw next
(push n node-list))
- ;; if node had multiple children, draw branches
+ ;; if node has multiple children, draw branches
(t
(undo-tree-move-down 1)
(undo-tree-insert ?|)
- (backward-char 1)
- (setq trunk-pos (point))
+ (undo-tree-move-backward 1)
+ (move-marker (setq trunk-pos (make-marker)) (point))
;; left subtrees
- (backward-char
+ (undo-tree-move-backward
(- (undo-tree-node-char-lwidth node)
(undo-tree-node-char-lwidth
(car (undo-tree-node-next node)))))
- (setq pos (point))
+ (move-marker (setq pos (make-marker)) (point))
(setq n (cons nil (undo-tree-node-next node)))
(dotimes (i (/ num-children 2))
(setq n (cdr n))
@@ -3224,7 +3492,7 @@
(undo-tree-move-forward 1)
(undo-tree-move-down 1)
(undo-tree-insert ?/)
- (backward-char 2)
+ (undo-tree-move-backward 2)
(undo-tree-move-down 1)
;; link node to its representation in visualizer
(unless (markerp (undo-tree-node-marker (car n)))
@@ -3238,7 +3506,7 @@
(+ (undo-tree-node-char-rwidth (car n))
(undo-tree-node-char-lwidth (cadr n))
undo-tree-visualizer-spacing 1))
- (setq pos (point)))
+ (move-marker pos (point)))
;; middle subtree (only when number of children is odd)
(when (= (mod num-children 2) 1)
(setq n (cdr n))
@@ -3248,7 +3516,7 @@
(undo-tree-node-next node))))
(undo-tree-move-down 1)
(undo-tree-insert ?|)
- (backward-char 1)
+ (undo-tree-move-backward 1)
(undo-tree-move-down 1)
;; link node to its representation in visualizer
(unless (markerp (undo-tree-node-marker (car n)))
@@ -3262,9 +3530,9 @@
(+ (undo-tree-node-char-rwidth (car n))
(if (cadr n) (undo-tree-node-char-lwidth (cadr n)) 0)
undo-tree-visualizer-spacing 1))
- (setq pos (point)))
+ (move-marker pos (point)))
;; right subtrees
- (incf trunk-pos)
+ (move-marker trunk-pos (1+ trunk-pos))
(dotimes (i (/ num-children 2))
(setq n (cdr n))
(when (or (null active-branch)
@@ -3274,7 +3542,7 @@
(goto-char trunk-pos)
(undo-tree-insert ?_ (- pos trunk-pos 1))
(goto-char pos)
- (backward-char 1)
+ (undo-tree-move-backward 1)
(undo-tree-move-down 1)
(undo-tree-insert ?\\)
(undo-tree-move-down 1)
@@ -3291,13 +3559,12 @@
(+ (undo-tree-node-char-rwidth (car n))
(if (cadr n) (undo-tree-node-char-lwidth (cadr n)) 0)
undo-tree-visualizer-spacing 1))
- (setq pos (point))))
+ (move-marker pos (point))))
))
;; return list of nodes to draw next
(nreverse node-list)))
-
(defun undo-tree-node-char-lwidth (node)
;; Return left-width of NODE measured in characters.
(if (= (length (undo-tree-node-next node)) 0) 0
@@ -3328,7 +3595,7 @@
;; delete region instead of single char if transient-mark-mode is enabled
(setq mark-active nil)
(backward-delete-char arg)
- (when (boundp 'undo-tree-insert-face)
+ (when undo-tree-insert-face
(put-text-property (- (point) arg) (point) 'face undo-tree-insert-face)))
@@ -3342,18 +3609,99 @@
(setq line (line-number-at-pos))
;; if buffer doesn't have enough lines, add some
(when (/= line (+ row arg))
- (insert (make-string (- arg (- line row)) ?\n)))
+ (cond
+ ((< arg 0)
+ (insert (make-string (- line row arg) ?\n))
+ (forward-line (+ arg (- row line))))
+ (t (insert (make-string (- arg (- line row)) ?\n)))))
(undo-tree-move-forward col)))
+(defun undo-tree-move-up (&optional arg)
+ ;; Move up, extending buffer if necessary.
+ (unless arg (setq arg 1))
+ (undo-tree-move-down (- arg)))
+
+
(defun undo-tree-move-forward (&optional arg)
;; Move forward, extending buffer if necessary.
(unless arg (setq arg 1))
- (let ((n (- (line-end-position) (point))))
- (if (> n arg)
- (forward-char arg)
- (end-of-line)
- (insert (make-string (- arg n) ? )))))
+ (let (n)
+ (cond
+ ((>= arg 0)
+ (setq n (- (line-end-position) (point)))
+ (if (> n arg)
+ (forward-char arg)
+ (end-of-line)
+ (insert (make-string (- arg n) ? ))))
+ ((< arg 0)
+ (setq arg (- arg))
+ (setq n (- (point) (line-beginning-position)))
+ (when (< (- n 2) arg) ; -2 to create left-margin
+ ;; no space left - shift entire buffer contents right!
+ (let ((pos (move-marker (make-marker) (point))))
+ (set-marker-insertion-type pos t)
+ (goto-char (point-min))
+ (while (not (eobp))
+ (insert-before-markers (make-string (- arg -2 n) ? ))
+ (forward-line 1))
+ (goto-char pos)))
+ (backward-char arg)))))
+
+
+(defun undo-tree-move-backward (&optional arg)
+ ;; Move backward, extending buffer if necessary.
+ (unless arg (setq arg 1))
+ (undo-tree-move-forward (- arg)))
+
+
+(defun undo-tree-move-to-parent (node)
+ ;; Move to position of parent of NODE, extending buffer if necessary.
+ (let* ((parent (undo-tree-node-previous node))
+ (n (undo-tree-node-next parent))
+ (l (length n)) p)
+ (goto-char (undo-tree-node-marker node))
+ (unless (= l 1)
+ ;; move horizontally
+ (setq p (undo-tree-position node n))
+ (cond
+ ;; node in centre subtree: no horizontal movement
+ ((and (= (mod l 2) 1) (= p (/ l 2))))
+ ;; node in left subtree: move right
+ ((< p (/ l 2))
+ (setq n (nthcdr p n))
+ (undo-tree-move-forward
+ (+ (undo-tree-node-char-rwidth (car n))
+ (/ undo-tree-visualizer-spacing 2) 1))
+ (dotimes (i (- (/ l 2) p 1))
+ (setq n (cdr n))
+ (undo-tree-move-forward
+ (+ (undo-tree-node-char-lwidth (car n))
+ (undo-tree-node-char-rwidth (car n))
+ undo-tree-visualizer-spacing 1)))
+ (when (= (mod l 2) 1)
+ (setq n (cdr n))
+ (undo-tree-move-forward
+ (+ (undo-tree-node-char-lwidth (car n))
+ (/ undo-tree-visualizer-spacing 2) 1))))
+ (t ;; node in right subtree: move left
+ (setq n (nthcdr (/ l 2) n))
+ (when (= (mod l 2) 1)
+ (undo-tree-move-backward
+ (+ (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)))
+ (undo-tree-move-backward
+ (+ (undo-tree-node-char-lwidth (car n))
+ (undo-tree-node-char-rwidth (car n))
+ undo-tree-visualizer-spacing 1))
+ (setq n (cdr n)))
+ (undo-tree-move-backward
+ (+ (undo-tree-node-char-lwidth (car n))
+ (/ undo-tree-visualizer-spacing 2) 1)))))
+ ;; move vertically
+ (undo-tree-move-up 3)))
(defun undo-tree-timestamp-to-string
@@ -3401,9 +3749,9 @@
-
+
;;; =====================================================================
-;;; Visualizer mode commands
+;;; Visualizer commands
(defun undo-tree-visualizer-mode ()
"Major mode used in undo-tree visualizer.
@@ -3432,34 +3780,51 @@
(defun undo-tree-visualize-undo (&optional arg)
"Undo changes. A numeric ARG serves as a repeat count."
(interactive "p")
- (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face)
- (inhibit-read-only t))
- (undo-tree-draw-node (undo-tree-current buffer-undo-tree)))
- (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer)
- (deactivate-mark)
- (unwind-protect
- (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-undo arg))
- (switch-to-buffer-other-window undo-tree-visualizer-buffer-name)
- (let ((inhibit-read-only t))
- (undo-tree-draw-node (undo-tree-current buffer-undo-tree) 'current))
- (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff))))
+ (let ((old (undo-tree-current buffer-undo-tree))
+ current)
+ ;; unhighlight old current node
+ (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face)
+ (inhibit-read-only t))
+ (undo-tree-draw-node old))
+ ;; undo in parent buffer
+ (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer)
+ (deactivate-mark)
+ (unwind-protect
+ (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-undo-1 arg))
+ (setq current (undo-tree-current buffer-undo-tree))
+ (switch-to-buffer-other-window undo-tree-visualizer-buffer-name)
+ ;; when using lazy drawing, extend tree upwards as required
+ (when undo-tree-visualizer-lazy-drawing
+ (undo-tree-expand-up old current))
+ ;; highlight new current node
+ (let ((inhibit-read-only t)) (undo-tree-draw-node current 'current))
+ ;; update diff display, if any
+ (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff)))))
(defun undo-tree-visualize-redo (&optional arg)
"Redo changes. A numeric ARG serves as a repeat count."
(interactive "p")
- (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face)
- (inhibit-read-only t))
- (undo-tree-draw-node (undo-tree-current buffer-undo-tree)))
- (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer)
- (deactivate-mark)
- (unwind-protect
- (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-redo arg))
- (switch-to-buffer-other-window undo-tree-visualizer-buffer-name)
- (goto-char (undo-tree-node-marker (undo-tree-current buffer-undo-tree)))
- (let ((inhibit-read-only t))
- (undo-tree-draw-node (undo-tree-current buffer-undo-tree) 'current))
- (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff))))
+ (let ((old (undo-tree-current buffer-undo-tree))
+ current)
+ ;; unhighlight old current node
+ (let ((undo-tree-insert-face 'undo-tree-visualizer-active-branch-face)
+ (inhibit-read-only t))
+ (undo-tree-draw-node (undo-tree-current buffer-undo-tree)))
+ ;; redo in parent buffer
+ (switch-to-buffer-other-window undo-tree-visualizer-parent-buffer)
+ (deactivate-mark)
+ (unwind-protect
+ (let ((undo-tree-inhibit-kill-visualizer t)) (undo-tree-redo-1 arg))
+ (setq current (undo-tree-current buffer-undo-tree))
+ (switch-to-buffer-other-window undo-tree-visualizer-buffer-name)
+ ;; when using lazy drawing, extend tree downwards as required
+ (when undo-tree-visualizer-lazy-drawing
+ (undo-tree-expand-down old current))
+ ;; highlight new current node
+ (let ((inhibit-read-only t)) (undo-tree-draw-node current 'current))
+ ;; update diff display, if any
+ (when undo-tree-visualizer-diff (undo-tree-visualizer-update-diff)))))
(defun undo-tree-visualize-switch-branch-right (arg)
@@ -3549,6 +3914,77 @@
(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 'branch, undo to last branch point. If X is 'register,
+undo to last register. If X is 'saved, undo to last saved state.
+
+Interactively, a single \\[universal-argument] specifies
+`branch', a double \\[universal-argument] \[universal-argument]
+spcified `saved', and a negative prefix argument specifies
+`register'."
+ (interactive "P")
+ (when (and (called-interactively-p 'any) x)
+ (setq x (prefix-numeric-value x)
+ x (cond
+ ((< x 0) 'register)
+ ((<= x 4) 'branch)
+ (t 'saved))))
+ (let ((current (undo-tree-current buffer-undo-tree))
+ r)
+ (while (and (undo-tree-node-previous current)
+ (or (undo-tree-visualize-undo) t)
+ (setq current (undo-tree-current buffer-undo-tree))
+ ;; branch point
+ (not (or (and (or (null x) (eq x 'branch))
+ (> (undo-tree-num-branches) 1))
+ ;; register
+ (and (or (null x) (eq x 'register))
+ (setq r (undo-tree-node-register current))
+ (undo-tree-register-data-p
+ (setq r (registerv-data (get-register r))))
+ (eq current (undo-tree-register-data-node r)))
+ ;; saved state
+ (and (or (null x) (eq x 'saved))
+ (undo-tree-node-unmodified-p current))
+ ))))))
+
+
+(defun undo-tree-visualize-redo-to-x (&optional x)
+ "Redo to next branch point or register.
+If X is the symbol `branch', redo to next branch point ignoring
+registers. If X is the symbol 'register', redo to next register,
+ignoring branch points.
+
+Interactively, a positive prefix argument specifies `branch', and
+a negative prefix argument specifies `register'."
+ (interactive "P")
+ (when (and (called-interactively-p 'any) x)
+ (setq x (prefix-numeric-value x)
+ x (cond
+ ((< x 0) 'register)
+ ((<= x 4) 'branch)
+ (t 'saved))))
+ (let ((current (undo-tree-current buffer-undo-tree))
+ r)
+ (while (and (undo-tree-node-next current)
+ (or (undo-tree-visualize-redo) t)
+ (setq current (undo-tree-current buffer-undo-tree))
+ ;; branch point
+ (not (or (and (or (null x) (eq x 'branch))
+ (> (undo-tree-num-branches) 1))
+ ;; register
+ (and (or (null x) (eq x 'register))
+ (setq r (undo-tree-node-register current))
+ (undo-tree-register-data-p
+ (setq r (registerv-data (get-register r))))
+ (eq current (undo-tree-register-data-node r)))
+ ;; saved state
+ (and (or (null x) (eq x 'saved))
+ (undo-tree-node-unmodified-p current))
+ ))))))
+
+
(defun undo-tree-visualizer-toggle-timestamps ()
"Toggle display of time-stamps."
(interactive)
@@ -3560,16 +3996,54 @@
(defun undo-tree-visualizer-scroll-left (&optional arg)
(interactive "p")
+ (scroll-left (or arg 1) t))
+
+
+(defun undo-tree-visualizer-scroll-right (&optional arg)
+ (interactive "p")
(scroll-right (or arg 1) t))
-(defun undo-tree-visualizer-scroll-right (&optional arg)
- (interactive "p")
- (scroll-left (or arg 1) t))
-
-
-
-
+(defun undo-tree-visualizer-scroll-up (&optional arg)
+ (interactive "P")
+ (if (or (and (numberp arg) (< arg 0)) (eq arg '-))
+ (undo-tree-visualizer-scroll-down arg)
+ ;; scroll up and expand newly-visible portion of tree
+ (unwind-protect
+ (scroll-up-command arg)
+ (undo-tree-expand-down
+ (nth (undo-tree-node-branch (undo-tree-current buffer-undo-tree))
+ (undo-tree-node-next (undo-tree-current buffer-undo-tree)))))
+ ;; signal error if at eob
+ (when (and (not undo-tree-visualizer-needs-extending-down) (eobp))
+ (scroll-up))))
+
+
+(defun undo-tree-visualizer-scroll-down (&optional arg)
+ (interactive "P")
+ (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
+ (let ((scroll-lines
+ (or arg (- (window-height) next-screen-context-lines)))
+ (window-line (1- (line-number-at-pos (window-start)))))
+ (when (and undo-tree-visualizer-needs-extending-up
+ (< window-line scroll-lines))
+ (let ((inhibit-read-only t))
+ (goto-char (point-min))
+ (undo-tree-move-up (- scroll-lines window-line)))))
+ ;; scroll down and expand newly-visible portion of tree
+ (unwind-protect
+ (scroll-down-command arg)
+ (undo-tree-expand-up
+ (undo-tree-node-previous (undo-tree-current buffer-undo-tree))))
+ ;; signal error if at bob
+ (when (and (not undo-tree-visualizer-needs-extending-down) (bobp))
+ (scroll-down))))
+
+
+
+
;;; =====================================================================
;;; Visualizer selection mode
@@ -3597,10 +4071,15 @@
(dotimes (i arg)
(unless (undo-tree-node-previous node) (throw 'top t))
(setq node (undo-tree-node-previous node))))
- (goto-char (undo-tree-node-marker node))
+ ;; when using lazy drawing, extend tree upwards as required
+ (when undo-tree-visualizer-lazy-drawing
+ (undo-tree-expand-up undo-tree-visualizer-selected-node node))
+ ;; update diff display, if any
(when (and undo-tree-visualizer-diff
(not (eq node undo-tree-visualizer-selected-node)))
(undo-tree-visualizer-update-diff node))
+ ;; move to selected node
+ (goto-char (undo-tree-node-marker node))
(setq undo-tree-visualizer-selected-node node)))
@@ -3614,10 +4093,15 @@
(throw 'bottom t))
(setq node
(nth (undo-tree-node-branch node) (undo-tree-node-next node)))))
- (goto-char (undo-tree-node-marker node))
+ ;; when using lazy drawing, extend tree upwards as required
+ (when undo-tree-visualizer-lazy-drawing
+ (undo-tree-expand-down undo-tree-visualizer-selected-node node))
+ ;; update diff display, if any
(when (and undo-tree-visualizer-diff
(not (eq node undo-tree-visualizer-selected-node)))
(undo-tree-visualizer-update-diff node))
+ ;; move to selected node
+ (goto-char (undo-tree-node-marker node))
(setq undo-tree-visualizer-selected-node node)))
@@ -3639,7 +4123,7 @@
(when (and undo-tree-visualizer-diff node
(not (eq node undo-tree-visualizer-selected-node)))
(undo-tree-visualizer-update-diff node))
- (setq undo-tree-visualizer-selected-node node)))
+ (when node (setq undo-tree-visualizer-selected-node node))))
(defun undo-tree-visualizer-select-left (&optional arg)
@@ -3660,10 +4144,10 @@
(when (and undo-tree-visualizer-diff node
(not (eq node undo-tree-visualizer-selected-node)))
(undo-tree-visualizer-update-diff node))
- (setq undo-tree-visualizer-selected-node node)))
-
-
-
+ (when node (setq undo-tree-visualizer-selected-node node))))
+
+
+
;;; =====================================================================
;;; Visualizer diff display
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [ELPA-diffs] /srv/bzr/emacs/elpa r320: Update undo-tree to version 0.6.3,
Toby S. Cubitt <=