config-completion.el (10654B)
1 ;;; config-completion.el --- -*- lexical-binding: t -*- 2 ;;; Commentary: 3 ;;; Setup completion framework 4 ;;; Code 5 6 (use-package consult 7 :bind 8 ("M-g M-g" . consult-goto-line) 9 ("M-K" . consult-keep-lines) 10 ("M-s M-b" . consult-buffer) 11 ("M-s M-f" . consult-find) 12 ("M-s M-g" . consult-grep) 13 ("M-s M-r" . consult-ripgrep) 14 ("M-s M-h" . consult-history) 15 ("M-s M-i" . consult-imenu) 16 ("M-s M-l" . consult-line) 17 ("M-s M-m" . consult-mark) 18 ("M-s M-y" . consult-yank-pop) 19 ("M-s M-s" . consult-outline)) 20 21 (use-package consult-xref 22 :config 23 (setq xref-show-xrefs-function #'consult-xref 24 xref-show-definitions-function #'consult-xref) 25 (defvar consult--xref-history nil 26 "History for the `consult-recent-xref' results.") 27 28 (defun consult-recent-xref (&optional markers) 29 "Jump to a marker in MARKERS list (defaults to `xref--history'. 30 31 The command supports preview of the currently selected marker position. 32 The symbol at point is added to the future history." 33 (interactive) 34 (consult--read 35 (consult--global-mark-candidates 36 (or markers (flatten-list xref--history))) 37 :prompt "Go to Xref: " 38 :annotate (consult--line-prefix) 39 :category 'consult-location 40 :sort nil 41 :require-match t 42 :lookup #'consult--lookup-location 43 :history '(:input consult--xref-history) 44 :add-history (thing-at-point 'symbol) 45 :state (consult--jump-state)))) 46 47 ;; https://github.com/oantolin/embark/blob/master/embark-consult.el 48 (use-package embark 49 :unless noninteractive 50 :bind 51 ("C-." . embark-act) 52 ("M-." . embark-dwim) 53 ("C-h b" . embark-bindings) 54 ("C-h B" . embark-bindings-at-point) 55 ("C-h M" . embark-bindings-in-keymap) 56 ("C-h E" . embark-on-last-message) 57 (:map completion-list-mode-map 58 ("." . embark-act)) 59 (:map embark-collect-mode-map 60 ("a") ; I don't like my own default :) 61 ("." . embark-act) 62 ("F" . consult-focus-lines)) 63 (:map embark-package-map 64 ("t" . try)) 65 (:map embark-identifier-map 66 ("(" . insert-parentheses) 67 ("[" . insert-pair-map)) 68 (:map embark-expression-map 69 ("(" . insert-parentheses) 70 ("[" . insert-pair-map)) 71 (:map embark-region-map 72 ("(" . insert-parentheses) 73 ("[" . insert-pair-map) 74 ("D" . dictionary-search)) 75 (:map embark-email-map 76 ("+" . add-email-to-ecomplete) 77 ("\\" . remove-email-from-ecomplete)) 78 (:map embark-encode-map 79 ("p" . topaz-paste-region)) 80 (:map embark-url-map 81 ("x" . browse-url-generic) 82 ("p" . pocket-lib-add-urls)) 83 (:map embark-identifier-map 84 ("D" . dictionary-lookup-definition)) 85 :custom 86 (embark-quit-after-action t) 87 (prefix-help-command #'embark-prefix-help-command) 88 (embark-indicators '(embark-minimal-indicator 89 embark-highlight-indicator 90 embark-isearch-highlight-indicator)) 91 (embark-cycle-key ".") 92 (embark-help-key "?") 93 (embark-confirm-act-all nil) 94 :config 95 (setq embark-candidate-collectors 96 (cl-substitute 'embark-sorted-minibuffer-candidates 97 'embark-minibuffer-candidates 98 embark-candidate-collectors)) 99 (dolist (cmd '(comment-dwim 100 insert-parentheses 101 insert-pair 102 markdown-insert-code 103 markdown-insert-italic 104 markdown-insert-bold 105 org-emphasize 106 cdlatex-math-modify 107 TeX-font)) 108 (push #'embark--mark-target (alist-get cmd embark-around-action-hooks))) 109 (push #'embark--xref-push-marker 110 (alist-get 'find-file embark-pre-action-hooks)) 111 (defun embark-on-last-message (arg) 112 "Act on the last message displayed in the echo area." 113 (interactive "P") 114 (with-current-buffer "*Messages*" 115 (goto-char (1- (point-max))) 116 (embark-act arg))) 117 118 (defmacro ct/embark-display-in-side-window (side) 119 `(defun ,(intern (concat "display-in-side-window--" (symbol-name side))) (&optional buffer) 120 (interactive "b") 121 (when-let* ((buffer (or buffer (current-buffer))) 122 (display-buffer-overriding-action '((display-buffer-in-side-window) 123 (dedicated . t) 124 (side . ,side) 125 (window-parameters . ((no-delete-other-windows . t)))))) 126 (display-buffer buffer)))) 127 (define-key embark-buffer-map (kbd "s b") (ct/embark-display-in-side-window bottom)) 128 (define-key embark-buffer-map (kbd "s l") (ct/embark-display-in-side-window left)) 129 (define-key embark-buffer-map (kbd "s r") (ct/embark-display-in-side-window right)) 130 ) 131 132 (use-package embark-consult 133 :unless noninteractive 134 :hook 135 (embark-collect-mode . consult-preview-at-point-mode)) 136 137 (use-package emacs 138 :unless noninteractive 139 :custom 140 (completion-cycle-threshold 2) 141 (completion-ignore-case t) 142 (completion-show-inline-help nil) 143 (completions-detailed t) 144 (enable-recursive-minibuffers t) 145 (read-buffer-completion-ignore-case t) 146 (read-file-name-completion-ignore-case t) 147 (resize-mini-windows t) 148 :config 149 (minibuffer-depth-indicate-mode 1) 150 (minibuffer-electric-default-mode 1)) 151 152 (use-package mct 153 :unless noninteractive 154 :custom 155 (mct-completion-window-size (cons #'mct-frame-height-third 1)) 156 (mct-remove-shadowed-file-names t) ; works when `file-name-shadow-mode' is enabled 157 (mct-hide-completion-mode-line t) 158 (mct-minimum-input 3) 159 (mct-live-completion 'visible) 160 (mct-live-update-delay 0.6) 161 (mct-persist-dynamic-completion t) 162 :config 163 (mct-mode 1) 164 (defun my-sort-by-alpha-length (elems) 165 "Sort ELEMS first alphabetically, then by length." 166 (sort elems (lambda (c1 c2) 167 (or (string-version-lessp c1 c2) 168 (< (length c1) (length c2)))))) 169 170 (defun my-sort-by-history (elems) 171 "Sort ELEMS by minibuffer history. 172 Use `mct-sort-sort-by-alpha-length' if no history is available." 173 (if-let ((hist (and (not (eq minibuffer-history-variable t)) 174 (symbol-value minibuffer-history-variable)))) 175 (minibuffer--sort-by-position hist elems) 176 (my-sort-by-alpha-length elems))) 177 178 (defun my-sort-multi-category (elems) 179 "Sort ELEMS per completion category." 180 (pcase (mct--completion-category) 181 ('nil elems) ; no sorting 182 ('kill-ring elems) 183 ('project-file (my-sort-by-alpha-length elems)) 184 (_ (my-sort-by-history elems)))) 185 186 ;; Specify the sorting function. 187 (setq completions-sort #'my-sort-multi-category) 188 189 ;; Add prompt indicator to `completing-read-multiple'. We display 190 ;; [`completing-read-multiple': <separator>], e.g., 191 ;; [`completing-read-multiple': ,] if the separator is a comma. This 192 ;; is adapted from the README of the `vertico' package by Daniel 193 ;; Mendler. I made some small tweaks to propertize the segments of 194 ;; the prompt. 195 (defun crm-indicator (args) 196 (cons (format "[`crm-separator': %s] %s" 197 (propertize 198 (replace-regexp-in-string 199 "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" "" 200 crm-separator) 201 'face 'error) 202 (car args)) 203 (cdr args))) 204 205 (advice-add #'completing-read-multiple :filter-args #'crm-indicator)) 206 207 (use-package marginalia 208 :unless noninteractive 209 :config 210 (marginalia-mode 1)) 211 212 (use-package corfu 213 :unless noninteractive 214 :bind (("C-<tab>" . corfu-candidate-overlay-complete-at-point)) 215 :init 216 (require 'corfu-popupinfo) 217 (require 'corfu-history) 218 (require 'corfu-candidate-overlay) 219 :config 220 (global-corfu-mode 1) 221 (setq corfu-popupinfo-delay '(1.25 . 0.5)) 222 (corfu-popupinfo-mode 1) 223 (corfu-candidate-overlay-mode) 224 ;; Sort by input history (no need to modify `corfu-sort-function'). 225 (with-eval-after-load 'savehist 226 (corfu-history-mode 1) 227 (add-to-list 'savehist-additional-variables 'corfu-history)) 228 229 ;; Adapted from Corfu's manual. 230 (defun contrib/corfu-enable-always-in-minibuffer () 231 "Enable Corfu in the minibuffer if MCT or Vertico is not active. 232 Useful for prompts such as `eval-expression' and `shell-command'." 233 (unless (or (bound-and-true-p vertico--input) 234 (bound-and-true-p mct--active)) 235 (corfu-mode 1))) 236 237 (add-hook 'minibuffer-setup-hook #'contrib/corfu-enable-always-in-minibuffer 1)) 238 239 (use-package corfu-candidate-overlay 240 :after corfu 241 :bind (("C-<tab>" . corfu-candidate-overlay-complete-at-point)) 242 :config 243 (corfu-candidate-overlay-mode +1)) 244 245 (use-package cape 246 :bind (("C-c p f" . cape-file) 247 ("C-c p /" . cape-dabbrev) 248 :map corfu-map 249 ("M-/" . cape-dabbrev) 250 ("C-x C-f" . cape-file)) 251 :config 252 (add-to-list 'completion-at-point-functions #'cape-file)) 253 254 (use-package orderless 255 :unless noninteractive 256 :config 257 ;; We make the SPC key insert a literal space and the same for the 258 ;; question mark. Spaces are used to delimit orderless groups, while 259 ;; the quedtion mark is a valid regexp character. 260 (let ((map minibuffer-local-completion-map)) 261 (define-key map (kbd "SPC") nil) 262 (define-key map (kbd "?") nil)) 263 264 ;; Because SPC works for Orderless and is trivial to activate, I like to 265 ;; put `orderless' at the end of my `completion-styles'. Like this: 266 (setq completion-styles 267 '(basic substring initials flex partial-completion orderless)) 268 (setq completion-category-overrides 269 '((file (styles . (basic partial-completion orderless)))))) 270 271 (use-package tempel 272 :bind (("M-+" . tempel-complete) ;; Alternative tempel-expand 273 ("M-*" . tempel-insert)) 274 :init 275 ;; (defun tempel-setup-capf () 276 ;; ;; Add the Tempel Capf to `completion-at-point-functions'. 277 ;; ;; `tempel-expand' only triggers on exact matches. Alternatively use 278 ;; ;; `tempel-complete' if you want to see all matches, but then you 279 ;; ;; should also configure `tempel-trigger-prefix', such that Tempel 280 ;; ;; does not trigger too often when you don't expect it. NOTE: We add 281 ;; ;; `tempel-expand' *before* the main programming mode Capf, such 282 ;; ;; that it will be tried first. 283 ;; (setq-local completion-at-point-functions 284 ;; (cons #'tempel-expand 285 ;; completion-at-point-functions))) 286 (setq tempel-path (expand-file-name "templates" user-emacs-directory)) 287 ;; (add-hook 'conf-mode-hook 'tempel-setup-capf) 288 ;; (add-hook 'prog-mode-hook 'tempel-setup-capf) 289 ;; (add-hook 'text-mode-hook 'tempel-setup-capf) 290 ) 291 292 (use-package tempel-collection 293 :after tempel) 294 295 (provide 'config-completion) 296 ;;; config-completion.el ends here