dotfiles/emacs/.emacs.d/config/init-completion.el

232 lines
8.5 KiB
EmacsLisp

;; -*- lexical-binding: t; -*-
;; Nicer minibuffer completion
;; First Vertico, which provides the core incremental minibuffer completion engine
(use-package vertico
:straight (:files (:defaults "extensions/vertico-repeat.el"
"extensions/vertico-directory.el"))
:init
(vertico-mode))
(use-package vertico-repeat
:straight (:type built-in)
:after vertico
:config
(add-hook 'minibuffer-setup-hook #'vertico-repeat-save)
:general
(leader-map "r" #'vertico-repeat))
(use-package vertico-directory
:straight (:type built-in)
:after vertico
:general
(vertico-map "RET" #'vertico-directory-enter
"DEL" #'vertico-directory-delete-char
"M-DEL" #'vertico-directory-delete-word)
;; Tidy shadowed file names
:hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
;; Save history in order to persist sort order across emacs sessions
(use-package savehist
:straight (:type built-in)
:config
(savehist-mode 1)
:custom
(savehist-additional-variables '(projectile-project-command-history
evil-jumps-history
vertico-repeat-history)))
;; Then orderless, which adds the ability to filter completions in an intuitive way
(use-package orderless
:ensure t
:custom
(completion-styles '(orderless basic))
(completion-category-overrides '((file (styles basic partial-completion)))))
;; Marginalia adds annotations to completion candidates
(use-package marginalia
:demand t
:config
(marginalia-mode 1)
(add-to-list 'marginalia-prompt-categories '("Find file:" . project-file))
(add-to-list 'marginalia-prompt-categories '("Find dir:" . project-file))
(add-to-list 'marginalia-prompt-categories '("Switch to project" . file))
(add-to-list 'marginalia-prompt-categories '("recipe\\|package" . straight))
(add-to-list 'marginalia-prompt-categories '("Password entry" . password-store))
:general
(minibuffer-local-map "M-A" #'marginalia-cycle)
:custom
(marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil)))
;; Embark adds context actions to completion candidates (and other things!)
(use-package embark
:config
;; Put xref targets at the top of the list in programming modes
(defun embark-prod-mode-hook ()
(setq-local embark-target-finders (remove #'embark-target-identifier-at-point embark-target-finders))
(add-to-list 'embark-target-finders #'embark-target-identifier-at-point))
(add-hook 'prog-mode-hook #'embark-prod-mode-hook)
(defun embark-which-key-indicator ()
"An embark indicator that displays keymaps using which-key.
The which-key help message will show the type and value of the
current target followed by an ellipsis if there are further
targets."
(lambda (&optional keymap targets prefix)
(if (null keymap)
(which-key--hide-popup-ignore-command)
(which-key--show-keymap
(if (eq (caar targets) 'embark-become)
"Become"
(format "Act on %s '%s'%s"
(plist-get (car targets) :type)
(embark--truncate-target (plist-get (car targets) :target))
(if (cdr targets) "" "")))
(if prefix
(pcase (lookup-key keymap prefix 'accept-default)
((and (pred keymapp) km) km)
(_ (key-binding prefix 'accept-default)))
keymap)
nil nil t))))
(defvar-keymap embark-straight-map
:doc "Keymap for actions for straight.el"
:parent embark-general-map
"u" #'straight-visit-package-website
"r" #'straight-get-recipe
"i" #'straight-use-package
"c" #'straight-check-package
"F" #'straight-pull-package
"f" #'straight-fetch-package
"p" #'straight-push-package
"n" #'straight-normalize-package
"m" #'straight-merge-package)
(add-to-list 'embark-keymap-alist '(straight . embark-straight-map))
(with-eval-after-load 'pass
(defun embark-target-finder-pass ()
"Identify password-store entries at point."
(when-let ((entry (and (eq major-mode 'pass-mode)
(pass-closest-entry))))
`(password-store . ,entry)))
(add-to-list 'embark-target-finders #'embark-target-finder-pass)
(defvar-keymap embark-password-store-actions
:doc "Keymap for actions for password-store."
:parent embark-general-map
"c" #'password-store-copy
"RET" #'password-store-copy
"f" #'password-store-copy-field
"i" #'password-store-insert
"I" #'password-store-generate
"r" #'password-store-rename
"e" #'password-store-edit
"k" #'password-store-remove
"U" #'password-store-url)
(add-to-list 'embark-keymap-alist '(password-store . embark-password-store-actions)))
(add-to-list 'embark-target-injection-hooks '(xref-find-references embark--ignore-target))
(defun embark-target-finder-forge ()
"Identify Forge commits/issues/PRs at point."
(when-let ((target (and
(fboundp 'forge--browse-target)
(forge--browse-target))))
`(forge ,(or
(and (stringp target) target)
(ignore-errors (forge-get-url target))
(s-chomp (thing-at-point 'line t)))
,(line-beginning-position)
. ,(line-end-position))))
(defun embark-forge-magit-setup ()
(make-local-variable 'embark-target-finders)
(add-to-list 'embark-target-finders #'embark-target-finder-forge))
(add-hook 'magit-mode-hook #'embark-forge-magit-setup)
(defvar-keymap embark-forge-actions
:doc "Keymap for actions for forge."
:parent embark-general-map
"RET" #'forge-browse
"y" #'forge-copy-url-at-point-as-kill)
(add-to-list 'embark-keymap-alist '(forge . embark-forge-actions))
:general
((emacs normal motion insert visual) "C-." #'embark-act)
((emacs normal motion insert visual) "M-." #'embark-dwim)
("C-." #'embark-act)
("M-." #'embark-dwim)
(embark-general-map "C-k" #'browse-url-or-search
"/" #'consult-line)
(embark-file-map "s" #'sudo-edit-find-file
"l" #'vlf
"g" #'magit-file-dispatch)
('normal embark-collect-mode-map
"TAB" #'forward-button
"?" #'describe-mode
"A" #'embark-collect-direct-action-minor-mode
"S" #'tabulated-list-sort
"a" #'embark-act
"b" #'backward-button
"e" #'embark-export
"f" #'forward-button
"gr" #'revert-buffer
"n" #'next-line
"p" #'previous-line
"q" #'quit-window
"s" #'isearch-forward
"v" #'embark-collect-toggle-view
"z" #'embark-collect-zebra-minor-mode
"{" #'tabulated-list-narrow-current-column
"}" #'tabulated-list-widen-current-column
"<backtab>" #'backward-button)
:custom
(embark-prompter 'embark-keymap-prompter)
(embark-indicators '(embark-which-key-indicator
embark-highlight-indicator
embark-isearch-highlight-indicator)))
;; Consult adds a bunch of completing-read based utilities
(use-package consult
:init
(setq xref-show-xrefs-function #'consult-xref
xref-show-definitions-function #'consult-xref)
:custom
(consult-project-function #'projectile-project-root)
(consult-find-args "find . -not ( -wholename */.git/* -prune )")
(consult-narrow-key "<")
:general
([remap switch-to-buffer] #'consult-buffer)
([remap imenu] #'consult-imenu)
([remap projectile-ripgrep] #'consult-ripgrep)
([remap projectile-grep] #'consult-grep)
("C-c p" #'consult-yank-from-kill-ring)
(minibuffer-local-map "M-r" #'consult-history))
(use-package consult-projectile
:after (consult projectile)
:commands (consult-projectile)
:general
(projectile-command-map "RET" #'consult-projectile))
(use-package consult-eglot
:after (consult eglot)
:general
(eglot-prefix-map "s" #'consult-eglot-symbols))
(use-package consult-org-roam
:after (consult org-roam)
:config
(consult-org-roam-mode 1)
:custom
(consult-org-roam-grep-func #'consult-ripgrep)
(consult-org-roam-buffer-after-buffers t)
:general
(org-roam-commands-map "b" #'consult-org-roam-backlinks
"B" #'consult-org-roam-backlinks-recursive
"l" #'consult-org-roam-forward-links))
(use-package embark-consult
:general
(leader-map "/" embark-consult-search-map))
;; Make grep-like embark collect buffers editable
(use-package wgrep
:general
(grep-mode-map "C-x C-q" #'wgrep-change-to-wgrep-mode))
(provide 'init-completion)