Rethink map! macro; replace :local=>:L, :defer=>:map* (addresses #19)

This commit is contained in:
Henrik Lissner 2017-01-02 20:59:28 -05:00
parent 5536ab887d
commit e1000fcfc5
8 changed files with 174 additions and 143 deletions

View file

@ -193,13 +193,14 @@ Examples:
(evil-ex-define-cmd cmd fn)) (evil-ex-define-cmd cmd fn))
;; Register keywords for proper indentation (see `map!') ;; Register keywords for proper indentation (see `map!')
(put ':prefix '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 ':map* 'lisp-indent-function 'defun)
(put ':when 'lisp-indent-function 'defun) (put ':after 'lisp-indent-function 'defun)
(put ':unless 'lisp-indent-function 'defun) (put ':when 'lisp-indent-function 'defun)
(put ':leader 'lisp-indent-function 'defun) (put ':unless 'lisp-indent-function 'defun)
(put ':localleader 'lisp-indent-function 'defun) (put ':leader 'lisp-indent-function 'defun)
(put ':localleader 'lisp-indent-function 'defun)
(defmacro map! (&rest rest) (defmacro map! (&rest rest)
"A nightmare of a key-binding macro that will use `evil-define-key', "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, plist key flags. It was designed to make binding multiple keys more concise,
like in vim. 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 States
:n normal :n normal
:v visual :v visual
@ -215,19 +221,22 @@ States
:o operator :o operator
:m motion :m motion
:r replace :r replace
:L local
These can be combined (order doesn't matter), e.g. :nvi will apply to 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 normal, visual and insert mode. The state resets after the following
key=>def pair. key=>def pair.
Capitalize the state flag to make it a local binding.
If omitted, the keybind will be defined globally. If omitted, the keybind will be defined globally.
Flags Flags
:unset [KEY] ; unset key :unset [KEY] ; unset key
:nodefer ; don't use `evil-delay' for future keybinds (:map [KEYMAP] [...]) ; apply inner keybinds to KEYMAP
(:map [KEYMAP] [...]) ; apply all inner keybinds to KEYMAP (:map* [KEYMAP] [...]) ; apply inner keybinds to KEYMAP (deferred)
(:prefix [PREFIX] [...]) ; assign prefix to all inner keybindings (:prefix [PREFIX] [...]) ; assign prefix to all inner keybindings
(:after [FEATURE] [...]) ; apply keybinds when [FEATURE] loads (:after [FEATURE] [...]) ; apply keybinds when [FEATURE] loads
Conditional keybinds Conditional keybinds
(:when [CONDITION] [...]) (:when [CONDITION] [...])
@ -242,8 +251,7 @@ Example
(:when IS-MAC (:when IS-MAC
:n \"M-s\" 'some-fn :n \"M-s\" 'some-fn
:i \"M-o\" (lambda (interactive) (message \"Hi\"))))" :i \"M-o\" (lambda (interactive) (message \"Hi\"))))"
(let ((i 0) (let ((keymaps (if (boundp 'keymaps) keymaps))
(keymaps (if (boundp 'keymaps) keymaps))
(state-map '(("n" . normal) (state-map '(("n" . normal)
("v" . visual) ("v" . visual)
("i" . insert) ("i" . insert)
@ -252,73 +260,89 @@ Example
("m" . motion) ("m" . motion)
("r" . replace))) ("r" . replace)))
(prefix (if (boundp 'prefix) prefix)) (prefix (if (boundp 'prefix) prefix))
(nodefer (if (boundp 'nodefer) nodefer)) (defer (if (boundp 'defer) defer))
key def states forms) local key def states forms)
(while rest (while rest
(setq key (pop rest)) (setq key (pop rest))
(push (push
(reverse (reverse
(cond ((listp key) ; it's a sub exp (cond
`(,(macroexpand `(map! ,@key)))) ;; it's a sub expr
((listp key)
`(,(macroexpand `(map! ,@key))))
((keywordp key) ;; it's a flag
(when (memq key '(:leader :localleader)) ((keywordp key)
(push (cond ((eq key :leader) (when (memq key '(:leader :localleader))
doom-leader) (push (cond ((eq key :leader)
((eq key :localleader) doom-leader)
doom-localleader)) ((eq key :localleader)
rest) doom-localleader))
(setq key :prefix)) rest)
(pcase key (setq key :prefix))
(:prefix (setq prefix (concat prefix (kbd (pop rest)))) nil) (pcase key
(:map (setq keymaps (-list (pop rest))) nil) (:prefix (setq prefix (concat prefix (kbd (pop rest)))) nil)
(:nodefer (setq nodefer t) nil) (:map (setq keymaps (-list (pop rest))) nil)
(:unset `(,(macroexpand `(map! ,(kbd (pop rest)) nil)))) (:map* (setq defer t keymaps (-list (pop rest))) nil)
(:after (prog1 `((after! ,(pop rest) ,(macroexpand `(map! ,@rest)))) (setq rest '()))) (:unset `(,(macroexpand `(map! ,(kbd (pop rest)) nil))))
(:when (prog1 `((if ,(pop rest) ,(macroexpand `(map! ,@rest)))) (setq rest '()))) (:after (prog1 `((after! ,(pop rest) ,(macroexpand `(map! ,@rest)))) (setq rest '())))
(:unless (prog1 `((if (not ,(pop rest)) ,(macroexpand `(map! ,@rest)))) (setq rest '()))) (:when (prog1 `((if ,(pop rest) ,(macroexpand `(map! ,@rest)))) (setq rest '())))
(otherwise ; might be a state prefix (:unless (prog1 `((if (not ,(pop rest)) ,(macroexpand `(map! ,@rest)))) (setq rest '())))
(mapc (lambda (letter) (otherwise ; might be a state prefix
(cond ((assoc letter state-map) (mapc (lambda (letter)
(push (cdr (assoc letter state-map)) states)) (cond ((assoc letter state-map)
(t (user-error "Invalid mode prefix %s in key %s" letter key)))) (push (cdr (assoc letter state-map)) states))
(split-string (substring (symbol-name key) 1) "" t)) ((string= letter "L")
(unless states (setq local t))
(user-error "Unrecognized keyword %s" key)) nil))) (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 ;; It's a key-def pair
((or (stringp key) ((or (stringp key)
(characterp key) (characterp key)
(vectorp key)) (vectorp key))
(when (stringp key) (when (stringp key)
(setq key (kbd key))) (setq key (kbd key)))
(when prefix (when prefix
(setq key (cond ((vectorp key) (vconcat prefix key)) (setq key (cond ((vectorp key) (vconcat prefix key))
(t (concat prefix key))))) (t (concat prefix key)))))
(unless (> (length rest) 0) (unless (> (length rest) 0)
(user-error "Map has no definition for %s" key)) (user-error "Map has no definition for %s" key))
(setq def (pop rest)) (setq def (pop rest))
(let (out-forms) (let (out-forms)
(cond ((and keymaps states) (cond ((and keymaps states)
(mapc (lambda (keymap) (mapc (lambda (keymap)
(push `(,(if nodefer 'evil-define-key* 'evil-define-key) (push `(,(if defer 'evil-define-key 'evil-define-key*)
',states ,keymap ,key ,def) ',states ,keymap ,key ,def)
out-forms)) out-forms))
keymaps)) keymaps))
(keymaps (keymaps
(mapc (lambda (keymap) (push `(define-key ,keymap ,key ,def) out-forms)) (mapc (lambda (keymap) (push `(define-key ,keymap ,key ,def) out-forms))
keymaps)) keymaps))
(states (states
(mapc (lambda (state) (push `(define-key (evil-state-property ',state :keymap t) ,key ,def) (mapc (lambda (state)
out-forms)) (push `(define-key
states)) (evil-state-property ',state ,(if local :local-keymap :keymap) t)
(t (push `(global-set-key ,key ,def) out-forms))) ,key ,def)
(setq states '()) out-forms))
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)))) (t (user-error "Invalid key %s" key))))
forms) forms))
(setq i (1+ i)))
`(progn ,@(apply #'nconc (delete nil (delete (list nil) (reverse forms)))))))) `(progn ,@(apply #'nconc (delete nil (delete (list nil) (reverse forms))))))))
(defmacro def-repeat! (command next-func prev-func) (defmacro def-repeat! (command next-func prev-func)

View file

@ -320,8 +320,8 @@
:i "<C-tab>" 'indent-for-tab-command :i "<C-tab>" 'indent-for-tab-command
:i "<A-tab>" (λ! (insert "\t")) :i "<A-tab>" (λ! (insert "\t"))
;; No dumb-tab for lisp ;; No dumb-tab for lisp
(:map 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) (:map* emacs-lisp-mode-map :i [remap doom/dumb-indent] 'indent-for-tab-command)
;; Highjacks space/backspace to: ;; Highjacks space/backspace to:
;; a) eat spaces on either side of the cursor, if present ( | ) -> (|) ;; a) eat spaces on either side of the cursor, if present ( | ) -> (|)
;; b) allow backspace to delete space-indented blocks intelligently ;; b) allow backspace to delete space-indented blocks intelligently
@ -344,15 +344,15 @@
:i "<C-up>" 'smart-up :i "<C-up>" 'smart-up
:i "<C-down>" 'smart-down :i "<C-down>" 'smart-down
;; Fix emacs motion keys ;; Fix emacs motion keys
:i "A-b" 'evil-backward-word-begin :i "A-b" 'evil-backward-word-begin
:i "A-w" 'evil-forward-word-begin :i "A-w" 'evil-forward-word-begin
:i "A-e" 'evil-forward-word-end :i "A-e" 'evil-forward-word-end
;; Textmate-esque insert-line before/after ;; Textmate-esque insert-line before/after
:i "<M-return>" 'evil-open-below :i [M-return] 'evil-open-below
:i "<S-M-return>" 'evil-open-above :i [S-M-return] 'evil-open-above
;; insert lines in-place) ;; insert lines in-place)
:n "<M-return>" (λ! (save-excursion (evil-insert-newline-below))) :n [M-return] (λ! (save-excursion (evil-insert-newline-below)))
:n "<S-M-return>" (λ! (save-excursion (evil-insert-newline-above))) :n [S-M-return] (λ! (save-excursion (evil-insert-newline-above)))
;; Make ESC quit all the things ;; Make ESC quit all the things
(:map (minibuffer-local-map (:map (minibuffer-local-map
minibuffer-local-ns-map minibuffer-local-ns-map
@ -378,20 +378,19 @@
"h" nil "h" nil
"g" 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 (map! :map key-translation-map
"A-o" (kbd "ø")
"A-O" (kbd "Ø") ;; Fix certain keys in the terminal
"A--" (kbd "") (:unless window-system "TAB" [tab])
"A-_" (kbd "")
"A-8" (kbd "") ;; Common unicode characters
"A-*" (kbd "°") :i "A-o" (kbd "ø")
"A-p" (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) (provide 'core-editor)
;;; core-editor.el ends here ;;; core-editor.el ends here

View file

@ -23,22 +23,30 @@
:config :config
(defvar helm-global-prompt " ") (defvar helm-global-prompt " ")
(map! :map helm-map (map! "M-x" 'helm-M-x
"C-S-n" 'helm-next-source "A-x" 'helm-M-x
"C-S-p" 'helm-previous-source "M-X" 'helm-apropos
"C-u" 'helm-delete-minibuffer-contents "A-X" 'helm-apropos
"C-w" 'backward-kill-word "A-X" 'helm-apropos
"M-v" 'clipboard-yank "M-o" 'helm-find-files
"C-r" 'evil-paste-from-register ; Evil registers in helm! Glorious!
"C-b" 'backward-word (:map helm-map
"<left>" 'backward-char "C-S-n" 'helm-next-source
"<right>" 'forward-char "C-S-p" 'helm-previous-source
"<escape>" 'helm-keyboard-quit "C-u" 'helm-delete-minibuffer-contents
"ESC" 'helm-keyboard-quit "C-w" 'backward-kill-word
[escape] 'helm-keyboard-quit "M-v" 'clipboard-yank
"<tab>" 'helm-execute-persistent-action "C-r" 'evil-paste-from-register ; Evil registers in helm! Glorious!
:map helm-generic-files-map "C-b" 'backward-word
:e "ESC" 'helm-keyboard-quit) "<left>" 'backward-char
"<right>" 'forward-char
"<escape>" 'helm-keyboard-quit
"ESC" 'helm-keyboard-quit
[escape] 'helm-keyboard-quit
"<tab>" 'helm-execute-persistent-action)
(:map* helm-generic-files-map
:e "ESC" 'helm-keyboard-quit))
;;; Popup setup ;;; Popup setup
(def-popup! "\\` ?\\*[hH]elm.*?\\*\\'" :align below :size 14 :select t :regexp t) (def-popup! "\\` ?\\*[hH]elm.*?\\*\\'" :align below :size 14 :select t :regexp t)

View file

@ -64,24 +64,23 @@
;; overridden when the neotree buffer is spawned). So we bind them in a hook. ;; overridden when the neotree buffer is spawned). So we bind them in a hook.
(add-hook 'neo-after-create-hook 'doom|neotree-init-keymap) (add-hook 'neo-after-create-hook 'doom|neotree-init-keymap)
(defun doom|neotree-init-keymap (&rest _) (defun doom|neotree-init-keymap (&rest _)
(map! :map evil-motion-state-local-map (map! :Lm "\\\\" 'evil-window-prev
"\\\\" 'evil-window-prev :Lm "ESC ESC" 'neotree-hide
"ESC ESC" 'neotree-hide :Lm "q" 'neotree-hide
"q" 'neotree-hide :Lm [return] 'neotree-enter
[return] 'neotree-enter :Lm "RET" 'neotree-enter
"RET" 'neotree-enter :Lm "<return>" 'neotree-enter
"<return>" 'neotree-enter :Lm "J" 'neotree-select-next-sibling-node
"J" 'neotree-select-next-sibling-node :Lm "K" 'neotree-select-previous-sibling-node
"K" 'neotree-select-previous-sibling-node :Lm "H" 'neotree-select-up-node
"H" 'neotree-select-up-node :Lm "L" 'neotree-select-down-node
"L" 'neotree-select-down-node :Lm "v" 'neotree-enter-vertical-split
"v" 'neotree-enter-vertical-split :Lm "s" 'neotree-enter-horizontal-split
"s" 'neotree-enter-horizontal-split :Lm "c" 'neotree-create-node
"c" 'neotree-create-node :Lm "d" 'neotree-delete-node
"d" 'neotree-delete-node :Lm "C-r" 'neotree-refresh
"C-r" 'neotree-refresh :Lm "r" 'neotree-rename-node
"r" 'neotree-rename-node :Lm "R" 'neotree-change-root)))
"R" 'neotree-change-root)))
(use-package projectile (use-package projectile
:config :config

View file

@ -9,6 +9,11 @@
(sp-with-modes '(css-mode scss-mode less-css-mode stylus-mode) (sp-with-modes '(css-mode scss-mode less-css-mode stylus-mode)
(sp-local-pair "/*" "*/" :post-handlers '(("[d-3]||\n[i]" "RET") ("| " "SPC")))) (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 (use-package css-mode
:mode "\\.css$" :mode "\\.css$"
:init :init
@ -51,9 +56,6 @@
(push '("scss" "css") projectile-other-file-alist) (push '("scss" "css") projectile-other-file-alist)
(setq scss-compile-at-save nil)) (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) (provide 'module-css)
;;; module-css.el ends here ;;; module-css.el ends here

View file

@ -3,9 +3,6 @@
(associate! emacs-lisp-mode :match "\\(/Cask\\|\\.\\(el\\|gz\\)\\)$") (associate! emacs-lisp-mode :match "\\(/Cask\\|\\.\\(el\\|gz\\)\\)$")
(add-hook! emacs-lisp-mode '(eldoc-mode highlight-numbers-mode)) (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) (add-hook 'emacs-lisp-mode-hook 'doom/elisp-init)
(defun doom/elisp-init () (defun doom/elisp-init ()
(def-company-backend! emacs-lisp-mode (elisp yasnippet)) (def-company-backend! emacs-lisp-mode (elisp yasnippet))
@ -25,6 +22,9 @@
(delq (assq 'emacs-lisp-mode editorconfig-indentation-alist) (delq (assq 'emacs-lisp-mode editorconfig-indentation-alist)
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)) (remove-hook 'emacs-lisp-mode-hook 'doom/elisp-init))
(add-hook 'emacs-lisp-mode-hook 'doom/elisp-hook) (add-hook 'emacs-lisp-mode-hook 'doom/elisp-hook)

View file

@ -233,8 +233,7 @@
"Q" 'doom/org-agenda-quit))) "Q" 'doom/org-agenda-quit)))
(defun doom|org-keybinds () (defun doom|org-keybinds ()
(map! :nodefer (map! (:map org-mode-map
(:map org-mode-map
"RET" nil "RET" nil
"C-j" nil "C-j" nil
"C-k" nil "C-k" nil

View file

@ -11,8 +11,7 @@
'(call-interactively 'counsel-find-file) '(call-interactively 'counsel-find-file)
))))) )))))
(map! :nodefer (map! [f9] 'what-face
[f9] 'what-face
;; Essential ;; Essential
(:when (featurep 'helm) (:when (featurep 'helm)
"M-x" 'helm-M-x "M-x" 'helm-M-x
@ -282,9 +281,10 @@
:nv "<C-tab>" 'aya-create :nv "<C-tab>" 'aya-create
;; yasnippet ;; yasnippet
(:map yas-minor-mode-map (:after yasnippet
:i [tab] 'yas-expand (:map yas-minor-mode-map
:v [tab] 'doom/yas-insert-snippet) :i [tab] 'yas-expand
:v [tab] 'doom/yas-insert-snippet))
;; company-mode and vim-like omni-complete ;; company-mode and vim-like omni-complete
:i "C-SPC" 'doom/company-complete :i "C-SPC" 'doom/company-complete