Files
sydnix/users/crumb/programs/emacs/modules/syd-completion.el
2025-01-19 18:41:38 -07:00

129 lines
5.3 KiB
EmacsLisp
Executable File

;;; syd-completion.el -*- lexical-binding: t; -*-
(require 'syd-general)
(use-package emacs
:custom
;; Allow the opening of new minibuffers from inside existing minibuffers.
((enable-recursive-minibuffers t)
;; Hide commands in M-x which do not work in the current mode.
(read-extended-command-predicate #'command-completion-default-include-p))
:config
;; Disable blinking cursor. Aesthetically, I personally don't fancy it;
;; technically, it doesn't play well with `evil-terminal-cursor-changer'.
(blink-cursor-mode -1))
;; Consult adds various search and navigation tools using Emacs' completing-read
;; function; i.e., in our case, Vertico.
(use-package consult
:defer t)
(use-package embark-consult
:after (embark consult))
;; Vertico is a simple completion engine that replaces Emacs' built-in
;; completion engine, achieving Just Works™ compatibility. This is in contrast
;; to e.g. Helm and Ivy, which spawn ecosystems orthogonal to Emacs, and
;; diametrically-opposed to each other.
(use-package vertico
:hook (on-first-input . vertico-mode)
:general (:keymaps 'vertico-map
"DEL" #'vertico-directory-delete-char
"C-SPC" #'+vertico/embark-preview
"C-j" #'vertico-next
"C-k" #'vertico-previous
"C-M-j" #'vertico-next-group
"C-M-k" #'vertico-previous-group)
:custom ((vertico-resize nil)
(vertico-count 17)
(vertico-cycle t))
:config
(setq-default completion-in-region-function #'consult-completion-in-region)
;; 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))
(defun +vertico-orderless-dispatch (pattern _index _total)
"Like `orderless-affix-dispatch', but allows affixes to be escaped.
Shamelessly stolen from Doom. }:3"
(let ((len (length pattern))
(alist orderless-affix-dispatch-alist))
(when (> len 0)
(cond
;; Ignore single dispatcher character
((and (= len 1) (alist-get (aref pattern 0) alist)) #'ignore)
;; Prefix
((when-let ((style (alist-get (aref pattern 0) alist))
((not (char-equal (aref pattern (max (1- len) 1)) ?\\))))
(cons style (substring pattern 1))))
;; Suffix
((when-let ((style (alist-get (aref pattern (1- len)) alist))
((not (char-equal (aref pattern (max 0 (- len 2))) ?\\))))
(cons style (substring pattern 0 -1))))))))
;; Orderless provides a completion style that divides the pattern into
;; space-separated components, and matches candidates that match all of the
;; components in any order. Each component can match in any one of several
;; ways: literally, as a regexp, as an initialism, in the flex style, or as
;; multiple word prefixes. By default, regexp and literal matches are enabled.
(use-package orderless
:after vertico
:custom ((completion-styles '(orderless basic))
(completion-category-overrides
'((file
(styles ;basic-remote
orderless partial-completion))))
(orderless-style-dispatchers '(+vertico-orderless-dispatch))
;; TODO: See Doom's `+vertico-orderless-dispatch'.
(orderless-affix-dispatch-alist
'((?! . orderless-without-literal)
(?& . orderless-annotation)
;; %1 -> {1, ₁, ꘡, ⒈, ...}
(?% . char-fold-to-regexp)
;; ,wcb -> {with-current-buffer, widget-convert-button, ...}
(?, . orderless-initialism)
(?= . orderless-literal)
(?^ . orderless-literal-prefix)
(?~ . orderless-flex)))))
;;;###autoload
(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 (plist-get (car targets) :type) '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 (lambda (binding)
(not (string-suffix-p "-argument" (cdr binding))))))))
;; TODO: Mark the Embark export buffer as a popup.
(use-package embark
:after vertico
:defer t
:custom ((which-key-use-C-h-commands nil)
(prefix-help-command #'embark-prefix-help-command)
;; Embark uses their own custom interface that is essentially
;; equivalent to which-key; just use which-key. }:)
(embark-indicators '(embark-which-key-indicator)))
:general
(:keymaps 'minibuffer-local-map
"C-;" `("Actions" . ,#'embark-act))
(:keymaps 'syd-leader-map
"a" `("Actions" . ,#'embark-act)))
(provide 'syd-completion)