* lisp/repeat.el: Fix long-standing problem when a random key activates map
* lisp/repeat.el (repeat-check-key): New defcustom (bug#51390). (repeat--command-property): New internal function. (repeat-check-key): New function. (repeat-post-hook): Use repeat--command-property and repeat-check-key. * test/lisp/repeat-tests.el (repeat-tests-check-key): New test.
This commit is contained in:
parent
ef4954b69c
commit
ea5a90b4f4
2 changed files with 69 additions and 9 deletions
|
@ -360,6 +360,24 @@ of the specified number of seconds."
|
|||
:group 'convenience
|
||||
:version "28.1")
|
||||
|
||||
(defcustom repeat-check-key t
|
||||
"Whether to check that the last key exists in the repeat map.
|
||||
When non-nil and the last typed key (with or without modifiers)
|
||||
doesn't exist in the keymap attached by the `repeat-map' property,
|
||||
then don't activate that keymap for the next command. So only the
|
||||
same keys among repeatable keys are allowed in the repeating sequence.
|
||||
For example, with a non-nil value, only `C-x u u' repeats undo,
|
||||
whereas `C-/ u' doesn't.
|
||||
|
||||
You can also set the property `repeat-check-key' on the command symbol.
|
||||
This property can override the value of this variable.
|
||||
When the variable value is non-nil, but the property value is `no',
|
||||
then don't check the last key. Also when the variable value is nil,
|
||||
but the property value is `t', then check the last key."
|
||||
:type 'boolean
|
||||
:group 'convenience
|
||||
:version "28.1")
|
||||
|
||||
(defcustom repeat-echo-function #'repeat-echo-message
|
||||
"Function to display a hint about available keys.
|
||||
Function is called after every repeatable command with one argument:
|
||||
|
@ -405,16 +423,26 @@ See `describe-repeat-maps' for a list of all repeatable commands."
|
|||
(defvar repeat--prev-mb '(0)
|
||||
"Previous minibuffer state.")
|
||||
|
||||
(defun repeat--command-property (property)
|
||||
(or (and (symbolp this-command)
|
||||
(get this-command property))
|
||||
(and (symbolp real-this-command)
|
||||
(get real-this-command property))))
|
||||
|
||||
(defun repeat-check-key (key map)
|
||||
"Check if the last key is suitable to activate the repeating MAP."
|
||||
(let ((property (repeat--command-property 'repeat-check-key)))
|
||||
(or (if repeat-check-key (eq property 'no) (not (eq property t)))
|
||||
(lookup-key map (vector key))
|
||||
;; Try without modifiers:
|
||||
(lookup-key map (vector (event-basic-type key))))))
|
||||
|
||||
(defun repeat-post-hook ()
|
||||
"Function run after commands to set transient keymap for repeatable keys."
|
||||
(let ((was-in-progress repeat-in-progress))
|
||||
(setq repeat-in-progress nil)
|
||||
(when repeat-mode
|
||||
(let ((rep-map (or repeat-map
|
||||
(and (symbolp this-command)
|
||||
(get this-command 'repeat-map))
|
||||
(and (symbolp real-this-command)
|
||||
(get real-this-command 'repeat-map)))))
|
||||
(let ((rep-map (or repeat-map (repeat--command-property 'repeat-map))))
|
||||
(when rep-map
|
||||
(when (and (symbolp rep-map) (boundp rep-map))
|
||||
(setq rep-map (symbol-value rep-map)))
|
||||
|
@ -426,10 +454,8 @@ See `describe-repeat-maps' for a list of all repeatable commands."
|
|||
;; in the middle of repeating sequence (bug#47566).
|
||||
(or (< (minibuffer-depth) (car repeat--prev-mb))
|
||||
(eq current-minibuffer-command (cdr repeat--prev-mb)))
|
||||
;; Exit when the last char is not among repeatable keys,
|
||||
;; so e.g. `C-x u u' repeats undo, whereas `C-/ u' doesn't.
|
||||
(or (lookup-key map (this-command-keys-vector))
|
||||
prefix-arg))
|
||||
(or (not repeat-keep-prefix) prefix-arg)
|
||||
(repeat-check-key last-command-event map))
|
||||
|
||||
;; Messaging
|
||||
(unless prefix-arg
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
(defvar repeat-tests-map
|
||||
(let ((map (make-sparse-keymap)))
|
||||
(define-key map (kbd "C-x w a") 'repeat-tests-call-a)
|
||||
(define-key map (kbd "M-C-a") 'repeat-tests-call-a)
|
||||
(define-key map (kbd "M-C-z") 'repeat-tests-call-a)
|
||||
map)
|
||||
"Keymap for keys that initiate repeating sequences.")
|
||||
|
||||
|
@ -70,6 +72,38 @@
|
|||
;; Check for self-inserting keys
|
||||
(should (equal (buffer-string) inserted)))
|
||||
|
||||
(ert-deftest repeat-tests-check-key ()
|
||||
(with-repeat-mode
|
||||
(let ((repeat-echo-function 'ignore))
|
||||
(let ((repeat-check-key t))
|
||||
(repeat-tests--check
|
||||
"C-x w a b a c"
|
||||
'((1 a) (1 b) (1 a)) "c")
|
||||
(repeat-tests--check
|
||||
"M-C-a b a c"
|
||||
'((1 a) (1 b) (1 a)) "c")
|
||||
(repeat-tests--check
|
||||
"M-C-z b a c"
|
||||
'((1 a)) "bac")
|
||||
(unwind-protect
|
||||
(progn
|
||||
(put 'repeat-tests-call-a 'repeat-check-key 'no)
|
||||
(repeat-tests--check
|
||||
"M-C-z b a c"
|
||||
'((1 a) (1 b) (1 a)) "c"))
|
||||
(put 'repeat-tests-call-a 'repeat-check-key nil)))
|
||||
(let ((repeat-check-key nil))
|
||||
(repeat-tests--check
|
||||
"M-C-z b a c"
|
||||
'((1 a) (1 b) (1 a)) "c")
|
||||
(unwind-protect
|
||||
(progn
|
||||
(put 'repeat-tests-call-a 'repeat-check-key t)
|
||||
(repeat-tests--check
|
||||
"M-C-z b a c"
|
||||
'((1 a)) "bac"))
|
||||
(put 'repeat-tests-call-a 'repeat-check-key nil))))))
|
||||
|
||||
(ert-deftest repeat-tests-exit-key ()
|
||||
(with-repeat-mode
|
||||
(let ((repeat-echo-function 'ignore))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue