Commit 2645ae12 authored by Stefan Monnier's avatar Stefan Monnier

* lisp/simple.el (undo-redo): New command

(undo--last-change-was-undo-p): New function.

* test/lisp/simple-tests.el (simple-tests--exec): New function.
(simple-tests--undo): New test.
parent fe903c5a
Pipeline #4767 passed with stage
in 53 minutes and 33 seconds
......@@ -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
......
......@@ -73,6 +73,9 @@ dimension.
* 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
......
......@@ -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.")
......
......@@ -392,6 +392,48 @@ See bug#35036."
(should (equal ?\s (char-syntax ?\n))))))
;;; 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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment