diff --git a/modules/completion/corfu/README.org b/modules/completion/corfu/README.org index 91d64ad01..ca8d49053 100644 --- a/modules/completion/corfu/README.org +++ b/modules/completion/corfu/README.org @@ -30,8 +30,6 @@ utilities for fine-tuning. Only some of common behaviors are documented here. - +dabbrev :: Enable and configure [[doom-package:dabbrev]] as a close-to-universal CAPF fallback. -- +on-ret +on-ret-pt :: - Enable corresponding completion-style features. See [[*Usage]]. ** Packages - [[doom-package:corfu]] @@ -64,7 +62,6 @@ words. Snippets may also appear in the candidate list if available. 🔨 /This module's usage documentation is incomplete./ [[doom-contrib-module:][Complete it?]] #+end_quote -** Code completion By default, completion gets triggered after typing 2 non-space consecutive characters, by means of [[kbd:][C-SPC]] at any moment or [[kbd:][TAB]] on a line with proper indentation. Many styles of completion are documented below, which can be @@ -110,29 +107,19 @@ to be only visual or for there to be no preview, configure (setq corfu-preview-current nil) #+end_src -** Commit on [[kbd:][RET]] (~+on-ret~) -Some people prefer to use [[kbd:][RET]] to commit, so here we bind it to Corfu's insertion -function. Note that Corfu allows "no candidate" to be selected, and in that -case, it will just quit without inserting. To make it less obtrusive by default, -the popup starts in this unselected state. See [[var:corfu-preselect]] to alter this -behavior; it can start with the first candidate selected, for instance. +** Commit on [[kbd:][RET]] with pass-through +A lot of people like to use [[kbd:][RET]] to commit, so here we bind it to Corfu's +insertion function. Note that Corfu allows "no candidate" to be selected, and in +that case, we have a custom binding to quit completion and pass-through. To make +it less obtrusive by default, the popup starts in this unselected state. See +[[var:corfu-preselect]] to alter the initial behavior; it can start with the first +one selected, for instance. Then, you have to move one candidate backwards to +pass-through The exact action of [[kbd:][RET]] can be changed via +[[var:+corfu-want-ret-to-confirm]]. -| Keybind | Description | -|---------+--------------------------| -| [[kbd:][RET]] | Insert candidate or quit | - -** Commit on [[kbd:][RET]] with pass-through (~+on-ret-pt~) -This enables [[kbd:][RET]] to work as a finisher like above. The difference is that -without a current candidate, after quitting it passes-through to whatever action -would have happened normally. So if you're in the minibuffer composing a shell -command and press [[kbd:][RET]], unless a candidate is selected, it quits completion then -commits the minibuffer automatically. Contrast to the above, you would need to -press twice to commit. [[var:corfu-preselect]] is important here, as having the -first candidate from the start prevents the pass-through. - -| Keybind | Description | -|---------+-------------------------------------------| -| [[kbd:][RET]] | Insert candidate or quit and pass-through | +| Keybind | Description | +|---------+-----------------------| +| [[kbd:][RET]] | Insert candidate DWIM | ** Cycle directionally If you'd rather think in directions rather than next/previous, arrow keys and vi @@ -151,23 +138,13 @@ You may unbind them by setting to nil, see ~map!~'s documentation. | [[kbd:][C-S-k]] | (evil) Go to previous doc line | ** Cycle with [[kbd:][TAB]] -You may wish to bind the following [[kbd:][TAB]]-based cycling alternatives with the -snippet below the table: +[[kbd:][TAB]]-based cycling alternatives are also bound according to the table below: | Keybind | Description | |---------+--------------------------| | [[kbd:][TAB]] | Go to next candidate | | [[kbd:][S-TAB]] | Go to previous candidate | -#+begin_src emacs-lisp -(map! :after corfu - :map corfu-map - [tab] #'corfu-next - "TAB" #'corfu-next - [backtab] #'corfu-previous - "S-TAB" #'corfu-previous) -#+end_src - ** Searching with multiple keywords (~+orderless~) If the [[doom-module::completion corfu +orderless]] flag is enabled, users can perform code completion with multiple search keywords by use of space as the @@ -225,6 +202,10 @@ A few variables may be set to change behavior of this module: - [[var:+corfu-want-minibuffer-completion]] :: Enables Corfu in the minibuffer, where it may be obtrusive. May also be set to ~aggresive~ to enable even in some places without ~completion-at-point~. +- [[var:+corfu-want-ret-to-confirm]] :: + Enables commiting with [[RET]] when the popup is visible. Default is ~t~, may be set to + ~'minibuffer~ if you want to commit both the completion and the minibuffer when + active. When ~nil~, it is always passed-through. ** Adding CAPFs to a mode To add other CAPFs on a mode-per-mode basis, put either of the following in your @@ -240,30 +221,6 @@ 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. -For programming modes where you want a CAPF to be active only in documentation -and comments, define the following function and use it as a Cape predicate. It -fixes the issue Cape's implementation has with tree-sitter. - -#+begin_src emacs-lisp -;;;###autoload -(defun +corfu-in-doc-or-comment-p (&optional _sym) - "Return non-nil if point is in a docstring or comment." - (or (nth 4 (syntax-ppss)) - (when-let ((faces '(font-lock-comment-face - font-lock-doc-face - tree-sitter-hl-face:doc - tree-sitter-hl-face:comment)) - (fs (get-text-property (point) 'face))) - (if (listp fs) - (cl-loop for f in fs - if (memq f faces) - return t) - (memq fs faces))))) - -;; Use this as #'some-capf above -(cape-capf-predicate #'another-capf #'+corfu-in-doc-or-comment-p) -#+end_src - ** Adding CAPFs to a key You may want to add other CAPFs to keys, so as to not pollute auto completion and use only when demanded. To do so, adapt the snippet below into your diff --git a/modules/completion/corfu/config.el b/modules/completion/corfu/config.el index 1bffdf9b5..d410d8093 100644 --- a/modules/completion/corfu/config.el +++ b/modules/completion/corfu/config.el @@ -8,6 +8,14 @@ Setting this to `aggressive' will enable Corfu in more commands which use the minibuffer such as `query-replace'.") +(defvar +corfu-want-ret-to-confirm t + "Configure how the user expects RET to behave. +Possible values are: +- t (default): Insert candidate if one is selected, pass-through otherwise; +- `minibuffer': Insert candidate if one is selected, pass-through otherwise, + and immediatelly exit if in the minibuffer; +- nil: Pass-through without inserting.") + ;; ;;; Packages (use-package! corfu diff --git a/modules/config/default/config.el b/modules/config/default/config.el index 8a304d490..864e14d1e 100644 --- a/modules/config/default/config.el +++ b/modules/config/default/config.el @@ -459,52 +459,42 @@ Continues comments if executed from a commented line. Consults "C-s" command)) (map! :when (modulep! :completion corfu) - :after corfu - (:map corfu-mode-map - :when (modulep! :completion corfu +individual) - :prefix "C-x" - :gi "C-l" #'cape-line - :gi "C-k" #'cape-keyword - :gi "C-f" #'cape-file - :gi "s" #'cape-dict - :gi "C-s" #'yasnippet-capf - :gi "C-n" #'cape-dabbrev - :gi "C-p" #'cape-history) (:map corfu-map "C-S-s" #'+corfu-move-to-minibuffer "C-p" #'corfu-previous "C-n" #'corfu-next + "S-TAB" #'corfu-previous + [backtab] #'corfu-previous + "TAB" #'corfu-next + [tab] #'corfu-next (:when (modulep! :completion corfu +orderless) [remap corfu-insert-separator] #'+corfu-smart-sep-toggle-escape))) - (when-let ((cmds-del - `(menu-item "Reset completion" corfu-reset - :filter ,(lambda (cmd) - (interactive) - (when (and (>= corfu--index 0) - (eq corfu-preview-current 'insert)) - cmd)))) - (cmds-ret-pt - `(menu-item "Insert completion or pass-through" corfu-insert - :filter ,(lambda (cmd) - (interactive) - (if (>= corfu--index 0) - cmd - (corfu-quit)))))) + (let ((cmds-del + `(menu-item "Reset completion" corfu-reset + :filter ,(lambda (cmd) + (interactive) + (when (and (>= corfu--index 0) + (eq corfu-preview-current 'insert)) + cmd)))) + (cmds-ret + `(menu-item "Insert completion DWIM" corfu-insert + :filter ,(lambda (cmd) + (interactive) + (cond ((null +corfu-want-ret-to-confirm) + (corfu-quit)) + ((or (not (minibufferp nil t)) + (eq +corfu-want-ret-to-confirm t)) + (when (>= corfu--index 0) cmd)) + ((eq +corfu-want-ret-to-confirm 'minibuffer) + (funcall-interactively cmd) + nil) + (t cmd)))))) (map! :when (modulep! :completion corfu) - :after corfu :map corfu-map [backspace] cmds-del "DEL" cmds-del - (:when (modulep! :completion corfu +on-ret) - :gi [return] #'corfu-insert - :gi "RET" #'corfu-insert) - (:when (modulep! :completion corfu +on-ret-pt) - :gi [return] cmds-ret-pt - :gi "RET" cmds-ret-pt) - (:unless (or (modulep! :completion corfu +on-ret) - (modulep! :completion corfu +on-ret-pt)) - :gi [return] nil - :gi "RET" nil))) + :gi [return] cmds-ret + :gi "RET" cmds-ret)) ;; 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 diff --git a/templates/init.example.el b/templates/init.example.el index 7a5e4e6c7..cef45ecb3 100644 --- a/templates/init.example.el +++ b/templates/init.example.el @@ -22,6 +22,7 @@ :completion company ; the ultimate code completion backend + ;;(corfu +orderless) ; complete with cap(f), cape and a flying feather! ;;helm ; the *other* search engine for love and life ;;ido ; the other *other* search engine... ;;ivy ; a search engine for love and life