💥 Remove :feature category
:feature was a "catch-all" category. Many of its modules fit better in other categories, so they've been moved: - feature/debugger -> tools/debugger - feature/evil -> editor/evil - feature/eval -> tools/eval - feature/lookup -> tools/lookup - feature/snippets -> editor/snippets - feature/file-templates -> editor/file-templates - feature/workspaces -> ui/workspaces More potential changes in the future: - A new :term category for terminal emulation modules (eshell, term and vterm). - A new :os category for modules dedicated to os-specific functionality. The :tools macos module would fit here, but so would modules for nixos and arch. - A new :services category for web-service integration, like wakatime, twitter, elfeed, gist and pastebin services.
This commit is contained in:
parent
52eed893fe
commit
77e4cc4d58
193 changed files with 304 additions and 303 deletions
174
modules/editor/evil/+commands.el
Normal file
174
modules/editor/evil/+commands.el
Normal file
|
@ -0,0 +1,174 @@
|
|||
;;; editor/evil/+commands.el -*- lexical-binding: t; -*-
|
||||
|
||||
(evil-define-operator +evil:open-scratch-buffer (bang)
|
||||
(interactive "<!>")
|
||||
(doom/open-scratch-buffer bang))
|
||||
|
||||
(evil-define-command +evil:pwd (bang)
|
||||
"Display the current working directory. If BANG, copy it to your clipboard."
|
||||
(interactive "<!>")
|
||||
(if (not bang)
|
||||
(pwd)
|
||||
(kill-new default-directory)
|
||||
(message "Copied to clipboard")))
|
||||
|
||||
(evil-define-command +evil:make (arguments &optional bang)
|
||||
"Run make with ARGUMENTS.
|
||||
If BANG is non-nil, open compilation output in a comint buffer.
|
||||
|
||||
If BANG, then run ARGUMENTS as a full command. This command understands vim file
|
||||
modifiers (like %:p:h). See `+evil*resolve-vim-path' for details."
|
||||
(interactive "<sh><!>")
|
||||
(+evil:compile (format "make %s"
|
||||
(evil-ex-replace-special-filenames
|
||||
arguments))
|
||||
bang))
|
||||
|
||||
(evil-define-command +evil:compile (arguments &optional bang)
|
||||
"Run `compile-command' with ARGUMENTS.
|
||||
If BANG is non-nil, open compilation output in a comint buffer.
|
||||
|
||||
This command understands vim file modifiers (like %:p:h). See
|
||||
`+evil*resolve-vim-path' for details."
|
||||
(interactive "<sh><!>")
|
||||
(compile (evil-ex-replace-special-filenames
|
||||
(format "%s %s"
|
||||
(eval compile-command)
|
||||
arguments))
|
||||
bang))
|
||||
|
||||
(evil-define-command +evil:reverse-lines (beg end)
|
||||
"Reverse lines between BEG and END."
|
||||
(interactive "<r>")
|
||||
(reverse-region beg end))
|
||||
|
||||
(evil-define-command +evil:cd (&optional path)
|
||||
"Change `default-directory' with `cd'."
|
||||
(interactive "<f>")
|
||||
(let ((path (or path "~")))
|
||||
(cd path)
|
||||
(message "Changed directory to '%s'" (abbreviate-file-name (expand-file-name path)))))
|
||||
|
||||
(evil-define-command +evil:kill-all-buffers (&optional bang)
|
||||
"Kill all buffers. If BANG, kill current session too."
|
||||
(interactive "<!>")
|
||||
(if (and bang (fboundp '+workspace/kill-session))
|
||||
(+workspace/kill-session)
|
||||
(doom/kill-all-buffers)))
|
||||
|
||||
(evil-define-command +evil:kill-matching-buffers (&optional bang pattern)
|
||||
"Kill all buffers matching PATTERN regexp. If BANG, only match project
|
||||
buffers."
|
||||
(interactive "<a>")
|
||||
(doom/kill-matching-buffers pattern bang))
|
||||
|
||||
|
||||
;;
|
||||
;; Commands
|
||||
|
||||
;;; Custom commands
|
||||
;; Editing
|
||||
(evil-ex-define-cmd "@" #'+evil:macro-on-all-lines) ; TODO Test me
|
||||
(evil-ex-define-cmd "al[ign]" #'+evil:align)
|
||||
(evil-ex-define-cmd "ral[ign]" #'+evil:align-right)
|
||||
(evil-ex-define-cmd "enhtml" #'+web:encode-html-entities)
|
||||
(evil-ex-define-cmd "dehtml" #'+web:decode-html-entities)
|
||||
(evil-ex-define-cmd "mc" #'+multiple-cursors:evil-mc)
|
||||
(evil-ex-define-cmd "iedit" #'evil-multiedit-ex-match)
|
||||
(evil-ex-define-cmd "na[rrow]" #'+evil:narrow-buffer)
|
||||
(evil-ex-define-cmd "retab" #'+evil:retab)
|
||||
(evil-ex-define-cmd "rev[erse]" #'+evil:reverse-lines)
|
||||
|
||||
;;; External resources
|
||||
;; TODO (evil-ex-define-cmd "db" #'doom:db)
|
||||
;; TODO (evil-ex-define-cmd "dbu[se]" #'doom:db-select)
|
||||
;; TODO (evil-ex-define-cmd "go[ogle]" #'doom:google-search)
|
||||
(evil-ex-define-cmd "lo[okup]" #'+lookup:online)
|
||||
(evil-ex-define-cmd "dash" #'+lookup:dash)
|
||||
(evil-ex-define-cmd "http" #'httpd-start) ; start http server
|
||||
(evil-ex-define-cmd "repl" #'+eval:repl) ; invoke or send to repl
|
||||
|
||||
;; TODO (evil-ex-define-cmd "rx" 'doom:regex) ; open re-builder
|
||||
(evil-ex-define-cmd "sh[ell]" #'+eshell:run)
|
||||
(evil-ex-define-cmd "t[mux]" #'+tmux:run) ; send to tmux
|
||||
(evil-ex-define-cmd "tcd" #'+tmux:cd-here) ; cd to default-directory in tmux
|
||||
(evil-ex-define-cmd "pad" #'+evil:open-scratch-buffer)
|
||||
|
||||
;;; GIT
|
||||
(evil-ex-define-cmd "gist" #'+gist:send) ; send current buffer/region to gist
|
||||
(evil-ex-define-cmd "gistl" #'+gist:list) ; list gists by user
|
||||
(evil-ex-define-cmd "gbrowse" #'+vc:git-browse) ; show file/region in github/gitlab
|
||||
(evil-ex-define-cmd "gissues" #'forge-browse-issues) ; show github issues
|
||||
(evil-ex-define-cmd "git" #'magit-status) ; open magit status window
|
||||
(evil-ex-define-cmd "gstage" #'magit-stage)
|
||||
(evil-ex-define-cmd "gunstage" #'magit-unstage)
|
||||
(evil-ex-define-cmd "gblame" #'magit-blame)
|
||||
(evil-ex-define-cmd "grevert" #'git-gutter:revert-hunk)
|
||||
|
||||
;;; Dealing with buffers
|
||||
(evil-ex-define-cmd "k[ill]" #'doom/kill-this-buffer)
|
||||
(evil-ex-define-cmd "k[ill]all" #'+evil:kill-all-buffers)
|
||||
(evil-ex-define-cmd "k[ill]m" #'+evil:kill-matching-buffers)
|
||||
(evil-ex-define-cmd "k[ill]o" #'doom/kill-other-buffers)
|
||||
(evil-ex-define-cmd "k[ill]b" #'doom/kill-buried-buffers)
|
||||
(evil-ex-define-cmd "l[ast]" #'doom/popup-restore)
|
||||
(evil-ex-define-cmd "m[sg]" #'view-echo-area-messages)
|
||||
(evil-ex-define-cmd "pop[up]" #'doom/popup-this-buffer)
|
||||
|
||||
;;; Project navigation
|
||||
(evil-ex-define-cmd "a" #'projectile-find-other-file)
|
||||
(evil-ex-define-cmd "cd" #'+evil:cd)
|
||||
(evil-ex-define-cmd "pwd" #'+evil:pwd)
|
||||
|
||||
(cond ((featurep! :completion ivy)
|
||||
(evil-ex-define-cmd "ag" #'+ivy:ag)
|
||||
(evil-ex-define-cmd "agc[wd]" #'+ivy:ag-from-cwd)
|
||||
(evil-ex-define-cmd "rg" #'+ivy:rg)
|
||||
(evil-ex-define-cmd "rgc[wd]" #'+ivy:rg-from-cwd)
|
||||
(evil-ex-define-cmd "pt" #'+ivy:pt)
|
||||
(evil-ex-define-cmd "ptc[wd]" #'+ivy:pt-from-cwd)
|
||||
(evil-ex-define-cmd "grep" #'+ivy:grep)
|
||||
(evil-ex-define-cmd "grepc[wd]" #'+ivy:grep-from-cwd)
|
||||
(evil-ex-define-cmd "sw[iper]" #'+ivy:swiper)
|
||||
(evil-ex-define-cmd "todo" #'+ivy:todo))
|
||||
|
||||
((featurep! :completion helm)
|
||||
(evil-ex-define-cmd "ag" #'+helm:ag)
|
||||
(evil-ex-define-cmd "agc[wd]" #'+helm:ag-from-cwd)
|
||||
(evil-ex-define-cmd "rg" #'+helm:rg)
|
||||
(evil-ex-define-cmd "rgc[wd]" #'+helm:rg-from-cwd)
|
||||
(evil-ex-define-cmd "pt" #'+helm:pt)
|
||||
(evil-ex-define-cmd "ptc[wd]" #'+helm:pt-from-cwd)
|
||||
(evil-ex-define-cmd "grep" #'+helm:grep)
|
||||
(evil-ex-define-cmd "grepc[wd]" #'+helm:grep-from-cwd)
|
||||
;; (evil-ex-define-cmd "todo" #'+helm:todo) TODO implement `+helm:todo'
|
||||
))
|
||||
|
||||
;;; Project tools
|
||||
(evil-ex-define-cmd "compile" #'+evil:compile)
|
||||
(evil-ex-define-cmd "mak[e]" #'+evil:make)
|
||||
;; (evil-ex-define-cmd "debug" #'+debug/run)
|
||||
(evil-ex-define-cmd "er[rors]" #'flycheck-list-errors)
|
||||
|
||||
;;; File operations
|
||||
(evil-ex-define-cmd "cp" #'+evil:copy-this-file)
|
||||
(evil-ex-define-cmd "mv" #'+evil:move-this-file)
|
||||
(evil-ex-define-cmd "rm" #'+evil:delete-this-file)
|
||||
|
||||
;;; Sessions/tabs
|
||||
(evil-ex-define-cmd "sclear" #'+workspace/kill-session)
|
||||
(evil-ex-define-cmd "sl[oad]" #'doom/quickload-session)
|
||||
(evil-ex-define-cmd "ss[ave]" #'doom/quicksave-session)
|
||||
(evil-ex-define-cmd "tabc[lose]" #'+workspace:delete)
|
||||
(evil-ex-define-cmd "tabclear" #'doom/kill-all-buffers)
|
||||
(evil-ex-define-cmd "tabl[ast]" #'+workspace/switch-to-last)
|
||||
(evil-ex-define-cmd "tabload" #'+workspace:load)
|
||||
(evil-ex-define-cmd "tabn[ew]" #'+workspace:new)
|
||||
(evil-ex-define-cmd "tabn[ext]" #'+workspace:switch-next)
|
||||
(evil-ex-define-cmd "tabp[rev]" #'+workspace:switch-previous)
|
||||
(evil-ex-define-cmd "tabr[ename]" #'+workspace:rename)
|
||||
(evil-ex-define-cmd "tabs" #'+workspace/display)
|
||||
(evil-ex-define-cmd "tabsave" #'+workspace:save)
|
||||
|
||||
;;; Org-mode
|
||||
(evil-ex-define-cmd "cap" #'org-capture)
|
204
modules/editor/evil/+everywhere.el
Normal file
204
modules/editor/evil/+everywhere.el
Normal file
|
@ -0,0 +1,204 @@
|
|||
;;; editor/evil/+everywhere.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; We load evil-collection ourselves for these reasons:
|
||||
;;
|
||||
;; 1. To truly lazy load it. Some of its modules, like
|
||||
;; evil-collection-{elisp-mode,buff-menu} are loaded immediately, because
|
||||
;; Emacs loads their packages immediately, which pulls in all of
|
||||
;; evil-collection (and other packages with it, sometimes).
|
||||
;; 2. This ensures a predictable load order, versus lazy loading using :defer or
|
||||
;; :after-call. This means users can use (after! org ...) and be sure that
|
||||
;; their changes will override evil-collection's.
|
||||
;; 3. Eventually, I'd like to remove evil-collection. It changes too often,
|
||||
;; introduces breaking bugs too frequently, and I don't always agree with
|
||||
;; their design choices. Regardless, there are useful tidbits I'd like to
|
||||
;; keep. This will be a slow transition, but this file is where most of it
|
||||
;; will happen.
|
||||
;; 4. Adds `+evil-collection-disabled-list', to make it easier for users to
|
||||
;; disable modules, and to reduce the effort required to maintain our copy of
|
||||
;; `evil-collection-list' (now I can just copy it from time to time).
|
||||
|
||||
(defvar +evil-collection-disabled-list
|
||||
'(anaconda-mode
|
||||
buff-menu
|
||||
comint
|
||||
company
|
||||
custom
|
||||
eldoc
|
||||
elisp-mode
|
||||
ert
|
||||
free-keys
|
||||
help
|
||||
helm
|
||||
image
|
||||
ivy
|
||||
kotlin-mode
|
||||
occur
|
||||
package-menu
|
||||
ruby-mode
|
||||
simple
|
||||
slime)
|
||||
"A list of `evil-collection' modules to ignore. See the definition of this
|
||||
variable for an explanation of the defaults (in comments). See
|
||||
`evil-collection-mode-list' for a list of available options.")
|
||||
|
||||
(defvar evil-collection-setup-minibuffer nil)
|
||||
|
||||
;; This has to be defined here since evil-collection doesn't autoload its own.
|
||||
;; It must be updated whenever evil-collection updates theirs.
|
||||
(defvar evil-collection-mode-list
|
||||
`(ag
|
||||
alchemist
|
||||
anaconda-mode
|
||||
arc-mode
|
||||
bookmark
|
||||
(buff-menu "buff-menu")
|
||||
calc
|
||||
calendar
|
||||
cider
|
||||
cmake-mode
|
||||
comint
|
||||
company
|
||||
compile
|
||||
custom
|
||||
cus-theme
|
||||
daemons
|
||||
deadgrep
|
||||
debbugs
|
||||
debug
|
||||
diff-mode
|
||||
dired
|
||||
disk-usage
|
||||
doc-view
|
||||
ebib
|
||||
edbi
|
||||
edebug
|
||||
ediff
|
||||
eglot
|
||||
elfeed
|
||||
elisp-mode
|
||||
elisp-refs
|
||||
emms
|
||||
epa
|
||||
ert
|
||||
eshell
|
||||
eval-sexp-fu
|
||||
evil-mc
|
||||
eww
|
||||
flycheck
|
||||
flymake
|
||||
free-keys
|
||||
geiser
|
||||
ggtags
|
||||
git-timemachine
|
||||
go-mode
|
||||
grep
|
||||
guix
|
||||
hackernews
|
||||
helm
|
||||
help
|
||||
helpful
|
||||
ibuffer
|
||||
image
|
||||
image-dired
|
||||
image+
|
||||
imenu-list
|
||||
indium
|
||||
info
|
||||
ivy
|
||||
js2-mode
|
||||
log-view
|
||||
lsp-ui-imenu
|
||||
lua-mode
|
||||
kotlin-mode
|
||||
macrostep
|
||||
man
|
||||
magit
|
||||
magit-todos
|
||||
,@(when evil-collection-setup-minibuffer '(minibuffer))
|
||||
mu4e
|
||||
mu4e-conversation
|
||||
neotree
|
||||
notmuch
|
||||
nov
|
||||
;; occur is in replace.el which was built-in before Emacs 26.
|
||||
(occur ,(if (<= emacs-major-version 25) "replace" 'replace))
|
||||
omnisharp
|
||||
outline
|
||||
p4
|
||||
(package-menu package)
|
||||
pass
|
||||
(pdf pdf-view)
|
||||
popup
|
||||
proced
|
||||
process-menu
|
||||
prodigy
|
||||
profiler
|
||||
python
|
||||
quickrun
|
||||
racer
|
||||
realgud
|
||||
reftex
|
||||
restclient
|
||||
rjsx-mode
|
||||
robe
|
||||
ruby-mode
|
||||
rtags
|
||||
simple
|
||||
slime
|
||||
(term term ansi-term multi-term)
|
||||
tetris
|
||||
tide
|
||||
transmission
|
||||
typescript-mode
|
||||
vc-annotate
|
||||
vc-dir
|
||||
vc-git
|
||||
vdiff
|
||||
view
|
||||
vlf
|
||||
w3m
|
||||
wdired
|
||||
wgrep
|
||||
which-key
|
||||
woman
|
||||
xref
|
||||
youtube-dl
|
||||
(ztree ztree-diff)))
|
||||
|
||||
(defun +evil-collection-init (module)
|
||||
(unless (memq (or (car-safe module) module) +evil-collection-disabled-list)
|
||||
(doom-log "Initialized evil-collection-%s" (or (car-safe module) module))
|
||||
(with-demoted-errors "evil-collection error: %s"
|
||||
(evil-collection-init (list module)))))
|
||||
|
||||
|
||||
;;
|
||||
;; Bootstrap
|
||||
|
||||
;; These modes belong to packages that Emacs always loads at startup, causing
|
||||
;; evil-collection to load immediately. We avoid this by loading them after
|
||||
;; evil-collection has first loaded...
|
||||
(after! evil-collection
|
||||
(let (+evil-collection-disabled-list)
|
||||
(mapc #'+evil-collection-init '(comint custom help))))
|
||||
|
||||
;; ...or on first invokation of their associated major/minor modes.
|
||||
(add-transient-hook! 'Buffer-menu-mode
|
||||
(+evil-collection-init '(buff-menu "buff-menu")))
|
||||
(add-transient-hook! 'image-mode
|
||||
(+evil-collection-init 'image))
|
||||
(add-transient-hook! 'emacs-lisp-mode
|
||||
(+evil-collection-init 'elisp-mode))
|
||||
(add-transient-hook! 'occur-mode
|
||||
(+evil-collection-init (if EMACS26+ 'replace "replace")))
|
||||
|
||||
(evil-define-key* 'normal process-menu-mode-map
|
||||
"q" #'kill-this-buffer
|
||||
"d" #'process-menu-delete-process)
|
||||
|
||||
;; Load the rest
|
||||
(dolist (mode evil-collection-mode-list)
|
||||
(dolist (req (or (cdr-safe mode) (list mode)))
|
||||
(with-eval-after-load req
|
||||
(+evil-collection-init mode))))
|
176
modules/editor/evil/README.org
Normal file
176
modules/editor/evil/README.org
Normal file
|
@ -0,0 +1,176 @@
|
|||
#+TITLE: feature/evil
|
||||
#+DATE: February 2, 2017
|
||||
#+SINCE: v2.0
|
||||
#+STARTUP: inlineimages
|
||||
|
||||
* Table of Contents :TOC_3:noexport:
|
||||
- [[#description][Description]]
|
||||
- [[#module-flags][Module Flags]]
|
||||
- [[#plugins][Plugins]]
|
||||
- [[#hacks][Hacks]]
|
||||
- [[#prerequisites][Prerequisites]]
|
||||
- [[#features][Features]]
|
||||
- [[#ported-vim-plugins][Ported vim plugins]]
|
||||
- [[#custom-text-objects][Custom Text Objects]]
|
||||
- [[#custom-ex-commands][Custom Ex Commands]]
|
||||
- [[#configuration][Configuration]]
|
||||
- [[#removing-evil-mode][Removing evil-mode]]
|
||||
- [[#restoring-old-substitution-behavior-on-ss][Restoring old substitution behavior on s/S]]
|
||||
|
||||
* Description
|
||||
This holy module brings the vim experience to Emacs.
|
||||
|
||||
** Module Flags
|
||||
+ =+everywhere= Enables evilified keybinds everywhere possible. Uses the
|
||||
[[https://github.com/emacs-evil/evil-collection][evil-collection]] plugin as a foundation.
|
||||
|
||||
** Plugins
|
||||
+ [[https://github.com/emacs-evil/evil][evil]]
|
||||
+ [[https://github.com/wcsmith/evil-args][evil-args]]
|
||||
+ [[https://github.com/linktohack/evil-commentary][evil-commentary]]
|
||||
+ [[https://github.com/PythonNut/evil-easymotion][evil-easymotion]]
|
||||
+ [[https://github.com/cute-jumper/evil-embrace.el][evil-embrace]]
|
||||
+ [[https://github.com/syl20bnr/evil-escape][evil-escape]]
|
||||
+ [[https://github.com/Dewdrops/evil-exchange][evil-exchange]]
|
||||
+ [[https://github.com/TheBB/evil-indent-plus][evil-indent-plus]]
|
||||
+ [[https://github.com/redguardtoo/evil-matchit][evil-matchit]]
|
||||
+ [[https://github.com/cofi/evil-numbers][evil-numbers]]
|
||||
+ [[https://github.com/noctuid/evil-textobj-anyblock][evil-textobj-anyblock]]
|
||||
+ [[https://github.com/hlissner/evil-snipe][evil-snipe]]
|
||||
+ [[https://github.com/emacs-evil/evil-surround][evil-surround]]
|
||||
+ [[https://github.com/alexmurray/evil-vimish-fold][evil-vimish-fold]]
|
||||
+ [[https://github.com/bling/evil-visualstar][evil-visualstar]]
|
||||
+ [[https://github.com/ninrod/exato][exato]]
|
||||
+ [[https://github.com/emacs-evil/evil-collection][evil-collection]]*
|
||||
|
||||
** Hacks
|
||||
+ When a window is split, the new window will be focused.
|
||||
+ The o/O keys will respect and continue commented lines (can be disabled by
|
||||
setting ~+evil-want-o/O-to-continue-comments~ to ~nil~).
|
||||
+ In visual mode, =*= and =#= will search for the current selection instead of
|
||||
the word-at-point.
|
||||
+ The ~:g[lobal]~ ex command has been modified to highlight matches.
|
||||
+ More of vim's filename modifiers are supported in ex commands (like ~:p~,
|
||||
~:p:h~ or ~:t~) than vanilla evil-mode offers.
|
||||
+ A custom filename modifier is available in Doom: ~:P~, which expands to the
|
||||
project root (throws an error if not in a project).
|
||||
|
||||
* Prerequisites
|
||||
This module has no external prerequisites.
|
||||
|
||||
* Features
|
||||
** Ported vim plugins
|
||||
The following vim plugins have been ported to evil:
|
||||
|
||||
| Vim Plugin | Emacs Plugin | Keybind(s) |
|
||||
|-----------------------+--------------------------------+--------------------------------------|
|
||||
| vim-commentary | evil-commentary | omap =gc= |
|
||||
| vim-easymotion | evil-easymotion | omap =gs= |
|
||||
| vim-seek or vim-sneak | evil-snipe | mmap =s=/=S=, omap =z=/=Z= & =x=/=x= |
|
||||
| vim-surround | evil-embrace and evil-surround | vmap =S=, omap =ys= |
|
||||
|
||||
In other modules:
|
||||
+ The tools/neotree & tools/treemacs modules provide a =NERDTree= equivalent.
|
||||
+ The editor/multiple-cursors module contains functionality equal to the
|
||||
following vim plugins:
|
||||
+ evil-multiedit => vim-multiedit
|
||||
+ evil-mc => vim-multiple-cursors
|
||||
|
||||
** Custom Text Objects
|
||||
This module provides a couple extra text objects, along with the built-in ones.
|
||||
For posterity, here are the built-in ones:
|
||||
|
||||
+ =w W= words
|
||||
+ =s= sentences
|
||||
+ =p= paragraphs
|
||||
+ =b= parenthesized blocks
|
||||
+ =b ( ) { } [ ] < >= braces, parentheses and brackets
|
||||
+ =' " `= quotes
|
||||
+ =t= tags
|
||||
+ =o= symbols
|
||||
|
||||
And these are text objects added by this module:
|
||||
|
||||
+ =a= C-style fucntion arguments (provided by ~evil-args~)
|
||||
+ =B= any block delimited by braces, parentheses or backets (provided by
|
||||
~evil-textobj-anyblock~)
|
||||
+ =i j k= By indentation (=k= includes on line above and =j= includes one line
|
||||
below) (provided by ~evil-indent-plus~)
|
||||
+ =x= XML attributes (provided by ~exato~)
|
||||
|
||||
** Custom Ex Commands
|
||||
| Ex Command | Description |
|
||||
|-----------------------+--------------------------------------------------------------------------------------|
|
||||
| ~:@~ | Apply macro on selected lines |
|
||||
| ~:ag[!] REGEXP~ | Perform a project search with ag |
|
||||
| ~:agcwd[!] REGEXP~ | Perform a project search with ag from the current directory |
|
||||
| ~:al[ign][!] REGEXP~ | Align text to the first match of REGEXP. If BANG, align all matches on each line |
|
||||
| ~:cp[!] NEWPATH~ | Copy the current file to NEWPATH |
|
||||
| ~:dash QUERY~ | Look up QUERY (or the symbol at point) in dash docsets |
|
||||
| ~:dehtml [INPUT]~ | HTML decode selected text / inserts result if INPUT is given |
|
||||
| ~:enhtml [INPUT]~ | HTML encode selected text / inserts result if INPUT is given |
|
||||
| ~:grep[!]~ | Perform a project search with git-grep |
|
||||
| ~:grepcwd[!]~ | Perform a project search with git-grep from the current directory |
|
||||
| ~:iedit REGEXP~ | Invoke iedit on all matches for REGEXP |
|
||||
| ~:k[ill]all[!]~ | Kill all buffers (if BANG, affect buffer across workspaces) |
|
||||
| ~:k[ill]b~ | Kill all buried buffers |
|
||||
| ~:k[ill]m[!] REGEXP~ | Kill buffers whose name matches REGEXP (if BANG, affect buffers across workspaces) |
|
||||
| ~:k[ill]o~ | Kill all other buffers besides the selected one |
|
||||
| ~:k[ill]~ | Kill the current buffer |
|
||||
| ~:lo[okup] QUERY~ | Look up QUERY on an online search engine |
|
||||
| ~:mc REGEXP~ | Invoke multiple cursors on all matches for REGEXP |
|
||||
| ~:mv[!] NEWPATH~ | Move the current file to NEWPATH |
|
||||
| ~:na[rrow]~ | Narrow the buffer to the selection |
|
||||
| ~:pad~ | Open a scratch pad for running code quickly |
|
||||
| ~:pt[!]~ | Perform a project search with pt |
|
||||
| ~:ptcwd[!]~ | Perform a project search with pt from the current directory |
|
||||
| ~:ral[ign][!] REGEXP~ | Right-Align text that matches REGEXP. If BANG, align all matches on each line |
|
||||
| ~:repl~ | Open a REPL and/or copy the current selection to it |
|
||||
| ~:retab~ | Convert indentation to the default within the selection |
|
||||
| ~:rev[erse]~ | Reverse the selected lines |
|
||||
| ~:rg[!]~ | Perform a project search with ripgrep |
|
||||
| ~:rgcwd[!]~ | Perform a project search with rigprep from the current directory |
|
||||
| ~:rm[!] [PATH]~ | Delete the current buffer's file and buffer |
|
||||
| ~:tcd[!]~ | Send =cd X= to tmux. X = the project root if BANG, X = ~default-directory~ otherwise |
|
||||
|
||||
* Configuration
|
||||
** Removing evil-mode
|
||||
You must do two things to remove Evil:
|
||||
|
||||
1. Remove =:editor evil= from =~/.doom.d/init.el=,
|
||||
2. Run ~doom refresh~ to clean up lingering dependencies and refresh yuor
|
||||
autoloads files.
|
||||
3. [OPTIONAL] You may want to assign new values to ~doom-leader-alt-key~ and
|
||||
~doom-localleader-alt-key~. These are bound to =C-c= and =C-c l= by default.
|
||||
|
||||
#+begin_quote
|
||||
Ignore ~doom-leader-key~ and ~doom-localleader-key~, they don't apply to
|
||||
non-evil sessions.
|
||||
#+end_quote
|
||||
|
||||
Evil-specific configuration and keybindings (defined with ~map!~) will be
|
||||
ignored without =:editor evil= present (and omitted when byte-compiling).
|
||||
|
||||
Keep in mind that, at the time of this writing, Doom was designed by a vimmer,
|
||||
for vimmers. Little consideration has been put into designing a keybind scheme
|
||||
for vanilla Emacs users (though it's being worked on!).
|
||||
|
||||
That means that much of Doom's functionality will be orphaned in an evil-less
|
||||
setup. You'll have to set your own keybinds.
|
||||
|
||||
I suggest studying [[file:../../config/default/+emacs-bindings.el][config/default/+emacs-bindings.el]] to see what keybinds are
|
||||
available for non-evil users. Otherwise, you may find inspiration [[file:../../../docs/example_configs.org][on the example
|
||||
Doom configurations page]].
|
||||
|
||||
** Restoring old substitution behavior on s/S
|
||||
Doom replaces the =s= and =S= keys with the =evil-snipe= package (a port of
|
||||
vim-seek/vim-sneak for 2-character versions of f/F/t/T).
|
||||
|
||||
To disable evil-snipe on s/S, you can either:
|
||||
|
||||
1. Disable ~evil-snipe-mode~ by adding ~(after! evil-snipe (evil-snipe-mode
|
||||
-1))~ to =$DOOMDIR/config.el=,
|
||||
2. Or disable =evil-snipe= completely with ~(package! evil-snipe :disable t)~
|
||||
added to =$DOOMDIR/packages.el=, but this will also disable incremental
|
||||
highlighting for the f/F/t/T motions keys.
|
||||
3. Or use =cl= and =cc=, respectively; they do the same thing.
|
207
modules/editor/evil/autoload/advice.el
Normal file
207
modules/editor/evil/autoload/advice.el
Normal file
|
@ -0,0 +1,207 @@
|
|||
;;; editor/evil/autoload/advice.el -*- lexical-binding: t; -*-
|
||||
|
||||
(defun +evil--insert-newline (&optional above _noextranewline)
|
||||
(let ((pos (save-excursion (beginning-of-line-text) (point)))
|
||||
comment-auto-fill-only-comments)
|
||||
(require 'smartparens)
|
||||
(evil-narrow-to-field
|
||||
(if above
|
||||
(if (save-excursion (nth 4 (sp--syntax-ppss pos)))
|
||||
(evil-save-goal-column
|
||||
(setq evil-auto-indent nil)
|
||||
(goto-char pos)
|
||||
(let ((ws (abs (skip-chars-backward " \t"))))
|
||||
;; FIXME oh god why
|
||||
(save-excursion
|
||||
(if comment-line-break-function
|
||||
(funcall comment-line-break-function)
|
||||
(comment-indent-new-line))
|
||||
(when (and (derived-mode-p 'c-mode 'c++-mode 'objc-mode 'java-mode 'js2-mode)
|
||||
(eq (char-after) ?/))
|
||||
(insert "*"))
|
||||
(insert
|
||||
(make-string (max 0 (+ ws (skip-chars-backward " \t")))
|
||||
32)))
|
||||
(insert (make-string (max 1 ws) 32))))
|
||||
(evil-move-beginning-of-line)
|
||||
(insert (if use-hard-newlines hard-newline "\n"))
|
||||
(forward-line -1)
|
||||
(back-to-indentation))
|
||||
(evil-move-end-of-line)
|
||||
(cond ((sp-point-in-comment pos)
|
||||
(setq evil-auto-indent nil)
|
||||
(if comment-line-break-function
|
||||
(funcall comment-line-break-function)
|
||||
(comment-indent-new-line)))
|
||||
;; TODO Find a better way to do this
|
||||
((and (eq major-mode 'haskell-mode)
|
||||
(fboundp 'haskell-indentation-newline-and-indent))
|
||||
(setq evil-auto-indent nil)
|
||||
(haskell-indentation-newline-and-indent))
|
||||
(t
|
||||
(insert (if use-hard-newlines hard-newline "\n"))
|
||||
(back-to-indentation)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*insert-newline-below-and-respect-comments (orig-fn count)
|
||||
(if (or (not +evil-want-o/O-to-continue-comments)
|
||||
(not (eq this-command 'evil-open-below))
|
||||
(evil-insert-state-p))
|
||||
(funcall orig-fn count)
|
||||
(cl-letf (((symbol-function 'evil-insert-newline-below)
|
||||
(lambda () (+evil--insert-newline))))
|
||||
(let ((evil-auto-indent evil-auto-indent))
|
||||
(funcall orig-fn count)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*insert-newline-above-and-respect-comments (orig-fn count)
|
||||
(if (or (not +evil-want-o/O-to-continue-comments)
|
||||
(not (eq this-command 'evil-open-above))
|
||||
(evil-insert-state-p))
|
||||
(funcall orig-fn count)
|
||||
(cl-letf (((symbol-function 'evil-insert-newline-above)
|
||||
(lambda () (+evil--insert-newline 'above))))
|
||||
(let ((evil-auto-indent evil-auto-indent))
|
||||
(funcall orig-fn count)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*static-reindent (orig-fn &rest args)
|
||||
"Don't move cursor on indent."
|
||||
(save-excursion (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 ((project-root (doom-project-root (file-name-directory (expand-file-name path)))))
|
||||
(unless project-root
|
||||
(user-error "Not in a project"))
|
||||
(abbreviate-file-name 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)))
|
||||
|
||||
;;;###autoload (autoload '+evil*window-split "editor/evil/autoload/advice" nil t)
|
||||
(evil-define-command +evil*window-split (&optional count file)
|
||||
"Same as `evil-window-split', but focuses (and recenters) the new split."
|
||||
:repeat nil
|
||||
(interactive "P<f>")
|
||||
(split-window (selected-window) count
|
||||
(if evil-split-window-below 'above 'below))
|
||||
(call-interactively
|
||||
(if evil-split-window-below
|
||||
#'evil-window-up
|
||||
#'evil-window-down))
|
||||
(recenter)
|
||||
(when (and (not count) evil-auto-balance-windows)
|
||||
(balance-windows (window-parent)))
|
||||
(if file (evil-edit file)))
|
||||
|
||||
;;;###autoload (autoload '+evil*window-vsplit "editor/evil/autoload/advice" nil t)
|
||||
(evil-define-command +evil*window-vsplit (&optional count file)
|
||||
"Same as `evil-window-vsplit', but focuses (and recenters) the new split."
|
||||
:repeat nil
|
||||
(interactive "P<f>")
|
||||
(split-window (selected-window) count
|
||||
(if evil-vsplit-window-right 'left 'right))
|
||||
(call-interactively
|
||||
(if evil-vsplit-window-right
|
||||
#'evil-window-left
|
||||
#'evil-window-right))
|
||||
(recenter)
|
||||
(when (and (not count) evil-auto-balance-windows)
|
||||
(balance-windows (window-parent)))
|
||||
(if file (evil-edit file)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*escape (&rest _)
|
||||
"Call `doom/escape' if `evil-force-normal-state' is called interactively."
|
||||
(when (called-interactively-p 'any)
|
||||
(call-interactively #'doom/escape)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*make-numbered-markers-global (orig-fn char)
|
||||
(or (and (>= char ?2) (<= char ?9))
|
||||
(funcall orig-fn char)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*set-jump (orig-fn &rest args)
|
||||
"Set a jump point and ensure ORIG-FN doesn't set any new jump points."
|
||||
(evil-set-jump (if (markerp (car args)) (car args)))
|
||||
(let ((evil--jumps-jumping t))
|
||||
(apply orig-fn args)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil*fix-dabbrev-in-minibuffer ()
|
||||
"Make `try-expand-dabbrev' from `hippie-expand' work in minibuffer. See
|
||||
`he-dabbrev-beg', so we need to redefine syntax for '/'."
|
||||
(set-syntax-table (let* ((table (make-syntax-table)))
|
||||
(modify-syntax-entry ?/ "." table)
|
||||
table)))
|
33
modules/editor/evil/autoload/embrace.el
Normal file
33
modules/editor/evil/autoload/embrace.el
Normal file
|
@ -0,0 +1,33 @@
|
|||
;;; editor/evil/autoload/embrace.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil--embrace-get-pair (char)
|
||||
(if-let* ((pair (cdr-safe (assoc (string-to-char char) evil-surround-pairs-alist))))
|
||||
pair
|
||||
(if-let* ((pair (assoc-default char embrace--pairs-list)))
|
||||
(if-let* ((real-pair (and (functionp (embrace-pair-struct-read-function pair))
|
||||
(funcall (embrace-pair-struct-read-function pair)))))
|
||||
real-pair
|
||||
(cons (embrace-pair-struct-left pair) (embrace-pair-struct-right pair)))
|
||||
(cons char char))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil--embrace-escaped ()
|
||||
"Backslash-escaped surround character support for embrace."
|
||||
(let ((char (read-char "\\")))
|
||||
(if (eq char 27)
|
||||
(cons "" "")
|
||||
(let ((pair (+evil--embrace-get-pair (string char)))
|
||||
(text (if (sp-point-in-string) "\\\\%s" "\\%s")))
|
||||
(cons (format text (car pair))
|
||||
(format text (cdr pair)))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil--embrace-latex ()
|
||||
"LaTeX command support for embrace."
|
||||
(cons (format "\\%s{" (read-string "\\")) "}"))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil--embrace-elisp-fn ()
|
||||
"Elisp function support for embrace."
|
||||
(cons (format "(%s " (or (read-string "(") "")) ")"))
|
260
modules/editor/evil/autoload/evil.el
Normal file
260
modules/editor/evil/autoload/evil.el
Normal file
|
@ -0,0 +1,260 @@
|
|||
;; editor/evil/autoload/evil.el -*- lexical-binding: t; -*-
|
||||
;;;###if (featurep! :editor evil)
|
||||
|
||||
;;;###autodef
|
||||
(defun set-evil-initial-state! (modes state)
|
||||
"Set the initialize STATE of MODES using `evil-set-initial-state'."
|
||||
(declare (indent defun))
|
||||
(after! evil
|
||||
(if (listp modes)
|
||||
(dolist (mode (doom-enlist modes))
|
||||
(evil-set-initial-state mode state))
|
||||
(evil-set-initial-state modes state))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Commands
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil/visual-indent ()
|
||||
"vnoremap < <gv"
|
||||
(interactive)
|
||||
(evil-shift-right (region-beginning) (region-end))
|
||||
(evil-normal-state)
|
||||
(evil-visual-restore))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil/visual-dedent ()
|
||||
"vnoremap > >gv"
|
||||
(interactive)
|
||||
(evil-shift-left (region-beginning) (region-end))
|
||||
(evil-normal-state)
|
||||
(evil-visual-restore))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil/reselect-paste ()
|
||||
"Return to visual mode and reselect the last pasted region."
|
||||
(interactive)
|
||||
(cl-destructuring-bind (_ _ _ beg end &optional _)
|
||||
evil-last-paste
|
||||
(evil-visual-make-selection
|
||||
(save-excursion (goto-char beg) (point-marker))
|
||||
end)))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil/paste-preserve-register ()
|
||||
"Call `evil-paste-after' without overwriting the clipboard (by writing to the
|
||||
0 register instead). This allows you to paste the same text again afterwards."
|
||||
(interactive)
|
||||
(let ((evil-this-register ?0))
|
||||
(call-interactively #'evil-paste-after)))
|
||||
|
||||
(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')."
|
||||
(when (window-dedicated-p)
|
||||
(user-error "Cannot swap a dedicated window"))
|
||||
(let* ((this-window (selected-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)
|
||||
(window-dedicated-p this-window))
|
||||
(setq that-buffer nil that-window nil))
|
||||
(if (not (or that-window (one-window-p t)))
|
||||
(funcall (pcase 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
|
||||
(pcase direction
|
||||
('up 'above)
|
||||
('down 'below)
|
||||
(_ direction))))
|
||||
(with-selected-window that-window
|
||||
(switch-to-buffer (doom-fallback-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 () "See `+evil--window-swap'" (interactive) (+evil--window-swap 'left))
|
||||
;;;###autoload
|
||||
(defun +evil/window-move-right () "See `+evil--window-swap'" (interactive) (+evil--window-swap 'right))
|
||||
;;;###autoload
|
||||
(defun +evil/window-move-up () "See `+evil--window-swap'" (interactive) (+evil--window-swap 'up))
|
||||
;;;###autoload
|
||||
(defun +evil/window-move-down () "See `+evil--window-swap'" (interactive) (+evil--window-swap 'down))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil/easymotion ()
|
||||
"Invoke and lazy-load `evil-easymotion' without compromising which-key
|
||||
integration."
|
||||
(interactive)
|
||||
(let ((prefix (this-command-keys)))
|
||||
(evil-define-key* 'motion 'global prefix nil)
|
||||
(evilem-default-keybindings prefix)
|
||||
(which-key-reload-key-sequence
|
||||
(vconcat (when evil-this-operator
|
||||
(where-is-internal evil-this-operator
|
||||
evil-normal-state-map
|
||||
t))
|
||||
prefix))))
|
||||
|
||||
|
||||
;;
|
||||
;;; Evil commands/operators
|
||||
|
||||
;;;###autoload (autoload '+evil:apply-macro "editor/evil/autoload/evil" nil t)
|
||||
(evil-define-operator +evil:apply-macro (beg end)
|
||||
"Apply macro to each line."
|
||||
:move-point nil
|
||||
(interactive "<r>")
|
||||
(let ((register (or evil-this-register (read-char)))
|
||||
macro)
|
||||
(cond ((or (and (eq register ?@) (eq evil-last-register ?:))
|
||||
(eq register ?:))
|
||||
(setq macro (lambda () (evil-ex-repeat nil))
|
||||
evil-last-register ?:))
|
||||
((eq register ?@)
|
||||
(unless evil-last-register
|
||||
(user-error "No previously executed keyboard macro."))
|
||||
(setq macro (evil-get-register evil-last-register t)))
|
||||
((setq macro (evil-get-register register t)
|
||||
evil-last-register register)))
|
||||
(unless macro
|
||||
(user-error "No macro recorded in %c register" register))
|
||||
(evil-change-state 'normal)
|
||||
(evil-with-single-undo
|
||||
(let ((lines (count-lines beg end)))
|
||||
(message "Applied macro in %c register %d times" register lines)
|
||||
(apply-macro-to-region-lines beg end macro)
|
||||
(message "Applied macro in %c register %d times...DONE" register lines)))))
|
||||
|
||||
;;;###autoload (autoload '+evil:retab "editor/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 "editor/evil/autoload/evil" nil t)
|
||||
(evil-define-operator +evil:narrow-buffer (beg end &optional bang)
|
||||
"Wrapper around `doom/clone-and-narrow-buffer'."
|
||||
:move-point nil
|
||||
(interactive "<r><!>")
|
||||
(doom/clone-and-narrow-buffer beg end bang))
|
||||
|
||||
|
||||
;;
|
||||
;;; Custom arg handlers
|
||||
|
||||
(defvar +evil--flag nil)
|
||||
|
||||
(defun +evil--ex-match-init (name &optional face update-hook)
|
||||
(with-current-buffer evil-ex-current-buffer
|
||||
(cond
|
||||
((eq +evil--flag 'start)
|
||||
(evil-ex-make-hl name
|
||||
:face (or face 'evil-ex-substitute-matches)
|
||||
:update-hook (or update-hook #'evil-ex-pattern-update-ex-info))
|
||||
(setq +evil--flag 'update))
|
||||
|
||||
((eq +evil--flag 'stop)
|
||||
(evil-ex-delete-hl name)))))
|
||||
|
||||
(defun +evil--ex-buffer-match (arg &optional hl-name flags beg end)
|
||||
(when (and (eq +evil--flag 'update)
|
||||
evil-ex-substitute-highlight-all
|
||||
(not (zerop (length arg))))
|
||||
(condition-case lossage
|
||||
(let ((pattern (evil-ex-make-substitute-pattern
|
||||
arg
|
||||
(or flags (list))))
|
||||
(range (or (evil-copy-range evil-ex-range)
|
||||
(evil-range (or beg (line-beginning-position))
|
||||
(or end (line-end-position))
|
||||
'line
|
||||
:expanded t))))
|
||||
(evil-expand-range range)
|
||||
(evil-ex-hl-set-region hl-name
|
||||
(max (evil-range-beginning range) (window-start))
|
||||
(min (evil-range-end range) (window-end)))
|
||||
(evil-ex-hl-change hl-name pattern))
|
||||
(end-of-file
|
||||
(evil-ex-pattern-update-ex-info nil "incomplete replacement"))
|
||||
(user-error
|
||||
(evil-ex-pattern-update-ex-info nil (format "?%s" lossage))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil-ex-buffer-match (flag &optional arg)
|
||||
(let ((hl-name 'evil-ex-buffer-match)
|
||||
(+evil--flag flag))
|
||||
(with-selected-window (minibuffer-selected-window)
|
||||
(+evil--ex-match-init hl-name)
|
||||
(+evil--ex-buffer-match arg hl-name (list (if evil-ex-substitute-global ?g))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil-ex-global-match (flag &optional arg)
|
||||
(let ((hl-name 'evil-ex-global-match)
|
||||
(+evil--flag flag))
|
||||
(with-selected-window (minibuffer-selected-window)
|
||||
(+evil--ex-match-init hl-name)
|
||||
(+evil--ex-buffer-match arg hl-name nil (point-min) (point-max)))))
|
||||
|
||||
;;;###autoload
|
||||
(defun +evil-ex-global-delim-match (flag &optional arg)
|
||||
(let ((hl-name 'evil-ex-global-delim-match)
|
||||
(+evil--flag flag))
|
||||
(with-selected-window (minibuffer-selected-window)
|
||||
(+evil--ex-match-init hl-name)
|
||||
(let ((result (car-safe (evil-delimited-arguments arg 2))))
|
||||
(+evil--ex-buffer-match result hl-name nil (point-min) (point-max))))))
|
||||
|
||||
;;;###autoload (autoload '+evil:align "editor/evil/autoload/evil" nil t)
|
||||
(evil-define-operator +evil:align (beg end pattern &optional bang)
|
||||
"Ex interface to `align-regexp'. PATTERN is a vim-style regexp. If BANG,
|
||||
repeat the alignment for all matches (otherwise just the first match on each
|
||||
line)."
|
||||
(interactive "<r><//g><!>")
|
||||
(align-regexp
|
||||
beg end
|
||||
(concat "\\(\\s-*\\)" (evil-transform-vim-style-regexp pattern))
|
||||
1 1 bang))
|
||||
|
||||
;;;###autoload (autoload '+evil:align-right "editor/evil/autoload/evil" nil t)
|
||||
(evil-define-operator +evil:align-right (beg end pattern &optional bang)
|
||||
"Like `+evil:align', except alignments are right-justified. PATTERN is a
|
||||
vim-style regexp. If BANG, repeat the alignment for all matches (otherwise just
|
||||
the first match on each line)."
|
||||
(interactive "<r><//g><!>")
|
||||
(align-regexp
|
||||
beg end
|
||||
(concat "\\(" (evil-transform-vim-style-regexp pattern) "\\)")
|
||||
-1 1 bang))
|
||||
|
||||
|
||||
;;
|
||||
;;; wgrep
|
||||
|
||||
;;;###autoload (autoload '+evil-delete "editor/evil/autoload/evil" nil t)
|
||||
(evil-define-operator +evil-delete (beg end type register yank-handler)
|
||||
"A wrapper around `evil-delete' for `wgrep' buffers that will invoke
|
||||
`wgrep-mark-deletion' on lines you try to delete."
|
||||
(interactive "<R><x><y>")
|
||||
(condition-case _ex
|
||||
(evil-delete beg end type register yank-handler)
|
||||
('text-read-only
|
||||
(evil-apply-on-block
|
||||
(lambda (beg _)
|
||||
(goto-char beg)
|
||||
(call-interactively #'wgrep-mark-deletion))
|
||||
beg (1- end) nil))))
|
33
modules/editor/evil/autoload/files.el
Normal file
33
modules/editor/evil/autoload/files.el
Normal file
|
@ -0,0 +1,33 @@
|
|||
;;; editor/evil/autoload/files.el -*- lexical-binding: t; -*-
|
||||
|
||||
;;;###autoload (autoload '+evil:delete-this-file "editor/evil/autoload/files" nil t)
|
||||
(evil-define-command +evil:delete-this-file (&optional filename force-p)
|
||||
"Delete FILENAME (defaults to the file associated with current buffer) and
|
||||
kills the buffer. If FORCE-P, force the deletion (don't ask for confirmation)."
|
||||
:repeat nil
|
||||
(interactive "<f><!>")
|
||||
(doom/delete-this-file (or filename (file-truename buffer-file-name))
|
||||
force-p))
|
||||
|
||||
;;;###autoload (autoload '+evil:move-this-file "editor/evil/autoload/files" nil t)
|
||||
(evil-define-command +evil:move-this-file (new-path &optional force-p)
|
||||
"Move current buffer's file to NEW-PATH. Replaces %, # and other vim-esque
|
||||
filename modifiers (see `+evil*ex-replace-special-filenames'). If FORCE-P,
|
||||
overwrite the destination file if it exists, without confirmation."
|
||||
:repeat nil
|
||||
(interactive "<f><!>")
|
||||
(when (or (not new-path) (string-empty-p new-path))
|
||||
(user-error "No new path was specified"))
|
||||
(doom/move-this-file new-path force-p))
|
||||
|
||||
;;;###autoload (autoload '+evil:copy-this-file "editor/evil/autoload/files" nil nil)
|
||||
(evil-define-command +evil:copy-this-file (new-path &optional force-p)
|
||||
"Copy current buffer's file to NEW-PATH. Replaces %, # and other vim-esque
|
||||
filename modifiers (see `+evil*ex-replace-special-filenames'). If FORCE-P,
|
||||
overwrite the destination file if it exists, without confirmation."
|
||||
:repeat nil
|
||||
(interactive "<f><!>")
|
||||
(when (or (not new-path) (string-empty-p new-path))
|
||||
(user-error "No new path was specified"))
|
||||
(doom/copy-this-file new-path force-p))
|
||||
|
309
modules/editor/evil/config.el
Normal file
309
modules/editor/evil/config.el
Normal file
|
@ -0,0 +1,309 @@
|
|||
;;; editor/evil/config.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; 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.
|
||||
|
||||
(defvar +evil-want-o/O-to-continue-comments t
|
||||
"If non-nil, the o/O keys will continue comment lines if the point is on a
|
||||
line with a linewise comment.")
|
||||
|
||||
;; Set these defaults before `evil'; use `defvar' so they can be changed prior
|
||||
;; to loading.
|
||||
(defvar evil-want-C-u-scroll t)
|
||||
(defvar evil-want-C-w-scroll t)
|
||||
(defvar evil-want-Y-yank-to-eol t)
|
||||
|
||||
(def-package! evil
|
||||
:hook (doom-init-modules . evil-mode)
|
||||
:demand t
|
||||
:preface
|
||||
(setq evil-want-visual-char-semi-exclusive t
|
||||
evil-magic t
|
||||
evil-echo-state t
|
||||
evil-indent-convert-tabs t
|
||||
evil-ex-search-vim-style-regexp t
|
||||
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
|
||||
evil-respect-visual-line-mode t
|
||||
;; more vim-like behavior
|
||||
evil-symbol-word-search t
|
||||
;; cursor appearance
|
||||
evil-default-cursor '+evil-default-cursor
|
||||
evil-normal-state-cursor 'box
|
||||
evil-emacs-state-cursor '(box +evil-emacs-cursor)
|
||||
evil-insert-state-cursor 'bar
|
||||
evil-visual-state-cursor 'hollow
|
||||
;; must be set before evil/evil-collection is loaded
|
||||
evil-want-keybinding (not (featurep! +everywhere)))
|
||||
|
||||
:config
|
||||
(evil-select-search-module 'evil-search-module 'evil-search)
|
||||
|
||||
(put 'evil-define-key* 'lisp-indent-function 'defun)
|
||||
|
||||
;; Done in a hook to ensure the popup rules load as late as possible
|
||||
(defun +evil|init-popup-rules ()
|
||||
(set-popup-rules!
|
||||
'(("^\\*evil-registers" :size 0.3)
|
||||
("^\\*Command Line" :size 8))))
|
||||
(add-hook 'doom-init-modules-hook #'+evil|init-popup-rules)
|
||||
|
||||
;; Change the cursor color in emacs mode
|
||||
(defvar +evil--default-cursor-color
|
||||
(or (ignore-errors (frame-parameter nil 'cursor-color))
|
||||
"#ffffff"))
|
||||
|
||||
(defun +evil-default-cursor () (set-cursor-color +evil--default-cursor-color))
|
||||
(defun +evil-emacs-cursor () (set-cursor-color (face-foreground 'warning)))
|
||||
|
||||
(defun +evil|update-cursor-color ()
|
||||
(setq +evil--default-cursor-color (face-background 'cursor)))
|
||||
(add-hook 'doom-load-theme-hook #'+evil|update-cursor-color)
|
||||
|
||||
(defun +evil|update-shift-width ()
|
||||
(setq evil-shift-width tab-width))
|
||||
(add-hook 'after-change-major-mode-hook #'+evil|update-shift-width t)
|
||||
|
||||
|
||||
;; --- keybind fixes ----------------------
|
||||
(after! wgrep
|
||||
;; A wrapper that invokes `wgrep-mark-deletion' across lines you use
|
||||
;; `evil-delete' in wgrep buffers.
|
||||
(define-key wgrep-mode-map [remap evil-delete] #'+evil-delete))
|
||||
|
||||
(defun +evil|disable-highlights ()
|
||||
"Disable ex search buffer highlights."
|
||||
(when (evil-ex-hl-active-p 'evil-ex-search)
|
||||
(evil-ex-nohighlight)
|
||||
t))
|
||||
(add-hook 'doom-escape-hook #'+evil|disable-highlights)
|
||||
|
||||
|
||||
;; --- evil hacks -------------------------
|
||||
(defun +evil|display-vimlike-save-message ()
|
||||
"Shorter, vim-esque save messages."
|
||||
(message "\"%s\" %dL, %dC written"
|
||||
(if buffer-file-name
|
||||
(file-relative-name (file-truename buffer-file-name) (doom-project-root))
|
||||
(buffer-name))
|
||||
(count-lines (point-min) (point-max))
|
||||
(buffer-size)))
|
||||
(unless noninteractive
|
||||
(setq save-silently t)
|
||||
(add-hook 'after-save-hook #'+evil|display-vimlike-save-message))
|
||||
;; Make ESC (from normal mode) the universal escaper. See `doom-escape-hook'.
|
||||
(advice-add #'evil-force-normal-state :after #'+evil*escape)
|
||||
;; Don't move cursor when indenting
|
||||
(advice-add #'evil-indent :around #'+evil*static-reindent)
|
||||
;; monkey patch `evil-ex-replace-special-filenames' to improve support for
|
||||
;; file modifiers like %:p:h. This adds support for most of vim's modifiers,
|
||||
;; and one custom one: %:P (expand to the project root).
|
||||
(advice-add #'evil-ex-replace-special-filenames :override #'+evil*resolve-vim-path)
|
||||
|
||||
;; make `try-expand-dabbrev' (from `hippie-expand') work in minibuffer
|
||||
(add-hook 'minibuffer-inactive-mode-hook #'+evil*fix-dabbrev-in-minibuffer)
|
||||
|
||||
;; Focus and recenter new splits
|
||||
(advice-add #'evil-window-split :override #'+evil*window-split)
|
||||
(advice-add #'evil-window-vsplit :override #'+evil*window-vsplit)
|
||||
|
||||
;; Integrate evil's jump-list into some navigational commands
|
||||
(advice-add #'counsel-git-grep-action :around #'+evil*set-jump)
|
||||
(advice-add #'helm-ag--find-file-action :around #'+evil*set-jump)
|
||||
(advice-add #'xref-push-marker-stack :around #'+evil*set-jump)
|
||||
|
||||
;; In evil, registers 2-9 are buffer-local. In vim, they're global, so...
|
||||
(advice-add #'evil-global-marker-p :around #'+evil*make-numbered-markers-global)
|
||||
|
||||
;; Make o/O continue comments (see `+evil-want-o/O-to-continue-comments')
|
||||
(advice-add #'evil-open-above :around #'+evil*insert-newline-above-and-respect-comments)
|
||||
(advice-add #'evil-open-below :around #'+evil*insert-newline-below-and-respect-comments)
|
||||
|
||||
;; Recenter screen after most searches
|
||||
(advice-add! '(evil-visualstar/begin-search-forward
|
||||
evil-visualstar/begin-search-backward
|
||||
evil-ex-search-word-backward
|
||||
evil-ex-search-word-backward
|
||||
evil-ex-search-forward
|
||||
evil-ex-search-backward)
|
||||
:after #'doom*recenter)
|
||||
|
||||
;; --- custom interactive codes -----------
|
||||
;; 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)
|
||||
;; Other commands can make use of this
|
||||
(evil-define-interactive-code "<//>"
|
||||
:ex-arg buffer-match (list (if (evil-ex-p) evil-ex-argument)))
|
||||
(evil-define-interactive-code "<//g>"
|
||||
:ex-arg global-match (list (if (evil-ex-p) evil-ex-argument)))
|
||||
|
||||
;; 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)
|
||||
(dolist (sym '(evil-ex-global evil-ex-global-inverted))
|
||||
(evil-set-command-property sym :ex-arg 'global-delim-match))
|
||||
|
||||
;; Forward declare these so that ex completion works, even if the autoloaded
|
||||
;; functions aren't loaded yet.
|
||||
(evil-set-command-properties
|
||||
'+evil:align :move-point t :ex-arg 'buffer-match :ex-bang t :keep-visual t :suppress-operator t)
|
||||
|
||||
;; `evil-collection'
|
||||
(when (featurep! +everywhere)
|
||||
(load! "+everywhere"))
|
||||
|
||||
;; Custom evil ex commands
|
||||
(load! "+commands"))
|
||||
|
||||
|
||||
;;
|
||||
;; Packages
|
||||
|
||||
(def-package! evil-commentary
|
||||
:commands (evil-commentary
|
||||
evil-commentary-yank
|
||||
evil-commentary-yank-line
|
||||
evil-commentary-line)
|
||||
:config (evil-commentary-mode 1))
|
||||
|
||||
|
||||
(def-package! evil-easymotion
|
||||
:commands (evilem-create evilem-default-keybindings)
|
||||
:config
|
||||
;; Use evil-search backend, instead of isearch
|
||||
(evilem-make-motion evilem-motion-search-next #'evil-ex-search-next
|
||||
:bind ((evil-ex-search-highlight-all nil)))
|
||||
(evilem-make-motion evilem-motion-search-previous #'evil-ex-search-previous
|
||||
:bind ((evil-ex-search-highlight-all nil)))
|
||||
|
||||
(evilem-make-motion evilem-motion-search-word-forward #'evil-ex-search-word-forward
|
||||
:bind ((evil-ex-search-highlight-all nil)))
|
||||
(evilem-make-motion evilem-motion-search-word-backward #'evil-ex-search-word-backward
|
||||
:bind ((evil-ex-search-highlight-all nil))))
|
||||
|
||||
|
||||
(def-package! evil-embrace
|
||||
:commands (embrace-add-pair embrace-add-pair-regexp)
|
||||
:hook (LaTeX-mode . embrace-LaTeX-mode-hook)
|
||||
:hook (org-mode . embrace-org-mode-hook)
|
||||
:hook ((ruby-mode enh-ruby-mode) . embrace-ruby-mode-hook)
|
||||
:hook (emacs-lisp-mode . embrace-emacs-lisp-mode-hook)
|
||||
:hook ((emacs-lisp-mode lisp-mode) . +evil|embrace-lisp-mode-hook)
|
||||
:hook ((org-mode LaTeX-mode) . +evil|embrace-latex-mode-hook)
|
||||
:init
|
||||
(after! evil-surround
|
||||
(evil-embrace-enable-evil-surround-integration))
|
||||
:config
|
||||
(setq evil-embrace-show-help-p nil)
|
||||
|
||||
(defun +evil|embrace-latex-mode-hook ()
|
||||
(embrace-add-pair-regexp ?l "\\[a-z]+{" "}" #'+evil--embrace-latex))
|
||||
|
||||
(defun +evil|embrace-lisp-mode-hook ()
|
||||
(push (cons ?f (make-embrace-pair-struct
|
||||
:key ?f
|
||||
:read-function #'+evil--embrace-elisp-fn
|
||||
:left-regexp "([^ ]+ "
|
||||
:right-regexp ")"))
|
||||
embrace--pairs-list))
|
||||
|
||||
;; Add escaped-sequence support to embrace
|
||||
(setf (alist-get ?\\ (default-value 'embrace--pairs-list))
|
||||
(make-embrace-pair-struct
|
||||
:key ?\\
|
||||
:read-function #'+evil--embrace-escaped
|
||||
:left-regexp "\\[[{(]"
|
||||
:right-regexp "\\[]})]")))
|
||||
|
||||
|
||||
(def-package! evil-escape
|
||||
:commands (evil-escape)
|
||||
:after-call (evil-normal-state-exit-hook)
|
||||
:init
|
||||
(setq evil-escape-excluded-states '(normal visual multiedit emacs motion)
|
||||
evil-escape-excluded-major-modes '(neotree-mode treemacs-mode term-mode vterm-mode)
|
||||
evil-escape-key-sequence "jk"
|
||||
evil-escape-delay 0.25)
|
||||
(evil-define-key* '(insert replace visual operator) 'global "\C-g" #'evil-escape)
|
||||
:config
|
||||
;; no `evil-escape' in minibuffer
|
||||
(add-hook 'evil-escape-inhibit-functions #'minibufferp)
|
||||
;; so that evil-escape-mode-hook runs, and can be toggled by evil-mc
|
||||
(evil-escape-mode +1))
|
||||
|
||||
|
||||
(def-package! evil-exchange
|
||||
:commands evil-exchange
|
||||
:config
|
||||
(defun +evil|escape-exchange ()
|
||||
(when evil-exchange--overlays
|
||||
(evil-exchange-cancel)
|
||||
t))
|
||||
(add-hook 'doom-escape-hook #'+evil|escape-exchange))
|
||||
|
||||
|
||||
(def-package! evil-numbers
|
||||
:commands (evil-numbers/inc-at-pt evil-numbers/dec-at-pt))
|
||||
|
||||
|
||||
(def-package! evil-matchit
|
||||
:commands (evilmi-jump-items global-evil-matchit-mode
|
||||
evilmi-outer-text-object evilmi-inner-text-object)
|
||||
:config (global-evil-matchit-mode 1)
|
||||
:init
|
||||
(global-set-key [remap evil-jump-item] #'evilmi-jump-items)
|
||||
(define-key evil-inner-text-objects-map "%" #'evilmi-inner-text-object)
|
||||
(define-key evil-outer-text-objects-map "%" #'evilmi-outer-text-object)
|
||||
:config
|
||||
;; Fixes #519 where d% wouldn't leave a dangling end-parenthesis
|
||||
(evil-set-command-properties 'evilmi-jump-items :type 'inclusive :jump t)
|
||||
|
||||
(defun +evil|simple-matchit ()
|
||||
"A hook to force evil-matchit to favor simple bracket jumping. Helpful when
|
||||
the new algorithm is confusing, like in python or ruby."
|
||||
(setq-local evilmi-always-simple-jump t))
|
||||
(add-hook 'python-mode-hook #'+evil|simple-matchit))
|
||||
|
||||
|
||||
(def-package! evil-snipe
|
||||
:commands (evil-snipe-mode evil-snipe-override-mode
|
||||
evil-snipe-local-mode evil-snipe-override-local-mode)
|
||||
:after-call pre-command-hook
|
||||
:init
|
||||
(setq evil-snipe-smart-case t
|
||||
evil-snipe-scope 'line
|
||||
evil-snipe-repeat-scope 'visible
|
||||
evil-snipe-char-fold t)
|
||||
:config
|
||||
(add-to-list 'evil-snipe-disabled-modes 'Info-mode nil #'eq)
|
||||
(evil-snipe-mode +1)
|
||||
(evil-snipe-override-mode +1))
|
||||
|
||||
|
||||
(def-package! evil-surround
|
||||
:commands (global-evil-surround-mode
|
||||
evil-surround-edit
|
||||
evil-Surround-edit
|
||||
evil-surround-region)
|
||||
:config (global-evil-surround-mode 1))
|
||||
|
||||
|
||||
;; Allows you to use the selection for * and #
|
||||
(def-package! evil-visualstar
|
||||
:commands (evil-visualstar/begin-search
|
||||
evil-visualstar/begin-search-forward
|
||||
evil-visualstar/begin-search-backward)
|
||||
:init
|
||||
(evil-define-key* 'visual 'global
|
||||
"*" #'evil-visualstar/begin-search-forward
|
||||
"#" #'evil-visualstar/begin-search-backward))
|
||||
|
||||
|
||||
;;
|
||||
;; Text object plugins
|
||||
|
||||
(def-package! exato
|
||||
:commands (evil-outer-xml-attr evil-inner-xml-attr))
|
29
modules/editor/evil/packages.el
Normal file
29
modules/editor/evil/packages.el
Normal file
|
@ -0,0 +1,29 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; editor/evil/packages.el
|
||||
|
||||
(package! evil)
|
||||
(package! evil-args)
|
||||
(package! evil-commentary)
|
||||
(package! evil-easymotion)
|
||||
(package! evil-embrace)
|
||||
(package! evil-escape)
|
||||
(package! evil-exchange)
|
||||
(package! evil-indent-plus)
|
||||
(package! evil-matchit)
|
||||
(package! evil-numbers)
|
||||
(package! evil-textobj-anyblock)
|
||||
(package! evil-snipe)
|
||||
(package! evil-surround)
|
||||
(package! evil-visualstar)
|
||||
(package! exato)
|
||||
|
||||
|
||||
;;
|
||||
(when (featurep! +everywhere)
|
||||
;; `evil-collection-neotree' uses the `neotree-make-executor' macro, but this
|
||||
;; requires neotree be available during byte-compilation (while installing).
|
||||
(when (featurep! :ui neotree)
|
||||
(package! neotree)
|
||||
(autoload 'neotree-make-executor "neotree" nil nil 'macro))
|
||||
|
||||
(package! evil-collection))
|
70
modules/editor/evil/test/test-evil.el
Normal file
70
modules/editor/evil/test/test-evil.el
Normal file
|
@ -0,0 +1,70 @@
|
|||
;; -*- no-byte-compile: t; -*-
|
||||
;;; editor/evil/test/test-evil.el
|
||||
|
||||
(describe "feature/evil"
|
||||
:var (resv project-root)
|
||||
(before-all
|
||||
(require! :editor evil)
|
||||
(require 'evil)
|
||||
(load! "../autoload/evil"))
|
||||
(after-all
|
||||
(unload-feature 'evil t))
|
||||
(before-each
|
||||
(fset 'resv #'+evil*resolve-vim-path)
|
||||
(spy-on 'doom-project-root :and-call-fake (lambda () project-root)))
|
||||
|
||||
;; `evil-ex-replace-special-filenames' / `+evil*resolve-vim-path'
|
||||
(describe "file modifiers"
|
||||
(it "supports basic vim file modifiers"
|
||||
(let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el")
|
||||
(default-directory "~/.emacs.d/test/modules/")
|
||||
(project-root "~/.emacs.d/"))
|
||||
(expect (resv "%") :to-equal "feature/test-evil.el")
|
||||
(expect (resv "%:r") :to-equal "feature/test-evil")
|
||||
(expect (resv "%:r.elc") :to-equal "feature/test-evil.elc")
|
||||
(expect (resv "%:e") :to-equal "el")
|
||||
(expect (resv "%:p") :to-equal (expand-file-name buffer-file-name))
|
||||
(expect (resv "%:h") :to-equal "feature")
|
||||
(expect (resv "%:t") :to-equal "test-evil.el")
|
||||
(expect (resv "%:.") :to-equal "feature/test-evil.el")
|
||||
(expect (resv "%:~") :to-equal "~/.emacs.d/test/modules/feature/test-evil.el")
|
||||
(expect (file-truename (resv "%:p"))
|
||||
:to-equal (file-truename buffer-file-name))))
|
||||
|
||||
(it "supports nested vim file modifiers"
|
||||
(let ((buffer-file-name "~/vim/src/version.c")
|
||||
(default-directory "~/vim/")
|
||||
(project-root "~/vim/"))
|
||||
(expect (resv "%:p") :to-equal (expand-file-name "~/vim/src/version.c"))
|
||||
(expect (resv "%:p:.") :to-equal "src/version.c")
|
||||
(expect (resv "%:p:~") :to-equal "~/vim/src/version.c")
|
||||
(expect (resv "%:h") :to-equal "src")
|
||||
(expect (resv "%:p:h") :to-equal (expand-file-name "~/vim/src"))
|
||||
(expect (resv "%:p:h:h") :to-equal (expand-file-name "~/vim"))
|
||||
(expect (resv "%:t") :to-equal "version.c")
|
||||
(expect (resv "%:p:t") :to-equal "version.c")
|
||||
(expect (resv "%:r") :to-equal "src/version")
|
||||
(expect (resv "%:p:r") :to-equal (expand-file-name "~/vim/src/version"))
|
||||
(expect (resv "%:t:r") :to-equal "version")))
|
||||
|
||||
(it "cleans up empty file modifiers"
|
||||
(let (buffer-file-name default-directory)
|
||||
(expect (resv "%") :to-equal "")
|
||||
(expect (resv "%:r") :to-equal "")
|
||||
(expect (resv "%:e") :to-equal "")
|
||||
(expect (resv "%:h") :to-equal "")
|
||||
(expect (resv "%:t") :to-equal "")
|
||||
(expect (resv "%:.") :to-equal "")
|
||||
(expect (resv "%:~") :to-equal "")
|
||||
(expect (resv "%:P") :to-equal "")))
|
||||
|
||||
(it "supports substitution modifiers"
|
||||
(let ((buffer-file-name "~/.emacs.d/test/modules/feature/test-evil.el")
|
||||
(default-directory "~/.emacs.d/test/modules/"))
|
||||
(expect (resv "%:s?e?x?") :to-equal "fxature/test-evil.el")
|
||||
(expect (resv "%:gs?e?x?") :to-equal "fxaturx/txst-xvil.xl")))
|
||||
|
||||
(it "cleans up empty substitution modifiers"
|
||||
(let (buffer-file-name default-directory)
|
||||
(expect (resv "%:s?e?x?") :to-equal "")
|
||||
(expect (resv "%:gs?e?x?") :to-equal "")))))
|
Loading…
Add table
Add a link
Reference in a new issue