This is the only internal usage of :bind, which I want to avoid, because it pulls in bind-key, which offers no real benefit over just about any other key binding function or macro, so I'd rather use what is already available (like map!).
393 lines
16 KiB
EmacsLisp
393 lines
16 KiB
EmacsLisp
;;; completion/vertico/config.el -*- lexical-binding: t; -*-
|
|
|
|
(defvar +vertico-company-completion-styles '(basic partial-completion orderless)
|
|
"Completion styles for company to use.
|
|
|
|
The completion/vertico module uses the orderless completion style by default,
|
|
but this returns too broad a candidate set for company completion. This variable
|
|
overrides `completion-styles' during company completion sessions.")
|
|
|
|
(defvar +vertico-consult-dir-container-executable "docker"
|
|
"Command to call for listing container hosts.")
|
|
|
|
(defvar +vertico-consult-dir-container-args nil
|
|
"Command to call for listing container hosts.")
|
|
|
|
;;
|
|
;;; Packages
|
|
|
|
(use-package! vertico
|
|
:hook (doom-first-input . vertico-mode)
|
|
:init
|
|
(defadvice! +vertico-crm-indicator-a (args)
|
|
:filter-args #'completing-read-multiple
|
|
(cons (format "[CRM%s] %s"
|
|
(replace-regexp-in-string
|
|
"\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
|
|
crm-separator)
|
|
(car args))
|
|
(cdr args)))
|
|
:config
|
|
(setq vertico-resize nil
|
|
vertico-count 17
|
|
vertico-cycle t)
|
|
(setq-default completion-in-region-function
|
|
(lambda (&rest args)
|
|
(apply (if vertico-mode
|
|
#'consult-completion-in-region
|
|
#'completion--in-region)
|
|
args)))
|
|
|
|
(map! :when (modulep! :editor evil +everywhere)
|
|
:map vertico-map
|
|
"M-RET" #'vertico-exit-input
|
|
"C-SPC" #'+vertico/embark-preview
|
|
"C-j" #'vertico-next
|
|
"C-M-j" #'vertico-next-group
|
|
"C-k" #'vertico-previous
|
|
"C-M-k" #'vertico-previous-group
|
|
"C-h" (cmds! (eq 'file (vertico--metadata-get 'category)) #'vertico-directory-up)
|
|
"C-l" (cmds! (eq 'file (vertico--metadata-get 'category)) #'+vertico/enter-or-preview))
|
|
|
|
;; Cleans up path when moving directories with shadowed paths syntax, e.g.
|
|
;; cleans ~/foo/bar/// to /, and ~/foo/bar/~/ to ~/.
|
|
(add-hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy)
|
|
(add-hook 'minibuffer-setup-hook #'vertico-repeat-save)
|
|
(map! :map vertico-map "DEL" #'vertico-directory-delete-char)
|
|
|
|
;; These commands are problematic and automatically show the *Completions* buffer
|
|
(advice-add #'tmm-add-prompt :after #'minibuffer-hide-completions)
|
|
(defadvice! +vertico--suppress-completion-help-a (fn &rest args)
|
|
:around #'ffap-menu-ask
|
|
(letf! ((#'minibuffer-completion-help #'ignore))
|
|
(apply fn args))))
|
|
|
|
|
|
(use-package! orderless
|
|
:after-call doom-first-input-hook
|
|
:config
|
|
(defadvice! +vertico--company-capf--candidates-a (fn &rest args)
|
|
"Highlight company matches correctly, and try default completion styles before
|
|
orderless."
|
|
:around #'company-capf--candidates
|
|
(let ((orderless-match-faces [completions-common-part])
|
|
(completion-styles +vertico-company-completion-styles))
|
|
(apply fn args)))
|
|
|
|
(defun +vertico-orderless-dispatch (pattern _index _total)
|
|
(cond
|
|
;; Ensure $ works with Consult commands, which add disambiguation suffixes
|
|
((string-suffix-p "$" pattern)
|
|
`(orderless-regexp . ,(concat (substring pattern 0 -1) "[\x200000-\x300000]*$")))
|
|
;; Ignore single !
|
|
((string= "!" pattern) `(orderless-literal . ""))
|
|
;; Without literal
|
|
((string-prefix-p "!" pattern) `(orderless-without-literal . ,(substring pattern 1)))
|
|
;; Annotation
|
|
((string-prefix-p "&" pattern) `(orderless-annotation . ,(substring pattern 1)))
|
|
((string-suffix-p "&" pattern) `(orderless-annotation . ,(substring pattern 0 -1)))
|
|
;; Character folding
|
|
((string-prefix-p "%" pattern) `(char-fold-to-regexp . ,(substring pattern 1)))
|
|
((string-suffix-p "%" pattern) `(char-fold-to-regexp . ,(substring pattern 0 -1)))
|
|
;; Initialism matching
|
|
((string-prefix-p "`" pattern) `(orderless-initialism . ,(substring pattern 1)))
|
|
((string-suffix-p "`" pattern) `(orderless-initialism . ,(substring pattern 0 -1)))
|
|
;; Literal matching
|
|
((string-prefix-p "=" pattern) `(orderless-literal . ,(substring pattern 1)))
|
|
((string-suffix-p "=" pattern) `(orderless-literal . ,(substring pattern 0 -1)))
|
|
;; Flex matching
|
|
((string-prefix-p "~" pattern) `(orderless-flex . ,(substring pattern 1)))
|
|
((string-suffix-p "~" pattern) `(orderless-flex . ,(substring pattern 0 -1)))))
|
|
(add-to-list
|
|
'completion-styles-alist
|
|
'(+vertico-basic-remote
|
|
+vertico-basic-remote-try-completion
|
|
+vertico-basic-remote-all-completions
|
|
"Use basic completion on remote files only"))
|
|
(setq completion-styles '(orderless basic)
|
|
completion-category-defaults nil
|
|
;; note that despite override in the name orderless can still be used in
|
|
;; find-file etc.
|
|
completion-category-overrides '((file (styles +vertico-basic-remote orderless partial-completion)))
|
|
orderless-style-dispatchers '(+vertico-orderless-dispatch)
|
|
orderless-component-separator #'orderless-escapable-split-on-space)
|
|
;; ...otherwise find-file gets different highlighting than other commands
|
|
(set-face-attribute 'completions-first-difference nil :inherit nil))
|
|
|
|
|
|
(use-package! consult
|
|
:defer t
|
|
:preface
|
|
(define-key!
|
|
[remap bookmark-jump] #'consult-bookmark
|
|
[remap evil-show-marks] #'consult-mark
|
|
[remap evil-show-jumps] #'+vertico/jump-list
|
|
[remap evil-show-registers] #'consult-register
|
|
[remap goto-line] #'consult-goto-line
|
|
[remap imenu] #'consult-imenu
|
|
[remap Info-search] #'consult-info
|
|
[remap locate] #'consult-locate
|
|
[remap load-theme] #'consult-theme
|
|
[remap man] #'consult-man
|
|
[remap recentf-open-files] #'consult-recent-file
|
|
[remap switch-to-buffer] #'consult-buffer
|
|
[remap switch-to-buffer-other-window] #'consult-buffer-other-window
|
|
[remap switch-to-buffer-other-frame] #'consult-buffer-other-frame
|
|
[remap yank-pop] #'consult-yank-pop
|
|
[remap persp-switch-to-buffer] #'+vertico/switch-workspace-buffer)
|
|
:config
|
|
(defadvice! +vertico--consult-recentf-a (&rest _args)
|
|
"`consult-recent-file' needs to have `recentf-mode' on to work correctly.
|
|
`consult-buffer' needs `recentf-mode' to show file candidates."
|
|
:before (list #'consult-recent-file #'consult-buffer)
|
|
(recentf-mode +1))
|
|
|
|
(setq consult-project-function #'doom-project-root
|
|
consult-narrow-key "<"
|
|
consult-line-numbers-widen t
|
|
consult-async-min-input 2
|
|
consult-async-refresh-delay 0.15
|
|
consult-async-input-throttle 0.2
|
|
consult-async-input-debounce 0.1
|
|
consult-fd-args
|
|
'((if (executable-find "fdfind" 'remote) "fdfind" "fd")
|
|
"--color=never"
|
|
;; https://github.com/sharkdp/fd/issues/839
|
|
"--full-path --absolute-path"
|
|
"--hidden --exclude .git"
|
|
(if (featurep :system 'windows) "--path-separator=/")))
|
|
|
|
(consult-customize
|
|
consult-ripgrep consult-git-grep consult-grep
|
|
consult-bookmark consult-recent-file
|
|
+default/search-project +default/search-other-project
|
|
+default/search-project-for-symbol-at-point
|
|
+default/search-cwd +default/search-other-cwd
|
|
+default/search-notes-for-symbol-at-point
|
|
+default/search-emacsd
|
|
consult--source-recent-file consult--source-project-recent-file consult--source-bookmark
|
|
:preview-key "C-SPC")
|
|
(consult-customize
|
|
consult-theme
|
|
:preview-key (list "C-SPC" :debounce 0.5 'any))
|
|
(when (modulep! :lang org)
|
|
(defvar +vertico--consult-org-source
|
|
(list :name "Org Buffer"
|
|
:category 'buffer
|
|
:narrow ?o
|
|
:hidden t
|
|
:face 'consult-buffer
|
|
:history 'buffer-name-history
|
|
:state #'consult--buffer-state
|
|
:new
|
|
(lambda (name)
|
|
(with-current-buffer (get-buffer-create name)
|
|
(insert "#+title: " name "\n\n")
|
|
(org-mode)
|
|
(consult--buffer-action (current-buffer))))
|
|
:items
|
|
(lambda ()
|
|
(mapcar #'buffer-name
|
|
(if (featurep 'org)
|
|
(org-buffer-list)
|
|
(seq-filter
|
|
(lambda (x)
|
|
(eq (buffer-local-value 'major-mode x) 'org-mode))
|
|
(buffer-list)))))))
|
|
(add-to-list 'consult-buffer-sources '+vertico--consult-org-source 'append)))
|
|
|
|
|
|
(use-package! consult-dir
|
|
:defer t
|
|
:init
|
|
(map! [remap list-directory] #'consult-dir
|
|
(:after vertico
|
|
:map vertico-map
|
|
"C-x C-d" #'consult-dir
|
|
"C-x C-j" #'consult-dir-jump-file))
|
|
:config
|
|
(when (modulep! :tools docker)
|
|
;; TODO: Replace with `tramp-container--completion-function' when we drop
|
|
;; support for <29
|
|
(defun +vertico--consult-dir-container-hosts (host)
|
|
"Get a list of hosts from HOST."
|
|
(cl-loop for line in (cdr
|
|
(ignore-errors
|
|
(apply #'process-lines +vertico-consult-dir-container-executable
|
|
(append +vertico-consult-dir-container-args (list "ps")))))
|
|
for cand = (split-string line "[[:space:]]+" t)
|
|
collect (format "/%s:%s:/" host (car (last cand)))))
|
|
|
|
(defun +vertico--consult-dir-podman-hosts ()
|
|
(let ((+vertico-consult-dir-container-executable "podman"))
|
|
(+vertico--consult-dir-container-hosts "podman")))
|
|
|
|
(defun +vertico--consult-dir-docker-hosts ()
|
|
(let ((+vertico-consult-dir-container-executable "docker"))
|
|
(+vertico--consult-dir-container-hosts "docker")))
|
|
|
|
(defvar +vertico--consult-dir-source-tramp-podman
|
|
`(:name "Podman"
|
|
:narrow ?p
|
|
:category file
|
|
:face consult-file
|
|
:history file-name-history
|
|
:items ,#'+vertico--consult-dir-podman-hosts)
|
|
"Podman candidate source for `consult-dir'.")
|
|
|
|
(defvar +vertico--consult-dir-source-tramp-docker
|
|
`(:name "Docker"
|
|
:narrow ?d
|
|
:category file
|
|
:face consult-file
|
|
:history file-name-history
|
|
:items ,#'+vertico--consult-dir-docker-hosts)
|
|
"Docker candidate source for `consult-dir'.")
|
|
|
|
(add-to-list 'consult-dir-sources '+vertico--consult-dir-source-tramp-podman t)
|
|
(add-to-list 'consult-dir-sources '+vertico--consult-dir-source-tramp-docker t))
|
|
|
|
(add-to-list 'consult-dir-sources 'consult-dir--source-tramp-ssh t)
|
|
(add-to-list 'consult-dir-sources 'consult-dir--source-tramp-local t))
|
|
|
|
(use-package! consult-flycheck
|
|
:when (and (modulep! :checkers syntax)
|
|
(not (modulep! :checkers syntax +flymake)))
|
|
:after (consult flycheck))
|
|
|
|
(use-package! consult-yasnippet
|
|
:when (modulep! :editor snippets)
|
|
:defer t
|
|
:init (map! [remap yas-insert-snippet] #'consult-yasnippet))
|
|
|
|
|
|
(use-package! embark
|
|
:defer t
|
|
:init
|
|
(setq which-key-use-C-h-commands nil
|
|
prefix-help-command #'embark-prefix-help-command)
|
|
(map! [remap describe-bindings] #'embark-bindings
|
|
"C-;" #'embark-act ; to be moved to :config default if accepted
|
|
(:map minibuffer-local-map
|
|
"C-;" #'embark-act
|
|
"C-c C-;" #'embark-export
|
|
"C-c C-l" #'embark-collect
|
|
:desc "Export to writable buffer" "C-c C-e" #'+vertico/embark-export-write)
|
|
(:leader
|
|
:desc "Actions" "a" #'embark-act)) ; to be moved to :config default if accepted
|
|
:config
|
|
(require 'consult)
|
|
|
|
(set-popup-rule! "^\\*Embark Export:" :size 0.35 :ttl 0 :quit nil)
|
|
|
|
(after! which-key
|
|
(defadvice! +vertico--embark-which-key-prompt-a (fn &rest args)
|
|
"Hide the which-key indicator immediately when using the completing-read prompter."
|
|
:around #'embark-completing-read-prompter
|
|
(which-key--hide-popup-ignore-command)
|
|
(let ((embark-indicators
|
|
(remq #'embark-which-key-indicator embark-indicators)))
|
|
(apply fn args)))
|
|
(cl-nsubstitute #'+vertico-embark-which-key-indicator #'embark-mixed-indicator embark-indicators))
|
|
|
|
;; add the package! target finder before the file target finder,
|
|
;; so we don't get a false positive match.
|
|
(let ((pos (or (cl-position
|
|
'embark-target-file-at-point
|
|
embark-target-finders)
|
|
(length embark-target-finders))))
|
|
(cl-callf2
|
|
cons
|
|
'+vertico-embark-target-package-fn
|
|
(nthcdr pos embark-target-finders)))
|
|
(defvar-keymap +vertico/embark-doom-package-map
|
|
:doc "Keymap for Embark package actions for packages installed by Doom."
|
|
:parent embark-general-map
|
|
"h" #'doom/help-packages
|
|
"b" #'doom/bump-package
|
|
"c" #'doom/help-package-config
|
|
"u" #'doom/help-package-homepage)
|
|
(setf (alist-get 'package embark-keymap-alist) #'+vertico/embark-doom-package-map)
|
|
(map! (:map embark-file-map
|
|
:desc "Open target with sudo" "s" #'doom/sudo-find-file
|
|
(:when (modulep! :tools magit)
|
|
:desc "Open magit-status of target" "g" #'+vertico/embark-magit-status)
|
|
(:when (modulep! :ui workspaces)
|
|
:desc "Open in new workspace" "TAB" #'+vertico/embark-open-in-new-workspace
|
|
:desc "Open in new workspace" "<tab>" #'+vertico/embark-open-in-new-workspace))))
|
|
|
|
|
|
(use-package! marginalia
|
|
:hook (doom-first-input . marginalia-mode)
|
|
:init
|
|
(map! :map minibuffer-local-map
|
|
:desc "Cycle marginalia views" "M-A" #'marginalia-cycle)
|
|
:config
|
|
(when (modulep! +icons)
|
|
(add-hook 'marginalia-mode-hook #'nerd-icons-completion-marginalia-setup))
|
|
(advice-add #'marginalia--project-root :override #'doom-project-root)
|
|
(pushnew! marginalia-command-categories
|
|
'(+default/find-file-under-here . file)
|
|
'(doom/find-file-in-emacsd . project-file)
|
|
'(doom/find-file-in-other-project . project-file)
|
|
'(doom/find-file-in-private-config . file)
|
|
'(doom/describe-active-minor-mode . minor-mode)
|
|
'(flycheck-error-list-set-filter . builtin)
|
|
'(persp-switch-to-buffer . buffer)
|
|
'(projectile-find-file . project-file)
|
|
'(projectile-recentf . project-file)
|
|
'(projectile-switch-to-buffer . buffer)
|
|
'(projectile-switch-project . project-file)))
|
|
|
|
|
|
(use-package! wgrep
|
|
:commands wgrep-change-to-wgrep-mode
|
|
:config (setq wgrep-auto-save-buffer t))
|
|
|
|
|
|
(use-package! vertico-posframe
|
|
:when (modulep! +childframe)
|
|
:hook (vertico-mode . vertico-posframe-mode)
|
|
:config
|
|
(add-hook 'doom-after-reload-hook #'posframe-delete-all))
|
|
|
|
;; From https://github.com/minad/vertico/wiki#candidate-display-transformations-custom-candidate-highlighting
|
|
;;
|
|
;; Uses `add-face-text-property' instead of `propertize' unlike the above snippet
|
|
;; because `'append' is necessary to not override the match font lock
|
|
;; See: https://github.com/minad/vertico/issues/389
|
|
(use-package! vertico-multiform
|
|
:hook (vertico-mode . vertico-multiform-mode)
|
|
:config
|
|
(defvar +vertico-transform-functions nil)
|
|
|
|
(cl-defmethod vertico--format-candidate :around
|
|
(cand prefix suffix index start &context ((not +vertico-transform-functions) null))
|
|
(dolist (fun (ensure-list +vertico-transform-functions))
|
|
(setq cand (funcall fun cand)))
|
|
(cl-call-next-method cand prefix suffix index start))
|
|
|
|
(defun +vertico-highlight-directory (file)
|
|
"If FILE ends with a slash, highlight it as a directory."
|
|
(when (string-suffix-p "/" file)
|
|
(add-face-text-property 0 (length file) 'marginalia-file-priv-dir 'append file))
|
|
file)
|
|
|
|
(defun +vertico-highlight-enabled-mode (cmd)
|
|
"If MODE is enabled, highlight it as font-lock-constant-face."
|
|
(let ((sym (intern cmd)))
|
|
(with-current-buffer (nth 1 (buffer-list))
|
|
(if (or (eq sym major-mode)
|
|
(and
|
|
(memq sym minor-mode-list)
|
|
(boundp sym)
|
|
(symbol-value sym)))
|
|
(add-face-text-property 0 (length cmd) 'font-lock-constant-face 'append cmd)))
|
|
cmd))
|
|
|
|
(add-to-list 'vertico-multiform-categories
|
|
'(file
|
|
(+vertico-transform-functions . +vertico-highlight-directory)))
|
|
(add-to-list 'vertico-multiform-commands
|
|
'(execute-extended-command
|
|
(+vertico-transform-functions . +vertico-highlight-enabled-mode))))
|