diff --git a/modules/completion/corfu/README.org b/modules/completion/corfu/README.org index d88e89969..94eb2ae16 100644 --- a/modules/completion/corfu/README.org +++ b/modules/completion/corfu/README.org @@ -25,9 +25,7 @@ and highly non-native, but has some extra features and more maturity. - +dabbrev :: Enable and configure [[doom-package:dabbrev]] as a close-to-universal CAPF fallback. -- +individual :: - Add bindings for specific CAPFs under the [[kbd:][C-x]] prefix. -- +on-type +on-ret +on-ret-pt +direction +tab :: +- +on-ret +on-ret-pt :: Enable corresponding completion-style features. See [[*Usage]]. ** Packages @@ -64,9 +62,8 @@ words. Snippets may also appear in the candidate list if available. ** 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 offered, which can be composed with -module flags to suit the user; they are described in subsections. The following -keybindings are generally available: +indentation. Many styles of completion are documented below, which can be +composed to suit the user. The following keybindings are generally available: | Keybind | Description | |---------+---------------------------------------------| @@ -84,17 +81,30 @@ keybindings are generally available: | [[kbd:][C-SPC]] | (when not completing) Complete | | [[kbd:][C-M-i]] | (emacs) (when not completing) Complete | -Bindings in the following sections are additive, and get enabled by the -corresponding module flags. Additionally, for users of evil [[kdb:][C-SPC]] is smart -regarding your state. In normal-like states, enter insert then start corfu; in -visual-like states, perform [[help:evil-change][evil-change]] (which leaves you in insert state) then -start corfu; in insert-like states, start corfu immediatelly. +Bindings in the following sections are additive, and get enabled by including +the corresponding ~config.el~ snippets or via flags. Additionally, for users of +evil, [[kdb:][C-SPC]] is smart regarding your state. In normal-like states, enter insert +then start corfu; in visual-like states, perform [[help:evil-change][evil-change]] (which leaves you +in insert state) then start corfu; in insert-like states, start corfu +immediatelly. -** Commit on type (~+on-type~) -When the completion popup is visible and the current candidate is previewed into -the buffer, further input commits that candidate as previewed. Note it does not -perform candidate exit actions, such as expanding snippets. This is intended for -people who prefer to leave [[kbd:][RET]] free. +** Commit preview on type +When the completion popup is visible, by default the current candidate is +previewed into the buffer, and further input commits that candidate as previewed +(note it does not perform candidate exit actions, such as expanding snippets). +If neither ~+on-ret~ or ~+on-ret-pt~ are enabled, this becomes the only default +way to commit a candidate ([[kbd:][RET]] is unbound in that case). + +The feature is in line with other common editors, but if you prefer the preview +to be only visual or for there to be no preview, configure +[[var:corfu-preview-current]]. + +#+begin_src emacs-lisp +;; Non-inserting preview +(setq corfu-preview-current t) +;; No preview +(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 @@ -120,9 +130,10 @@ first candidate from the start prevents the pass-through. |---------+-------------------------------------------| | [[kbd:][RET]] | Insert candidate or quit and pass-through | -** Cycle directionally (~+direction~) -If you'd rather think in directions rather than next/previous, enable arrow keys -and vi movements to control the selection and documentation view. +** Cycle directionally +If you'd rather think in directions rather than next/previous, arrow keys and vi +movements to control the selection and documentation view are bound by default. +A snippet to unbind them is included after the table. | Keybind | Description | |----------+---------------------------------| @@ -135,14 +146,41 @@ and vi movements to control the selection and documentation view. | [[kbd:][C-S-j]] | (evil) Go to next doc line | | [[kbd:][C-S-k]] | (evil) Go to previous doc line | -** Cycle with [[kbd:][TAB]] (~+tab~) -Binds [[kbd:][TAB]]-based cycling alternatives. +#+begin_src emacs-lisp +(map! (:after corfu + :map corfu-map + "" nil + "" nil + ;; Evil + "C-k" nil + "C-j" nil) + (:after corfu-popupinfo + :map corfu-popupinfo-map + "C-" nil + "C-" nil + ;; Evil + "C-S-k" nil + "C-S-j" nil)) +#+end_src + +** Cycle with [[kbd:][TAB]] +You may wish to bind the following [[kbd:][TAB]]-based cycling alternatives with the +snippet below the table: | 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 @@ -156,29 +194,50 @@ backslash, including the space in the search term, and pressing it with an already escaped separator before point deletes it. Thus, you can cycle back if you accidentaly press more than needed. -| Keybind | Description | -|---------+------------------------------------------------------| -| [[kbd:][C-SPC]] | (when completing) Insert separator DWIM | -| [[kbd:][SPC]] | Quit autocompletion or insert space after a wildcard | +| Keybind | Description | +|---------+-------------------------------------------------| +| [[kbd:][C-SPC]] | (evil) (when completing) Insert separator DWIM | +| [[kbd:][M-SPC]] | (emacs) (when completing) Insert separator DWIM | +| [[kbd:][SPC]] | (when completing) Quit autocompletion | +| [[kbd:][SPC]] | (when completing with separators) Self-insert | -** Manually call generic CAPFs (~+individual~) +** 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 those who enable the -~+individual~ module flag. They are listed below: +look through). As an example, set the these binds with the following snippet: -| 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~ | +| Keybind | Description | +|---------+------------------| +| [[kbd:][C-x]] [[kbd:][C-l]] | ~cape-line~ | +| [[kbd:][C-x]] [[kbd:][C-k]] | ~cape-keyword~ | +| [[kbd:][C-x]] [[kbd:][C-f]] | ~cape-file~ | +| [[kbd:][C-x]] [[kbd:][s]] | ~cape-dict~ | +| [[kbd:][C-x]] [[kbd:][C-s]] | ~yasnippet-capf~ | +| [[kbd:][C-x]] [[kbd:][C-n]] | ~cape-dabbrev~ | +| [[kbd:][C-x]] [[kbd:][C-p]] | ~cape-history~ | + +#+begin_src emacs-lisp +;; `corfu-mode-map' is not tied to the popup being visible, whereas `corfu-map' +;; is only active while completing. +(map! :map corfu-mode-map + :prefix "C-x" + "C-l" #'cape-line + "C-k" #'cape-keyword + "C-f" #'cape-file + "s" #'cape-dict + "C-s" #'yasnippet-capf + "C-n" #'cape-dabbrev + "C-p" #'cape-history) +#+end_src + +** Exporting to the minibuffer +The entries shown in the completion popup can be exported to another +~completion-in-region~ minibuffer, giving access to all the manipulations those +suites allow. Using Vertico 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. ** Exporting to the minibuffer The entries shown in the completion popup can be exported to another @@ -209,6 +268,8 @@ A few variables may be set to change behavior of this module: - [[var:corfu-preselect]] :: Configures startup selection, choosing between the first candidate or the prompt. +- [[var:corfu-preview-current]] :: + Configures current candidate preview. - [[var:+corfu-buffer-scanning-size-limit]] :: Sets the maximum buffer size to be scanned by ~cape-dabbrev~. Defaults to 1 MB. Set this if you are having performance problems using the CAPF. @@ -230,6 +291,30 @@ 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 To add other CAPFs to keys, adapt the snippet below into your ~config.el~: #+begin_src emacs-lisp diff --git a/modules/completion/corfu/autoload.el b/modules/completion/corfu/autoload.el index 1df01bdaf..60c274c4d 100644 --- a/modules/completion/corfu/autoload.el +++ b/modules/completion/corfu/autoload.el @@ -38,21 +38,4 @@ (save-excursion (backward-char 1) (insert-char ?\\))) (t - ;; Without this corfu quits immediately. - (setq this-command #'corfu-insert-separator) (call-interactively #'corfu-insert-separator)))) - -;;;###autoload -(defun +corfu-in-doc-or-comment-p (_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))))) diff --git a/modules/completion/corfu/config.el b/modules/completion/corfu/config.el index a576a7dc4..192693e28 100644 --- a/modules/completion/corfu/config.el +++ b/modules/completion/corfu/config.el @@ -58,6 +58,7 @@ use the minibuffer such as `query-replace'.") (add-to-list 'completion-category-overrides `(lsp-capf (styles ,@completion-styles))) (add-to-list 'corfu-auto-commands #'lispy-colon) (add-to-list 'corfu-continue-commands #'+corfu-move-to-minibuffer) + (add-to-list 'corfu-continue-commands #'+corfu-smart-sep-toggle-escape) (add-hook 'evil-insert-state-exit-hook #'corfu-quit) (when (modulep! +icons) diff --git a/modules/config/default/+evil-bindings.el b/modules/config/default/+evil-bindings.el index 57277c815..40979e429 100644 --- a/modules/config/default/+evil-bindings.el +++ b/modules/config/default/+evil-bindings.el @@ -162,26 +162,32 @@ (:when (modulep! :completion corfu) (:after corfu (:map corfu-mode-map - :e "C-M-i" #'completion-at-point - (: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)))) + :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-SPC" #'corfu-insert-separator + "C-k" #'corfu-previous + "C-j" #'corfu-next "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 + "C-h" #'corfu-popupinfo-toggle ;; Reversed because popupinfo assumes opposite of what feels intuitive ;; with evil. - (:when (modulep! :completion corfu +direction) - "C-S-k" #'corfu-popupinfo-scroll-down - "C-S-j" #'corfu-popupinfo-scroll-up) - "C-h" #'corfu-popupinfo-toggle))) + "C-S-k" #'corfu-popupinfo-scroll-down + "C-S-j" #'corfu-popupinfo-scroll-up + "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))))) ;;; :completion (separate) (map! (:when (modulep! :completion ivy) diff --git a/modules/config/default/config.el b/modules/config/default/config.el index 6c42ad09e..8a304d490 100644 --- a/modules/config/default/config.el +++ b/modules/config/default/config.el @@ -475,21 +475,7 @@ Continues comments if executed from a commented line. Consults "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 +tab) - :gi [tab] #'corfu-next - :gi "TAB" #'corfu-next - :gi [backtab] #'corfu-previous - :gi "S-TAB" #'corfu-previous)) - (:after corfu-popupinfo - :map corfu-popupinfo-map - (:when (modulep! :completion corfu +direction) - "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)))) + [remap corfu-insert-separator] #'+corfu-smart-sep-toggle-escape))) (when-let ((cmds-del `(menu-item "Reset completion" corfu-reset :filter ,(lambda (cmd) @@ -517,8 +503,8 @@ Continues comments if executed from a commented line. Consults :gi "RET" cmds-ret-pt) (:unless (or (modulep! :completion corfu +on-ret) (modulep! :completion corfu +on-ret-pt)) - [return] nil - "RET" nil))) + :gi [return] nil + :gi "RET" nil))) ;; 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