Refactor feature/evil hacks & advice; fix tests
This commit is contained in:
parent
0c3484414c
commit
5cd29479f4
6 changed files with 166 additions and 163 deletions
|
@ -193,3 +193,99 @@ evil-window-move-* (e.g. `evil-window-move-far-left')"
|
|||
(goto-char beg)
|
||||
(call-interactively #'wgrep-mark-deletion))
|
||||
beg (1- end) nil))))
|
||||
|
||||
|
||||
;;
|
||||
;; Advice
|
||||
;;
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*static-reindent (orig-fn &rest args)
|
||||
"Don't move cursor on indent."
|
||||
(save-excursion (apply orig-fn args)))
|
||||
|
||||
;;;###autoload
|
||||
(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 emacs))
|
||||
(evil-normal-state +1))
|
||||
(apply orig-fn args))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*resolve-vim-path (file-name)
|
||||
"Take a path and resolve any vim-like filename modifiers in it. This adds
|
||||
support for most vim file modifiers, as well as:
|
||||
|
||||
%:P Resolves to `doom-project-root'.
|
||||
|
||||
See http://vimdoc.sourceforge.net/htmldoc/cmdline.html#filename-modifiers for
|
||||
more information on modifiers."
|
||||
(let* (case-fold-search
|
||||
(regexp (concat "\\(?:^\\|[^\\\\]\\)"
|
||||
"\\([#%]\\)"
|
||||
"\\(\\(?::\\(?:[PphtreS~.]\\|g?s[^:\t\n ]+\\)\\)*\\)"))
|
||||
(matches
|
||||
(cl-loop with i = 0
|
||||
while (and (< i (length file-name))
|
||||
(string-match regexp file-name i))
|
||||
do (setq i (1+ (match-beginning 0)))
|
||||
and collect
|
||||
(cl-loop for j to (/ (length (match-data)) 2)
|
||||
collect (match-string j file-name)))))
|
||||
(dolist (match matches)
|
||||
(let ((flags (split-string (car (cdr (cdr match))) ":" t))
|
||||
(path (and buffer-file-name
|
||||
(pcase (car (cdr match))
|
||||
("%" (file-relative-name buffer-file-name))
|
||||
("#" (save-excursion (other-window 1) (file-relative-name buffer-file-name))))))
|
||||
flag global)
|
||||
(if (not path)
|
||||
(setq path "")
|
||||
(while flags
|
||||
(setq flag (pop flags))
|
||||
(when (string-suffix-p "\\" flag)
|
||||
(setq flag (concat flag (pop flags))))
|
||||
(when (string-prefix-p "gs" flag)
|
||||
(setq global t
|
||||
flag (substring flag 1)))
|
||||
(setq path
|
||||
(or (pcase (substring flag 0 1)
|
||||
("p" (expand-file-name path))
|
||||
("~" (concat "~/" (file-relative-name path "~")))
|
||||
("." (file-relative-name path default-directory))
|
||||
("t" (file-name-nondirectory (directory-file-name path)))
|
||||
("r" (file-name-sans-extension path))
|
||||
("e" (file-name-extension path))
|
||||
("S" (shell-quote-argument path))
|
||||
("h"
|
||||
(let ((parent (file-name-directory (expand-file-name path))))
|
||||
(unless (equal (file-truename path)
|
||||
(file-truename parent))
|
||||
(if (file-name-absolute-p path)
|
||||
(directory-file-name parent)
|
||||
(file-relative-name parent)))))
|
||||
("s"
|
||||
(if (featurep 'evil)
|
||||
(when-let* ((args (evil-delimited-arguments (substring flag 1) 2)))
|
||||
(let ((pattern (evil-transform-vim-style-regexp (car args)))
|
||||
(replace (cadr args)))
|
||||
(replace-regexp-in-string
|
||||
(if global pattern (concat "\\(" pattern "\\).*\\'"))
|
||||
(evil-transform-vim-style-regexp replace) path t t
|
||||
(unless global 1))))
|
||||
path))
|
||||
("P"
|
||||
(let ((default-directory (file-name-directory (expand-file-name path))))
|
||||
(abbreviate-file-name (doom-project-root))))
|
||||
(_ path))
|
||||
"")))
|
||||
;; strip trailing slash, if applicable
|
||||
(when (and (not (string= path "")) (equal (substring path -1) "/"))
|
||||
(setq path (substring path 0 -1))))
|
||||
(setq file-name
|
||||
(replace-regexp-in-string (format "\\(?:^\\|[^\\\\]\\)\\(%s\\)"
|
||||
(regexp-quote (string-trim-left (car match))))
|
||||
path file-name t t 1))))
|
||||
(replace-regexp-in-string regexp "\\1" file-name t)))
|
||||
|
|
|
@ -45,9 +45,6 @@
|
|||
(set! :popup "^\\*evil-registers" '((size . 0.3)))
|
||||
(set! :popup "^\\*Command Line" '((size . 8)))
|
||||
|
||||
;; Don't interfere with localleader key
|
||||
(define-key evil-motion-state-map "\\" nil)
|
||||
|
||||
;; Set cursor colors later, once theme is loaded
|
||||
(defun +evil*init-cursors (&rest _)
|
||||
(setq evil-default-cursor (face-background 'cursor nil t)
|
||||
|
@ -63,19 +60,11 @@
|
|||
(dolist (mode '(help-mode debugger-mode))
|
||||
(evil-set-initial-state mode 'normal))
|
||||
|
||||
;; make `try-expand-dabbrev' from `hippie-expand' work in minibuffer
|
||||
;; @see `he-dabbrev-beg', so we need re-define syntax for '/'
|
||||
(defun minibuffer-inactive-mode-hook-setup ()
|
||||
(set-syntax-table (let* ((table (make-syntax-table)))
|
||||
(modify-syntax-entry ?/ "." table)
|
||||
table)))
|
||||
(add-hook 'minibuffer-inactive-mode-hook #'minibuffer-inactive-mode-hook-setup)
|
||||
|
||||
|
||||
;; --- keybind fixes ----------------------
|
||||
(map! (:after wgrep
|
||||
;; a wrapper that invokes `wgrep-mark-deletion' across lines
|
||||
;; you use `evil-delete' on.
|
||||
;; A wrapper that invokes `wgrep-mark-deletion' across lines you use
|
||||
;; `evil-delete' in wgrep buffers.
|
||||
:map wgrep-mode-map [remap evil-delete] #'+evil-delete)
|
||||
|
||||
;; replace native folding commands
|
||||
|
@ -86,10 +75,6 @@
|
|||
[remap evil-close-folds] #'+evil:fold-close-all
|
||||
[remap evil-open-folds] #'+evil:fold-open-all)
|
||||
|
||||
|
||||
;; --- evil hacks -------------------------
|
||||
(advice-add #'evil-force-normal-state :after #'doom/escape)
|
||||
|
||||
(defun +evil|disable-highlights ()
|
||||
"Disable ex search buffer highlights."
|
||||
(when (evil-ex-hl-active-p 'evil-ex-search)
|
||||
|
@ -97,28 +82,40 @@
|
|||
t))
|
||||
(add-hook 'doom-escape-hook #'+evil|disable-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,
|
||||
restore normal mode. This prevents insert state from bleeding into other modes
|
||||
across windows."
|
||||
(unless (memq evil-state '(normal motion emacs))
|
||||
(evil-normal-state +1))
|
||||
(apply orig-fn args))
|
||||
|
||||
;; --- evil hacks -------------------------
|
||||
;; Make ESC (from normal mode) the universal escaper. See `doom-escape-hook'.
|
||||
(advice-add #'evil-force-normal-state :after #'doom/escape)
|
||||
;; Ensure buffer is in normal mode when we leave it and return to it.
|
||||
(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)))
|
||||
;; Don't move cursor when indenting
|
||||
(advice-add #'evil-indent :around #'+evil*static-reindent)
|
||||
|
||||
;; monkey patch `evil-ex-replace-special-filenames' to add more ex
|
||||
;; substitution flags to evil-mode
|
||||
(advice-add #'evil-ex-replace-special-filenames :override #'doom-resolve-vim-path)
|
||||
(advice-add #'evil-ex-replace-special-filenames :override #'+evil*resolve-vim-path)
|
||||
|
||||
;; make `try-expand-dabbrev' from `hippie-expand' work in minibuffer
|
||||
;; @see `he-dabbrev-beg', so we need re-define syntax for '/'
|
||||
(defun +evil*fix-dabbrev-in-minibuffer ()
|
||||
(set-syntax-table (let* ((table (make-syntax-table)))
|
||||
(modify-syntax-entry ?/ "." table)
|
||||
table)))
|
||||
(add-hook 'minibuffer-inactive-mode-hook #'+evil*fix-dabbrev-in-minibuffer)
|
||||
|
||||
;; Move to new split -- setting `evil-split-window-below' &
|
||||
;; `evil-vsplit-window-right' to non-nil mimics this, but that doesn't update
|
||||
;; window history. That means when you delete a new split, Emacs leaves you on
|
||||
;; the 2nd to last window on the history stack, which is jarring.
|
||||
;;
|
||||
;; Also recenters window on cursor in new split
|
||||
(defun +evil*window-follow (&rest _) (evil-window-down 1) (recenter))
|
||||
(advice-add #'evil-window-split :after #'+evil*window-follow)
|
||||
(defun +evil*window-vfollow (&rest _) (evil-window-right 1) (recenter))
|
||||
(advice-add #'evil-window-vsplit :after #'+evil*window-vfollow)
|
||||
|
||||
;; These arg types will highlight matches in the current buffer
|
||||
(evil-ex-define-argument-type buffer-match :runner +evil-ex-buffer-match)
|
||||
(evil-ex-define-argument-type global-match :runner +evil-ex-global-match)
|
||||
|
||||
;; By default :g[lobal] doesn't highlight matches in the current buffer. I've
|
||||
;; got to write my own argument type and interactive code to get it to do so.
|
||||
(evil-ex-define-argument-type global-delim-match :runner +evil-ex-global-delim-match)
|
||||
|
@ -137,18 +134,7 @@ across windows."
|
|||
(evil-set-command-properties
|
||||
'+evil:align :move-point t :ex-arg 'buffer-match :ex-bang t :evil-mc t :keep-visual t :suppress-operator t)
|
||||
(evil-set-command-properties
|
||||
'+evil:mc :move-point nil :ex-arg 'global-match :ex-bang t :evil-mc t)
|
||||
|
||||
;; Move to new split -- setting `evil-split-window-below' &
|
||||
;; `evil-vsplit-window-right' to non-nil mimics this, but that doesn't update
|
||||
;; window history. That means when you delete a new split, Emacs leaves you on
|
||||
;; the 2nd to last window on the history stack, which is jarring.
|
||||
;;
|
||||
;; Also recenters window on cursor in new split
|
||||
(defun +evil*window-follow (&rest _) (evil-window-down 1) (recenter))
|
||||
(defun +evil*window-vfollow (&rest _) (evil-window-right 1) (recenter))
|
||||
(advice-add #'evil-window-split :after #'+evil*window-follow)
|
||||
(advice-add #'evil-window-vsplit :after #'+evil*window-vfollow))
|
||||
'+evil:mc :move-point nil :ex-arg 'global-match :ex-bang t :evil-mc t))
|
||||
|
||||
|
||||
;;
|
||||
|
|
|
@ -5,8 +5,47 @@
|
|||
|
||||
;;
|
||||
;; `evil-ex-replace-special-filenames'
|
||||
;; NOTE The majority of this function is tested in core/test/core-lib.el, this
|
||||
;; only tests the evil-mode-specific functionality.
|
||||
(def-test! resolve-vim-path
|
||||
(cl-flet ((do-it #'evil-ex-replace-special-filenames))
|
||||
;; file modifiers
|
||||
(let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el")
|
||||
(default-directory "~/.emacs.d/test/modules/"))
|
||||
(should (equal (do-it "%") "feature/test-evil.el"))
|
||||
(should (equal (do-it "%:r") "feature/test-evil"))
|
||||
(should (equal (do-it "%:r.elc") "feature/test-evil.elc"))
|
||||
(should (equal (do-it "%:e") "el"))
|
||||
(should (equal (do-it "%:p") (expand-file-name buffer-file-name)))
|
||||
(should (equal (do-it "%:h") "feature"))
|
||||
(should (equal (do-it "%:t") "test-evil.el"))
|
||||
(should (equal (do-it "%:.") "feature/test-evil.el"))
|
||||
(should (equal (do-it "%:~") "~/.emacs.d/test/modules/feature/test-evil.el"))
|
||||
(should (equal (file-truename (do-it "%:p"))
|
||||
(file-truename buffer-file-name))))
|
||||
;; nested file modifiers
|
||||
(let ((buffer-file-name "~/vim/src/version.c")
|
||||
(default-directory "~/vim/"))
|
||||
(should (equal (do-it "%:p") (expand-file-name "~/vim/src/version.c")))
|
||||
(should (equal (do-it "%:p:.") "src/version.c"))
|
||||
(should (equal (do-it "%:p:~") "~/vim/src/version.c"))
|
||||
(should (equal (do-it "%:h") "src"))
|
||||
(should (equal (do-it "%:p:h") (expand-file-name "~/vim/src")))
|
||||
(should (equal (do-it "%:p:h:h") (expand-file-name "~/vim")))
|
||||
(should (equal (do-it "%:t") "version.c"))
|
||||
(should (equal (do-it "%:p:t") "version.c"))
|
||||
(should (equal (do-it "%:r") "src/version"))
|
||||
(should (equal (do-it "%:p:r") (expand-file-name "~/vim/src/version")))
|
||||
(should (equal (do-it "%:t:r") "version")))
|
||||
;; empty file modifiers
|
||||
(let (buffer-file-name default-directory)
|
||||
(should (equal (do-it "%") ""))
|
||||
(should (equal (do-it "%:r") ""))
|
||||
(should (equal (do-it "%:e") ""))
|
||||
(should (equal (do-it "%:h") ""))
|
||||
(should (equal (do-it "%:t") ""))
|
||||
(should (equal (do-it "%:.") ""))
|
||||
(should (equal (do-it "%:~") ""))
|
||||
(should (equal (do-it "%:P") "")))))
|
||||
|
||||
(def-test! file-modifiers
|
||||
(cl-flet ((do-it #'evil-ex-replace-special-filenames))
|
||||
(let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el")
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue