Refactor & optimize define-leader-key!

- Provides a 10-30% boost in startup time
- which-key advice is no longer needed
This commit is contained in:
Henrik Lissner 2019-04-05 01:24:16 -04:00
parent 5cdb96888f
commit ea3d9e2957
No known key found for this signature in database
GPG Key ID: 5F6C0EA160557395

View File

@ -80,14 +80,35 @@ If any hook returns non-nil, all hooks after it are ignored.")
(defalias 'define-key! #'general-def) (defalias 'define-key! #'general-def)
(defalias 'unmap! #'general-unbind) (defalias 'unmap! #'general-unbind)
;; We avoid `general-create-definer' to ensure that :states, :wk-full-keys and ;; A `define-leader-key' defined with `general-create-definer' consumes 20-30%
;; :keymaps cannot be overwritten. ;; of Doom's startup time, we reimplement it ourselves.
(defmacro define-leader-key! (&rest args) (defmacro define-leader-key! (&rest keys)
`(general-define-key "Define a leader key on `doom-leader-key'."
:states nil (let (prefix forms wkforms)
:wk-full-keys nil (while keys
:keymaps 'doom-leader-map (let ((key (pop keys))
,@args)) (def (pop keys)))
(if (keywordp key)
(when (memq key '(:prefix :infix))
(setq prefix def))
(let ((unquoted-def (cdr-safe (doom-unquote def))))
(when prefix
(setq key `(general--concat t ,prefix ,key)))
(when-let* ((desc (plist-get unquoted-def :which-key)))
(push `(which-key-add-key-based-replacements
(general--concat t doom-leader-key ,key)
,desc)
wkforms))
(push `(define-key doom-leader-map (general--kbd ,key)
,(if (general--extended-def-p unquoted-def)
(plist-get unquoted-def :def)
def))
forms)))))
(macroexp-progn
(append (nreverse forms)
(when wkforms
`((eval-after-load 'which-key
(lambda () ,@(nreverse wkforms)))))))))
(general-create-definer define-localleader-key! (general-create-definer define-localleader-key!
:major-modes t :major-modes t
@ -124,68 +145,12 @@ If any hook returns non-nil, all hooks after it are ignored.")
(concat "\\(?:" (concat "\\(?:"
(cl-loop for key in (append (list doom-leader-key doom-leader-alt-key) (cl-loop for key in (append (list doom-leader-key doom-leader-alt-key)
(where-is-internal 'doom/leader)) (where-is-internal 'doom/leader))
if (stringp key) collect (regexp-quote key) into keys for keystr = (if (stringp key) key (key-description key))
else collect (regexp-quote (key-description key)) into keys collect (regexp-quote keystr) into keys
finally return (string-join keys "\\|")) finally return (string-join keys "\\|"))
"\\)")))) "\\)"))))
(add-hook 'doom-after-init-modules-hook #'doom|init-leader-keys) (add-hook 'doom-after-init-modules-hook #'doom|init-leader-keys)
;; However, the prefix command approach (along with :wk-full-keys in
;; `define-leader-key!') means that which-key is only informed of the key
;; sequence minus `doom-leader-key'/`doom-leader-alt-key'. e.g. binding to `SPC
;; f s' creates a wildcard label for any key that ends in 'f s'.
;;
;; So we forcibly inject `doom-leader-key' and `doom-leader-alt-key' into the
;; which-key key replacement regexp for keybinds created on `doom-leader-map'.
;; This is a dirty hack, but I'd rather this than general being responsible for
;; 50% of Doom's startup time.
(defun doom*general-extended-def-:which-key (_state keymap key edef kargs)
(with-eval-after-load 'which-key
(let* ((wk (general--getf2 edef :which-key :wk))
(major-modes (general--getf edef kargs :major-modes))
(keymaps (plist-get kargs :keymaps))
;; index of keymap in :keymaps
(keymap-index (cl-dotimes (ind (length keymaps))
(when (eq (nth ind keymaps) keymap)
(cl-return ind))))
(mode (let ((mode (if (and major-modes (listp major-modes))
(nth keymap-index major-modes)
major-modes)))
(if (eq mode t)
(general--remove-map keymap)
mode)))
(key (key-description key))
(key-regexp (concat (if (general--getf edef kargs :wk-full-keys)
"\\`"
;; Modification begin
(if (memq 'doom-leader-map keymaps)
(concat "\\`" doom-which-key-leader-prefix-regexp " ")))
;; Modification end
(regexp-quote key)
"\\'"))
(prefix (plist-get kargs :prefix))
(binding (or (when (and (plist-get edef :def)
(not (plist-get edef :keymp)))
(plist-get edef :def))
(when (and prefix (string= key prefix))
(plist-get kargs :prefix-command))))
(replacement (cond ((stringp wk)
(cons nil wk))
(wk)))
(match/replacement
(cons
(cons (when (general--getf edef kargs :wk-match-keys)
key-regexp)
(when (and (general--getf edef kargs :wk-match-binding)
binding
(symbolp binding))
(symbol-name binding)))
replacement)))
(general--add-which-key-replacement mode match/replacement)
(when (and (consp replacement) (not (functionp replacement)))
(general--add-which-key-title-prefix mode key (cdr replacement))))))
(advice-add #'general-extended-def-:which-key :override #'doom*general-extended-def-:which-key)
;; ;;
;;; Packages ;;; Packages