home

My NixOS systems configurations.
Log | Files | Refs | LICENSE

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