]> git.eshelyaron.com Git - emacs.git/commitdiff
* lisp/simple.el (undo-redo): New command
authorStefan Monnier <monnier@iro.umontreal.ca>
Sun, 9 Feb 2020 03:06:41 +0000 (22:06 -0500)
committerStefan Monnier <monnier@iro.umontreal.ca>
Sun, 9 Feb 2020 03:06:41 +0000 (22:06 -0500)
(undo--last-change-was-undo-p): New function.

* test/lisp/simple-tests.el (simple-tests--exec): New function.
(simple-tests--undo): New test.

doc/emacs/fixit.texi
etc/NEWS
lisp/simple.el
test/lisp/simple-tests.el

index 3665faf3a8f411486d1d2f9a10da2834f3b4ca29..69a476c5d164b17d2db23f5c2a06901eec5a5dc8 100644 (file)
@@ -66,6 +66,7 @@ changes have already been undone, the undo command signals an error.
 
 @cindex redo
 @findex undo-only
+@findex undo-redo
   Any command other than an undo command breaks the sequence of undo
 commands.  Starting from that moment, the entire sequence of undo
 commands that you have just performed are themselves placed into the
@@ -77,6 +78,8 @@ undo commands.
   Alternatively, if you want to resume undoing, without redoing
 previous undo commands, use @kbd{M-x undo-only}.  This is like
 @code{undo}, but will not redo changes you have just undone.
+To complement it @kbd{M-x undo-redo} will undo previous undo commands
+(and will not record itself as an undoable command).
 
   If you notice that a buffer has been modified accidentally, the
 easiest way to recover is to type @kbd{C-/} repeatedly until the stars
index 55c1a47fbfb3d8091fde6e1a713b011c304e7e6b..7b358ff271555b22f4bf7b63410827ff43ea0ed5 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -73,6 +73,9 @@ dimension.
 \f
 * Editing Changes in Emacs 28.1
 
++++
+** New command 'undo-redo'
+
 +++
 ** 'read-number' now has its own history variable.
 Additionally, the function now accepts a HIST argument which can be
index 09447900ded9a2f1f6aa79b8c5a531d16e301a8c..8efba57c4d0ece3c2e110e0719451a7e4ab05660 100644 (file)
@@ -2662,6 +2662,30 @@ Contrary to `undo', this will not redo a previous undo."
   (interactive "*p")
   (let ((undo-no-redo t)) (undo arg)))
 
+(defun undo--last-change-was-undo-p (undo-list)
+  (while (and (consp undo-list) (eq (car undo-list) nil))
+    (setq undo-list (cdr undo-list)))
+  (gethash undo-list undo-equiv-table))
+
+(defun undo-redo (&optional arg)
+  "Undo the last ARG undos."
+  (interactive "*p")
+  (cond
+   ((not (undo--last-change-was-undo-p buffer-undo-list))
+    (user-error "No undo to undo"))
+   (t
+    (let* ((ul buffer-undo-list)
+           (new-ul
+            (let ((undo-in-progress t))
+              (while (and (consp ul) (eq (car ul) nil))
+                (setq ul (cdr ul)))
+              (primitive-undo arg ul)))
+           (new-pul (undo--last-change-was-undo-p new-ul)))
+      (message "Redo%s" (if undo-in-region " in region" ""))
+      (setq this-command 'undo)
+      (setq pending-undo-list new-pul)
+      (setq buffer-undo-list new-ul)))))
+
 (defvar undo-in-progress nil
   "Non-nil while performing an undo.
 Some change-hooks test this variable to do something different.")
index ae201465678bcfe15f4e275b9844d3d42ecca0f7..eb3b0296ea8726e6c9fffd4b62a901149b1d0f43 100644 (file)
@@ -392,6 +392,48 @@ See bug#35036."
       (should (equal ?\s (char-syntax ?\n))))))
 
 \f
+;;; undo tests
+
+(defun simple-tests--exec (cmds)
+  (dolist (cmd cmds)
+    (setq last-command this-command)
+    (setq this-command cmd)
+    (run-hooks 'pre-command-hook)
+    (command-execute cmd)
+    (run-hooks 'post-command-hook)
+    (undo-boundary)))
+
+(ert-deftest simple-tests--undo ()
+  (with-temp-buffer
+    (buffer-enable-undo)
+    (dolist (x '("a" "b" "c" "d" "e"))
+      (insert x)
+      (undo-boundary))
+    (should (equal (buffer-string) "abcde"))
+    (simple-tests--exec '(undo undo))
+    (should (equal (buffer-string) "abc"))
+    (simple-tests--exec '(backward-char undo))
+    (should (equal (buffer-string) "abcd"))
+    (simple-tests--exec '(undo))
+    (should (equal (buffer-string) "abcde"))
+    (simple-tests--exec '(backward-char undo undo))
+    (should (equal (buffer-string) "abc"))
+    (simple-tests--exec '(backward-char undo-redo))
+    (should (equal (buffer-string) "abcd"))
+    (simple-tests--exec '(undo))
+    (should (equal (buffer-string) "abc"))
+    (simple-tests--exec '(backward-char undo-redo undo-redo))
+    (should (equal (buffer-string) "abcde"))
+    (simple-tests--exec '(undo undo))
+    (should (equal (buffer-string) "abc"))
+    (simple-tests--exec '(backward-char undo-only undo-only))
+    (should (equal (buffer-string) "a"))
+    (simple-tests--exec '(backward-char undo-redo undo-redo))
+    (should (equal (buffer-string) "abc"))
+    (simple-tests--exec '(backward-char undo-redo undo-redo))
+    (should (equal (buffer-string) "abcde"))
+    ))
+
 ;;; undo auto-boundary tests
 (ert-deftest undo-auto-boundary-timer ()
   (should