]> git.eshelyaron.com Git - emacs.git/commitdiff
Improve support of property repeat-continue-only in repeat-mode (bug#74140)
authorJuri Linkov <juri@linkov.net>
Tue, 17 Dec 2024 18:45:42 +0000 (20:45 +0200)
committerEshel Yaron <me@eshelyaron.com>
Mon, 23 Dec 2024 15:11:54 +0000 (16:11 +0100)
* lisp/repeat.el (repeat-get-map): Add optional arg 'rep-map'.
Move the check for 'repeat-continue-only' from 'repeat-pre-hook'.
Improve its logic to check if the current map 'repeat-in-progress'
exists in the list from the 'repeat-continue-only' property.
(repeat-post-hook): Set 'repeat-in-progress' to the symbol
from the property 'repeat-map'.

* test/lisp/repeat-tests.el (repeat-tests-another-repeat-map):
Add new keymap to test multiple parallel repeat-maps.
(repeat-tests-continue-another): New test that uses commands
from 'repeat-tests-another-repeat-map' shared with
'repeat-tests-repeat-map'.

(cherry picked from commit 9232c985ef3d874755b0cbf4399fcc7077c308b5)

lisp/repeat.el
test/lisp/repeat-tests.el

index cea54b75868d7f059b09cc8ae56856751fdf9adf..a0e4ae6bafb975b7844f4c56f45fb85e5329f127 100644 (file)
@@ -451,10 +451,17 @@ See `describe-repeat-maps' for a list of all repeatable commands."
       (and (symbolp real-this-command)
            (get real-this-command property))))
 
-(defun repeat-get-map ()
+(defun repeat-get-map (&optional rep-map)
   "Return a transient map for keys repeatable after the current command."
   (when repeat-mode
-    (let ((rep-map (or repeat-map (repeat--command-property 'repeat-map))))
+    (let ((rep-map (or rep-map repeat-map (repeat--command-property 'repeat-map)))
+          (continue-only (repeat--command-property 'repeat-continue-only)))
+      (when continue-only
+        (if repeat-in-progress
+            (when (and (consp continue-only)
+                       (memq repeat-in-progress continue-only))
+              (setq rep-map repeat-in-progress))
+          (setq rep-map nil)))
       (when rep-map
         (when (and (symbolp rep-map) (boundp rep-map))
           (setq rep-map (symbol-value rep-map)))
@@ -500,37 +507,32 @@ See `describe-repeat-maps' for a list of all repeatable commands."
 
 (defun repeat-post-hook ()
   "Function run after commands to set transient keymap for repeatable keys."
-  (let ((was-in-progress repeat-in-progress))
+  (let* ((was-in-progress repeat-in-progress)
+         (map-sym (or repeat-map (repeat--command-property 'repeat-map)))
+         (map (repeat-get-map map-sym)))
     (setq repeat-in-progress nil)
-    (let ((map (repeat-get-map)))
-      (when (and (repeat-check-map map)
-                 (let ((continue-only (repeat--command-property 'repeat-continue-only)))
-                   (or (null continue-only)
-                       (and (or (not (consp continue-only))
-                                (memq (repeat--command-property 'repeat-map)
-                                      continue-only))
-                            was-in-progress))))
-        ;; Messaging
-        (funcall repeat-echo-function map)
-
-        ;; Adding an exit key
-        (when repeat-exit-key
-          (setq map (copy-keymap map))
-          (define-key map (if (key-valid-p repeat-exit-key)
-                              (kbd repeat-exit-key)
-                            repeat-exit-key)
-                      'ignore))
-
-        (setq repeat-in-progress t)
-        (repeat--clear-prev)
-        (let ((exitfun (set-transient-map map)))
-          (setq repeat--transient-exitfun exitfun)
-
-          (let* ((prop (repeat--command-property 'repeat-exit-timeout))
-                 (timeout (unless (eq prop 'no) (or prop repeat-exit-timeout))))
-            (when timeout
-              (setq repeat-exit-timer
-                    (run-with-idle-timer timeout nil #'repeat-exit)))))))
+    (when (repeat-check-map map)
+      ;; Messaging
+      (funcall repeat-echo-function map)
+
+      ;; Adding an exit key
+      (when repeat-exit-key
+        (setq map (copy-keymap map))
+        (define-key map (if (key-valid-p repeat-exit-key)
+                            (kbd repeat-exit-key)
+                          repeat-exit-key)
+                    'ignore))
+
+      (setq repeat-in-progress map-sym)
+      (repeat--clear-prev)
+      (let ((exitfun (set-transient-map map)))
+        (setq repeat--transient-exitfun exitfun)
+
+        (let* ((prop (repeat--command-property 'repeat-exit-timeout))
+               (timeout (unless (eq prop 'no) (or prop repeat-exit-timeout))))
+          (when timeout
+            (setq repeat-exit-timer
+                  (run-with-idle-timer timeout nil #'repeat-exit))))))
 
     (setq repeat-map nil)
     (setq repeat--prev-mb
index d69d431146a2d565cd23bbbf7358956b2637353c..4039a84c4d390e5d3e65572d9ebaf2cede28c357 100644 (file)
@@ -24,8 +24,8 @@
 (require 'ert)
 (require 'repeat)
 
-;; Key mnemonics: a - Activate (enter, also b), c - Continue (also d),
-;;                o - continue-Only (not activate), q - Quit (exit)
+;; Key mnemonics: a - Activate (enter, also b, s), c - Continue (also d, t),
+;;                o - continue-Only (not activate, also u), q - Quit (exit)
 
 (defvar repeat-tests-calls nil)
 
   (interactive "p")
   (push `(,arg q) repeat-tests-calls))
 
+(defun repeat-tests-call-s (&optional arg)
+  (interactive "p")
+  (push `(,arg s) repeat-tests-calls))
+
+(defun repeat-tests-call-t (&optional arg)
+  (interactive "p")
+  (push `(,arg t) repeat-tests-calls))
+
+(defun repeat-tests-call-u (&optional arg)
+  (interactive "p")
+  (push `(,arg u) repeat-tests-calls))
+
 ;; Global keybindings
-(defvar-keymap repeat-tests-map
+(defvar-keymap repeat-tests-global-map
   :doc "Keymap for keys that initiate repeating sequences."
   "C-x w a" 'repeat-tests-call-a
   "C-M-a"   'repeat-tests-call-a
   "C-M-b"   'repeat-tests-call-b
-  "C-M-o"   'repeat-tests-call-o)
+  "C-M-o"   'repeat-tests-call-o
+  "C-M-s"   'repeat-tests-call-s
+  "C-M-u"   'repeat-tests-call-u)
+
+(defvar-keymap repeat-tests-another-repeat-map
+  :doc "Keymap for repeating other sequences."
+  :repeat ( :enter         (repeat-tests-call-s)
+            :continue-only (repeat-tests-call-o
+                            repeat-tests-call-u))
+  "s"     'ignore ;; for non-nil repeat-check-key only
+  "t"     'repeat-tests-call-t
+  "C-M-o" 'repeat-tests-call-o
+  "C-M-u" 'repeat-tests-call-u)
 
 (defvar-keymap repeat-tests-repeat-map
   :doc "Keymap for repeating sequences."
   (should (equal (buffer-string) inserted)))
 
 (ert-deftest repeat-tests-check-key ()
-  (with-repeat-mode repeat-tests-map
+  (with-repeat-mode repeat-tests-global-map
     (let ((repeat-echo-function 'ignore))
       (let ((repeat-check-key t))
         (repeat-tests--check
           (put 'repeat-tests-call-b 'repeat-check-key nil))))))
 
 (ert-deftest repeat-tests-exit-command ()
-  (with-repeat-mode repeat-tests-map
+  (with-repeat-mode repeat-tests-global-map
     (let ((repeat-echo-function 'ignore))
       ;; 'c' doesn't continue since 'q' exited
       (repeat-tests--check
        '((1 a) (1 c) (1 d) (1 q)) "c"))))
 
 (ert-deftest repeat-tests-exit-key ()
-  (with-repeat-mode repeat-tests-map
+  (with-repeat-mode repeat-tests-global-map
     (let ((repeat-echo-function 'ignore))
       (let ((repeat-exit-key nil))
         (repeat-tests--check
          '((1 a) (1 c) (1 d) (1 c)) "z")))))
 
 (ert-deftest repeat-tests-keep-prefix ()
-  (with-repeat-mode repeat-tests-map
+  (with-repeat-mode repeat-tests-global-map
     (let ((repeat-echo-function 'ignore))
       (repeat-tests--check
        "C-x w a c d c z"
 ;; TODO: :tags '(:expensive-test)  for repeat-exit-timeout
 
 (ert-deftest repeat-tests-continue-only ()
-  (with-repeat-mode repeat-tests-map
+  (with-repeat-mode repeat-tests-global-map
     (let ((repeat-echo-function 'ignore)
           (repeat-check-key nil))
       ;; 'C-M-o' used as continue-only
        "C-M-o c z"
        '((1 o)) "cz"))))
 
+(ert-deftest repeat-tests-continue-another ()
+  (with-repeat-mode repeat-tests-global-map
+    (let ((repeat-echo-function 'ignore)
+          (repeat-check-key nil))
+      ;; First test without 'C-M-O'
+      (repeat-tests--check
+       "C-M-s t t z"
+       '((1 s) (1 t) (1 t)) "z")
+      ;; 'C-M-u' used as continue-only
+      (repeat-tests--check
+       "C-M-s t C-M-u t z"
+       '((1 s) (1 t) (1 u) (1 t)) "z")
+      ;; 'C-M-u' should not activate
+      (repeat-tests--check
+       "C-M-u t z"
+       '((1 u)) "tz")
+      ;; 'C-M-o' shared with another map should continue current map
+      (repeat-tests--check
+       "C-M-s t C-M-o t C-M-o t z"
+       '((1 s) (1 t) (1 o) (1 t) (1 o) (1 t)) "z"))))
+
 \f
 (require 'use-package)