diff --git a/core/core-defuns.el b/core/core-defuns.el index c78d7812c..f1d29a8cc 100644 --- a/core/core-defuns.el +++ b/core/core-defuns.el @@ -193,13 +193,14 @@ Examples: (evil-ex-define-cmd cmd fn)) ;; Register keywords for proper indentation (see `map!') - (put ':prefix 'lisp-indent-function 'defun) - (put ':map 'lisp-indent-function 'defun) - (put ':after 'lisp-indent-function 'defun) - (put ':when 'lisp-indent-function 'defun) - (put ':unless 'lisp-indent-function 'defun) - (put ':leader 'lisp-indent-function 'defun) - (put ':localleader 'lisp-indent-function 'defun) + (put ':prefix 'lisp-indent-function 'defun) + (put ':map 'lisp-indent-function 'defun) + (put ':map* 'lisp-indent-function 'defun) + (put ':after 'lisp-indent-function 'defun) + (put ':when 'lisp-indent-function 'defun) + (put ':unless 'lisp-indent-function 'defun) + (put ':leader 'lisp-indent-function 'defun) + (put ':localleader 'lisp-indent-function 'defun) (defmacro map! (&rest rest) "A nightmare of a key-binding macro that will use `evil-define-key', @@ -207,6 +208,11 @@ Examples: plist key flags. It was designed to make binding multiple keys more concise, like in vim. +Yes, it tries to do too much. Yes, I only did it to make the \"frontend\" config +that little bit more concise. Yes, I could simply have used the above functions. +But it takes a little insanity to custom write your own emacs.d, so what else +were you expecting? + States :n normal :v visual @@ -215,19 +221,22 @@ States :o operator :m motion :r replace + :L local These can be combined (order doesn't matter), e.g. :nvi will apply to normal, visual and insert mode. The state resets after the following key=>def pair. + Capitalize the state flag to make it a local binding. + If omitted, the keybind will be defined globally. Flags - :unset [KEY] ; unset key - :nodefer ; don't use `evil-delay' for future keybinds - (:map [KEYMAP] [...]) ; apply all inner keybinds to KEYMAP - (:prefix [PREFIX] [...]) ; assign prefix to all inner keybindings - (:after [FEATURE] [...]) ; apply keybinds when [FEATURE] loads + :unset [KEY] ; unset key + (:map [KEYMAP] [...]) ; apply inner keybinds to KEYMAP + (:map* [KEYMAP] [...]) ; apply inner keybinds to KEYMAP (deferred) + (:prefix [PREFIX] [...]) ; assign prefix to all inner keybindings + (:after [FEATURE] [...]) ; apply keybinds when [FEATURE] loads Conditional keybinds (:when [CONDITION] [...]) @@ -242,8 +251,7 @@ Example (:when IS-MAC :n \"M-s\" 'some-fn :i \"M-o\" (lambda (interactive) (message \"Hi\"))))" - (let ((i 0) - (keymaps (if (boundp 'keymaps) keymaps)) + (let ((keymaps (if (boundp 'keymaps) keymaps)) (state-map '(("n" . normal) ("v" . visual) ("i" . insert) @@ -252,73 +260,89 @@ Example ("m" . motion) ("r" . replace))) (prefix (if (boundp 'prefix) prefix)) - (nodefer (if (boundp 'nodefer) nodefer)) - key def states forms) + (defer (if (boundp 'defer) defer)) + local key def states forms) (while rest (setq key (pop rest)) (push (reverse - (cond ((listp key) ; it's a sub exp - `(,(macroexpand `(map! ,@key)))) + (cond + ;; it's a sub expr + ((listp key) + `(,(macroexpand `(map! ,@key)))) - ((keywordp key) - (when (memq key '(:leader :localleader)) - (push (cond ((eq key :leader) - doom-leader) - ((eq key :localleader) - doom-localleader)) - rest) - (setq key :prefix)) - (pcase key - (:prefix (setq prefix (concat prefix (kbd (pop rest)))) nil) - (:map (setq keymaps (-list (pop rest))) nil) - (:nodefer (setq nodefer t) nil) - (:unset `(,(macroexpand `(map! ,(kbd (pop rest)) nil)))) - (:after (prog1 `((after! ,(pop rest) ,(macroexpand `(map! ,@rest)))) (setq rest '()))) - (:when (prog1 `((if ,(pop rest) ,(macroexpand `(map! ,@rest)))) (setq rest '()))) - (:unless (prog1 `((if (not ,(pop rest)) ,(macroexpand `(map! ,@rest)))) (setq rest '()))) - (otherwise ; might be a state prefix - (mapc (lambda (letter) - (cond ((assoc letter state-map) - (push (cdr (assoc letter state-map)) states)) - (t (user-error "Invalid mode prefix %s in key %s" letter key)))) - (split-string (substring (symbol-name key) 1) "" t)) - (unless states - (user-error "Unrecognized keyword %s" key)) nil))) + ;; it's a flag + ((keywordp key) + (when (memq key '(:leader :localleader)) + (push (cond ((eq key :leader) + doom-leader) + ((eq key :localleader) + doom-localleader)) + rest) + (setq key :prefix)) + (pcase key + (:prefix (setq prefix (concat prefix (kbd (pop rest)))) nil) + (:map (setq keymaps (-list (pop rest))) nil) + (:map* (setq defer t keymaps (-list (pop rest))) nil) + (:unset `(,(macroexpand `(map! ,(kbd (pop rest)) nil)))) + (:after (prog1 `((after! ,(pop rest) ,(macroexpand `(map! ,@rest)))) (setq rest '()))) + (:when (prog1 `((if ,(pop rest) ,(macroexpand `(map! ,@rest)))) (setq rest '()))) + (:unless (prog1 `((if (not ,(pop rest)) ,(macroexpand `(map! ,@rest)))) (setq rest '()))) + (otherwise ; might be a state prefix + (mapc (lambda (letter) + (cond ((assoc letter state-map) + (push (cdr (assoc letter state-map)) states)) + ((string= letter "L") + (setq local t)) + (t (user-error "Invalid mode prefix %s in key %s" letter key)))) + (split-string (substring (symbol-name key) 1) "" t)) + (unless states + (user-error "Unrecognized keyword %s" key)) + (when (assoc "L" states) + (cond ((= (length states) 1) + (user-error "local keybinding for %s must accompany another state" key)) + ((> (length keymaps) 0) + (user-error "local keybinding for %s cannot accompany a keymap" key)))) + nil))) - ;; It's a key-def pair - ((or (stringp key) - (characterp key) - (vectorp key)) - (when (stringp key) - (setq key (kbd key))) - (when prefix - (setq key (cond ((vectorp key) (vconcat prefix key)) - (t (concat prefix key))))) - (unless (> (length rest) 0) - (user-error "Map has no definition for %s" key)) - (setq def (pop rest)) - (let (out-forms) - (cond ((and keymaps states) - (mapc (lambda (keymap) - (push `(,(if nodefer 'evil-define-key* 'evil-define-key) - ',states ,keymap ,key ,def) - out-forms)) - keymaps)) - (keymaps - (mapc (lambda (keymap) (push `(define-key ,keymap ,key ,def) out-forms)) - keymaps)) - (states - (mapc (lambda (state) (push `(define-key (evil-state-property ',state :keymap t) ,key ,def) - out-forms)) - states)) - (t (push `(global-set-key ,key ,def) out-forms))) - (setq states '()) - out-forms)) + ;; It's a key-def pair + ((or (stringp key) + (characterp key) + (vectorp key)) + (when (stringp key) + (setq key (kbd key))) + (when prefix + (setq key (cond ((vectorp key) (vconcat prefix key)) + (t (concat prefix key))))) + (unless (> (length rest) 0) + (user-error "Map has no definition for %s" key)) + (setq def (pop rest)) + (let (out-forms) + (cond ((and keymaps states) + (mapc (lambda (keymap) + (push `(,(if defer 'evil-define-key 'evil-define-key*) + ',states ,keymap ,key ,def) + out-forms)) + keymaps)) + (keymaps + (mapc (lambda (keymap) (push `(define-key ,keymap ,key ,def) out-forms)) + keymaps)) + (states + (mapc (lambda (state) + (push `(define-key + (evil-state-property ',state ,(if local :local-keymap :keymap) t) + ,key ,def) + out-forms)) + states)) + (t (push `(,(if local 'local-set-key 'global-set-key) + ,key ,def) + out-forms))) + (setq states '() + local nil) + out-forms)) - (t (user-error "Invalid key %s" key)))) - forms) - (setq i (1+ i))) + (t (user-error "Invalid key %s" key)))) + forms)) `(progn ,@(apply #'nconc (delete nil (delete (list nil) (reverse forms)))))))) (defmacro def-repeat! (command next-func prev-func) diff --git a/core/core-editor.el b/core/core-editor.el index e8f865ff6..f012e69e4 100644 --- a/core/core-editor.el +++ b/core/core-editor.el @@ -320,8 +320,8 @@ :i "" 'indent-for-tab-command :i "" (λ! (insert "\t")) ;; No dumb-tab for lisp - (:map lisp-mode-map :i [remap doom/dumb-indent] 'indent-for-tab-command) - (:map emacs-lisp-mode-map :i [remap doom/dumb-indent] 'indent-for-tab-command) + (:map* lisp-mode-map :i [remap doom/dumb-indent] 'indent-for-tab-command) + (:map* emacs-lisp-mode-map :i [remap doom/dumb-indent] 'indent-for-tab-command) ;; Highjacks space/backspace to: ;; a) eat spaces on either side of the cursor, if present ( | ) -> (|) ;; b) allow backspace to delete space-indented blocks intelligently @@ -344,15 +344,15 @@ :i "" 'smart-up :i "" 'smart-down ;; Fix emacs motion keys - :i "A-b" 'evil-backward-word-begin - :i "A-w" 'evil-forward-word-begin - :i "A-e" 'evil-forward-word-end + :i "A-b" 'evil-backward-word-begin + :i "A-w" 'evil-forward-word-begin + :i "A-e" 'evil-forward-word-end ;; Textmate-esque insert-line before/after - :i "" 'evil-open-below - :i "" 'evil-open-above + :i [M-return] 'evil-open-below + :i [S-M-return] 'evil-open-above ;; insert lines in-place) - :n "" (λ! (save-excursion (evil-insert-newline-below))) - :n "" (λ! (save-excursion (evil-insert-newline-above))) + :n [M-return] (λ! (save-excursion (evil-insert-newline-below))) + :n [S-M-return] (λ! (save-excursion (evil-insert-newline-above))) ;; Make ESC quit all the things (:map (minibuffer-local-map minibuffer-local-ns-map @@ -378,20 +378,19 @@ "h" nil "g" nil))) -;; Fix certain keys in the terminal -(unless window-system - (map! :map key-translation-map - "TAB" [tab])) - -;; Common unicode characters (map! :map key-translation-map - "A-o" (kbd "ø") - "A-O" (kbd "Ø") - "A--" (kbd "–") - "A-_" (kbd "—") - "A-8" (kbd "•") - "A-*" (kbd "°") - "A-p" (kbd "π")) + + ;; Fix certain keys in the terminal + (:unless window-system "TAB" [tab]) + + ;; Common unicode characters + :i "A-o" (kbd "ø") + :i "A-O" (kbd "Ø") + :i "A--" (kbd "–") + :i "A-_" (kbd "—") + :i "A-8" (kbd "•") + :i "A-*" (kbd "°") + :i "A-p" (kbd "π")) (provide 'core-editor) ;;; core-editor.el ends here diff --git a/core/core-helm.el b/core/core-helm.el index 4fde161c6..dbd34ebe3 100644 --- a/core/core-helm.el +++ b/core/core-helm.el @@ -23,22 +23,30 @@ :config (defvar helm-global-prompt "››› ") - (map! :map helm-map - "C-S-n" 'helm-next-source - "C-S-p" 'helm-previous-source - "C-u" 'helm-delete-minibuffer-contents - "C-w" 'backward-kill-word - "M-v" 'clipboard-yank - "C-r" 'evil-paste-from-register ; Evil registers in helm! Glorious! - "C-b" 'backward-word - "" 'backward-char - "" 'forward-char - "" 'helm-keyboard-quit - "ESC" 'helm-keyboard-quit - [escape] 'helm-keyboard-quit - "" 'helm-execute-persistent-action - :map helm-generic-files-map - :e "ESC" 'helm-keyboard-quit) + (map! "M-x" 'helm-M-x + "A-x" 'helm-M-x + "M-X" 'helm-apropos + "A-X" 'helm-apropos + "A-X" 'helm-apropos + "M-o" 'helm-find-files + + (:map helm-map + "C-S-n" 'helm-next-source + "C-S-p" 'helm-previous-source + "C-u" 'helm-delete-minibuffer-contents + "C-w" 'backward-kill-word + "M-v" 'clipboard-yank + "C-r" 'evil-paste-from-register ; Evil registers in helm! Glorious! + "C-b" 'backward-word + "" 'backward-char + "" 'forward-char + "" 'helm-keyboard-quit + "ESC" 'helm-keyboard-quit + [escape] 'helm-keyboard-quit + "" 'helm-execute-persistent-action) + + (:map* helm-generic-files-map + :e "ESC" 'helm-keyboard-quit)) ;;; Popup setup (def-popup! "\\` ?\\*[hH]elm.*?\\*\\'" :align below :size 14 :select t :regexp t) diff --git a/core/core-project.el b/core/core-project.el index 7c98f97a9..04752a556 100644 --- a/core/core-project.el +++ b/core/core-project.el @@ -64,24 +64,23 @@ ;; overridden when the neotree buffer is spawned). So we bind them in a hook. (add-hook 'neo-after-create-hook 'doom|neotree-init-keymap) (defun doom|neotree-init-keymap (&rest _) - (map! :map evil-motion-state-local-map - "\\\\" 'evil-window-prev - "ESC ESC" 'neotree-hide - "q" 'neotree-hide - [return] 'neotree-enter - "RET" 'neotree-enter - "" 'neotree-enter - "J" 'neotree-select-next-sibling-node - "K" 'neotree-select-previous-sibling-node - "H" 'neotree-select-up-node - "L" 'neotree-select-down-node - "v" 'neotree-enter-vertical-split - "s" 'neotree-enter-horizontal-split - "c" 'neotree-create-node - "d" 'neotree-delete-node - "C-r" 'neotree-refresh - "r" 'neotree-rename-node - "R" 'neotree-change-root))) + (map! :Lm "\\\\" 'evil-window-prev + :Lm "ESC ESC" 'neotree-hide + :Lm "q" 'neotree-hide + :Lm [return] 'neotree-enter + :Lm "RET" 'neotree-enter + :Lm "" 'neotree-enter + :Lm "J" 'neotree-select-next-sibling-node + :Lm "K" 'neotree-select-previous-sibling-node + :Lm "H" 'neotree-select-up-node + :Lm "L" 'neotree-select-down-node + :Lm "v" 'neotree-enter-vertical-split + :Lm "s" 'neotree-enter-horizontal-split + :Lm "c" 'neotree-create-node + :Lm "d" 'neotree-delete-node + :Lm "C-r" 'neotree-refresh + :Lm "r" 'neotree-rename-node + :Lm "R" 'neotree-change-root))) (use-package projectile :config diff --git a/modules/module-css.el b/modules/module-css.el index deb0c3762..3dd2e0788 100644 --- a/modules/module-css.el +++ b/modules/module-css.el @@ -9,6 +9,11 @@ (sp-with-modes '(css-mode scss-mode less-css-mode stylus-mode) (sp-local-pair "/*" "*/" :post-handlers '(("[d-3]||\n[i]" "RET") ("| " "SPC")))) +(map! (:map* (css-mode-map scss-mode-map less-css-mode-map) + :n "M-R" 'doom/web-refresh-browser) + (:map* (css-mode-map scss-mode-map less-css-mode-map) + :localleader :nv ";" 'doom/append-semicolon)) + (use-package css-mode :mode "\\.css$" :init @@ -51,9 +56,6 @@ (push '("scss" "css") projectile-other-file-alist) (setq scss-compile-at-save nil)) -(map! :map (css-mode-map sass-mode-map scss-mode-map) - :n "M-R" 'doom/web-refresh-browser - (:localleader :nv ";" 'doom/append-semicolon)) (provide 'module-css) ;;; module-css.el ends here diff --git a/modules/module-elisp.el b/modules/module-elisp.el index c8ac76c91..0fc8be0e6 100644 --- a/modules/module-elisp.el +++ b/modules/module-elisp.el @@ -3,9 +3,6 @@ (associate! emacs-lisp-mode :match "\\(/Cask\\|\\.\\(el\\|gz\\)\\)$") (add-hook! emacs-lisp-mode '(eldoc-mode highlight-numbers-mode)) -;; Real go-to-definition for elisp -(map! :map emacs-lisp-mode-map :m "gd" 'doom/elisp-find-function-at-pt) - (add-hook 'emacs-lisp-mode-hook 'doom/elisp-init) (defun doom/elisp-init () (def-company-backend! emacs-lisp-mode (elisp yasnippet)) @@ -25,6 +22,9 @@ (delq (assq 'emacs-lisp-mode editorconfig-indentation-alist) editorconfig-indentation-alist)) + ;; Real go-to-definition for elisp + (map! :map emacs-lisp-mode-map :m "gd" 'doom/elisp-find-function-at-pt) + (remove-hook 'emacs-lisp-mode-hook 'doom/elisp-init)) (add-hook 'emacs-lisp-mode-hook 'doom/elisp-hook) diff --git a/modules/module-org.el b/modules/module-org.el index d4b3df41a..766b38003 100644 --- a/modules/module-org.el +++ b/modules/module-org.el @@ -233,8 +233,7 @@ "Q" 'doom/org-agenda-quit))) (defun doom|org-keybinds () - (map! :nodefer - (:map org-mode-map + (map! (:map org-mode-map "RET" nil "C-j" nil "C-k" nil diff --git a/private/my-bindings.el b/private/my-bindings.el index 9a6dbc7a8..98f8714e1 100644 --- a/private/my-bindings.el +++ b/private/my-bindings.el @@ -11,8 +11,7 @@ '(call-interactively 'counsel-find-file) ))))) -(map! :nodefer - [f9] 'what-face +(map! [f9] 'what-face ;; Essential (:when (featurep 'helm) "M-x" 'helm-M-x @@ -282,9 +281,10 @@ :nv "" 'aya-create ;; yasnippet - (:map yas-minor-mode-map - :i [tab] 'yas-expand - :v [tab] 'doom/yas-insert-snippet) + (:after yasnippet + (:map yas-minor-mode-map + :i [tab] 'yas-expand + :v [tab] 'doom/yas-insert-snippet)) ;; company-mode and vim-like omni-complete :i "C-SPC" 'doom/company-complete