diff --git a/modules/completion/corfu/README.org b/modules/completion/corfu/README.org index 4bbea003b..46f85b855 100644 --- a/modules/completion/corfu/README.org +++ b/modules/completion/corfu/README.org @@ -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 ~~ keybindings and insert state bindings are overriding your ~TAB~ key +assignments. + +In Evil mode, keybinding priorities are set such that: +1. ~~ 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 "" #'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?]] diff --git a/modules/completion/corfu/config.el b/modules/completion/corfu/config.el index ccef3a811..2d4475611 100644 --- a/modules/completion/corfu/config.el +++ b/modules/completion/corfu/config.el @@ -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 diff --git a/modules/config/default/+evil-bindings.el b/modules/config/default/+evil-bindings.el index 941d7d54a..56f847c18 100644 --- a/modules/config/default/+evil-bindings.el +++ b/modules/config/default/+evil-bindings.el @@ -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) - (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 - ;; 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 - [tab] - (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))) - (doom-lookup-key (kbd "TAB") (list (current-local-map)))) - it - (fboundp 'evil-jump-item) - #'evil-jump-item) +(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))) + ,@(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 + [tab] + (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))) + (doom-lookup-key (kbd "TAB") (list (current-local-map)))) + 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) @@ -90,9 +118,9 @@ :n "o" #'link-hint-open-link) (:unless (modulep! :input layout +bepo) - (:after (evil-org evil-easymotion) - :map evil-org-mode-map - :m "gsh" #'+org/goto-visible)) + (:after (evil-org evil-easymotion) + :map evil-org-mode-map + :m "gsh" #'+org/goto-visible)) (:when (modulep! :editor multiple-cursors) :prefix "gz" diff --git a/modules/config/default/config.el b/modules/config/default/config.el index 21aa7268d..667b6abb0 100644 --- a/modules/config/default/config.el +++ b/modules/config/default/config.el @@ -464,41 +464,76 @@ 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) - (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) - nil) - ((eq +corfu-want-ret-to-confirm 'minibuffer) - (funcall-interactively cmd) - nil) - ((and (or (not (minibufferp nil t)) - (eq +corfu-want-ret-to-confirm t)) - (>= corfu--index 0)) - cmd) - ((or (not (minibufferp nil t)) - (eq +corfu-want-ret-to-confirm t)) - nil) - (t cmd)))))) + (cond + ((and (>= corfu--index 0) + (eq corfu-preview-current 'insert)) + cmd))))) + (cmds-ret + `(menu-item "Insert completion DWIM" corfu-insert + :filter ,(lambda (cmd) + (cond + ((null +corfu-want-ret-to-confirm) + (corfu-quit) + nil) + ((eq +corfu-want-ret-to-confirm 'minibuffer) + (funcall-interactively cmd) + nil) + ((and (or (not (minibufferp nil t)) + (eq +corfu-want-ret-to-confirm t)) + (>= corfu--index 0)) + cmd) + ((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