Support a new ["..."] key binding syntax

* doc/lispref/keymaps.texi (Key Sequences):
(Changing Key Bindings): Document the various key syntaxes.

* lisp/emacs-lisp/byte-opt.el (byte-optimize-define-key)
(byte-optimize-define-keymap)
(byte-optimize-define-keymap--define): New functions to check and
expand ["..."] syntax at compile time.

* src/keymap.c (Fdefine_key): Understand the ["..."] syntax.
(syms_of_keymap): Define `kbd' symbols.
This commit is contained in:
Lars Ingebrigtsen 2021-10-17 20:48:01 +02:00
parent 8122501fca
commit e36d3fc452
4 changed files with 142 additions and 22 deletions

View file

@ -1186,6 +1186,67 @@ See Info node `(elisp) Integer Basics'."
(put 'concat 'byte-optimizer #'byte-optimize-concat)
(defun byte-optimize-define-key (form)
"Expand key bindings in FORM."
(let ((key (nth 2 form)))
(if (and (vectorp key)
(= (length key) 1)
(stringp (aref key 0)))
;; We have key on the form ["C-c C-c"].
(if (not (kbd-valid-p (aref key 0)))
(error "Invalid `kbd' syntax: %S" key)
(list (nth 0 form) (nth 1 form)
(kbd (aref key 0)) (nth 4 form)))
;; No improvement.
form)))
(put 'define-key 'byte-optimizer #'byte-optimize-define-key)
(defun byte-optimize-define-keymap (form)
"Expand key bindings in FORM."
(let ((result nil)
(orig-form form)
improved)
(push (pop form) result)
(while (and form
(keywordp (car form))
(not (eq (car form) :menu)))
(push (pop form) result)
(when (null form)
(error "Uneven number of keywords in %S" form))
(push (pop form) result))
;; Bindings.
(while form
(let ((key (pop form)))
(if (and (vectorp key)
(= (length key) 1)
(stringp (aref key 0)))
(progn
(unless (kbd-valid-p (aref key 0))
(error "Invalid `kbd' syntax: %S" key))
(push (kbd (aref key 0)) result)
(setq improved t))
;; No improvement.
(push key result)))
(when (null form)
(error "Uneven number of key bindings in %S" form))
(push (pop form) result))
(if improved
(nreverse result)
orig-form)))
(defun byte-optimize-define-keymap--define (form)
"Expand key bindings in FORM."
(let ((optimized (byte-optimize-define-keymap (nth 1 form))))
(if (eq optimized (nth 1 form))
;; No improvement.
form
(list (car form) optimized))))
(put 'define-keymap 'byte-optimizer #'byte-optimize-define-keymap)
(put 'define-keymap--define 'byte-optimizer
#'byte-optimize-define-keymap--define)
;; I'm not convinced that this is necessary. Doesn't the optimizer loop
;; take care of this? - Jamie
;; I think this may some times be necessary to reduce ie (quote 5) to 5,