From 5fb028b49daf4fe1bb347dcc91ca7b3dbd62d986 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Mon, 15 May 2017 13:52:22 +0200 Subject: [PATCH] feature/evil: refactor --- core/core-ui.el | 9 +- modules/feature/evil/autoload/evil.el | 208 +++++++++++++------------- modules/feature/evil/config.el | 176 ++++++++++------------ modules/lang/org/config.el | 3 + 4 files changed, 197 insertions(+), 199 deletions(-) diff --git a/core/core-ui.el b/core/core-ui.el index be7ac2f04..d28d221ec 100644 --- a/core/core-ui.el +++ b/core/core-ui.el @@ -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 diff --git a/modules/feature/evil/autoload/evil.el b/modules/feature/evil/autoload/evil.el index 64f5e0cc1..7048d342f 100644 --- a/modules/feature/evil/autoload/evil.el +++ b/modules/feature/evil/autoload/evil.el @@ -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 "") + (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 "") + (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 "") + (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 "") + (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 "") + (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 "") - (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 "") - (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 "") - (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 "") - (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 "") - (doom-narrow-buffer beg end bang)) diff --git a/modules/feature/evil/config.el b/modules/feature/evil/config.el index 2044a39d2..b36d50f45 100644 --- a/modules/feature/evil/config.el +++ b/modules/feature/evil/config.el @@ -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,93 +75,94 @@ (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) - "Define a text object." - (define-key evil-inner-text-objects-map key inner-fn) - (define-key evil-outer-text-objects-map key (or outer-fn inner-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 - "A hook run after ESC is pressed in normal mode (invoked by + ;; 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 () - "Run the `+evil-esc-hook'." - (run-hooks '+evil-esc-hook)) -(advice-add #'evil-force-normal-state :after #'+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) -(defun +evil|escape-minibuffer () - "Quit the minibuffer if open." - (when (minibuffer-window-active-p (minibuffer-window)) - (abort-recursive-edit))) + (defun +evil|escape-minibuffer () + "Quit the minibuffer if open." + (when (minibuffer-window-active-p (minibuffer-window)) + (abort-recursive-edit))) -(defun +evil|escape-highlights () - "Disable ex search buffer highlights." - (when (evil-ex-hl-active-p 'evil-ex-search) - (evil-ex-nohighlight))) + (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) - "If in anything but normal or motion mode when moving to another window, + (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) + (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) -(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) + (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) -;; 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 + :override #'+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 "" + :ex-arg buffer-match (list (when (evil-ex-p) evil-ex-argument))) + (evil-define-interactive-code "" + :ex-arg global-match (when (evil-ex-p) (evil-ex-parse-global evil-ex-argument))) -(evil-define-interactive-code "" - :ex-arg buffer-match (list (when (evil-ex-p) evil-ex-argument))) -(evil-define-interactive-code "" - :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) + "Rewritten :g[lobal] that will highlight buffer matches. Takes the same arguments." + :motion mark-whole-buffer :move-point nil + (interactive "") + (evil-ex-global beg end pattern command 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 "") - (evil-ex-global beg end pattern command invert)) + (evil-define-operator +evil:align (&optional beg end bang pattern) + "Ex interface to `align-regexp'. Accepts vim-style regexps." + (interactive "") + (align-regexp + beg end + (concat "\\(\\s-*\\)" + (if bang + (regexp-quote pattern) + (evil-transform-vim-style-regexp pattern))) + 1 1)) -(evil-define-operator +evil:align (&optional beg end bang pattern) - "Ex interface to `align-regexp'. Accepts vim-style regexps." - (interactive "") - (align-regexp - beg end - (concat "\\(\\s-*\\)" - (if bang - (regexp-quote pattern) - (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) diff --git a/modules/lang/org/config.el b/modules/lang/org/config.el index 5639e0c07..268571e68 100644 --- a/modules/lang/org/config.el +++ b/modules/lang/org/config.el @@ -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))