mirror of
https://github.com/doomemacs/doomemacs
synced 2025-08-01 12:17:25 -05:00
This commit updates the smart tab functionality so that: 1. The only functionality checked is for the modules that are enabled. 2. The priority of the TAB behavior is tunable by the user. This also updates the TAB behavior for the Corfu module to be `indent-for-tab-command` instead of `completion-at-point` so that users can use the TAB key to indent their code and navigating Org tables. We also address #7372 by checking overriding-terminal-local-map, as that is used by Embark.
196 lines
8.1 KiB
EmacsLisp
196 lines
8.1 KiB
EmacsLisp
;;; completion/corfu/config.el -*- lexical-binding: t; -*-
|
|
|
|
(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.")
|
|
|
|
(defvar +corfu-buffer-scanning-size-limit (* 1 1024 1024) ; 1 MB
|
|
"Size limit for a buffer to be scanned by `cape-dabbrev'.")
|
|
|
|
(defvar +corfu-want-minibuffer-completion t
|
|
"Whether to enable Corfu in the minibuffer.
|
|
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
|
|
:hook (doom-first-input . global-corfu-mode)
|
|
:init
|
|
(add-hook! 'minibuffer-setup-hook
|
|
(defun +corfu-enable-in-minibuffer ()
|
|
"Enable Corfu in the minibuffer."
|
|
(when (pcase +corfu-want-minibuffer-completion
|
|
('aggressive
|
|
(not (or (bound-and-true-p mct--active)
|
|
(bound-and-true-p vertico--input)
|
|
(eq (current-local-map) read-passwd-map)
|
|
(and (featurep 'helm-core) (helm--alive-p))
|
|
(and (featurep 'ido) (ido-active))
|
|
(where-is-internal 'minibuffer-complete
|
|
(list (current-local-map)))
|
|
(memq #'ivy--queue-exhibit post-command-hook))))
|
|
('nil nil)
|
|
(_ (where-is-internal #'completion-at-point
|
|
(list (current-local-map)))))
|
|
(setq-local corfu-echo-delay nil)
|
|
(corfu-mode +1))))
|
|
:config
|
|
(setq corfu-auto t
|
|
corfu-auto-delay 0.1
|
|
corfu-auto-prefix 2
|
|
global-corfu-modes '((not
|
|
erc-mode
|
|
circe-mode
|
|
help-mode
|
|
gud-mode
|
|
vterm-mode)
|
|
t)
|
|
corfu-cycle t
|
|
corfu-preselect 'prompt
|
|
corfu-count 16
|
|
corfu-max-width 120
|
|
corfu-on-exact-match nil
|
|
corfu-quit-at-boundary (if (modulep! +orderless) 'separator t)
|
|
corfu-quit-no-match (if (modulep! +orderless) 'separator t)
|
|
tab-always-indent 'complete)
|
|
(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)
|
|
|
|
;; If you want to update the visual hints after completing minibuffer commands
|
|
;; with Corfu and exiting, you have to do it manually.
|
|
(defadvice! +corfu--insert-before-exit-minibuffer-a ()
|
|
:before #'exit-minibuffer
|
|
(when (or (and (frame-live-p corfu--frame)
|
|
(frame-visible-p corfu--frame))
|
|
(and (featurep 'corfu-terminal)
|
|
(popon-live-p corfu-terminal--popon)))
|
|
(when (member isearch-lazy-highlight-timer timer-idle-list)
|
|
(apply (timer--function isearch-lazy-highlight-timer)
|
|
(timer--args isearch-lazy-highlight-timer)))
|
|
(when (member (bound-and-true-p anzu--update-timer) timer-idle-list)
|
|
(apply (timer--function anzu--update-timer)
|
|
(timer--args anzu--update-timer)))
|
|
(when (member (bound-and-true-p evil--ex-search-update-timer)
|
|
timer-idle-list)
|
|
(apply (timer--function evil--ex-search-update-timer)
|
|
(timer--args evil--ex-search-update-timer)))))
|
|
|
|
;; HACK: If your dictionaries aren't set up in text-mode buffers, ispell will
|
|
;; continuously pester you about errors. This ensures it only happens once
|
|
;; per session.
|
|
(defadvice! +corfu--auto-disable-ispell-capf-a (fn &rest args)
|
|
"If ispell isn't properly set up, only complain once per session."
|
|
:around #'ispell-completion-at-point
|
|
(condition-case-unless-debug e
|
|
(apply fn args)
|
|
('error
|
|
(message "Error: %s" (error-message-string e))
|
|
(message "Auto-disabling `text-mode-ispell-word-completion'")
|
|
(setq text-mode-ispell-word-completion nil)
|
|
(remove-hook 'completion-at-point-functions #'ispell-completion-at-point t)))))
|
|
|
|
(use-package! cape
|
|
:defer t
|
|
:init
|
|
(add-hook! prog-mode
|
|
(defun +corfu-add-cape-file-h ()
|
|
(add-hook 'completion-at-point-functions #'cape-file -10 t)))
|
|
(add-hook! (org-mode markdown-mode)
|
|
(defun +corfu-add-cape-elisp-block-h ()
|
|
(add-hook 'completion-at-point-functions #'cape-elisp-block 0 t)))
|
|
;; Enable Dabbrev completion basically everywhere as a fallback.
|
|
(when (modulep! +dabbrev)
|
|
(setq cape-dabbrev-check-other-buffers t)
|
|
;; Set up `cape-dabbrev' options.
|
|
(defun +dabbrev-friend-buffer-p (other-buffer)
|
|
(< (buffer-size other-buffer) +corfu-buffer-scanning-size-limit))
|
|
(add-hook! (prog-mode text-mode conf-mode comint-mode minibuffer-setup
|
|
eshell-mode)
|
|
(defun +corfu-add-cape-dabbrev-h ()
|
|
(add-hook 'completion-at-point-functions #'cape-dabbrev 20 t)))
|
|
(after! dabbrev
|
|
(setq dabbrev-friend-buffer-function #'+dabbrev-friend-buffer-p
|
|
dabbrev-ignored-buffer-regexps
|
|
'("^ "
|
|
"\\(TAGS\\|tags\\|ETAGS\\|etags\\|GTAGS\\|GRTAGS\\|GPATH\\)\\(<[0-9]+>\\)?")
|
|
dabbrev-upcase-means-case-search t)
|
|
(add-to-list 'dabbrev-ignored-buffer-modes 'pdf-view-mode)))
|
|
|
|
;; Make these capfs composable.
|
|
(advice-add #'lsp-completion-at-point :around #'cape-wrap-noninterruptible)
|
|
(advice-add #'lsp-completion-at-point :around #'cape-wrap-nonexclusive)
|
|
(advice-add #'comint-completion-at-point :around #'cape-wrap-nonexclusive)
|
|
(advice-add #'eglot-completion-at-point :around #'cape-wrap-nonexclusive)
|
|
(advice-add #'pcomplete-completions-at-point :around #'cape-wrap-nonexclusive)
|
|
;; From the `cape' readme. Without this, Eshell autocompletion is broken on
|
|
;; Emacs28.
|
|
(when (< emacs-major-version 29)
|
|
(advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent)
|
|
(advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify)))
|
|
|
|
(use-package! yasnippet-capf
|
|
:when (modulep! :editor snippets)
|
|
:defer t
|
|
:init
|
|
(add-hook! 'yas-minor-mode-hook
|
|
(defun +corfu-add-yasnippet-capf-h ()
|
|
(add-hook 'completion-at-point-functions #'yasnippet-capf 30 t))))
|
|
|
|
(use-package! corfu-terminal
|
|
:when (modulep! :os tty)
|
|
:when (not (display-graphic-p))
|
|
:hook ((corfu-mode . corfu-terminal-mode)))
|
|
|
|
|
|
;;
|
|
;;; Extensions
|
|
|
|
(use-package! corfu-history
|
|
:hook ((corfu-mode . corfu-history-mode))
|
|
:config
|
|
(after! savehist (add-to-list 'savehist-additional-variables 'corfu-history)))
|
|
|
|
(use-package! corfu-popupinfo
|
|
:hook ((corfu-mode . corfu-popupinfo-mode))
|
|
:config
|
|
(setq corfu-popupinfo-delay '(0.5 . 1.0)))
|
|
|
|
(use-package! nerd-icons-corfu
|
|
:when (modulep! +icons)
|
|
:defer t
|
|
:init
|
|
(after! corfu
|
|
(add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter)))
|
|
|
|
;; If vertico is not enabled, orderless will be installed but not configured.
|
|
;; That may break smart separator behavior, so we conditionally configure it.
|
|
(use-package! orderless
|
|
:when (and (not (modulep! :completion vertico))
|
|
(modulep! +orderless))
|
|
:config
|
|
(setq completion-styles '(orderless basic)
|
|
completion-category-defaults nil
|
|
completion-category-overrides '((file (styles orderless partial-completion)))
|
|
orderless-component-separator #'orderless-escapable-split-on-space)
|
|
(set-face-attribute 'completions-first-difference nil :inherit nil))
|