init-minibuffer.el 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. ;;; init-minibuffer.el --- Minibuffer Completion Configuration File -*- lexical-binding: t -*-
  2. ;;; Commentary:
  3. ;; Config for completion etc in the minibuffer (vertico, embark, consult, etc)
  4. ;; Most of it is taken from the READMEs and wikis of those packages.
  5. ;; Relies on orderless config in init-completion.el
  6. ;;; Code:
  7. (use-package vertico
  8. :ensure (vertico :files (:defaults "extensions/*"))
  9. :hook (elpaca-after-init . vertico-mode)
  10. :custom (vertico-cycle t)
  11. :config
  12. ;; Do not allow the cursor in the minibuffer prompt
  13. (setq minibuffer-prompt-properties
  14. '(read-only t cursor-intangible t intangible t face minibuffer-prompt))
  15. (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
  16. (setq enable-recursive-minibuffers t)
  17. (minibuffer-depth-indicate-mode t)
  18. ;; Add prompt indicator to `completing-read-multiple'.
  19. ;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
  20. (defun crm-indicator (args)
  21. (cons (format "[CRM%s] %s"
  22. (replace-regexp-in-string
  23. "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
  24. crm-separator)
  25. (car args))
  26. (cdr args)))
  27. (advice-add #'completing-read-multiple :filter-args #'crm-indicator)
  28. ;; Emacs 28: Hide commands in M-x which do not work in the current mode.
  29. ;; Vertico commands are hidden in normal buffers.
  30. (setq read-extended-command-predicate
  31. #'command-completion-default-include-p)
  32. (advice-add #'vertico--format-candidate :around
  33. (lambda (orig cand prefix suffix index start)
  34. (setq cand (funcall orig cand prefix suffix index start))
  35. (concat
  36. (if (= vertico--index index)
  37. (propertize "» " 'face 'vertico-current)
  38. " ")
  39. cand)))
  40. ;; https://github.com/minad/vertico/wiki#ding-when-wrapping-around
  41. (advice-add #'vertico-next
  42. :around
  43. #'(lambda (origin &rest args)
  44. (let ((beg-index vertico--index))
  45. (apply origin args)
  46. (if (not (eq 1 (abs (- beg-index vertico--index))))
  47. (ding)))))
  48. ;; https://github.com/minad/vertico/wiki#useful-commands-from-outside-minibuffer
  49. (defun down-from-outside ()
  50. "Move to next candidate in minibuffer, even when minibuffer isn't selected."
  51. (interactive)
  52. (with-selected-window (active-minibuffer-window)
  53. (execute-kbd-macro [down])))
  54. (defun up-from-outside ()
  55. "Move to previous candidate in minibuffer, even when minibuffer isn't selected."
  56. (interactive)
  57. (with-selected-window (active-minibuffer-window)
  58. (execute-kbd-macro [up])))
  59. (defun preview-from-outside ()
  60. "Preview the selected candidate, even when minibuffer isn't selected."
  61. (interactive)
  62. (with-selected-window (active-minibuffer-window)
  63. (execute-kbd-macro (kbd "M-."))))
  64. (defun to-and-fro-minibuffer ()
  65. "Go back and forth between minibuffer and other window."
  66. (interactive)
  67. (if (window-minibuffer-p (selected-window))
  68. (select-window (minibuffer-selected-window))
  69. (select-window (active-minibuffer-window))))
  70. ;; Modified from https://github.com/minad/vertico/wiki#update-minibuffer-history-with-candidate-insertions
  71. (defadvice vertico-insert
  72. (after vertico-insert-add-history activate)
  73. "Make vertico-insert add to the minibuffer history."
  74. (if (and (not (eq minibuffer-history-variable t))
  75. (eq 'file (vertico--metadata-get 'category)))
  76. (add-to-history minibuffer-history-variable (minibuffer-contents))))
  77. ;; https://github.com/minad/vertico/wiki#customize-sorting-based-on-completion-category
  78. (defun sort-directories-first (files)
  79. ;; Still sort by history position, length and alphabetically
  80. (setq files (vertico-sort-history-length-alpha files))
  81. ;; But then move directories first
  82. (nconc (seq-filter (lambda (x) (string-suffix-p "/" x)) files)
  83. (seq-remove (lambda (x) (string-suffix-p "/" x)) files)))
  84. (defun toggle-sort-directories-first ()
  85. (interactive)
  86. (if (eq vertico-sort-function 'sort-directories-first)
  87. (set (make-local-variable 'vertico-sort-function) 'vertico-sort-history-length-alpha)
  88. (set (make-local-variable 'vertico-sort-function) 'sort-directories-first))
  89. (setq vertico--input t)
  90. (vertico--update))
  91. :bind (("C-M-<" . up-from-outside)
  92. ("C-M->" . down-from-outside)
  93. ("C-M-+" . preview-from-outside)
  94. ("M-X" . to-and-fro-minibuffer)
  95. (:map vertico-map
  96. ("M-RET" . minibuffer-force-complete-and-exit)
  97. ("M-D" . toggle-sort-directories-first))))
  98. (use-extension vertico vertico-multiform
  99. :config
  100. (vertico-multiform-mode +1)
  101. (defun vertico-multiform-buffer-grid ()
  102. "Toggle displaying Vertico as a grid in a large window (like a regular buffer).)"
  103. (interactive)
  104. (if (equal '(vertico-buffer-mode vertico-grid-mode) (car vertico-multiform--stack))
  105. (vertico-multiform-vertical)
  106. (setcar vertico-multiform--stack '(vertico-buffer-mode vertico-grid-mode))
  107. (vertico-multiform--toggle 1)))
  108. ;; https://github.com/minad/vertico/wiki#candidate-display-transformations-custom-candidate-highlighting
  109. (defvar +vertico-transform-functions nil)
  110. (cl-defmethod vertico--format-candidate :around
  111. (cand prefix suffix index start &context ((not +vertico-transform-functions) null))
  112. (dolist (fun (ensure-list +vertico-transform-functions))
  113. (setq cand (funcall fun cand)))
  114. (cl-call-next-method cand prefix suffix index start))
  115. (defun +vertico-highlight-directory (file)
  116. "If FILE ends with a slash, highlight it as a directory."
  117. (if (string-suffix-p "/" file)
  118. (propertize file 'face 'marginalia-file-priv-dir)
  119. file))
  120. (defun +vertico-highlight-enabled-mode (cmd)
  121. "If MODE is enabled, highlight it as font-lock-doc-face."
  122. (let ((sym (intern cmd)))
  123. (if (or (eq sym major-mode)
  124. (and
  125. (memq sym minor-mode-list)
  126. (boundp sym)))
  127. (propertize cmd 'face 'font-lock-doc-face)
  128. cmd)))
  129. (setq vertico-multiform-commands
  130. '((execute-extended-command
  131. (+vertico-transform-functions . +vertico-highlight-enabled-mode))))
  132. (setq vertico-multiform-categories
  133. '((file (+vertico-transform-functions . +vertico-highlight-directory))
  134. (imenu grid)))
  135. :bind (:map vertico-multiform-map
  136. ("M-H" . vertico-multiform-buffer-grid)))
  137. (use-extension vertico vertico-directory
  138. :config
  139. (defvar switching-project nil)
  140. (defun vertico-directory-enter-or-select-project ()
  141. "vertico-directory-enter wrapper that plays nicely with selecting new projects."
  142. (interactive)
  143. ;; When selecting a project, use this to return, instead of entering the directory
  144. (if switching-project
  145. (vertico-exit)
  146. (vertico-directory-enter)))
  147. (defun vertico-directory-slash ()
  148. (interactive)
  149. (if (and (>= vertico--index 0)
  150. (string-suffix-p "/" (vertico--candidate))
  151. (eq 'file (vertico--metadata-get 'category)))
  152. (vertico-insert)
  153. (insert "/")))
  154. (defun vertico-directory-home ()
  155. (interactive)
  156. (if (and (string-suffix-p "/" (vertico--candidate))
  157. (eq 'file (vertico--metadata-get 'category)))
  158. (insert "~/")
  159. (insert "~")))
  160. (defun read-project (orig &rest args)
  161. (let ((switching-project t))
  162. (apply orig args)))
  163. (advice-add 'project-prompt-project-dir :around
  164. 'read-project)
  165. ;; TODO this should be part of the vertico config
  166. (defun define-vertico-key (key &rest defs)
  167. "Define KEY conditionally in the vertico keymap.
  168. DEFS is a plist associating completion categories to commands."
  169. (let ((default-command (lookup-key vertico-map (kbd key))))
  170. (define-key vertico-map (kbd key)
  171. (list 'menu-item nil defs :filter
  172. (lambda (d)
  173. (or (plist-get d (completion-metadata-get
  174. (completion-metadata (minibuffer-contents)
  175. minibuffer-completion-table
  176. minibuffer-completion-predicate)
  177. 'category))
  178. default-command))))))
  179. (define-vertico-key "/"
  180. 'file #'vertico-directory-slash
  181. 'project-file #'vertico-directory-slash)
  182. (define-vertico-key "RET"
  183. 'file #'vertico-directory-enter-or-select-project
  184. 'project-file #'vertico-directory-enter)
  185. (define-vertico-key "~"
  186. 'file #'vertico-directory-home)
  187. (define-vertico-key "DEL"
  188. 'file #'vertico-directory-delete-char
  189. 'project-file #'vertico-directory-delete-char)
  190. (define-vertico-key "M-DEL"
  191. 'file #'vertico-directory-delete-word
  192. 'project-file #'vertico-directory-delete-word)
  193. :commands (vertico-directory-enter vertico-directory-delete-word vertico-directory-delete-char)
  194. ;; Tidy shadowed file names
  195. :hook (rfn-eshadow-update-overlay . vertico-directory-tidy))
  196. (use-extension vertico vertico-repeat
  197. :after savehist
  198. :bind
  199. ("C-\\" . vertico-repeat)
  200. ("C-|" . vertico-repeat-select)
  201. :hook (minibuffer-setup . vertico-repeat-save)
  202. :config
  203. (add-to-list 'savehist-additional-variables 'vertico-repeat-history))
  204. (use-extension vertico vertico-indexed
  205. :config
  206. (defmacro define-vertico-choose (n)
  207. `(defun ,(intern (format "vertico-indexed-choose-%s" n)) ()
  208. ,(format "Exit minibuffer with candidate %s." n)
  209. (interactive)
  210. (let ((vertico--index ,n))
  211. (funcall-interactively 'vertico-exit))))
  212. (defmacro define-vertico-insert (n)
  213. `(defun ,(intern (format "vertico-indexed-insert-%s" n)) ()
  214. ,(format "Insert candidate %s in minibuffer." n)
  215. (interactive)
  216. (let ((vertico--index ,n))
  217. (funcall-interactively 'vertico-insert))))
  218. (dotimes (n 10)
  219. (eval `(define-vertico-choose ,n))
  220. (eval `(define-vertico-insert ,n))
  221. (define-key vertico-map (kbd (format "C-%s" n)) (intern (format "vertico-indexed-choose-%s" n)))
  222. (define-key vertico-map (kbd (format "M-%s" n)) (intern (format "vertico-indexed-insert-%s" n))))
  223. (vertico-indexed-mode 1))
  224. (use-extension vertico vertico-quick
  225. :bind (:map vertico-map
  226. ("M-;" . vertico-quick-insert)
  227. ("M-'" . vertico-quick-exit)))
  228. (use-package consult
  229. :bind (;; C-c bindings (mode-specific-map)
  230. ("C-c h" . consult-history)
  231. ("C-c M-x" . consult-mode-command)
  232. ("C-c b" . consult-bookmark)
  233. ("C-c k" . consult-kmacro)
  234. ("C-c m" . consult-man)
  235. ("C-c i" . consult-info)
  236. ([remap Info-search] . consult-info)
  237. ;; C-x bindings (ctl-x-map)
  238. ("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command
  239. ("C-x b" . consult-buffer) ;; orig. switch-to-buffer
  240. ("C-x B" . consult-buffer-no-preview)
  241. ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window
  242. ("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame
  243. ("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab
  244. ("C-x r b" . consult-bookmark) ;; orig. bookmark-jump
  245. ("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer
  246. ;; Custom M-# bindings for fast register access
  247. ("M-#" . consult-register-load)
  248. ("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated)
  249. ("C-M-#" . consult-register)
  250. ;; Other custom bindings
  251. ("C-," . consult-line)
  252. ("C-S-s" . consult-line)
  253. ("C-c f" . consult-recent-file)
  254. ("C-c r" . consult-ripgrep)
  255. ("C-c ." . consult-ripgrep) ;; convenient for using with embark-act (C-. C-c . to search for thing at point)
  256. ;; TODO find an alternative to C-c c?
  257. ("C-c c r" . consult-ripgrep-auto-preview)
  258. ("C-c c s" . consult-ripgrep-case-sensitive)
  259. ("C-c C-^" . consult-ripgrep-parent)
  260. ("M-y" . consult-yank-pop) ;; orig. yank-pop
  261. ;; M-g bindings (goto-map)
  262. ("M-g e" . consult-compile-error)
  263. ("M-g f" . consult-flycheck)
  264. ("M-g g" . consult-goto-line) ;; orig. goto-line
  265. ("M-g M-g" . consult-goto-line) ;; orig. goto-line
  266. ("M-g o" . consult-outline) ;; Alternative: consult-org-heading
  267. ("M-g m" . consult-mark)
  268. ("M-g k" . consult-global-mark)
  269. ("M-g i" . consult-imenu)
  270. ("M-g I" . consult-imenu-multi)
  271. (:map isearch-mode-map
  272. ("M-e" . consult-isearch-history) ;; orig. isearch-edit-string
  273. ("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string
  274. ("M-s l" . consult-line)) ;; needed by consult-line to detect isearch
  275. (:map search-map
  276. ("f" . consult-fd)
  277. ("F" . consult-find)
  278. ("M-f" . consult-locate)
  279. ("g" . consult-grep)
  280. ("G" . consult-git-grep)
  281. ("r" . consult-ripgrep)
  282. ("R" . consult-ripgrep) ;; can't use r in isearch-mode, so add R too
  283. ("u" . consult-ripgrep-unrestricted)
  284. ("^" . consult-ripgrep-parent)
  285. ("l" . consult-line)
  286. ("L" . consult-line-multi)
  287. ("m" . consult-multi-occur)
  288. ("k" . consult-keep-lines)
  289. ("C-f" . consult-focus-lines)
  290. ("e" . consult-isearch-history))
  291. (:map vertico-map
  292. ;; These are used for previewing with some consult commands (see consult-customize call below)
  293. ("C-S-p" . vertico-previous)
  294. ("C-S-n" . vertico-next)
  295. ;; Toggle preview on/off without changing preview-key
  296. ("M-P" . consult-toggle-preview)
  297. ("C-x C-M-x" . remove-leading-hash)))
  298. :config
  299. ;; Configure register formatting. This improves the register
  300. ;; preview for `consult-register', `consult-register-load',
  301. ;; `consult-register-store' and the Emacs built-ins.
  302. (setq register-preview-delay 0
  303. register-preview-function #'consult-register-format)
  304. ;; Tweak the register preview window.
  305. ;; This adds thin lines, sorting and hides the mode line of the window.
  306. (advice-add #'register-preview :override #'consult-register-window)
  307. (add-to-list 'consult-mode-histories '(cider-repl-mode cider-repl-input-history))
  308. (defvar consult-line-map
  309. (let ((map (make-sparse-keymap)))
  310. (define-key map "\C-s" #'previous-history-element)
  311. map))
  312. (consult-customize consult-line :keymap consult-line-map)
  313. (defun consult-ripgrep-auto-preview (&optional dir initial)
  314. (interactive "P")
  315. (consult-ripgrep dir initial))
  316. (defun consult-ripgrep-unrestricted (&optional dir initial)
  317. (interactive "P")
  318. (let ((consult-ripgrep-args (replace-regexp-in-string "\\." "-uu ." consult-ripgrep-args)))
  319. (consult-ripgrep dir initial)))
  320. (defun consult-ripgrep-case-sensitive (&optional dir initial)
  321. (interactive "P")
  322. (let ((consult-ripgrep-args (replace-regexp-in-string "\\." "-s ." consult-ripgrep-args)))
  323. (consult-ripgrep dir initial)))
  324. (defun consult-buffer-no-preview ()
  325. (interactive)
  326. (consult-buffer))
  327. (defun consult-ripgrep-parent (&optional initial)
  328. (interactive "P")
  329. (consult-ripgrep (file-name-directory
  330. (directory-file-name (or (persp-current-project-root) default-directory)))
  331. initial))
  332. (consult-customize
  333. consult-theme
  334. :preview-key '(:debounce 0.2 any)
  335. ;; For these commands we can use C-N/C-P to scroll and preview, or M-. to preview
  336. consult-git-grep consult-grep
  337. consult-ripgrep-parent consult-ripgrep consult-ripgrep-case-sensitive consult-ripgrep-unrestricted
  338. consult-bookmark consult-recent-file consult-xref consult-buffer-no-preview
  339. consult--source-recent-file consult--source-project-recent-file consult--source-bookmark;
  340. :preview-key '("M-." :debounce 0.2 "C-S-n" :debounce 0.2 "C-S-p"))
  341. (defvar-local consult-toggle-preview-orig nil)
  342. (defun consult-toggle-preview ()
  343. "Command to enable/disable preview."
  344. (interactive)
  345. (if consult-toggle-preview-orig
  346. (setq consult--preview-function consult-toggle-preview-orig
  347. consult-toggle-preview-orig nil)
  348. (setq consult-toggle-preview-orig consult--preview-function
  349. consult--preview-function #'ignore)))
  350. (setq consult-narrow-key "<")
  351. (append-to-list* 'consult-buffer-filter
  352. "^\\*helpful"
  353. "^\\*Warnings\\*"
  354. "^\\*cider-test-report\\*"
  355. "^\\*cider-error\\*"
  356. "^\\*cider-inspect\\*")
  357. (setq consult-project-function (lambda (_) (persp-current-project-root)))
  358. ;; Switches perspective if we select a buffer from another perspective, but note that previewing
  359. ;; a buffer adds it to the current perspective, so preview should be disabled before removing
  360. ;; perspective narrowing
  361. (defun consult--persp-buffer-action (orig &rest args)
  362. (when (not (cdr args)) ;; (cdr args) is norecord, which should distinguish preview/non-preview
  363. (let ((buffer (window-normalize-buffer-to-switch-to (car args))))
  364. (unless (persp-is-current-buffer buffer)
  365. (let ((other-persp (persp-buffer-in-other-p buffer)))
  366. (when (eq (car-safe other-persp) (selected-frame))
  367. (persp-switch (cdr other-persp)))))))
  368. (apply orig args))
  369. (advice-add 'consult--buffer-action :around 'consult--persp-buffer-action)
  370. (defvar consult-initial-narrow-config
  371. '((consult-buffer . ?x)
  372. (consult-buffer-no-preview . ?x)
  373. (consult-buffer-other-window . ?x)
  374. (consult-project-extra-find . ?f)))
  375. ;; Add initial narrowing hook
  376. (defun consult-initial-narrow ()
  377. (when-let (key (alist-get this-command consult-initial-narrow-config))
  378. (setq unread-command-events (append unread-command-events (list key 32)))))
  379. (add-hook 'minibuffer-setup-hook #'consult-initial-narrow)
  380. (defvar consult--source-perspective-buffer
  381. `(:name "Perspective Buffer"
  382. :narrow (?x . "Perspective")
  383. :hidden t
  384. :category buffer
  385. :face consult-buffer
  386. :history buffer-name-history
  387. :state ,#'consult--buffer-state
  388. :enabled ,(lambda () persp-mode)
  389. :items
  390. ,(lambda ()
  391. (consult--buffer-query :sort 'visibility
  392. :predicate #'persp-is-current-buffer
  393. :as #'buffer-name)))
  394. "Perspective buffer candidate source for `consult-buffer'.")
  395. (add-to-list 'consult-buffer-sources 'consult--source-perspective-buffer t)
  396. ;; Copy of consult--source-project-file to use with perspective narrowing (identical except for narrowing key)
  397. ;; Put before consult--source-project-file so we get recentf behaviour here
  398. (defvar consult--source-perspective-files
  399. (plist-put (plist-put (copy-sequence consult--source-project-recent-file)
  400. :name "Project File")
  401. :narrow '(?x . "Perspective")))
  402. (add-to-list 'consult-buffer-sources 'consult--source-perspective-files t)
  403. ;; Versions of consult--source-project-buffer and consult--source-project-file for use by consult-project-buffer
  404. ;; They allow narrowing with b, f and a (instead of p)
  405. ;; f is the recentf version provided by consult
  406. ;; a is an "all files" version based on fd (respecting .gitignore, hidden by default)
  407. (defvar consult--project-source-project-buffer
  408. (plist-put (plist-put (copy-sequence consult--source-project-buffer)
  409. :hidden nil)
  410. :narrow '(?b . "Buffer")))
  411. (defvar consult--project-source-project-file-recentf
  412. (plist-put (plist-put (copy-sequence consult--source-project-recent-file)
  413. :hidden nil)
  414. :narrow '(?f . "File (Recentf)")))
  415. (defvar consult--project-source-project-file-all
  416. (plist-put (plist-put (copy-sequence consult--source-project-recent-file)
  417. :narrow '(?a . "File (All)"))
  418. :items '(lambda ()
  419. (when (eq 0 (call-process-shell-command "fd"))
  420. (when-let (root (consult--project-root))
  421. (let ((len (length root))
  422. (inv-root (propertize root 'invisible t)))
  423. (mapcar (lambda (x)
  424. (concat inv-root (substring x len)))
  425. (split-string
  426. (shell-command-to-string
  427. (format "fd --color never -t f -0 . %s" root))
  428. "\0" t))))))))
  429. (defun remove-leading-hash ()
  430. "Remove a # character from the beginning of the current line.
  431. Designed to be used for consult commands that automatically add a # at the beginning of the minibuffer.
  432. See `+become' and the functions that call it (e.g. `+become-consult-line')."
  433. (interactive)
  434. (save-excursion
  435. (beginning-of-line)
  436. (when (= ?# (char-after))
  437. (delete-forward-char 1))))
  438. (defun consult-project-buffer ()
  439. "Version of `consult-buffer' that only uses project-related sources."
  440. (interactive)
  441. (let ((consult-buffer-sources '(consult--project-source-project-buffer
  442. consult--project-source-project-file-recentf
  443. consult--project-source-project-file-all)))
  444. (consult-buffer)))
  445. ;; https://takeonrules.com/2024/06/08/adding-a-consult-function-for-visualizing-xref/
  446. (defvar consult--xref-history nil
  447. "History for the `consult-recent-xref' results.")
  448. (defun consult-recent-xref (&optional markers)
  449. "Jump to a marker in MARKERS list (defaults to `xref--history'.
  450. The command supports preview of the currently selected marker position.
  451. The symbol at point is added to the future history."
  452. (interactive)
  453. (consult--read
  454. (consult--global-mark-candidates
  455. (or markers (flatten-list xref--history)))
  456. :prompt "Go to Xref: "
  457. :annotate (consult--line-prefix)
  458. :category 'consult-location
  459. :sort nil
  460. :require-match t
  461. :lookup #'consult--lookup-location
  462. :history '(:input consult--xref-history)
  463. :add-history (thing-at-point 'symbol)
  464. :state (consult--jump-state))))
  465. (use-package consult-flycheck)
  466. (use-package consult-lsp
  467. :bind (:map lsp-mode-map
  468. ([remap xref-find-apropos] . consult-lsp-symbols)))
  469. (use-package consult-dir
  470. :bind (("C-x C-d" . consult-dir)
  471. :map vertico-map
  472. ("C-x C-d" . consult-dir)
  473. ("C-x C-j" . consult-dir-jump-file)))
  474. (use-package consult-git-log-grep
  475. :bind ("C-c g l" . consult-git-log-grep)
  476. :custom (consult-git-log-grep-open-function #'magit-show-commit))
  477. (use-package consult-ls-git
  478. :bind ("C-c g f" . consult-ls-git))
  479. (use-package consult-vc-modified-files
  480. :bind (:map vc-prefix-map ("f" . consult-vc-modified-files)))
  481. (use-package consult-project-extra)
  482. (use-package marginalia
  483. :hook (elpaca-after-init . marginalia-mode)
  484. :config
  485. ;; crux-recentf-find-file
  486. (add-to-list 'marginalia-prompt-categories '("Choose recent file" . file)))
  487. (use-package embark
  488. :bind
  489. (("C-." . embark-act)
  490. ("M-." . embark-dwim)
  491. ([remap xref-find-definitions-current-list-function] . embark-dwim-beginning-of-list)
  492. ("C-c C-o" . embark-export)
  493. ("C-h b" . embark-bindings)
  494. ("C-h B" . describe-bindings)
  495. (:map minibuffer-local-map
  496. ("M-." . embark-preview)
  497. ("C-," . embark-become)
  498. ("C-^" . embark-become-ripgrep-parent)
  499. ("C-S-SPC" . embark-select))
  500. (:map embark-become-file+buffer-map
  501. ("e" . consult-project-extra-find)
  502. ("E" . project-switch-consult-project-extra-find)))
  503. :custom
  504. (prefix-help-command 'embark-prefix-help-command)
  505. :config
  506. (defun embark-dwim-beginning-of-list ()
  507. "`embark-dwim' at the beginning of the current list.
  508. With a prefix argument, moves up `current-prefix-arg' sexps first."
  509. (interactive)
  510. (progn
  511. (when current-prefix-arg
  512. (sp-backward-up-sexp current-prefix-arg))
  513. (sp-beginning-of-sexp)
  514. (embark-dwim)))
  515. (defalias 'embark-become-ripgrep-parent (kmacro "C-, ^"))
  516. (defun embark-preview ()
  517. "Previews candidate in vertico buffer, unless it's a consult command"
  518. (interactive)
  519. (unless (bound-and-true-p consult--preview-function)
  520. (save-selected-window
  521. (let ((embark-quit-after-action nil))
  522. (embark-dwim)))))
  523. ;; Hide the mode line of the Embark live/completions buffers
  524. (add-to-list 'display-buffer-alist
  525. '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
  526. nil
  527. (window-parameters (mode-line-format . none)))))
  528. (use-package embark-consult
  529. :after (embark consult)
  530. ;; demand, combined with after means that this will load after embark and consult
  531. ;; See https://github.com/oantolin/embark/commit/47daded610b245caf01a97d74c940aff91fe14e2#r46010972
  532. :demand t
  533. :config
  534. (defun +become (fn)
  535. "Remove the leading # from the minibuffer, and call `FN'.
  536. Useful with embark-become, when changing from a command that uses # as a separator, to one that doesn't."
  537. (interactive)
  538. (setq unread-command-events (listify-key-sequence "\C-x\C-\M-x"))
  539. (funcall-interactively fn))
  540. (defun +become-consult-line ()
  541. "A version of `consult-line', designed for use with `embark-become'.
  542. The leading # added by other consult commands is removed."
  543. (interactive)
  544. (+become #'consult-line))
  545. (defun +become-consult-line ()
  546. "A version of `consult-imenu', designed for use with `embark-become'.
  547. The leading # added by other consult commands is removed."
  548. (interactive)
  549. (+become #'consult-imenu))
  550. :bind
  551. (:map embark-consult-async-search-map
  552. ("l" . +become-consult-line)
  553. ("f" . consult-focus-lines)
  554. ("i" . +become-consult-imenu)
  555. ("^" . consult-ripgrep-parent)
  556. ("u" . consult-ripgrep-unrestricted)
  557. ("c" . consult-ripgrep-case-sensitive))
  558. :hook
  559. (embark-collect-mode . consult-preview-at-point-mode))
  560. (use-package consult-todo
  561. ;; TODO use consult-todo-project when it works
  562. :bind ("C-c c t t" . consult-todo))
  563. (provide 'init-minibuffer)
  564. ;;; init-minibuffer.el ends here