;;; editor/evil/init.el -*- lexical-binding: t; -*- (defvar evil-collection-key-blacklist) ;; 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. Ideally, we'd do away with evil-collection entirely. It changes too often, ;; introduces breaking bugs too frequently, and I don't agree with all their ;; design choices. Regardless, it does more good than trouble, so it may be ;; here to stay. ;; 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). (when (and (not noninteractive) (not doom-reloading-p) (modulep! +everywhere)) (setq evil-collection-company-use-tng (modulep! :completion company +tng) ;; must be set before evil/evil-collection is loaded evil-want-keybinding nil) (defvar +evil-collection-disabled-list '(anaconda-mode buff-menu calc comint company custom eldoc elisp-mode ert free-keys helm help indent image kotlin-mode outline replace shortdoc simple slime lispy) "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) ;; We do this ourselves, and better. (defvar evil-collection-want-unimpaired-p nil) ;; Doom binds goto-reference on gD and goto-assignments on gA ourselves (defvar evil-collection-want-find-usages-bindings-p nil) ;; Reduces keybind conflicts between outline-mode and org-mode (which is ;; derived from outline-mode). (defvar evil-collection-outline-enable-in-minor-mode-p nil) ;; We handle loading evil-collection ourselves (defvar evil-collection--supported-modes nil) ;; This has to be defined here since evil-collection doesn't autoload its own. ;; It must be updated whenever evil-collection updates theirs. Here's an easy ;; way to update it: ;; ;; (with-current-buffer ;; (url-retrieve-synchronously "https://raw.githubusercontent.com/emacs-evil/evil-collection/master/evil-collection.el" t t) ;; (goto-char (point-min)) ;; (when (re-search-forward "^(defvar evil-collection--supported-modes\n[^(]+") ;; (let ((list (sexp-at-point))) ;; ;; Fixes ;; (when (assq 'pdf list) ;; (setf (alist-get 'pdf list) '(pdf-tools))) ;; (let ((diff (cl-set-difference evil-collection-mode-list list :test #'equal))) ;; (list (- (length list) (length evil-collection-mode-list)) ;; diff) ;; (message "diff: %s" diff) ;; (kill-new (prin1-to-string list)))))) (defvar evil-collection-mode-list `(2048-game ag alchemist anaconda-mode apropos arc-mode atomic-chrome auto-package-update beginend bm bookmark (buff-menu "buff-menu") calc calendar cider cmake-mode comint company compile consult corfu (custom cus-edit) cus-theme daemons dashboard deadgrep debbugs debug devdocs dictionary diff-hl diff-mode dired dired-sidebar disk-usage doc-view docker ebib ebuku edbi edebug ediff eglot explain-pause-mode elfeed eldoc elisp-mode elisp-refs elisp-slime-nav embark emms ,@(if (> emacs-major-version 28) '(emoji)) epa ert eshell eval-sexp-fu evil-mc eww fanyi finder flycheck flymake forge free-keys geiser ggtags git-timemachine gnus go-mode grep guix hackernews helm help helpful hg-histedit hungry-delete ibuffer image image-dired image+ imenu imenu-list (indent "indent") indium info ivy js2-mode leetcode lispy log-edit log-view lsp-ui-imenu lua-mode kotlin-mode macrostep man (magit magit-repos magit-submodule) magit-section magit-todos markdown-mode monky mpc mu4e mu4e-conversation neotree newsticker notmuch nov omnisharp org org-present org-roam osx-dictionary outline p4 (package-menu package) pass (pdf pdf-tools) popup proced prodigy profiler python quickrun racer racket-describe realgud reftex replace restclient rg ripgrep rjsx-mode robe rtags ruby-mode scheme scroll-lock selectrum sh-script ,@(if (> emacs-major-version 27) '(shortdoc)) simple simple-mpc slime sly snake so-long speedbar tablist tar-mode telega (term term ansi-term multi-term) tetris thread tide timer-list transmission trashed tuareg typescript-mode vc-annotate vc-dir vc-git vdiff vertico view vlf vterm vundo w3m wdired wgrep which-key woman xref xwidget yaml-mode youtube-dl zmusic (ztree ztree-diff))) (defun +evil-collection-init (module &optional disabled-list) "Initialize evil-collection-MODULE. Unlike `evil-collection-init', this respects `+evil-collection-disabled-list', and complains if a module is loaded too early (during startup)." (unless (memq (or (car-safe module) module) disabled-list) (doom-log "Initialized evil-collection-%s %s" (or (car-safe module) module) (if doom-init-time "" "(too early!)")) (with-demoted-errors "evil-collection error: %s" (evil-collection-init (list module))))) (defadvice! +evil-collection-disable-blacklist-a (fn) :around #'evil-collection-vterm-toggle-send-escape ; allow binding to ESC (let (evil-collection-key-blacklist) (funcall-interactively fn))) ;; These modes belong to packages that Emacs always loads at startup, causing ;; evil-collection and it's co-packages to all load immediately. We avoid this ;; by loading them after evil-collection has first loaded... (with-eval-after-load 'evil-collection ;; Don't let evil-collection interfere with certain keys (setq evil-collection-key-blacklist (append (list doom-leader-key doom-localleader-key doom-leader-alt-key) evil-collection-key-blacklist (when (modulep! :tools lookup) '("gd" "gf" "K")) (when (modulep! :tools eval) '("gr" "gR")) '("[" "]" "gz" ""))) (evil-define-key* 'normal process-menu-mode-map "q" #'kill-current-buffer "d" #'process-menu-delete-process) (mapc #'+evil-collection-init '(comint custom))) ;; ...or on first invokation of their associated major/minor modes. (after! evil ;; Emacs loads these two packages immediately, at startup, which needlessly ;; convolutes load order for evil-collection-help. (add-transient-hook! 'help-mode (+evil-collection-init 'help)) (add-transient-hook! 'Buffer-menu-mode (+evil-collection-init '(buff-menu "buff-menu"))) (add-transient-hook! 'calc-mode (+evil-collection-init 'calc)) (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 'replace)) (add-transient-hook! 'indent-rigidly (+evil-collection-init '(indent "indent"))) (add-transient-hook! 'minibuffer-setup-hook (when evil-collection-setup-minibuffer (+evil-collection-init 'minibuffer) (evil-collection-minibuffer-insert))) (add-transient-hook! 'process-menu-mode (+evil-collection-init '(process-menu simple))) (add-transient-hook! 'shortdoc-mode (+evil-collection-init 'shortdoc)) (add-transient-hook! 'tabulated-list-mode (+evil-collection-init 'tabulated-list)) (add-transient-hook! 'tab-bar-mode (+evil-collection-init 'tab-bar)) ;; HACK Do this ourselves because evil-collection break's `eval-after-load' ;; load order by loading their target plugin before applying keys. This ;; makes it hard for end-users to overwrite these keybinds with a ;; simple `after!' or `with-eval-after-load'. (dolist (mode evil-collection-mode-list) (dolist (req (or (cdr-safe mode) (list mode))) (with-eval-after-load req (+evil-collection-init mode +evil-collection-disabled-list))))))