diff --git a/lisp/doom-keybinds.el b/lisp/doom-keybinds.el index 0cc6e4841..3f4532515 100644 --- a/lisp/doom-keybinds.el +++ b/lisp/doom-keybinds.el @@ -25,6 +25,11 @@ and Emacs states, and for non-evil users.") (defvar doom-leader-map (make-sparse-keymap) "An overriding keymap for keys.") +(defvar doom-localleader-map-alist nil + "An alist mapping major modes to their localleader keymaps.") + +(defvar doom-localleader-map (make-sparse-keymap) + "The current major mode's localleader keymap.") ;; ;;; Global keybind settings @@ -93,20 +98,19 @@ all hooks after it are ignored.") (defun doom/escape (&optional interactive) "Run `doom-escape-hook'." (interactive (list 'interactive)) - (let ((inhibit-quit t)) - (cond ((minibuffer-window-active-p (minibuffer-window)) - ;; quit the minibuffer if open. + (cond ((minibuffer-window-active-p (minibuffer-window)) + ;; quit the minibuffer if open. + (when interactive + (setq this-command 'abort-recursive-edit)) + (abort-recursive-edit)) + ;; Run all escape hooks. If any returns non-nil, then stop there. + ((run-hook-with-args-until-success 'doom-escape-hook)) + ;; don't abort macros + ((or defining-kbd-macro executing-kbd-macro) nil) + ;; Back to the default + ((unwind-protect (keyboard-quit) (when interactive - (setq this-command 'abort-recursive-edit)) - (abort-recursive-edit)) - ;; Run all escape hooks. If any returns non-nil, then stop there. - ((run-hook-with-args-until-success 'doom-escape-hook)) - ;; don't abort macros - ((or defining-kbd-macro executing-kbd-macro) nil) - ;; Back to the default - ((unwind-protect (keyboard-quit) - (when interactive - (setq this-command 'keyboard-quit))))))) + (setq this-command 'keyboard-quit)))))) (global-set-key [remap keyboard-quit] #'doom/escape) @@ -146,11 +150,8 @@ all hooks after it are ignored.") forms)) (when-let (desc (cadr (memq :which-key udef))) (prependq! - wkforms `((which-key-add-key-based-replacements - (general--concat t doom-leader-alt-key ,key) - ,desc) - (which-key-add-key-based-replacements - (general--concat t doom-leader-key ,key) + wkforms `((which-key-add-keymap-based-replacements doom-leader-map + ,key ,desc)))))))) (macroexp-progn (append (and wkforms `((after! which-key ,@(nreverse wkforms)))) @@ -169,6 +170,43 @@ See `doom-leader-key' and `doom-leader-alt-key' to change the leader prefix." :keymaps 'doom-leader-map ,@args)) +(defmacro doom--define-localleader-leader-key (&rest keys) + (let ((modes (cl-mapcar #'general--remove-map + (doom-unquote (progn (pop keys) (pop keys))))) + prefix forms wkforms result) + (macroexp-progn (dolist (mode modes result) + (unless (keymapp (alist-get mode doom-localleader-map-alist)) + (setf (alist-get mode doom-localleader-map-alist) + (make-sparse-keymap))) + (let ((keys keys)) + (while keys + (let ((key (pop keys)) + (def (pop keys))) + (if (keywordp key) + (when (memq key '(:prefix :infix)) + (setq prefix def)) + (when prefix + (setq key `(general--concat t ,prefix ,key))) + (let* ((udef (cdr-safe (doom-unquote def))) + (bdef (if (general--extended-def-p udef) + (general--extract-def (general--normalize-extended-def udef)) + def))) + (unless (eq bdef :ignore) + (push `(define-key + (alist-get ',mode doom-localleader-map-alist) + (general--kbd ,key) + ,bdef) + forms)) + (when-let (desc (cadr (memq :which-key udef))) + (prependq! + wkforms `((which-key-add-keymap-based-replacements + (alist-get ',mode doom-localleader-map-alist) + ,key + ,desc)))))))) + (prependq! result + (append (and wkforms `((after! which-key ,@(nreverse wkforms)))) + (nreverse forms)))))))) + (defmacro define-localleader-key! (&rest args) "Define key. @@ -196,8 +234,17 @@ localleader prefix." ;; :prefix/:non-normal-prefix properties because general is incredibly slow ;; binding keys en mass with them in conjunction with :states -- an effective ;; doubling of Doom's startup time! -(define-prefix-command 'doom/leader 'doom-leader-map) (define-key doom-leader-map [override-state] 'all) +(define-prefix-command 'doom-leader-map) +(define-prefix-command 'doom-localleader-map) +(fset 'doom/leader doom-leader-map) ; For backwards compatibility. + +(defun doom-update-localleader-key-h () + "Set the localleader keys for the current major-mode." + (set-keymap-parent doom-localleader-map + (cdr (assq major-mode doom-localleader-map-alist)))) + +(add-hook 'post-command-hook #'doom-update-localleader-key-h) ;; Bind `doom-leader-key' and `doom-leader-alt-key' as late as possible to give ;; the user a chance to modify them. @@ -211,9 +258,12 @@ localleader prefix." (set-keymap-parent doom-leader-map mode-specific-map)) ((equal doom-leader-alt-key "C-x") (set-keymap-parent doom-leader-map ctl-x-map))) - (define-key map (kbd doom-leader-alt-key) 'doom/leader)) - (evil-define-key* '(normal visual motion) map (kbd doom-leader-key) 'doom/leader) - (evil-define-key* '(emacs insert) map (kbd doom-leader-alt-key) 'doom/leader)) + (define-key map (kbd doom-leader-alt-key) #'doom-leader-map) + (define-key map (kbd doom-localleader-alt-key) #'doom-localleader-map)) + (evil-define-key* '(normal visual motion) map (kbd doom-leader-key) #'doom-leader-map) + (evil-define-key* '(emacs insert) map (kbd doom-leader-alt-key) #'doom-leader-map) + (evil-define-key* '(normal visual motion) map (kbd doom-localleader-key) #'doom-localleader-map) + (evil-define-key* '(emacs insert) map (kbd doom-localleader-alt-key) #'doom-localleader-map)) (general-override-mode +1)))) @@ -284,7 +334,6 @@ For example, :nvi will map to (list 'normal 'visual 'insert). See (let ((key (pop rest))) (cond ((listp key) (doom--map-nested nil key)) - ((keywordp key) (pcase key (:leader @@ -292,7 +341,7 @@ For example, :nvi will map to (list 'normal 'visual 'insert). See (setq doom--map-fn 'doom--define-leader-key)) (:localleader (doom--map-commit) - (setq doom--map-fn 'define-localleader-key!)) + (setq doom--map-fn 'doom--define-localleader-leader-key)) (:after (doom--map-nested (list 'after! (pop rest)) rest) (setq rest nil)) @@ -318,6 +367,8 @@ For example, :nvi will map to (list 'normal 'visual 'insert). See :prefix prefix) rest)) (push `(defvar ,keymap (make-sparse-keymap)) + doom--map-forms) + (push `(define-prefix-command ',keymap) doom--map-forms)))) (:prefix (cl-destructuring-bind (prefix . desc)