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

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

[elpa] externals/undo-tree 79b382b 083/195: Fixed bug in undo-list-pop-c


From: Stefan Monnier
Subject: [elpa] externals/undo-tree 79b382b 083/195: Fixed bug in undo-list-pop-changeset when called with non-null DISCARD-POS.
Date: Sat, 28 Nov 2020 13:41:26 -0500 (EST)

branch: externals/undo-tree
commit 79b382b335aef29041f2312fc5747ed3534376af
Author: Toby S. Cubitt <toby-undo-tree@dr-qubit.org>
Commit: Toby S. Cubitt <toby-undo-tree@dr-qubit.org>

    Fixed bug in undo-list-pop-changeset when called with non-null DISCARD-POS.
    
    Through a subtle chain of consequences, this bug occasionally caused
    undo-tree-mode to lost large amounts of undo history:
    
    1. If undo-list-pop-changeset was called with non-null DISCARD-POS argument 
on
       a buffer-undo-list changeset whose final element was a point-motion entry
       (integer), it erroneously ate undo entries beyond the end of the 
changeset.
    
    2. If the changeset ending in a point-motion entry was the final one before
       the buffer-undo-list canary, or (probably) if there was an 
arbitrary-length
       sequence of such changesets before the canary, then this bug caused
       undo-list-pop-changeset to eat the canary too.
    
    3. With the canary missing (presumed dead), the next call to
       undo-list-transfer-to-tree would interpret this as a signal that Emacs 
had
       discarded undo history, so would throw away the entire undo tree, 
replacing
       it with a new tree containing only the current contents buffer-undo-list,
       thereby causing substantial loss of undo history.
    
    Thanks to Magnar Sveen for his sterling efforts in helping track this down!
---
 undo-tree.el | 16 ++++++++++------
 1 file changed, 10 insertions(+), 6 deletions(-)

diff --git a/undo-tree.el b/undo-tree.el
index ffa590b..db09227 100644
--- a/undo-tree.el
+++ b/undo-tree.el
@@ -610,6 +610,10 @@
 ;;   being discarded when switching major-mode
 ;; * added `undo-tree-enabled-undo-in-region' customization option to allow
 ;;   undo-in-region to be disabled.
+;; * fixed bug in `undo-list-pop-changeset' which, through a subtle chain of
+;;   consequences, occasionally caused undo-tree-mode to lose large amounts of
+;;   undo history (thanks to Magnar Sveen for his sterling efforts in helping
+;;   track this down!)
 ;;
 ;; Version 0.3.3;
 ;; * added `term-mode' to `undo-tree-incompatible-major-modes'
@@ -1374,17 +1378,17 @@ Comparison is done with `eq'."
   (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
-  (unless (eq (car buffer-undo-list) 'undo-tree-canary)
+  ;; 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)))
               (car buffer-undo-list))
-       ;; discard position entries at head of undo list
-       (when discard-pos
-         (while (and discard-pos (integerp (car buffer-undo-list)))
-           (setq buffer-undo-list (cdr buffer-undo-list))))
         (setcdr p (list (pop buffer-undo-list)))
        (setq p (cdr p)))
       changeset)))



reply via email to

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