branch: externals/cursor-undo
commit e82084c3d491ff7199e14cc8da69c250b9bda492
Author: Luke Lee <luke@gauss>
Commit: Luke Lee <luke@gauss>

    Fix read-only buffer undo operations on end of undo list
    
    (cundo-is-cursor-undo-entry, cundo-is-undo-boundary): New functions
    for boundary conditions.
    (cundo-track-screen-start, undo): fix for cleaner code and boundary.
---
 cursor-undo.el | 48 +++++++++++++++++++++++++++++++++++-------------
 1 file changed, 35 insertions(+), 13 deletions(-)

diff --git a/cursor-undo.el b/cursor-undo.el
index cd10f20c46..12c5443cc7 100644
--- a/cursor-undo.el
+++ b/cursor-undo.el
@@ -5,7 +5,7 @@
 ;; Author:       Luke Lee <luke.yx....@gmail.com>
 ;; Maintainer:   Luke Lee <luke.yx....@gmail.com>
 ;; Keywords:     undo, cursor
-;; Version:      1.1.4
+;; Version:      1.1.5
 
 ;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
@@ -138,7 +138,7 @@
 (defun cundo-track-screen-start (prv-screen-start)
   (let ((entry (list 'apply 'cundo-restore-win prv-screen-start)))
     (if (eq buffer-undo-list 't)
-        (setq buffer-undo-list entry)
+        (setq buffer-undo-list (list entry))
       (push entry buffer-undo-list))))
 
 (defun cundo-track-prev-point (prev-point)
@@ -288,23 +288,45 @@ relative screen position (screen-pos=NIL) nor `point' 
position (no-move=t)."))
 ;;   then safely set `buffer-read-only' back to NIL and continue your
 ;;   editing.
 ;;
+
+(defun cundo-is-cursor-undo-entry (undolist)
+  (if (listp undolist)
+      (let ((uitem (if (null (car undolist))
+                       (cadr undolist)
+                     (car undolist))))
+        (or (numberp uitem) ;; point marker
+            ;; Cursor-undo created undo entry
+            (and (eq #'apply (nth 0 uitem))
+                 (eq #'cundo-restore-win (nth 1 uitem)))))
+    (eq undolist 't)))
+
+(defun cundo-is-undo-boundary ()
+  (let ((undolist (if (eq last-command 'undo)
+                      pending-undo-list
+                    buffer-undo-list)))
+    (if (listp undolist)
+        (equal '(apply cdr nil) ;; undo boundary
+               (if (null (car undolist))
+                   (cadr undolist)
+                 (car undolist)))
+      (eq undolist 't))))
+
 (define-advice undo (:around (orig-func &rest args)
                              undo-cursor-in-read-only-buffer)
   (interactive "P") ;; Change the behavior from "*P" to "P"
   (if (if (eq last-command 'undo)
           ;; last-command is undo, check pending undo list if the first command
-          ;; is cursor movement or not
-          (and (listp pending-undo-list)
-               (numberp (car pending-undo-list)))
+          ;; is a cursor movement or not
+          (cundo-is-cursor-undo-entry pending-undo-list)
         ;; not a continuous undo, check first command is cursor movement or not
-        (and (listp buffer-undo-list)
-             (null (car buffer-undo-list))
-             (numberp (cadr buffer-undo-list))))
-      (apply orig-func args)
-    (if buffer-read-only
-        (if (listp pending-undo-list)
-            (user-error "Buffer is read-only: cannot undo an editing command!")
-          (apply orig-func args))
+        (cundo-is-cursor-undo-entry buffer-undo-list))
+      ;; if it's a cursor undo, go `undo' regardless of read-only settings
+      (let ((buffer-read-only nil)) ;; temp dynamically binding
+        (apply orig-func args))
+    ;; Not cursor undo
+    (if (and buffer-read-only
+             (not (cundo-is-undo-boundary)))
+        (user-error "Buffer is read-only: cannot undo an editing command")
       (apply orig-func args))))
 
 ;;;

Reply via email to