diff --git a/modules/completion/corfu/README.org b/modules/completion/corfu/README.org index 534aa04a2..75124ff46 100644 --- a/modules/completion/corfu/README.org +++ b/modules/completion/corfu/README.org @@ -26,6 +26,14 @@ and highly non-native, but has some extra features and more maturity. - +orderless :: Pull in [[doom-package:orderless]] if necessary and apply multi-component completion (still needed if [[doom-module::completion vertico]] is active). +- +dabbrev :: + Enable and configure [[doom-package:dabbrev]] as a close-to-universal CAPF + fallback. +- +dict :: + Enable and configure dictionary completion for text modes and related regions + in programming modes. +- +emoji :: + Enable and configure emoji completion via the emoji input method. ** Packages - [[doom-package:corfu]] @@ -63,26 +71,25 @@ By default, completion gets triggered after typing 2 non-space consecutive characters, or by means of the [[kbd:][C-SPC]] keybinding at any moment. While the popup is visible, the following relevant keys are available: -| Keybind | Description | -|----------+------------------------------------------------------------------| -| [[kbd:][]] | Go to next candidate | -| [[kbd:][]] | Go to previous candidate | -| [[kbd:][C-n]] | Go to next candidate | -| [[kbd:][C-p]] | Go to previous candidate | -| [[kbd:][C-j]] | (evil) Go to next candidate | -| [[kbd:][C-k]] | (evil) Go to previous candidate | -| [[kbd:][C-]] | Go to next doc line | -| [[kbd:][C-]] | Go to previous doc line | -| [[kbd:][C-S-n]] | Go to next doc line | -| [[kbd:][C-S-p]] | Go to previous doc line | -| [[kbd:][C-S-j]] | (evil) Go to next doc line | -| [[kbd:][C-S-k]] | (evil) Go to previous doc line | -| [[kbd:][C-h]] | Toggle documentation (if available) | +| Keybind | Description | +|----------+---------------------------------------------------------| +| [[kbd:][]] | Go to next candidate | +| [[kbd:][]] | Go to previous candidate | +| [[kbd:][C-n]] | Go to next candidate | +| [[kbd:][C-p]] | Go to previous candidate | +| [[kbd:][C-j]] | (evil) Go to next candidate | +| [[kbd:][C-k]] | (evil) Go to previous candidate | +| [[kbd:][C-]] | Go to next doc line | +| [[kbd:][C-]] | Go to previous doc line | +| [[kbd:][C-S-n]] | Go to next doc line | +| [[kbd:][C-S-p]] | Go to previous doc line | +| [[kbd:][C-S-j]] | (evil) Go to next doc line | +| [[kbd:][C-S-k]] | (evil) Go to previous doc line | +| [[kbd:][C-h]] | Toggle documentation (if available) | | [[kbd:][M-m]] | Export to minibuffer (if [[doom-module::completion vertico]]) | -| [[kbd:][M-S-j]] | (evil) Export to minibuffer (if [[doom-module::completion vertico]]) | -| [[kbd:][RET]] | Insert candidate | -| [[kbd:][SPC]] | (after wildcard) Reset completion | -| [[kbd:][DEL]] | Reset completion | +| [[kbd:][M-j]] | (evil) Export to minibuffer (if [[doom-module::completion vertico]]) | +| [[kbd:][RET]] | Insert candidate | +| [[kbd:][SPC]] | Quit autocompletion after a wildcard or pass-through | | [[kbd:][C-SPC]] | Complete (unless [[doom-module::completion corfu +tng]]) | | [[kbd:][C-SPC]] | (when completing) Insert separator DWIM (see below) | @@ -95,6 +102,7 @@ following additional binds: | [[kbd:][TAB]] | Complete | | [[kbd:][TAB]] | (when completing) Go to next candidate | | [[kbd:][S-TAB]] | (when completing) Go to previous candidate | +| [[kbd:][DEL]] | (when completing) Reset completion DWIM-style | ** Searching with multiple keywords If the [[doom-module::completion corfu +orderless]] flag is enabled, users can @@ -129,15 +137,19 @@ A few variables may be set to change behavior of this module: Configures behavior for exact matches. Its default is nil, and it's recommended to leave it at that. Otherwise, single matches on snippet keys expand immediately. +- [[var:+corfu-buffer-scanning-size-limit]] :: + Sets the maximum buffer size to be scanned by ~cape-dabbrev~ and + ~cape-lines~. Defaults to 1 MB. Set this if you are having performance + problems using either CAPF. ** Adding CAPFs to a mode To add other CAPFs on a mode-per-mode basis, put either of the following in your ~config.el~: #+begin_src emacs-lisp -(add-hook! some-mode (add-to-list 'completion-at-point-functions #'some-capf)) +(add-hook! some-mode (add-hook 'completion-at-point-functions #'some-capf depth t)) ;; OR, but note the different call signature -(add-hook 'some-mode-hook (lambda () (add-to-list 'completion-at-point-functions #'some-capf))) +(add-hook 'some-mode-hook (lambda () (add-hook 'completion-at-point-functions #'some-capf depth t))) #+end_src ~DEPTH~ above is an integer between -100, 100, and defaults to 0 of omitted. Also @@ -147,6 +159,17 @@ accepts the quoted arguments form above. * Troubleshooting [[doom-report:][Report an issue?]] +If you have performance issues with ~cape-dabbrev~, the first thing I recommend +doing is to look at the list of buffers Dabbrev is scanning: + +#+begin_src emacs-lisp +(dabbrev--select-buffers) ; => (# #> # ...) +(length (dabbrev--select-buffers)) ; => 37 +#+end_src + +... and modify ~dabbrev-ignored-buffer-regexps~ or ~dabbrev-ignored-buffer-modes~ +accordingly. + * Frequently asked questions /This module has no FAQs yet./ [[doom-suggest-faq:][Ask one?]] diff --git a/modules/completion/corfu/config.el b/modules/completion/corfu/config.el index 5d142b600..d87fa3d65 100644 --- a/modules/completion/corfu/config.el +++ b/modules/completion/corfu/config.el @@ -1,5 +1,11 @@ ;;; completion/corfu/config.el -*- lexical-binding: t; -*- +(defvar +corfu-buffer-scanning-size-limit (* 1 1024 1024) ; 1 MB + "Size limit for a buffer to be scanned by `cape-line' or `cape-dabbrev'. + +As an exception, `cape-line' will also scan buffers with the same +major mode regardless of size.") + ;; ;;; Packages (use-package! corfu @@ -17,7 +23,7 @@ t) corfu-cycle t corfu-separator (when (modulep! +orderless) ?\s) - corfu-preselect 'valid + corfu-preselect (if (modulep! +tng) 'prompt 'valid) corfu-count 16 corfu-max-width 120 corfu-preview-current 'insert @@ -36,6 +42,31 @@ :v "C-SPC" (cmd! (call-interactively #'evil-change) (call-interactively #'completion-at-point))) + (defun +corfu-enable-in-minibuffer () + "Enable Corfu in the minibuffer if `completion-at-point' is bound." + (when (where-is-internal #'completion-at-point (list (current-local-map))) + (setq-local corfu-echo-delay nil) + (corfu-mode +1))) + (add-hook 'minibuffer-setup-hook #'+corfu-enable-in-minibuffer) + ;; If you want to update the visual hints after completing minibuffer commands + ;; with Corfu and exiting, you have to do it manually. + (defadvice! +corfu--insert-before-exit-minibuffer-a () + :before #'exit-minibuffer + (when (or (and (frame-live-p corfu--frame) + (frame-visible-p corfu--frame)) + (and (featurep 'corfu-terminal) + (popon-live-p corfu-terminal--popon))) + (when (member isearch-lazy-highlight-timer timer-idle-list) + (apply (timer--function isearch-lazy-highlight-timer) + (timer--args isearch-lazy-highlight-timer))) + (when (member (bound-and-true-p anzu--update-timer) timer-idle-list) + (apply (timer--function anzu--update-timer) + (timer--args anzu--update-timer))) + (when (member (bound-and-true-p evil--ex-search-update-timer) + timer-idle-list) + (apply (timer--function evil--ex-search-update-timer) + (timer--args evil--ex-search-update-timer))))) + (after! evil (add-hook 'evil-insert-state-exit-hook #'corfu-quit)) @@ -73,10 +104,78 @@ :init (add-hook! prog-mode (defun +corfu-add-cape-file-h () - (add-to-list 'completion-at-point-functions #'cape-file))) + (add-hook 'completion-at-point-functions #'cape-file -10 t))) (add-hook! (org-mode markdown-mode) (defun +corfu-add-cape-elisp-block-h () - (add-to-list 'completion-at-point-functions #'cape-elisp-block))) + (add-hook 'completion-at-point-functions #'cape-elisp-block 0 t))) + ;; Enable Dabbrev completion basically everywhere as a fallback. + (when (modulep! +dabbrev) + ;; Set up `cape-dabbrev' options. + (defun +dabbrev-friend-buffer-p (other-buffer) + (< (buffer-size other-buffer) +corfu-buffer-scanning-size-limit)) + (after! dabbrev + (setq cape-dabbrev-check-other-buffers t + dabbrev-friend-buffer-function #'+dabbrev-friend-buffer-p + dabbrev-ignored-buffer-regexps + '("^ " + "\\(TAGS\\|tags\\|ETAGS\\|etags\\|GTAGS\\|GRTAGS\\|GPATH\\)\\(<[0-9]+>\\)?") + dabbrev-upcase-means-case-search t) + (add-to-list 'dabbrev-ignored-buffer-modes 'pdf-view-mode) + + (add-hook! (prog-mode text-mode conf-mode comint-mode minibuffer-setup + eshell-mode) + (defun +corfu-add-cape-dabbrev-h () + (add-hook 'completion-at-point-functions #'cape-dabbrev 20 t))))) + (when (modulep! +line) + ;; Set up `cape-line' options. + (defun +cape-line-buffers () + (cl-loop for buf in (buffer-list) + if (or (eq major-mode (buffer-local-value 'major-mode buf)) + (< (buffer-size buf) +corfu-buffer-scanning-size-limit)) + collect buf)) + (setq cape-line-buffer-function #'+cape-line-buffers) + (add-hook! (text-mode comint-mode minibuffer-setup) + (defun +corfu-add-cape-line-h () + (add-hook 'completion-at-point-functions #'cape-line 20 t)))) + ;; Complete emojis :). + (when (and (modulep! +emoji) (> emacs-major-version 28)) + (add-hook! (prog-mode conf-mode) + (defun +corfu-add-cape-emoji-h () + (add-hook 'completion-at-point-functions + (cape-capf-inside-faces + (cape-capf-prefix-length #'cape-emoji 1) + ;; Only call inside comments and docstrings. + 'tree-sitter-hl-face:doc 'font-lock-doc-face + 'font-lock-comment-face 'tree-sitter-hl-face:comment) + 10 t))) + (add-hook! text-mode + (defun +corfu-add-cape-emoji-text-h () + (add-hook 'completion-at-point-functions + (cape-capf-prefix-length #'cape-emoji 1) 10 t)))) + ;; Enable dictionary-based autocompletion. + (when (modulep! +dict) + (add-hook! (prog-mode conf-mode) + (defun +corfu-add-cape-dict-h () + (add-hook 'completion-at-point-functions + (cape-capf-inside-faces + ;; Only call inside comments and docstrings. + #'cape-dict 'tree-sitter-hl-face:doc 'font-lock-doc-face + 'font-lock-comment-face 'tree-sitter-hl-face:comment) + 40 t))) + (add-hook! text-mode + (defun +corfu-add-cape-dict-text-h () + (add-hook 'completion-at-point-functions #'cape-dict 40 t)))) + + ;; Make these capfs composable. + (advice-add #'comint-completion-at-point :around #'cape-wrap-nonexclusive) + (advice-add #'eglot-completion-at-point :around #'cape-wrap-nonexclusive) + (advice-add #'lsp-completion-at-point :around #'cape-wrap-nonexclusive) + (advice-add #'pcomplete-completions-at-point :around #'cape-wrap-nonexclusive) + ;; From the `cape' readme. Without this, Eshell autocompletion is broken on + ;; Emacs28. + (when (< emacs-major-version 29) + (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent) + (advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify)) (advice-add #'lsp-completion-at-point :around #'cape-wrap-noninterruptible)) (use-package! yasnippet-capf