From: Juri Linkov Date: Thu, 17 Nov 2022 07:25:42 +0000 (+0200) Subject: * lisp/keymap.el (defvar-keymap): Add support for repeat-mode. X-Git-Tag: emacs-29.0.90~1616^2~123 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=ddbc33343cca8c66d841cc16eac77ea626e50e23;p=emacs.git * lisp/keymap.el (defvar-keymap): Add support for repeat-mode. Put symbol properties 'repeat-map' on commands from the keymap when a ':repeat' keyword is non-nil. Also include/exclude commands according to ':repeat (:enter (commands ...) :exit (commands ...))'. https://lists.gnu.org/archive/html/emacs-devel/2022-11/msg00968.html --- diff --git a/etc/NEWS b/etc/NEWS index bb2bd52134e..47fc9f1e8e3 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -4075,6 +4075,10 @@ This function allows defining a number of keystrokes with one form. ** New macro 'defvar-keymap'. This macro allows defining keymap variables more conveniently. +** 'repeat-map' can be defined in the macro 'defvar-keymap'. +This is possible either by using ':repeat t' or more advanced +':repeat (:enter (commands ...) :exit (commands ...))'. + --- ** 'kbd' can now be used in built-in, preloaded libraries. It no longer depends on edmacro.el and cl-lib.el. diff --git a/lisp/keymap.el b/lisp/keymap.el index 107565590c1..953fb233cbc 100644 --- a/lisp/keymap.el +++ b/lisp/keymap.el @@ -559,22 +559,37 @@ In addition to the keywords accepted by `define-keymap', this macro also accepts a `:doc' keyword, which (if present) is used as the variable documentation string. -\(fn VARIABLE-NAME &key DOC FULL PARENT SUPPRESS NAME PREFIX KEYMAP &rest [KEY DEFINITION]...)" +When a `:repeat' keyword is non-nil, put `repeat-map' symbol +properties on commands in this map for `repeat-mode'. The value +could also be a property list with properties `:enter' and `:exit', +for example, :repeat (:enter (commands ...) :exit (commands ...)). +`:enter' is a list of additional commands that only enter `repeat-mode'. +When the list is empty then by default all commands in the map enter +`repeat-mode'. This is applicable when a command has the `repeat-map' +symbol property on its symbol, but doesn't exist in the map. `:exit' +is a list of commands that exit `repeat-mode'. When the list is +empty, no commands in the map exit `repeat-mode'. This is applicable +when a command exists in the map, but doesn't have the `repeat-map' +symbol property on its symbol. + +\(fn VARIABLE-NAME &key DOC FULL PARENT SUPPRESS NAME PREFIX KEYMAP REPEAT &rest [KEY DEFINITION]...)" (declare (indent 1)) (let ((opts nil) - doc) + doc repeat props) (while (and defs (keywordp (car defs)) (not (eq (car defs) :menu))) (let ((keyword (pop defs))) (unless defs (error "Uneven number of keywords")) - (if (eq keyword :doc) - (setq doc (pop defs)) - (push keyword opts) - (push (pop defs) opts)))) + (pcase keyword + (:doc (setq doc (pop defs))) + (:repeat (setq repeat (pop defs))) + (_ (push keyword opts) + (push (pop defs) opts))))) (unless (zerop (% (length defs) 2)) (error "Uneven number of key/definition pairs: %s" defs)) + (let ((defs defs) key seen-keys) (while defs @@ -585,9 +600,28 @@ as the variable documentation string. (error "Duplicate definition for key '%s' in keymap '%s'" key variable-name) (push key seen-keys))))) - `(defvar ,variable-name - (define-keymap ,@(nreverse opts) ,@defs) - ,@(and doc (list doc))))) + + (when repeat + (let ((defs defs) + def) + (dolist (def (plist-get repeat :enter)) + (push `(put ',def 'repeat-map ',variable-name) props)) + (while defs + (pop defs) + (setq def (pop defs)) + (when (and (memq (car def) '(function quote)) + (not (memq (cadr def) (plist-get repeat :exit)))) + (push `(put ,def 'repeat-map ',variable-name) props))))) + + (let ((defvar-form + `(defvar ,variable-name + (define-keymap ,@(nreverse opts) ,@defs) + ,@(and doc (list doc))))) + (if repeat + `(progn + ,defvar-form + ,@(nreverse props)) + defvar-form)))) (defun make-non-key-event (symbol) "Mark SYMBOL as an event that shouldn't be returned from `where-is'."