feature/evil: refactor

This commit is contained in:
Henrik Lissner 2017-05-15 13:52:22 +02:00
parent 04c270d76b
commit 5fb028b49d
4 changed files with 197 additions and 199 deletions

View file

@ -23,9 +23,6 @@
mouse-yank-at-point t ; middle-click paste at point, not at click
resize-mini-windows 'grow-only ; Minibuffer resizing
show-help-function nil ; hide :help-echo text
show-paren-delay 0.075
show-paren-highlight-openparen t
show-paren-when-point-inside-paren t
split-width-threshold nil ; favor horizontal splits
uniquify-buffer-name-style 'forward
use-dialog-box nil ; always avoid GUI
@ -89,6 +86,12 @@ local value, whether or not it's permanent-local. Therefore, we cycle
(require 'winner)
(add-hook 'window-setup-hook #'winner-mode)
;; highlight matching delimiters
(setq show-paren-delay 0.2
show-paren-highlight-openparen t
show-paren-when-point-inside-paren t)
(show-paren-mode +1)
;;
;; Bootstrap

View file

@ -99,10 +99,114 @@ flags. See http://vimdoc.sourceforge.net/htmldoc/cmdline.html#filename-modifiers
path file-name t t 1))))
(setq file-name (replace-regexp-in-string regexp "\\1" file-name t))))
(defun +evil--window-swap (direction)
"Move current window to the next window in DIRECTION. If there are no windows
there and there is only one window, split in that direction and place this
window there. If there are no windows and this isn't the only window, use
evil-window-move-* (e.g. `evil-window-move-far-left')"
(let* ((this-window (get-buffer-window))
(this-buffer (current-buffer))
(that-window (windmove-find-other-window direction nil this-window))
(that-buffer (window-buffer that-window)))
(when (or (minibufferp that-buffer)
(doom-popup-p that-window))
(setq that-buffer nil that-window nil))
(if (not (or that-window (one-window-p t)))
(funcall (case direction
('left 'evil-window-move-far-left)
('right 'evil-window-move-far-right)
('up 'evil-window-move-very-top)
('down 'evil-window-move-very-bottom)))
(unless that-window
(setq that-window
(split-window this-window nil (cond ((eq direction 'up) 'above)
((eq direction 'down) 'below)
(t direction))))
(with-selected-window that-window
(switch-to-buffer doom-buffer))
(setq that-buffer (window-buffer that-window)))
(with-selected-window this-window
(switch-to-buffer that-buffer))
(with-selected-window that-window
(switch-to-buffer this-buffer))
(select-window that-window))))
;;
;; Custom argument handlers
;;
;;;###autoload
(defun +evil/window-move-left () "`+evil--window-swap'" (interactive) (+evil--window-swap 'left))
;;;###autoload
(defun +evil/window-move-right () "`+evil--window-swap'" (interactive) (+evil--window-swap 'right))
;;;###autoload
(defun +evil/window-move-up () "`+evil--window-swap'" (interactive) (+evil--window-swap 'up))
;;;###autoload
(defun +evil/window-move-down () "`+evil--window-swap'" (interactive) (+evil--window-swap 'down))
;;;###autoload (autoload '+evil:macro-on-all-lines "feature/evil/autoload/evil" nil t)
(evil-define-operator +evil:macro-on-all-lines (beg end &optional macro)
"Apply macro to each line."
:motion nil
:move-point nil
(interactive "<r><a>")
(unless (and beg end)
(setq beg (region-beginning)
end (region-end)))
(evil-ex-normal beg end
(concat "@"
(single-key-description
(or macro (read-char "@-"))))))
;;;###autoload (autoload '+evil:retab "feature/evil/autoload/evil" nil t)
(evil-define-operator +evil:retab (&optional beg end)
"Wrapper around `doom/retab'."
:motion nil :move-point nil :type line
(interactive "<r>")
(doom/retab beg end))
;;;###autoload (autoload '+evil:narrow-buffer "feature/evil/autoload/evil" nil t)
(evil-define-command +evil:narrow-buffer (beg end &optional bang)
"Wrapper around `doom-narrow-buffer'."
:move-point nil
(interactive "<r><!>")
(doom-narrow-buffer beg end bang))
;; --- code folding -----------------------
;; I wrote these for two reasons:
;; 1. To facilitate lazy-loading of hideshow.el (otherwise, evil wouldn't know what mode to use)
;; 2. To allow level-based folding (parity with vim), e.g. 2zr will open all
;; folds up to 2nd level folds.
;;;###autoload (autoload '+evil:open-folds-recursively "feature/evil/autoload/evil" nil t)
(evil-define-command +evil:open-folds-recursively (level)
"Opens all folds recursively, up to LEVEL."
(interactive "<c>")
(unless (bound-and-true-p hs-minor-mode)
(hs-minor-mode 1))
(if level (hs-hide-level level) (evil-open-folds)))
;;;###autoload (autoload '+evil:close-folds-recursively "feature/evil/autoload/evil" nil t)
(evil-define-command +evil:close-folds-recursively (level)
"Closes all folds recursively, up to LEVEL."
(interactive "<c>")
(unless (bound-and-true-p hs-minor-mode)
(hs-minor-mode 1))
(if level (hs-hide-level level) (evil-close-folds)))
;;;###autoload
(defun +evil/matchit-or-toggle-fold ()
"Do what I mean. If on a fold-able element, toggle the fold with
`hs-toggle-hiding'. Otherwise, if on a delimiter, jump to the matching one with
`evilmi-jump-items'. If in a magit-status buffer, use `magit-section-toggle'."
(interactive)
(cond ((eq major-mode 'magit-status-mode)
(call-interactively 'magit-section-toggle))
((ignore-errors (hs-already-hidden-p))
(hs-toggle-hiding))
(t
(call-interactively 'evilmi-jump-items))))
;; --- custom arg handlers ----------------
(defvar +evil--buffer-match-global evil-ex-substitute-global "")
@ -155,101 +259,3 @@ flags. See http://vimdoc.sourceforge.net/htmldoc/cmdline.html#filename-modifiers
(+evil--ex-match-init hl-name)
(let ((result (car-safe (evil-ex-parse-global arg))))
(+evil--ex-buffer-match result hl-name nil (point-min) (point-max))))))
;;;###autoload
(defun +evil-window-move (direction)
"Move current window to the next window in DIRECTION. If there are no windows
there and there is only one window, split in that direction and place this
window there. If there are no windows and this isn't the only window, use
evil-window-move-* (e.g. `evil-window-move-far-left')"
(let* ((this-window (get-buffer-window))
(this-buffer (current-buffer))
(that-window (windmove-find-other-window direction nil this-window))
(that-buffer (window-buffer that-window)))
(when (or (minibufferp that-buffer)
(doom-popup-p that-window))
(setq that-buffer nil that-window nil))
(if (not (or that-window (one-window-p t)))
(funcall (case direction
('left 'evil-window-move-far-left)
('right 'evil-window-move-far-right)
('up 'evil-window-move-very-top)
('down 'evil-window-move-very-bottom)))
(unless that-window
(setq that-window
(split-window this-window nil (cond ((eq direction 'up) 'above)
((eq direction 'down) 'below)
(t direction))))
(with-selected-window that-window
(switch-to-buffer doom-buffer))
(setq that-buffer (window-buffer that-window)))
(with-selected-window this-window
(switch-to-buffer that-buffer))
(with-selected-window that-window
(switch-to-buffer this-buffer))
(select-window that-window))))
;;;###autoload
(defun +evil/window-move-left () "`+evil-window-move'" (interactive) (+evil-window-move 'left))
;;;###autoload
(defun +evil/window-move-right () "`+evil-window-move'" (interactive) (+evil-window-move 'right))
;;;###autoload
(defun +evil/window-move-up () "`+evil-window-move'" (interactive) (+evil-window-move 'up))
;;;###autoload
(defun +evil/window-move-down () "`+evil-window-move'" (interactive) (+evil-window-move 'down))
;;;###autoload
(defun +evil/matchit-or-toggle-fold ()
"If on a fold-able element, toggle the fold (`hs-toggle-hiding'). Otherwise,
if on a delimiter, jump to the matching one (`evilmi-jump-items')."
(interactive)
(cond ((eq major-mode 'magit-status-mode)
(call-interactively 'magit-section-toggle))
((ignore-errors (hs-already-hidden-p))
(hs-toggle-hiding))
(t
(call-interactively 'evilmi-jump-items))))
;;;###autoload (autoload '+evil:macro-on-all-lines "feature/evil/autoload/evil" nil t)
(evil-define-operator +evil:macro-on-all-lines (beg end &optional macro)
"Apply macro to each line."
:motion nil
:move-point nil
(interactive "<r><a>")
(unless (and beg end)
(setq beg (region-beginning)
end (region-end)))
(evil-ex-normal beg end
(concat "@"
(single-key-description
(or macro (read-char "@-"))))))
;;;###autoload (autoload '+evil:open-folds-recursively "feature/evil/autoload/evil" nil t)
(evil-define-command +evil:open-folds-recursively (level)
"Opens all folds recursively, up to LEVEL."
(interactive "<c>")
(unless (bound-and-true-p hs-minor-mode)
(hs-minor-mode 1))
(if level (hs-hide-level level) (evil-open-folds)))
;;;###autoload (autoload '+evil:close-folds-recursively "feature/evil/autoload/evil" nil t)
(evil-define-command +evil:close-folds-recursively (level)
"Closes all folds recursively, up to LEVEL."
(interactive "<c>")
(unless (bound-and-true-p hs-minor-mode)
(hs-minor-mode 1))
(if level (hs-hide-level level) (evil-close-folds)))
;;;###autoload (autoload '+evil:retab "feature/evil/autoload/evil" nil t)
(evil-define-operator +evil:retab (&optional beg end)
"Wrapper around `doom/retab'."
:motion nil :move-point nil :type line
(interactive "<r>")
(doom/retab beg end))
;;;###autoload (autoload '+evil:narrow-buffer "feature/evil/autoload/evil" nil t)
(evil-define-command +evil:narrow-buffer (beg end &optional bang)
"Wrapper around `doom-narrow-buffer'."
:move-point nil
(interactive "<r><!>")
(doom-narrow-buffer beg end bang))

View file

@ -26,9 +26,7 @@
:init
(setq evil-want-C-u-scroll t
evil-want-visual-char-semi-exclusive t
evil-want-fine-undo nil
evil-want-Y-yank-to-eol t
evil-ex-interactive-search-highlight 'selected-window
evil-magic t
evil-echo-state t
evil-indent-convert-tabs t
@ -36,7 +34,12 @@
evil-ex-substitute-global t
evil-ex-visual-char-range t ; column range for ex commands
evil-insert-skip-empty-lines t
evil-mode-line-format 'nil
;; Move to new split
evil-split-window-below t
evil-vsplit-window-right t
;; more vim-like behavior
evil-symbol-word-search t
;; don't activate mark on shift-click
shift-select-mode nil)
@ -51,7 +54,7 @@
;; Don't interfere with localleader key
(define-key evil-motion-state-map "\\" nil)
;; Set cursor colors later, presumably once theme is loaded
;; Set cursor colors later, once theme is loaded
(defun +evil*init-cursors (&rest _)
(setq evil-default-cursor (face-background 'cursor nil t)
evil-normal-state-cursor 'box
@ -60,23 +63,10 @@
evil-visual-state-cursor 'hollow))
(advice-add #'load-theme :after #'+evil*init-cursors)
;; highlight matching delimiters where it's important
(defun +evil|show-paren-mode-off () (show-paren-mode -1))
(defun +evil|show-paren-mode-on ()
(unless (bound-and-true-p org-indent-mode) ; interferes with org-indent
(show-paren-mode +1)))
(add-hook 'evil-insert-state-entry-hook #'+evil|show-paren-mode-on)
(add-hook 'evil-insert-state-exit-hook #'+evil|show-paren-mode-off)
(add-hook 'evil-visual-state-entry-hook #'+evil|show-paren-mode-on)
(add-hook 'evil-visual-state-exit-hook #'+evil|show-paren-mode-off)
(add-hook 'evil-operator-state-entry-hook #'+evil|show-paren-mode-on)
(add-hook 'evil-operator-state-exit-hook #'+evil|show-paren-mode-off)
(add-hook 'evil-normal-state-entry-hook #'+evil|show-paren-mode-off)
;; default modes
(dolist (mode '(tabulated-list-mode view-mode comint-mode term-mode calendar-mode Man-mode grep-mode))
(evil-set-initial-state mode 'emacs))
(dolist (mode '(help-mode))
(dolist (mode '(help-mode debugger-mode))
(evil-set-initial-state mode 'normal))
;; make `try-expand-dabbrev' from `hippie-expand' work in mini-buffer
@ -85,81 +75,82 @@
(set-syntax-table (let* ((table (make-syntax-table)))
(modify-syntax-entry ?/ "." table)
table)))
(add-hook 'minibuffer-inactive-mode-hook #'minibuffer-inactive-mode-hook-setup))
(add-hook 'minibuffer-inactive-mode-hook #'minibuffer-inactive-mode-hook-setup)
(defsubst +evil--textobj (key inner-fn &optional outer-fn)
(defsubst +evil--textobj (key inner-fn &optional outer-fn)
"Define a text object."
(declare (indent defun))
(define-key evil-inner-text-objects-map key inner-fn)
(define-key evil-outer-text-objects-map key (or outer-fn inner-fn)))
;;
;; evil hacks
;;
;; --- keybind fixes ----------------------
(map! :n "zr" #'+evil:open-folds-recursively
:n "zm" #'+evil:close-folds-recursively
(defvar +evil-esc-hook nil
;; undo/redo for regions
:v "u" #'undo-tree-undo
:v "C-r" #'undo-tree-redo)
;; --- evil hacks -------------------------
(defvar +evil-esc-hook nil
"A hook run after ESC is pressed in normal mode (invoked by
`evil-force-normal-state').")
(defun +evil*attach-escape-hook ()
(defun +evil*attach-escape-hook ()
"Run the `+evil-esc-hook'."
(run-hooks '+evil-esc-hook))
(advice-add #'evil-force-normal-state :after #'+evil*attach-escape-hook)
(advice-add #'evil-force-normal-state :after #'+evil*attach-escape-hook)
(defun +evil|escape-minibuffer ()
(defun +evil|escape-minibuffer ()
"Quit the minibuffer if open."
(when (minibuffer-window-active-p (minibuffer-window))
(abort-recursive-edit)))
(defun +evil|escape-highlights ()
(defun +evil|escape-highlights ()
"Disable ex search buffer highlights."
(when (evil-ex-hl-active-p 'evil-ex-search)
(evil-ex-nohighlight)))
(add-hook! '+evil-esc-hook '(+evil|escape-minibuffer +evil|escape-highlights))
(add-hook! '+evil-esc-hook '(+evil|escape-minibuffer +evil|escape-highlights))
(defun +evil*restore-normal-state-on-windmove (orig-fn &rest args)
(defun +evil*restore-normal-state-on-windmove (orig-fn &rest args)
"If in anything but normal or motion mode when moving to another window,
restore normal mode. This prevents insert state from bleeding into other modes
across windows."
(unless (memq evil-state '(normal motion))
(evil-normal-state +1))
(apply orig-fn args))
(advice-add #'windmove-do-window-select :around #'+evil*restore-normal-state-on-windmove)
(advice-add #'windmove-do-window-select :around #'+evil*restore-normal-state-on-windmove)
(defun +evil*static-reindent (orig-fn &rest args)
(defun +evil*static-reindent (orig-fn &rest args)
"Don't move cursor on indent."
(save-excursion (apply orig-fn args)))
(advice-add #'evil-indent :around #'+evil*static-reindent)
(advice-add #'evil-indent :around #'+evil*static-reindent)
;; Move to new split
(defun +evil*window-follow (&rest _) (evil-window-down 1))
(defun +evil*window-vfollow (&rest _) (evil-window-right 1))
(advice-add #'evil-window-split :after #'+evil*window-follow)
(advice-add #'evil-window-vsplit :after #'+evil*window-vfollow)
;; monkey patch `evil-ex-replace-special-filenames' to add more ex
;; substitution flags to evil-mode
(advice-add #'evil-ex-replace-special-filenames
;; monkey patch `evil-ex-replace-special-filenames' to add more ex
;; substitution flags to evil-mode
(advice-add #'evil-ex-replace-special-filenames
:override #'+evil*ex-replace-special-filenames)
;; Add extra argument types that highlight matches in the current buffer.
;; TODO Must be simpler way to do this
(evil-ex-define-argument-type buffer-match :runner +evil-ex-buffer-match)
(evil-ex-define-argument-type global-match :runner +evil-ex-global-match)
;; Add extra argument types that highlight matches in the current buffer.
;; TODO Must be simpler way to do this
(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)))
(evil-define-interactive-code "<g//>"
(evil-define-interactive-code "<g//>"
:ex-arg global-match (when (evil-ex-p) (evil-ex-parse-global evil-ex-argument)))
(evil-define-operator +evil:global (beg end pattern command &optional invert)
(evil-define-operator +evil:global (beg end pattern command &optional invert)
"Rewritten :g[lobal] that will highlight buffer matches. Takes the same arguments."
:motion mark-whole-buffer :move-point nil
(interactive "<r><g//><!>")
(evil-ex-global beg end pattern command invert))
(evil-define-operator +evil:align (&optional beg end bang pattern)
(evil-define-operator +evil:align (&optional beg end bang pattern)
"Ex interface to `align-regexp'. Accepts vim-style regexps."
(interactive "<r><!><//>")
(align-regexp
@ -170,8 +161,8 @@ across windows."
(evil-transform-vim-style-regexp pattern)))
1 1))
(evil-ex-define-cmd "g[lobal]" #'+evil:global)
(evil-ex-define-cmd "al[ign]" #'+evil:align)
(evil-ex-define-cmd "g[lobal]" #'+evil:global)
(evil-ex-define-cmd "al[ign]" #'+evil:align))
;;
@ -383,7 +374,6 @@ the new algorithm is confusing, like in python or ruby."
(?\; "[;:]")))
:config
;; (evil-snipe-mode +1)
(evil-snipe-override-mode +1)
;; Switch to evil-easymotion/avy after a snipe
(map! :map evil-snipe-parent-transient-map
@ -434,6 +424,8 @@ the new algorithm is confusing, like in python or ruby."
neo-show-updir-line nil
neo-theme 'nerd ; fallback
neo-banner-message nil
neo-confirm-create-file #'off-p
neo-confirm-create-directory #'off-p
neo-show-hidden-files nil
neo-hidden-regexp-list
'(;; vcs folders
@ -447,16 +439,10 @@ the new algorithm is confusing, like in python or ruby."
"~$"
"^#.*#$"))
(set! :evil-state 'neotree-mode 'motion)
(evil-set-initial-state 'neotree-mode 'motion)
(push neo-buffer-name winner-boring-buffers)
(defun +evil*neotree-create-node (orig-fun &rest args)
"Don't ask for confirmation when creating files"
(cl-letf (((symbol-function 'yes-or-no-p) (lambda (&rest _) t)))
(apply orig-fun args)))
(advice-add #'neotree-create-node :around #'+evil*neotree-create-node)
;; `neotree-mode-map' are overridden when the neotree buffer is created. So we
;; bind them in a hook.
(add-hook 'neo-after-create-hook #'+evil|neotree-init-keymap)

View file

@ -46,6 +46,9 @@
"Run everytime `org-mode' is enabled."
(setq line-spacing 1)
;; show-paren-mode causes problems for org-indent-mode
(show-paren-mode -1)
(visual-line-mode +1)
(when (and (featurep 'evil) evil-mode)
(evil-org-mode +1))