From 2203246454fddd41e0a62e78b17befce561998b9 Mon Sep 17 00:00:00 2001 From: Hugo Heagren Date: Sun, 16 Jan 2022 00:21:36 +0000 Subject: bind-keys-form: new keyword :repeat-map, for defining repeat maps use-package-normalize/:bind: allow keyword :repeat-map. bind-keys-form: Add keyword :repeat-map. Specifying a symbol as the repeat-map defines a keymap with that name (and with the docstring `repeat-doc', if specified). Symbols for functions bound to keys under the scope of :repeat-map have their 'repeat-map property set to this map. Update docstring (and that of `bind-keys') to reflect changes. Rename `doc' to `prefix-doc' for clarity and consistency with 'repeat-doc'. --- lisp/use-package/bind-key.el | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'lisp/use-package/bind-key.el') diff --git a/lisp/use-package/bind-key.el b/lisp/use-package/bind-key.el index 1d611c2933c..bb09a6935a8 100644 --- a/lisp/use-package/bind-key.el +++ b/lisp/use-package/bind-key.el @@ -257,14 +257,22 @@ Accepts keyword arguments: for these bindings :prefix-docstring STR - docstring for the prefix-map variable :menu-name NAME - optional menu string for prefix map +:repeat-docstring STR - docstring for the repeat-map variable +:repeat-map MAP - name of the repeat map that should be created + for these bindings. If specified, the + 'repeat-map property of each command bound + (within the scope of the :repeat-map keyword) + is set to this map. :filter FORM - optional form to determine when bindings apply The rest of the arguments are conses of keybinding string and a function symbol (unquoted)." (let (map - doc + prefix-doc prefix-map prefix + repeat-map + repeat-doc filter menu-name pkg) @@ -276,11 +284,18 @@ function symbol (unquoted)." (not prefix-map)) (setq map (cadr args))) ((eq :prefix-docstring (car args)) - (setq doc (cadr args))) + (setq prefix-doc (cadr args))) ((and (eq :prefix-map (car args)) (not (memq map '(global-map override-global-map)))) (setq prefix-map (cadr args))) + ((eq :repeat-docstring (car args)) + (setq repeat-doc (cadr args))) + ((and (eq :repeat-map (car args)) + (not (memq map '(global-map + override-global-map)))) + (setq repeat-map (cadr args)) + (setq map repeat-map)) ((eq :prefix (car args)) (setq prefix (cadr args))) ((eq :filter (car args)) @@ -327,13 +342,16 @@ function symbol (unquoted)." (append (when prefix-map `((defvar ,prefix-map) - ,@(when doc `((put ',prefix-map 'variable-documentation ,doc))) + ,@(when prefix-doc `((put ',prefix-map 'variable-documentation ,prefix-doc))) ,@(if menu-name `((define-prefix-command ',prefix-map nil ,menu-name)) `((define-prefix-command ',prefix-map))) ,@(if (and map (not (eq map 'global-map))) (wrap map `((bind-key ,prefix ',prefix-map ,map ,filter))) `((bind-key ,prefix ',prefix-map nil ,filter))))) + (when repeat-map + `((defvar ,repeat-map (make-sparse-keymap) + ,@(when repeat-doc `(,repeat-doc))))) (wrap map (cl-mapcan (lambda (form) @@ -341,7 +359,11 @@ function symbol (unquoted)." (if prefix-map `((bind-key ,(car form) ,fun ,prefix-map ,filter)) (if (and map (not (eq map 'global-map))) - `((bind-key ,(car form) ,fun ,map ,filter)) + ;; Only needed in this branch, since when + ;; repeat-map is non-nil, map is always + ;; non-nil + `(,@(when repeat-map `((put ,fun 'repeat-map ',repeat-map))) + (bind-key ,(car form) ,fun ,map ,filter)) `((bind-key ,(car form) ,fun nil ,filter)))))) first)) (when next @@ -361,6 +383,12 @@ Accepts keyword arguments: for these bindings :prefix-docstring STR - docstring for the prefix-map variable :menu-name NAME - optional menu string for prefix map +:repeat-docstring STR - docstring for the repeat-map variable +:repeat-map MAP - name of the repeat map that should be created + for these bindings. If specified, the + 'repeat-map property of each command bound + (within the scope of the :repeat-map keyword) + is set to this map. :filter FORM - optional form to determine when bindings apply The rest of the arguments are conses of keybinding string and a -- cgit v1.2.3 From 5ef327ce9fc1397cdbbde8936eca37ae6383d787 Mon Sep 17 00:00:00 2001 From: Hugo Heagren Date: Mon, 17 Jan 2022 15:41:35 +0000 Subject: bind-key-form: allow :exit keyword inside repeat map Keys bound inside the scope of :exit are bound inside the repeat map, but do not have their repeat-map property set (so they run a function, but 'exit' the map). --- lisp/use-package/bind-key.el | 18 +++++++++++++++--- lisp/use-package/use-package-bind-key.el | 2 ++ 2 files changed, 17 insertions(+), 3 deletions(-) (limited to 'lisp/use-package/bind-key.el') diff --git a/lisp/use-package/bind-key.el b/lisp/use-package/bind-key.el index bb09a6935a8..a899aca0ffc 100644 --- a/lisp/use-package/bind-key.el +++ b/lisp/use-package/bind-key.el @@ -263,6 +263,9 @@ Accepts keyword arguments: 'repeat-map property of each command bound (within the scope of the :repeat-map keyword) is set to this map. +:exit BINDINGS - Within the scope of :repeat-map will bind the + key in the repeat map, but will not set the + 'repeat-map property of the bound command. :filter FORM - optional form to determine when bindings apply The rest of the arguments are conses of keybinding string and a @@ -273,12 +276,14 @@ function symbol (unquoted)." prefix repeat-map repeat-doc + repeat-type ;; Only used internally filter menu-name pkg) ;; Process any initial keyword arguments - (let ((cont t)) + (let ((cont t) + (arg-change-func 'cddr)) (while (and cont args) (if (cond ((and (eq :map (car args)) (not prefix-map)) @@ -296,6 +301,9 @@ function symbol (unquoted)." override-global-map)))) (setq repeat-map (cadr args)) (setq map repeat-map)) + ((eq :exit (car args)) + (setq repeat-type :exit + arg-change-func 'cdr)) ((eq :prefix (car args)) (setq prefix (cadr args))) ((eq :filter (car args)) @@ -304,7 +312,7 @@ function symbol (unquoted)." (setq menu-name (cadr args))) ((eq :package (car args)) (setq pkg (cadr args)))) - (setq args (cddr args)) + (setq args (funcall arg-change-func args)) (setq cont nil)))) (when (or (and prefix-map (not prefix)) @@ -362,7 +370,8 @@ function symbol (unquoted)." ;; Only needed in this branch, since when ;; repeat-map is non-nil, map is always ;; non-nil - `(,@(when repeat-map `((put ,fun 'repeat-map ',repeat-map))) + `(,@(when (and repeat-map (not (eq repeat-type :exit))) + `((put ,fun 'repeat-map ',repeat-map))) (bind-key ,(car form) ,fun ,map ,filter)) `((bind-key ,(car form) ,fun nil ,filter)))))) first)) @@ -389,6 +398,9 @@ Accepts keyword arguments: 'repeat-map property of each command bound (within the scope of the :repeat-map keyword) is set to this map. +:exit BINDINGS - Within the scope of :repeat-map will bind the + key in the repeat map, but will not set the + 'repeat-map property of the bound command. :filter FORM - optional form to determine when bindings apply The rest of the arguments are conses of keybinding string and a diff --git a/lisp/use-package/use-package-bind-key.el b/lisp/use-package/use-package-bind-key.el index d056d4266cc..73ea8ca83e0 100644 --- a/lisp/use-package/use-package-bind-key.el +++ b/lisp/use-package/use-package-bind-key.el @@ -91,11 +91,13 @@ deferred until the prefix key sequence is pressed." ;; :filter SEXP ;; :menu-name STRING ;; :package SYMBOL + ;; :exit used within :repeat-map ((or (and (eq x :map) (symbolp (cadr arg))) (and (eq x :prefix) (stringp (cadr arg))) (and (eq x :prefix-map) (symbolp (cadr arg))) (and (eq x :prefix-docstring) (stringp (cadr arg))) (and (eq x :repeat-map) (symbolp (cadr arg))) + (eq x :exit) (and (eq x :repeat-docstring) (stringp (cadr arg))) (eq x :filter) (and (eq x :menu-name) (stringp (cadr arg))) -- cgit v1.2.3 From c4bd2aa3b8094135c34c86893790f051cb5e1457 Mon Sep 17 00:00:00 2001 From: Hugo Heagren Date: Thu, 20 Jan 2022 10:59:37 +0000 Subject: bind-key-form: allow :continue keyword inside repeat map Purely syntactic sugar, using :continue is the same as not using any keyword inside :repeat-map at all. Amend end of function to pass repeat-map value onto next invocation in recursive uses. This allows for the same repeat map to be used for :exit and :continue. --- lisp/use-package/bind-key.el | 18 +++++++++++++++--- lisp/use-package/use-package-bind-key.el | 3 ++- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'lisp/use-package/bind-key.el') diff --git a/lisp/use-package/bind-key.el b/lisp/use-package/bind-key.el index a899aca0ffc..87a33e3d6ca 100644 --- a/lisp/use-package/bind-key.el +++ b/lisp/use-package/bind-key.el @@ -266,6 +266,10 @@ Accepts keyword arguments: :exit BINDINGS - Within the scope of :repeat-map will bind the key in the repeat map, but will not set the 'repeat-map property of the bound command. +:continue BINDINGS - Within the scope of :repeat-map forces the + same behaviour as if no special keyword had + been used (that is, the command is bound, and + it's 'repeat-map property set) :filter FORM - optional form to determine when bindings apply The rest of the arguments are conses of keybinding string and a @@ -301,6 +305,9 @@ function symbol (unquoted)." override-global-map)))) (setq repeat-map (cadr args)) (setq map repeat-map)) + ((eq :continue (car args)) + (setq repeat-type :continue + arg-change-func 'cdr)) ((eq :exit (car args)) (setq repeat-type :exit arg-change-func 'cdr)) @@ -376,9 +383,10 @@ function symbol (unquoted)." `((bind-key ,(car form) ,fun nil ,filter)))))) first)) (when next - (bind-keys-form (if pkg - (cons :package (cons pkg next)) - next) map))))))) + (bind-keys-form `(,@(when repeat-map `(:repeat-map ,repeat-map)) + ,@(if pkg + (cons :package (cons pkg next)) + next)) map))))))) ;;;###autoload (defmacro bind-keys (&rest args) @@ -401,6 +409,10 @@ Accepts keyword arguments: :exit BINDINGS - Within the scope of :repeat-map will bind the key in the repeat map, but will not set the 'repeat-map property of the bound command. +:continue BINDINGS - Within the scope of :repeat-map forces the + same behaviour as if no special keyword had + been used (that is, the command is bound, and + it's 'repeat-map property set) :filter FORM - optional form to determine when bindings apply The rest of the arguments are conses of keybinding string and a diff --git a/lisp/use-package/use-package-bind-key.el b/lisp/use-package/use-package-bind-key.el index 73ea8ca83e0..9642f311750 100644 --- a/lisp/use-package/use-package-bind-key.el +++ b/lisp/use-package/use-package-bind-key.el @@ -91,12 +91,13 @@ deferred until the prefix key sequence is pressed." ;; :filter SEXP ;; :menu-name STRING ;; :package SYMBOL - ;; :exit used within :repeat-map + ;; :continue and :exit are used within :repeat-map ((or (and (eq x :map) (symbolp (cadr arg))) (and (eq x :prefix) (stringp (cadr arg))) (and (eq x :prefix-map) (symbolp (cadr arg))) (and (eq x :prefix-docstring) (stringp (cadr arg))) (and (eq x :repeat-map) (symbolp (cadr arg))) + (eq x :continue) (eq x :exit) (and (eq x :repeat-docstring) (stringp (cadr arg))) (eq x :filter) -- cgit v1.2.3 From 1143f14d650c7201d7ddbcb7012dc2c9bf3b1824 Mon Sep 17 00:00:00 2001 From: Hugo Heagren Date: Fri, 28 Jan 2022 22:26:41 +0000 Subject: bind-keys-form: error for repeat sub-keywords without :repeat-map Error descriptively if :continue or :exit is specified without :repeat-map. --- lisp/use-package/bind-key.el | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lisp/use-package/bind-key.el') diff --git a/lisp/use-package/bind-key.el b/lisp/use-package/bind-key.el index 87a33e3d6ca..643094daa7f 100644 --- a/lisp/use-package/bind-key.el +++ b/lisp/use-package/bind-key.el @@ -326,6 +326,10 @@ function symbol (unquoted)." (and prefix (not prefix-map))) (error "Both :prefix-map and :prefix must be supplied")) + (when repeat-type + (unless repeat-map + (error ":continue and :exit require specifying :repeat-map"))) + (when (and menu-name (not prefix)) (error "If :menu-name is supplied, :prefix must be too")) -- cgit v1.2.3