diff --git a/modules/completion/corfu/README.org b/modules/completion/corfu/README.org index fe9b09ee0..e9354f8a2 100644 --- a/modules/completion/corfu/README.org +++ b/modules/completion/corfu/README.org @@ -71,27 +71,26 @@ 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) | -| [[kbd:][M-m]] | Export to minibuffer (if [[doom-module::completion vertico]]) | -| [[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) | +| 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:][C-S-s]] | Export to minibuffer (if [[doom-module::completion vertico]]) | +| [[kbd:][RET]] | Insert candidate | +| [[kbd:][SPC]] | Quit autocompletion or pass-through after a wildcard | +| [[kbd:][C-SPC]] | Complete (unless [[doom-module::completion corfu +tng]]) | +| [[kbd:][C-SPC]] | (when completing) Insert separator DWIM (see below) | If you prefer a [[kbd:][TAB]]-centric completion style, enable the [[doom-module::completion corfu +tng]] flag so that, instead, you trigger completion with [[kbd:][TAB]], getting the @@ -129,9 +128,42 @@ exported to a consult minibuffer, giving access to all the manipulations the Vertico suite allows. For instance, one could use this to export with [[doom-package:embark]] via [[kbd:][C-c C-l]] and get a buffer with all candidates. +** Manually call generic CAPFs +Completion at point functions have the property that, when called interactively +via their symbol, they work as a call to ~completion-at-point~ where +[[var:completion-at-point-functions]] is bound to that CAPF alone. This allows to +assign generic functions to a binding and call as needed, leaving the default +value used for most completion tasks much leaner (thus, faster and easier to +look through). This module provides some such bindings for Evil users (see the +table below), and you're free map your own of course. Emacs users have to map it +themselves for now, due to the author's lack of knowledge on ergonomic +equivalents to the Evil ones. If you have suggestions, though, we'd be happy to +know! + +| Keybind | Description | +|---------+---------------------------------| +| [[kbd:][C-x]] [[kbd:][C-l]] | (insert-state) ~cape-line~ | +| [[kbd:][C-x]] [[kbd:][C-k]] | (insert-state) ~cape-keyword~ | +| [[kbd:][C-x]] [[kbd:][C-f]] | (insert-state) ~cape-file~ | +| [[kbd:][C-x]] [[kbd:][s]] | (insert-state) ~cape-dict~ | +| [[kbd:][C-x]] [[kbd:][C-s]] | (insert-state) ~yasnippet-capf~ | +| [[kbd:][C-x]] [[kbd:][C-n]] | (insert-state) ~cape-dabbrev~ | +| [[kbd:][C-x]] [[kbd:][C-p]] | (insert-state) ~cape-history~ | + * Configuration A few variables may be set to change behavior of this module: +- [[var:completion-at-point-functions]] :: + This is not a module/package variable, but a builtin Emacs one. Even so, it's + very important to how Corfu works, so we document it here. It contains a list + of functions that are called in turn to generate completion candidates. The + regular (non-lexical) value should contain few entries and they should + generally be context aware, so as to predict what you need. Additional + functions can be added as you get into more and more specific contexts. Also, + there may be cases where you know beforehand the kind of candidate needed, and + want to enable only that one. For this, the variable may be lexically bound to + the correct value, or you may call the CAPF interactively if a single function + is all you need. - [[var:corfu-auto-delay]] :: Number of seconds till completion occurs automatically. Defaults to 0.1. - [[var:corfu-auto-prefix]] :: @@ -158,6 +190,20 @@ To add other CAPFs on a mode-per-mode basis, put either of the following in your see ~add-hook!~'s documentation for additional ways to call it. ~add-hook~ only accepts the quoted arguments form above. +** Adding CAPFs to a key +To add other CAPFs to keys, adapt the snippet below into your ~config.el~: +#+begin_src emacs-lisp +;; For binding inside `corfu-mode-map'. Line 1 ensures the binding only exists +;; after some-mode-hook runs. Line 2 is needed only if the binding can't leak +;; into other Corfu buffers. When neither of the above make sense, the `map!' +;; call is enough. +(add-hook! some-mode ; Only needed if the binding is mode-specific + (make-local-variable 'corfu-mode-map) + (map! :map corfu-mode-map + :prefix "C-x" ; C-x is usually used as prefix, but it's not required + "e" #'cape-emoji)) ; Evil users probably want :i to avoid this in other states +#+end_src + * Troubleshooting [[doom-report:][Report an issue?]] diff --git a/modules/completion/corfu/config.el b/modules/completion/corfu/config.el index 0710b838e..d4bad1f24 100644 --- a/modules/completion/corfu/config.el +++ b/modules/completion/corfu/config.el @@ -32,17 +32,6 @@ tab-always-indent (if (modulep! +tng) 'complete tab-always-indent)) (add-to-list 'completion-category-overrides `(lsp-capf (styles ,@completion-styles))) - (map! :map corfu-mode-map - :e "C-M-i" #'completion-at-point - :i "C-SPC" #'completion-at-point - :n "C-SPC" (cmd! (call-interactively #'evil-insert-state) - (call-interactively #'completion-at-point)) - :v "C-SPC" (cmd! (call-interactively #'evil-change) - (call-interactively #'completion-at-point))) - (map! :unless (modulep! :editor evil) - :map corfu-mode-map - "C-M-i" #'completion-at-point) - (add-hook! 'minibuffer-setup-hook (defun +corfu-enable-in-minibuffer () "Enable Corfu in the minibuffer if `completion-at-point' is bound." @@ -56,32 +45,9 @@ (when (modulep! +icons) (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)) - (let ((cmds-del (cmds! (and (modulep! +tng) - (> corfu--index -1) - (eq corfu-preview-current 'insert)) - #'corfu-reset))) - (map! :map corfu-map - [return] #'corfu-insert - "RET" #'corfu-insert - (:when (modulep! +orderless) - " " #'+corfu-smart-sep-toggle-escape) - (:when (modulep! +tng) - [tab] #'corfu-next - [backtab] #'corfu-previous - "TAB" #'corfu-next - "S-TAB" #'corfu-previous - [backspace] cmds-del - "DEL" cmds-del))) - (when (modulep! +orderless) (after! orderless - (setq orderless-component-separator #'orderless-escapable-split-on-space))) - - (after! vertico - (map! :map corfu-map - "M-m" #'+corfu-move-to-minibuffer - (:when (modulep! :editor evil) - "M-J" #'+corfu-move-to-minibuffer)))) + (setq orderless-component-separator #'orderless-escapable-split-on-space)))) (use-package! cape :defer t @@ -175,16 +141,4 @@ (use-package! corfu-popupinfo :hook ((corfu-mode . corfu-popupinfo-mode)) :config - (setq corfu-popupinfo-delay '(0.5 . 1.0)) - (map! :map corfu-map - "C-" #'corfu-popupinfo-scroll-down - "C-" #'corfu-popupinfo-scroll-up - "C-S-p" #'corfu-popupinfo-scroll-down - "C-S-n" #'corfu-popupinfo-scroll-up - "C-h" #'corfu-popupinfo-toggle) - (map! :when (modulep! :editor evil) - :map corfu-popupinfo-map - ;; Reversed because popupinfo assumes opposite of what feels intuitive - ;; with evil. - "C-S-k" #'corfu-popupinfo-scroll-down - "C-S-j" #'corfu-popupinfo-scroll-up)) + (setq corfu-popupinfo-delay '(0.5 . 1.0))) diff --git a/modules/config/default/+emacs-bindings.el b/modules/config/default/+emacs-bindings.el index 7aa4dfc41..2402e7885 100644 --- a/modules/config/default/+emacs-bindings.el +++ b/modules/config/default/+emacs-bindings.el @@ -511,7 +511,7 @@ "C-x C-b" #'ibuffer "C-x K" #'doom/kill-this-buffer-in-all-windows - ;;; company-mode + ;;; completion (in-buffer) (:when (modulep! :completion company) "C-;" #'+company/complete (:after company @@ -537,6 +537,13 @@ "C-p" #'company-search-repeat-backward "C-s" (cmd! (company-search-abort) (company-filter-candidates)))) + (:when (modulep! :completion corfu) + :after corfu + (:map corfu-mode-map + "C-M-i" #'completion-at-point) + (:map corfu-popupinfo-map + "C-S-h" #'corfu-popupinfo-toggle)) + ;;; ein notebooks (:after ein:notebook-multilang :map ein:notebook-multilang-mode-map diff --git a/modules/config/default/+evil-bindings.el b/modules/config/default/+evil-bindings.el index c79c078f6..c935ac948 100644 --- a/modules/config/default/+evil-bindings.el +++ b/modules/config/default/+evil-bindings.el @@ -43,7 +43,10 @@ #'yas-expand (and (bound-and-true-p company-mode) (modulep! :completion company +tng)) - #'company-indent-or-complete-common) + #'company-indent-or-complete-common + (and (bound-and-true-p corfu-mode) + (modulep! :completion corfu +tng)) + #'completion-at-point) :m [tab] (cmds! (and (modulep! :editor snippets) (evil-visual-state-p) (or (eq evil-visual-selection 'line) @@ -127,7 +130,7 @@ ;; ;;; Module keybinds -;;; :completion +;;; :completion (in-buffer) (map! (:when (modulep! :completion company) :i "C-@" (cmds! (not (minibufferp)) #'company-complete-common) :i "C-SPC" (cmds! (not (minibufferp)) #'company-complete-common) @@ -156,7 +159,39 @@ "C-s" #'company-filter-candidates [escape] #'company-search-abort))) - (:when (modulep! :completion ivy) + (:when (modulep! :completion corfu) + (:after corfu + (:map corfu-mode-map + :e "C-M-i" #'completion-at-point + (:prefix "C-x" + :i "C-l" #'cape-line + :i "C-k" #'cape-keyword + :i "C-f" #'cape-file + :i "s" #'cape-dict + :i "C-s" #'yasnippet-capf + :i "C-n" #'cape-dabbrev + :i "C-p" #'cape-history) + (:unless (modulep! :completion corfu +tng) + :i "C-SPC" #'completion-at-point + :n "C-SPC" (cmd! (call-interactively #'evil-insert-state) + (call-interactively #'completion-at-point)) + :v "C-SPC" (cmd! (call-interactively #'evil-change) + (call-interactively #'completion-at-point)))) + (:map corfu-map + "C-u" (cmd! (let (corfu-cycle) + (funcall-interactively #'corfu-next (- corfu-count)))) + "C-d" (cmd! (let (corfu-cycle) + (funcall-interactively #'corfu-next corfu-count))))) + (:after corfu-popupinfo + :map corfu-popupinfo-map + ;; Reversed because popupinfo assumes opposite of what feels intuitive + ;; with evil. + "C-S-k" #'corfu-popupinfo-scroll-down + "C-S-j" #'corfu-popupinfo-scroll-up + "C-h" #'corfu-popupinfo-toggle))) + +;;; :completion (separate) +(map! (:when (modulep! :completion ivy) (:after ivy :map ivy-minibuffer-map "C-SPC" #'ivy-call-and-recenter ; preview file @@ -169,7 +204,8 @@ [C-return] #'+ivy/git-grep-other-window-action)) (:when (modulep! :completion helm) - (:after helm :map helm-map + (:after helm + :map helm-map [remap next-line] #'helm-next-line [remap previous-line] #'helm-previous-line [left] #'left-char diff --git a/modules/config/default/config.el b/modules/config/default/config.el index e67adf1e3..b8b8f2c91 100644 --- a/modules/config/default/config.el +++ b/modules/config/default/config.el @@ -458,6 +458,39 @@ Continues comments if executed from a commented line. Consults '(evil-ex-completion-map))) "C-s" command)) + (map! :when (modulep! :completion corfu) + :after corfu + (:map corfu-map + [return] #'corfu-insert + "RET" #'corfu-insert + "C-S-s" #'+corfu-move-to-minibuffer + "C-p" #'corfu-previous + "C-n" #'corfu-next + (:when (modulep! :completion corfu +orderless) + [remap completion-at-point] #'+corfu-smart-sep-toggle-escape) + (:when (modulep! :completion corfu +tng) + [tab] #'corfu-next + "TAB" #'corfu-next + [backtab] #'corfu-previous + "S-TAB" #'corfu-previous)) + (:after corfu-popupinfo + :map corfu-popupinfo-map + "C-" #'corfu-popupinfo-scroll-down + "C-" #'corfu-popupinfo-scroll-up + "C-S-p" #'corfu-popupinfo-scroll-down + "C-S-n" #'corfu-popupinfo-scroll-up + "C-S-u" (cmd! (funcall-interactively #'corfu-popupinfo-scroll-down corfu-popupinfo-min-height)) + "C-S-d" (cmd! (funcall-interactively #'corfu-popupinfo-scroll-up corfu-popupinfo-min-height)))) + + (when-let ((cmds-del (and (modulep! :completion corfu +tng) + '(menu-item "Reset completion" corfu-reset + :enable (and (> corfu--index -1) + (eq corfu-preview-current 'insert)))))) + (map! :after corfu + :map corfu-map + [backspace] cmds-del + "DEL" cmds-del)) + ;; Smarter C-a/C-e for both Emacs and Evil. C-a will jump to indentation. ;; Pressing it again will send you to the true bol. Same goes for C-e, except ;; it will ignore comments+trailing whitespace before jumping to eol.