merge: pull request #7739 from LemonBreezes/corfu-update-smart-tab

feat(corfu): update smart tab completion
This commit is contained in:
Henrik Lissner 2024-06-30 15:24:52 -04:00 committed by GitHub
commit 3cb9f17132
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 176 additions and 62 deletions

View file

@ -202,6 +202,15 @@ A few variables may be set to change behavior of this module:
- [[var:+corfu-want-minibuffer-completion]] ::
Whether to enable Corfu in the minibuffer. See its documentation for
additional tweaks.
- [[var:+corfu-want-tab-prefer-expand-snippets]] ::
Whether to prefer expanding snippets over cycling candidates when pressing
[[kbd:][TAB]].
- [[var:+corfu-want-tab-prefer-navigating-snippets]] ::
Whether to prefer navigating snippets over cycling candidates when pressing
[[kbd:][TAB]] and [[kbd:][S-TAB]].
- [[var:+corfu-want-tab-prefer-navigating-org-tables]] ::
Whether to prefer navigating org tables over cycling candidates when pressing
[[kbd:][TAB]] and [[kbd:][S-TAB]].
** Turning off auto-completion
To disable idle (as-you-type) completion, unset ~corfu-auto~:
@ -241,6 +250,8 @@ all CAPFs are interactive to be called this way, in which case you can use
* Troubleshooting
[[doom-report:][Report an issue?]]
** Troubleshooting ~cape-dabbrev~
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:
@ -268,6 +279,34 @@ debug the issue:
(search-in-dabbrev-buffers "\342\200\231")
#+end_src
** Fixing TAB Keybindings
If you encounter an issue where your ~TAB~ keybindings are not responding in Doom
Emacs while the ~:editor evil~ module is active, it's likely caused by a conflict
where ~<tab>~ keybindings and insert state bindings are overriding your ~TAB~ key
assignments.
In Evil mode, keybinding priorities are set such that:
1. ~<tab>~ keybindings supersede ~TAB~ keybindings and only work in GUI Emacs.
2. Bindings in insert state take precedence whenever the insert state is active.
To resolve this conflict and to assign your desired command to the ~TAB~ key, you
must redefine the keybindings with insert state set explicitly. You can do this
by configuring your ~evil~ keybindings for the insert state as follows:
#+begin_src emacs-lisp
(map! :gi "TAB" #'your-command
:gi "<tab>" #'your-command)
#+end_src
Place this code in your Doom Emacs configuration file to set the function ~your-command~ as the response to pressing ~TAB~ during insert mode.
Remember to replace ~#'your-command~ with the actual command you wish to invoke
with the ~TAB~ key.
If ever in a situation like this, use ~describe-key~ with ~C-h k~ and look at what
command is being called as well as what keymaps the command is defined in.
* Frequently asked questions
/This module has no FAQs yet./ [[doom-suggest-faq:][Ask one?]]

View file

@ -16,6 +16,18 @@ Possible values are:
Setting this to `aggressive' will enable Corfu in more commands which
use the minibuffer such as `query-replace'.")
(defvar +corfu-want-tab-prefer-expand-snippets nil
"If non-nil, prefer expanding snippets over cycling candidates with
TAB.")
(defvar +corfu-want-tab-prefer-navigating-snippets nil
"If non-nil, prefer navigating snippets over cycling candidates with
TAB/S-TAB.")
(defvar +corfu-want-tab-prefer-navigating-org-tables nil
"If non-nil, prefer navigating org tables over cycling candidates with
TAB/S-TAB.")
;;
;;; Packages
(use-package! corfu

View file

@ -38,38 +38,66 @@
;;; Global keybindings
;; Smart tab, these will only work in GUI Emacs
(map! :i [tab] (cmds! (and (modulep! :editor snippets)
(yas-maybe-expand-abbrev-key-filter 'yas-expand))
#'yas-expand
(and (bound-and-true-p company-mode)
(modulep! :completion company +tng))
#'company-indent-or-complete-common
(and (bound-and-true-p corfu-mode)
(modulep! :completion corfu))
#'completion-at-point)
:m [tab] (cmds! (and (modulep! :editor snippets)
(evil-visual-state-p)
(map! :i [tab]
`(menu-item "Evil insert smart tab" nil :filter
(lambda (cmd)
(cond
((or (doom-lookup-key [tab] overriding-terminal-local-map)
(doom-lookup-key (kbd "TAB") overriding-terminal-local-map))
cmd)
,@(when (modulep! :editor snippets)
'(((+yas-active-p)
#'yas-next-field-or-maybe-expand)
((yas-maybe-expand-abbrev-key-filter 'yas-expand)
#'yas-expand)))
,@(when (modulep! :completion company +tng)
'(((bound-and-true-p company-mode)
#'company-indent-or-complete-common)))
,@(when (modulep! :completion corfu)
'(((bound-and-true-p corfu-mode)
(if (derived-mode-p 'eshell-mode 'comint-mode)
#'completion-at-point
#'indent-for-tab-command)))))))
:m [tab]
`(menu-item "Evil motion smart tab" nil :filter
(lambda (cmd)
(cond
((or (doom-lookup-key [tab] overriding-terminal-local-map)
(doom-lookup-key (kbd "TAB") overriding-terminal-local-map))
cmd)
,@(when (modulep! :editor snippets)
'(((and (evil-visual-state-p)
(or (eq evil-visual-selection 'line)
(not (memq (char-after) (list ?\( ?\[ ?\{ ?\} ?\] ?\))))))
#'yas-insert-snippet
(and (modulep! :editor fold)
(save-excursion (end-of-line) (invisible-p (point))))
#'+fold/toggle
(not (memq (char-after)
(list ?\( ?\[ ?\{ ?\} ?\] ?\))))))
#'yas-insert-snippet)))
,@(when (modulep! :editor fold)
'(((save-excursion (end-of-line) (invisible-p (point)))
#'+fold/toggle)))
;; Fixes #4548: without this, this tab keybind overrides
;; mode-local ones for modes that don't have an evil
;; keybinding scheme or users who don't have :editor (evil
;; +everywhere) enabled.
(or (doom-lookup-key
((or (doom-lookup-key
[tab]
(list (evil-get-auxiliary-keymap (current-local-map) evil-state)
(list (evil-get-auxiliary-keymap (current-local-map)
evil-state)
(current-local-map)))
(doom-lookup-key
(kbd "TAB")
(list (evil-get-auxiliary-keymap (current-local-map) evil-state)))
(list (evil-get-auxiliary-keymap (current-local-map)
evil-state)))
(doom-lookup-key (kbd "TAB") (list (current-local-map))))
it
(fboundp 'evil-jump-item)
#'evil-jump-item)
cmd)
((fboundp 'evil-jump-item)
#'evil-jump-item))))
;; Extend smart tab for specific modes. This way, we process the entire
;; smart tab logic and only fall back to these commands at the end.
(:when (modulep! :lang org)
(:after org :map org-mode-map
[remap indent-for-tab-command]
`(menu-item "Go to the next field" org-table-next-field
:filter ,(lambda (cmd) (when (org-at-table-p) cmd)))))
(:after help :map help-mode-map
:n "o" #'link-hint-open-link)

View file

@ -464,22 +464,19 @@ Continues comments if executed from a commented line. Consults
[remap corfu-insert-separator] #'+corfu-smart-sep-toggle-escape
"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))
"C-n" #'corfu-next))
(let ((cmds-del
`(menu-item "Reset completion" corfu-reset
:filter ,(lambda (cmd)
(when (and (>= corfu--index 0)
(cond
((and (>= corfu--index 0)
(eq corfu-preview-current 'insert))
cmd))))
cmd)))))
(cmds-ret
`(menu-item "Insert completion DWIM" corfu-insert
:filter ,(lambda (cmd)
(interactive)
(cond ((null +corfu-want-ret-to-confirm)
(cond
((null +corfu-want-ret-to-confirm)
(corfu-quit)
nil)
((eq +corfu-want-ret-to-confirm 'minibuffer)
@ -492,13 +489,51 @@ Continues comments if executed from a commented line. Consults
((or (not (minibufferp nil t))
(eq +corfu-want-ret-to-confirm t))
nil)
(t cmd)))))
(cmds-tab
`(menu-item "Select next candidate or expand/traverse snippet" corfu-next
:filter (lambda (cmd)
(cond
,@(when (modulep! :editor snippets)
'(((and +corfu-want-tab-prefer-navigating-snippets
(memq (bound-and-true-p yas--active-field-overlay)
(overlays-in (1- (point)) (1+ (point)))))
#'yas-next-field-or-maybe-expand)
((and +corfu-want-tab-prefer-expand-snippets
(yas-maybe-expand-abbrev-key-filter 'yas-expand))
#'yas-expand)))
,@(when (modulep! :lang org)
'(((and +corfu-want-tab-prefer-navigating-org-tables
(featurep 'org)
(org-at-table-p))
#'org-table-next-field)))
(t cmd)))) )
(cmds-s-tab
`(menu-item "Select previous candidate or expand/traverse snippet"
corfu-previous
:filter (lambda (cmd)
(cond
,@(when (modulep! :editor snippets)
'(((and +corfu-want-tab-prefer-navigating-snippets
(memq (bound-and-true-p yas--active-field-overlay)
(overlays-in (1- (point)) (1+ (point)))))
#'yas-prev-field)))
,@(when (modulep! :lang org)
'(((and +corfu-want-tab-prefer-navigating-org-tables
(featurep 'org)
(org-at-table-p))
#'org-table-previous-field)))
(t cmd))))))
(map! :when (modulep! :completion corfu)
:map corfu-map
[backspace] cmds-del
"DEL" cmds-del
:gi [return] cmds-ret
:gi "RET" cmds-ret))
:gi "RET" cmds-ret
"S-TAB" cmds-s-tab
[backtab] cmds-s-tab
:gi "TAB" cmds-tab
:gi [tab] cmds-tab))
;; 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