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

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

[nongnu] elpa/evil 8a3ac25680: Fix evil-with-undo/evil-undo-pop with und


From: ELPA Syncer
Subject: [nongnu] elpa/evil 8a3ac25680: Fix evil-with-undo/evil-undo-pop with undo-tree
Date: Sat, 7 Jan 2023 15:58:58 -0500 (EST)

branch: elpa/evil
commit 8a3ac256804a4786bd8adbf6a3f6925162e2722f
Author: Toby S. Cubitt <tsc25@cantab.net>
Commit: Axel Forsman <axelsfor@gmail.com>

    Fix evil-with-undo/evil-undo-pop with undo-tree
    
    Addresses #1074
    
    - evil-with-undo:
      nconc'ing onto front of buffer-undo-list here can corrupt buffer-undo-list
      when in undo-tree-mode in rare circumstances (see issue #1074). Leave
      standard undo machinery to work as usual when undo is enabled. Deal with
      disabled undo by temporarily enabling then disabling undo, and 
transferring
      any undo changes to evil-temporary-undo.
    
    - evil-undo-pop:
      This function called `undo' directly from Elisp, which is wrong when in
      undo-tree-mode. Fix this by calling undo-tree-undo instead when in
      undo-tree-mode.
    
    Co-authored-by: Axel Forsman <axelsfor@gmail.com>
---
 evil-common.el | 69 ++++++++++++++++++++++++++++++++++------------------------
 1 file changed, 40 insertions(+), 29 deletions(-)

diff --git a/evil-common.el b/evil-common.el
index ae03ae8b90..a9d511f257 100644
--- a/evil-common.el
+++ b/evil-common.el
@@ -3629,6 +3629,14 @@ If no description is available, return the empty string."
 
 ;;; Undo
 
+(defvar buffer-undo-tree)
+(declare-function undo-tree-current "ext:undo-tree")
+(declare-function undo-tree-node-next "ext:undo-tree")
+(declare-function undo-tree-node-branch "ext:undo-tree")
+(declare-function undo-tree-node-branch "ext:undo-tree")
+(declare-function undo-tree-undo "ext:undo-tree")
+(declare-function undo-tree-snip-node "ext:undo-tree")
+
 (defun evil-start-undo-step (&optional continue)
   "Start a undo step.
 All following buffer modifications are grouped together as a
@@ -3667,46 +3675,49 @@ make the entries undoable as a single action. See
   "Execute BODY with enabled undo.
 If undo is disabled in the current buffer, the undo information
 is stored in `evil-temporary-undo' instead of `buffer-undo-list'."
-  (declare (indent defun)
-           (debug t))
-  `(unwind-protect
-       (let (buffer-undo-list)
-         (unwind-protect
-             (progn ,@body)
-           (setq evil-temporary-undo buffer-undo-list)
-           ;; ensure evil-temporary-undo starts with exactly one undo
-           ;; boundary marker, i.e. nil
-           (unless (null (car-safe evil-temporary-undo))
-             (push nil evil-temporary-undo))))
-     (unless (eq buffer-undo-list t)
-       ;; undo is enabled, so update the global buffer undo list
-       (setq buffer-undo-list
-             ;; prepend new undos (if there are any)
-             (if (cdr evil-temporary-undo)
-                 (nconc evil-temporary-undo buffer-undo-list)
-               buffer-undo-list)
-             evil-temporary-undo nil))))
+  (declare (debug t))
+  (let ((undo-list (make-symbol "undo-list")))
+    `(let ((,undo-list buffer-undo-list)
+           (evil-undo-system evil-undo-system))
+       (when (eq ,undo-list t) (setq buffer-undo-list nil
+                                     evil-undo-system nil))
+       (unwind-protect
+           (progn ,@body)
+         ;; ensure any new undo changes we've accumulated start with
+         ;; exactly one undo boundary marker, i.e. nil
+         (when (car-safe buffer-undo-list) (push nil buffer-undo-list))
+         (if (eq ,undo-list t)
+             ;; undo is disabled, so store undo information in
+             ;; evil-temporary-undo
+             (setq evil-temporary-undo buffer-undo-list
+                   buffer-undo-list t)
+           (setq evil-temporary-undo nil))))))
 
 (defmacro evil-with-single-undo (&rest body)
   "Execute BODY as a single undo step."
-  (declare (indent defun)
-           (debug t))
+  (declare (debug t))
   `(let (evil-undo-list-pointer)
      (evil-with-undo
+       (evil-start-undo-step)
        (unwind-protect
-           (progn
-             (evil-start-undo-step)
-             (let ((evil-in-single-undo t))
-               ,@body))
+           (let ((evil-in-single-undo t)) ,@body)
          (evil-end-undo-step)))))
 
 (defun evil-undo-pop ()
-  "Undo the last buffer change.
-Removes the last undo information from `buffer-undo-list'.
+  "Undo and forget the last buffer change.
 If undo is disabled in the current buffer, use the information
 in `evil-temporary-undo' instead."
-  (let ((paste-undo (list nil)))
-    (let ((undo-list (if (eq buffer-undo-list t)
+  (if (and (eq evil-undo-system 'undo-tree)
+           (not (eq buffer-undo-list t)))
+      (let (current)
+        (undo-tree-undo)
+        (setq current (undo-tree-current buffer-undo-tree)
+              current (nth (undo-tree-node-branch current)
+                           (undo-tree-node-next current)))
+        ;; Remove only if leaf to not have to adjust child buffer positions
+        (unless (undo-tree-node-next current) (undo-tree-snip-node current)))
+    (let ((paste-undo (list nil))
+          (undo-list (if (eq buffer-undo-list t)
                          evil-temporary-undo
                        buffer-undo-list)))
       (when (or (not undo-list) (car undo-list))



reply via email to

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