Polish :feature evil

This commit is contained in:
Henrik Lissner 2017-02-02 04:35:54 -05:00
parent 058967d4de
commit 8a9a67c346
3 changed files with 36 additions and 208 deletions

View file

@ -1,3 +1,4 @@
;;; core/evil/packages.el
;;;###autoload ;;;###autoload
(defun +evil*ex-replace-special-filenames (file-name) (defun +evil*ex-replace-special-filenames (file-name)
@ -140,154 +141,3 @@ evil-window-move-* (e.g. `evil-window-move-far-left')"
(switch-to-buffer this-buffer)) (switch-to-buffer this-buffer))
(select-window that-window)))) (select-window that-window))))
;; Register keywords for proper indentation (see `map!')
(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)
;;;###autoload
(defmacro map! (&rest rest)
"A nightmare of a key-binding macro that will use `evil-define-key',
`evil-define-key*', `define-key' and `global-set-key' depending on context and
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
:i insert
:e emacs
: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
(: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] [...])
(:unless [CONDITION] [...])
Example
(map! :map magit-mode-map
:m \"C-r\" 'do-something ; assign C-r in motion state
:nv \"q\" 'magit-mode-quit-window ; assign to 'q' in normal and visual states
\"C-x C-r\" 'a-global-keybind
(:when IS-MAC
:n \"M-s\" 'some-fn
:i \"M-o\" (lambda (interactive) (message \"Hi\"))))"
(let ((keymaps (if (boundp 'keymaps) keymaps))
(defer (if (boundp 'defer) defer))
(prefix (if (boundp 'prefix) prefix))
(state-map '(("n" . normal)
("v" . visual)
("i" . insert)
("e" . emacs)
("o" . operator)
("m" . motion)
("r" . replace)))
local key def states forms)
(while rest
(setq key (pop rest))
(cond
;; it's a sub expr
((listp key)
(push (macroexpand `(map! ,@key)) forms))
;; it's a flag
((keywordp key)
(when (cond ((eq key :leader)
(push +evil-leader rest))
((eq key :localleader)
(push +evil-localleader rest)))
(setq key :prefix))
(pcase key
(:prefix (setq prefix (concat prefix (kbd (pop rest)))))
(:map (setq keymaps (-list (pop rest))))
(:map* (setq defer t keymaps (-list (pop rest))))
(:unset `(,(macroexpand `(map! ,(kbd (pop rest))))))
(: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)))))))
;; 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))
(push
(cond ((and keymaps states)
(macroexp-progn
(mapcar (lambda (keymap)
`(,(if defer 'evil-define-key 'evil-define-key*)
',states ,keymap ,key ,def))
keymaps)))
(keymaps
(macroexp-progn
(mapcar (lambda (keymap)
`(define-key ,keymap ,key ,def))
keymaps)))
(states
(macroexp-progn
(mapcar (lambda (state)
`(define-key
(evil-state-property ',state ,(if local :local-keymap :keymap) t)
,key ,def))
states)))
(t `(,(if local 'local-set-key 'global-set-key)
,key ,def)))
forms)
(setq states '()
local nil))
(t (user-error "Invalid key %s" key))))
(macroexp-progn (reverse forms))))
(when noninteractive
(defmacro map! (&rest rest)))

View file

@ -1,4 +1,4 @@
;;; core-evil.el --- come to the dark side, we have cookies ;;; core/evil/config.el
;; I'm a vimmer at heart. Its modal philosophy suits me better, and this module ;; I'm a vimmer at heart. Its modal philosophy suits me better, and this module
;; strives to make Emacs a much better vim than vim was. ;; strives to make Emacs a much better vim than vim was.
@ -14,7 +14,7 @@
;; evil-mode ;; evil-mode
;; ;;
(use-package evil (use-package! evil
:demand t :demand t
:init :init
(setq evil-want-C-u-scroll t (setq evil-want-C-u-scroll t
@ -30,7 +30,7 @@
evil-insert-skip-empty-lines t) evil-insert-skip-empty-lines t)
:config :config
(defpopup! (def-popup!
("*evil-registers*" :size 0.3) ("*evil-registers*" :size 0.3)
("*Command Line*" :size 8)) ("*Command Line*" :size 8))
@ -56,17 +56,11 @@
(Man-mode . emacs) (Man-mode . emacs)
(grep-mode . emacs)))) (grep-mode . emacs))))
;;; Private macros
(defsubst +evil--textobj! (key inner-fn &optional outer-fn) (defsubst +evil--textobj! (key inner-fn &optional outer-fn)
"Define a text object." "Define a text object."
(define-key evil-inner-text-objects-map key inner-fn) (define-key evil-inner-text-objects-map key inner-fn)
(define-key evil-outer-text-objects-map key (or outer-fn inner-fn))) (define-key evil-outer-text-objects-map key (or outer-fn inner-fn)))
;; Shortcuts for the evil expression register
(defmacro $= (str &rest args) `(calc-eval (format ,str ,@args)))
(defmacro $r (char) `(evil-get-register ,char))
(defmacro $expand (path) `(evil-ex-replace-special-filenames ,path))
;; ;;
;; evil hacks ;; evil hacks
@ -89,9 +83,9 @@
;; Fix harmless (yet disruptive) error reporting w/ hidden buffers caused by ;; Fix harmless (yet disruptive) error reporting w/ hidden buffers caused by
;; workgroups killing windows ;; workgroups killing windows
;; TODO Delete timer on dead windows? ;; TODO Delete timer on dead windows?
;; (defun doom*ignore-errors (orig-fn &rest args) ;; (defun +evil*ignore-hl-errors (orig-fn &rest args)
;; (ignore-errors (apply orig-fn args))) ;; (ignore-errors (apply orig-fn args)))
;; (advice-add 'evil-ex-hl-do-update-highlight :around 'doom*ignore-errors) ;; (advice-add 'evil-ex-hl-do-update-highlight :around '+evil*ignore-hl-errors)
;; monkey patch `evil-ex-replace-special-filenames' to add more ex ;; monkey patch `evil-ex-replace-special-filenames' to add more ex
;; substitution flags to evil-mode ;; substitution flags to evil-mode
@ -99,8 +93,9 @@
:override '+evil*ex-replace-special-filenames) :override '+evil*ex-replace-special-filenames)
;; Add extra argument types that highlight matches in the current buffer. ;; Add extra argument types that highlight matches in the current buffer.
(evil-ex-define-argument-type buffer-match :runner doom-evil-ex-buffer-match) ;; TODO Must be simpler way to do this
(evil-ex-define-argument-type global-match :runner doom-evil-ex-global-match) (evil-ex-define-argument-type buffer-match :runner +evil-ex-buffer-match)
(evil-ex-define-argument-type global-match :runner +evil-ex-global-match)
(evil-define-interactive-code "<//>" (evil-define-interactive-code "<//>"
:ex-arg buffer-match (list (when (evil-ex-p) evil-ex-argument))) :ex-arg buffer-match (list (when (evil-ex-p) evil-ex-argument)))
@ -129,37 +124,22 @@
;; Plugins ;; Plugins
;; ;;
(use-package evil-anzu (use-package! evil-args
:init :commands (evil-inner-arg evil-outer-arg
;; evil-anzu is strangely slow on startup. Byte compiling doesn't help. We use evil-forward-arg evil-backward-arg
;; this to lazy load it instead.
;; (defun doom*evil-search (&rest _)
;; (require 'evil-anzu)
;; (advice-remove 'evil-ex-start-search 'doom*evil-search))
;; (advice-add 'evil-ex-start-search :before 'doom*evil-search)
:config
(setq anzu-cons-mode-line-p nil
anzu-minimum-input-length 1
anzu-search-threshold 250))
(use-package evil-args
:commands (evil-inner-arg evil-outer-arg evil-forward-arg evil-backward-arg
evil-jump-out-args) evil-jump-out-args)
:init :init (+evil--textobj! "a" 'evil-inner-arg 'evil-outer-arg))
(+evil--textobj! "a" 'evil-inner-arg 'evil-outer-arg))
(use-package evil-commentary (use-package! evil-commentary
:commands (evil-commentary evil-commentary-yank evil-commentary-line) :commands (evil-commentary evil-commentary-yank evil-commentary-line)
:config! (evil-commentary-mode 1)) :config (evil-commentary-mode 1))
(use-package evil-easymotion (use-package! evil-easymotion
:defer 1 :defer 1
:config :config
(defvar doom--evil-snipe-repeat-fn) (defvar +evil--snipe-repeat-fn)
(evilem-default-keybindings "g SPC") (evilem-default-keybindings "g SPC")
(evilem-define (kbd "g SPC n") 'evil-ex-search-next) (evilem-define (kbd "g SPC n") 'evil-ex-search-next)
@ -175,14 +155,14 @@
(evil-snipe-enable-highlight) (evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight))) (evil-snipe-enable-incremental-highlight)))
(setq doom--evil-snipe-repeat-fn (setq +evil--snipe-repeat-fn
(evilem-create 'evil-snipe-repeat (evilem-create 'evil-snipe-repeat
:bind ((evil-snipe-scope 'whole-buffer) :bind ((evil-snipe-scope 'whole-buffer)
(evil-snipe-enable-highlight) (evil-snipe-enable-highlight)
(evil-snipe-enable-incremental-highlight))))) (evil-snipe-enable-incremental-highlight)))))
(use-package evil-embrace (use-package! evil-embrace
:after evil-surround :after evil-surround
:config :config
(setq evil-embrace-show-help-p nil) (setq evil-embrace-show-help-p nil)
@ -236,7 +216,7 @@
(embrace-add-pair-regexp ?l "\\[a-z]+{" "}" '+evil--embrace-latex))) (embrace-add-pair-regexp ?l "\\[a-z]+{" "}" '+evil--embrace-latex)))
(use-package evil-escape (use-package! evil-escape
:commands evil-escape-mode :commands evil-escape-mode
:init :init
(defun +evil|escape-disable () (evil-escape-mode -1)) (defun +evil|escape-disable () (evil-escape-mode -1))
@ -251,7 +231,7 @@
evil-escape-delay 0.25)) evil-escape-delay 0.25))
(use-package evil-exchange (use-package! evil-exchange
:commands evil-exchange :commands evil-exchange
:config :config
(defun +evil*exchange-off () (defun +evil*exchange-off ()
@ -259,7 +239,7 @@
(advice-add 'evil-force-normal-state :after '+evil*exchange-off)) (advice-add 'evil-force-normal-state :after '+evil*exchange-off))
(use-package evil-indent-plus (use-package! evil-indent-plus
:commands (evil-indent-plus-i-indent :commands (evil-indent-plus-i-indent
evil-indent-plus-a-indent evil-indent-plus-a-indent
evil-indent-plus-i-indent-up evil-indent-plus-i-indent-up
@ -272,7 +252,7 @@
(+evil--textobj! "J" 'evil-indent-plus-i-indent-up-down 'evil-indent-plus-a-indent-up-down)) (+evil--textobj! "J" 'evil-indent-plus-i-indent-up-down 'evil-indent-plus-a-indent-up-down))
(use-package evil-matchit (use-package! evil-matchit
:commands (evilmi-jump-items evilmi-text-object global-evil-matchit-mode) :commands (evilmi-jump-items evilmi-text-object global-evil-matchit-mode)
:config (global-evil-matchit-mode 1) :config (global-evil-matchit-mode 1)
:init :init
@ -287,7 +267,7 @@ if on a delimiter, jump to the matching one (`evilmi-jump-items')."
(call-interactively 'evilmi-jump-items)))) (call-interactively 'evilmi-jump-items))))
(use-package evil-multiedit (use-package! evil-multiedit
:commands (evil-multiedit-match-all :commands (evil-multiedit-match-all
evil-multiedit-match-and-next evil-multiedit-match-and-next
evil-multiedit-match-and-prev evil-multiedit-match-and-prev
@ -298,17 +278,16 @@ if on a delimiter, jump to the matching one (`evilmi-jump-items')."
evil-multiedit-prev evil-multiedit-prev
evil-multiedit-abort evil-multiedit-abort
evil-multiedit-ex-match) evil-multiedit-ex-match)
:config :config (evil-multiedit-default-keybinds))
(evil-multiedit-default-keybinds))
(use-package evil-textobj-anyblock (use-package! evil-textobj-anyblock
:commands (evil-numbers/inc-at-pt evil-numbers/dec-at-pt) :commands (evil-numbers/inc-at-pt evil-numbers/dec-at-pt)
:init :init
(+evil--textobj! "B" 'evil-textobj-anyblock-inner-block 'evil-textobj-anyblock-a-block)) (+evil--textobj! "B" 'evil-textobj-anyblock-inner-block 'evil-textobj-anyblock-a-block))
(use-package evil-search-highlight-persist (use-package! evil-search-highlight-persist
:demand t :demand t
:commands (evil-textobj-anyblock-inner-block evil-textobj-anyblock-a-block) :commands (evil-textobj-anyblock-inner-block evil-textobj-anyblock-a-block)
:config :config
@ -316,7 +295,7 @@ if on a delimiter, jump to the matching one (`evilmi-jump-items')."
(advice-add 'evil-force-normal-state :after 'evil-search-highlight-persist-remove-all)) (advice-add 'evil-force-normal-state :after 'evil-search-highlight-persist-remove-all))
(use-package evil-snipe (use-package! evil-snipe
:demand t :demand t
:init :init
(setq evil-snipe-smart-case t (setq evil-snipe-smart-case t
@ -333,12 +312,12 @@ if on a delimiter, jump to the matching one (`evilmi-jump-items')."
(evil-snipe-mode 1) (evil-snipe-mode 1)
(evil-snipe-override-mode 1) (evil-snipe-override-mode 1)
;; Switch to evil-easymotion/avy after first snipe ;; Switch to evil-easymotion/avy after first snipe
(define-key evil-snipe-parent-transient-map "\C-;" (define-key evil-snipe-parent-transient-map (kbd "C-;")
(λ! (require 'evil-easymotion) (λ! (require 'evil-easymotion)
(call-interactively doom--evil-snipe-repeat-fn)))) (call-interactively +evil--snipe-repeat-fn))))
(use-package evil-surround (use-package! evil-surround
:commands (global-evil-surround-mode :commands (global-evil-surround-mode
evil-surround-edit evil-surround-edit
evil-Surround-edit evil-Surround-edit
@ -346,7 +325,7 @@ if on a delimiter, jump to the matching one (`evilmi-jump-items')."
:config (global-evil-surround-mode 1)) :config (global-evil-surround-mode 1))
(use-package evil-visualstar (use-package! evil-visualstar
:commands (global-evil-visualstar-mode :commands (global-evil-visualstar-mode
evil-visualstar/begin-search evil-visualstar/begin-search
evil-visualstar/begin-search-forward evil-visualstar/begin-search-forward
@ -355,7 +334,7 @@ if on a delimiter, jump to the matching one (`evilmi-jump-items')."
;; A side-panel for browsing my project files. Inspired by vim's NERDTree. ;; A side-panel for browsing my project files. Inspired by vim's NERDTree.
(use-package neotree (use-package! neotree
:commands (neotree-show :commands (neotree-show
neotree-hide neotree-hide
neotree-toggle neotree-toggle
@ -390,8 +369,8 @@ if on a delimiter, jump to the matching one (`evilmi-jump-items')."
;; Adding keybindings to `neotree-mode-map' wouldn't work for me (they get ;; Adding keybindings to `neotree-mode-map' wouldn't work for me (they get
;; 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 '+evil|neotree-init-keymap)
(defun doom|neotree-init-keymap (&rest _) (defun +evil|neotree-init-keymap (&rest _)
(let ((map evil-motion-state-local-map)) (let ((map evil-motion-state-local-map))
(define-key map (kbd "\\\\") 'evil-window-prev) (define-key map (kbd "\\\\") 'evil-window-prev)
(define-key map (kbd "RET") 'neotree-enter) (define-key map (kbd "RET") 'neotree-enter)

View file

@ -1,7 +1,6 @@
;;; packages.el ;;; core/evil/packages.el
(package! evil) (package! evil)
(package! evil-anzu)
(package! evil-args) (package! evil-args)
(package! evil-commentary) (package! evil-commentary)
(package! evil-easymotion) (package! evil-easymotion)