diff options
Diffstat (limited to '.emacs.d/lisp/init-minibuffer.el')
-rw-r--r-- | .emacs.d/lisp/init-minibuffer.el | 276 |
1 files changed, 205 insertions, 71 deletions
diff --git a/.emacs.d/lisp/init-minibuffer.el b/.emacs.d/lisp/init-minibuffer.el index 9fbcf0c..118f730 100644 --- a/.emacs.d/lisp/init-minibuffer.el +++ b/.emacs.d/lisp/init-minibuffer.el @@ -12,7 +12,7 @@ :config ;; Do not allow the cursor in the minibuffer prompt (setq minibuffer-prompt-properties - '(read-only t cursor-intangible t face minibuffer-prompt)) + '(read-only t cursor-intangible t intangible t face minibuffer-prompt)) (add-hook 'minibuffer-setup-hook #'cursor-intangible-mode) (setq enable-recursive-minibuffers t) (minibuffer-depth-indicate-mode t) @@ -42,24 +42,31 @@ " ") cand))) + ;; https://github.com/minad/vertico/wiki#ding-when-wrapping-around + (advice-add #'vertico-next + :around + #'(lambda (origin &rest args) + (let ((beg-index vertico--index)) + (apply origin args) + (if (not (eq 1 (abs (- beg-index vertico--index)))) + (ding))))) + + ;; https://github.com/minad/vertico/wiki#useful-commands-from-outside-minibuffer (defun down-from-outside () "Move to next candidate in minibuffer, even when minibuffer isn't selected." (interactive) (with-selected-window (active-minibuffer-window) (execute-kbd-macro [down]))) - (defun up-from-outside () "Move to previous candidate in minibuffer, even when minibuffer isn't selected." (interactive) (with-selected-window (active-minibuffer-window) (execute-kbd-macro [up]))) - (defun preview-from-outside () "Preview the selected candidate, even when minibuffer isn't selected." (interactive) (with-selected-window (active-minibuffer-window) (execute-kbd-macro (kbd "M-.")))) - (defun to-and-fro-minibuffer () "Go back and forth between minibuffer and other window." (interactive) @@ -67,18 +74,73 @@ (select-window (minibuffer-selected-window)) (select-window (active-minibuffer-window)))) - (defun minibuffer-really-quit () - "Quit minibuffer session, even if it is not the selected window." + ;; Modified from https://github.com/minad/vertico/wiki#update-minibuffer-history-with-candidate-insertions + (defadvice vertico-insert + (after vertico-insert-add-history activate) + "Make vertico-insert add to the minibuffer history." + (if (and (not (eq minibuffer-history-variable t)) + (eq 'file (vertico--metadata-get 'category))) + (add-to-history minibuffer-history-variable (minibuffer-contents)))) + + (defun toggle-sort-directories-first () (interactive) - (with-selected-window (active-minibuffer-window) - (minibuffer-keyboard-quit))) + (if (eq vertico-sort-function 'vertico-sort-directories-first) + (set (make-local-variable 'vertico-sort-function) 'vertico-sort-history-length-alpha) + (set (make-local-variable 'vertico-sort-function) 'vertico-sort-directories-first)) + (setq vertico--input t) + (vertico--update)) :bind (("C-M-<" . up-from-outside) ("C-M->" . down-from-outside) ("C-M-+" . preview-from-outside) ("M-X" . to-and-fro-minibuffer) - ("C-M-S-g" . minibuffer-really-quit) - (:map vertico-map ("M-RET" . minibuffer-force-complete-and-exit)))) + (:map vertico-map + ("M-RET" . minibuffer-force-complete-and-exit) + ("M-D" . toggle-sort-directories-first)))) + +(use-extension vertico vertico-multiform + :config + (vertico-multiform-mode +1) + + (defun vertico-multiform-buffer-grid () + "Toggle displaying Vertico as a grid in a large window (like a regular buffer).)" + (interactive) + (if (equal '(vertico-buffer-mode vertico-grid-mode) (car vertico-multiform--stack)) + (vertico-multiform-vertical) + (setcar vertico-multiform--stack '(vertico-buffer-mode vertico-grid-mode)) + (vertico-multiform--toggle 1))) + + ;; https://github.com/minad/vertico/wiki#candidate-display-transformations-custom-candidate-highlighting + (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." + (if (string-suffix-p "/" file) + (propertize file 'face 'marginalia-file-priv-dir) + file)) + (defun +vertico-highlight-enabled-mode (cmd) + "If MODE is enabled, highlight it as font-lock-doc-face." + (let ((sym (intern cmd))) + (if (or (eq sym major-mode) + (and + (memq sym minor-mode-list) + (boundp sym))) + (propertize cmd 'face 'font-lock-doc-face) + cmd))) + + (setq vertico-multiform-commands + '((execute-extended-command + (+vertico-transform-functions . +vertico-highlight-enabled-mode)))) + (setq vertico-multiform-categories + '((file (+vertico-transform-functions . +vertico-highlight-directory) + (:keymap . vertico-directory-map)) + (imenu grid))) + :bind (:map vertico-multiform-map + ("M-H" . vertico-multiform-buffer-grid))) (use-extension vertico vertico-directory :config @@ -115,28 +177,28 @@ DEFS is a plist associating completion categories to commands." (let ((default-command (lookup-key vertico-map (kbd key)))) (define-key vertico-map (kbd key) - (list 'menu-item nil defs :filter - (lambda (d) - (or (plist-get d (completion-metadata-get - (completion-metadata (minibuffer-contents) - minibuffer-completion-table - minibuffer-completion-predicate) - 'category)) - default-command)))))) + (list 'menu-item nil defs :filter + (lambda (d) + (or (plist-get d (completion-metadata-get + (completion-metadata (minibuffer-contents) + minibuffer-completion-table + minibuffer-completion-predicate) + 'category)) + default-command)))))) (define-vertico-key "/" - 'file #'vertico-directory-slash - 'project-file #'vertico-directory-slash) + 'file #'vertico-directory-slash + 'project-file #'vertico-directory-slash) (define-vertico-key "RET" - 'file #'vertico-directory-enter-or-select-project - 'project-file #'vertico-directory-enter) + 'file #'vertico-directory-enter-or-select-project + 'project-file #'vertico-directory-enter) (define-vertico-key "~" - 'file #'vertico-directory-home) + 'file #'vertico-directory-home) (define-vertico-key "DEL" - 'file #'vertico-directory-delete-char - 'project-file #'vertico-directory-delete-char) + 'file #'vertico-directory-delete-char + 'project-file #'vertico-directory-delete-char) (define-vertico-key "M-DEL" - 'file #'vertico-directory-delete-word - 'project-file #'vertico-directory-delete-word) + 'file #'vertico-directory-delete-word + 'project-file #'vertico-directory-delete-word) :commands (vertico-directory-enter vertico-directory-delete-word vertico-directory-delete-char) ;; Tidy shadowed file names :hook (rfn-eshadow-update-overlay . vertico-directory-tidy)) @@ -152,21 +214,21 @@ DEFS is a plist associating completion categories to commands." (use-extension vertico vertico-indexed :config - (defmacro define-choose (n) + (defmacro define-vertico-choose (n) `(defun ,(intern (format "vertico-indexed-choose-%s" n)) () ,(format "Exit minibuffer with candidate %s." n) (interactive) - (let ((current-prefix-arg ,n)) + (let ((vertico--index ,n)) (funcall-interactively 'vertico-exit)))) - (defmacro define-insert (n) + (defmacro define-vertico-insert (n) `(defun ,(intern (format "vertico-indexed-insert-%s" n)) () ,(format "Insert candidate %s in minibuffer." n) (interactive) - (let ((current-prefix-arg ,n)) + (let ((vertico--index ,n)) (funcall-interactively 'vertico-insert)))) (dotimes (n 10) - (eval `(define-choose ,n)) - (eval `(define-insert ,n)) + (eval `(define-vertico-choose ,n)) + (eval `(define-vertico-insert ,n)) (define-key vertico-map (kbd (format "C-%s" n)) (intern (format "vertico-indexed-choose-%s" n))) (define-key vertico-map (kbd (format "M-%s" n)) (intern (format "vertico-indexed-insert-%s" n)))) (vertico-indexed-mode 1)) @@ -179,32 +241,36 @@ DEFS is a plist associating completion categories to commands." (use-package consult :bind (;; C-c bindings (mode-specific-map) ("C-c h" . consult-history) - ("C-c m" . consult-mode-command) + ("C-c M-x" . consult-mode-command) ("C-c b" . consult-bookmark) ("C-c k" . consult-kmacro) + ("C-c m" . consult-man) + ("C-c i" . consult-info) + ([remap Info-search] . consult-info) ;; C-x bindings (ctl-x-map) ("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command ("C-x b" . consult-buffer) ;; orig. switch-to-buffer - ("C-x B" . consult-buffer-no-preview) ;; orig. switch-to-buffer + ("C-x B" . consult-buffer-no-preview) ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window ("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame + ("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab + ("C-x r b" . consult-bookmark) ;; orig. bookmark-jump + ("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer ;; Custom M-# bindings for fast register access ("M-#" . consult-register-load) ("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated) ("C-M-#" . consult-register) ;; Other custom bindings + ("C-," . consult-line) ("C-S-s" . consult-line) - ("M-*" . consult-line-thing-at-point) ("C-c f" . consult-recent-file) ("C-c r" . consult-ripgrep) + ("C-c ." . consult-ripgrep) ;; convenient for using with embark-act (C-. C-c . to search for thing at point) ;; TODO find an alternative to C-c c? ("C-c c r" . consult-ripgrep-auto-preview) ("C-c c s" . consult-ripgrep-case-sensitive) - ("C-c c z" . consult-z-ripgrep) - ("C-c C-*" . consult-ripgrep-thing-at-point) ("C-c C-^" . consult-ripgrep-parent) ("M-y" . consult-yank-pop) ;; orig. yank-pop - ("<help> a" . consult-apropos) ;; orig. apropos-command ;; M-g bindings (goto-map) ("M-g e" . consult-compile-error) ("M-g f" . consult-flycheck) @@ -227,41 +293,42 @@ DEFS is a plist associating completion categories to commands." ("G" . consult-git-grep) ("r" . consult-ripgrep) ("R" . consult-ripgrep) ;; can't use r in isearch-mode, so add R too - ("M-r" . consult-ripgrep-unrestricted) - ("*" . consult-ripgrep-thing-at-point) - ("z" . consult-z-ripgrep) + ("u" . consult-ripgrep-unrestricted) ("^" . consult-ripgrep-parent) ("l" . consult-line) ("L" . consult-line-multi) ("m" . consult-multi-occur) ("k" . consult-keep-lines) - ("u" . consult-focus-lines) - ("e" . consult-isearch)) + ("C-f" . consult-focus-lines) + ("e" . consult-isearch-history)) (:map vertico-map ;; These are used for previewing with some consult commands (see consult-customize call below) ("C-S-p" . vertico-previous) ("C-S-n" . vertico-next) ;; Toggle preview on/off without changing preview-key - ("M-P" . consult-toggle-preview))) + ("M-P" . consult-toggle-preview) + ("C-x C-M-x" . remove-leading-hash))) :config - ;; Optionally configure the register formatting. This improves the register + ;; Configure register formatting. This improves the register ;; preview for `consult-register', `consult-register-load', ;; `consult-register-store' and the Emacs built-ins. (setq register-preview-delay 0 register-preview-function #'consult-register-format) - ;; Optionally tweak the register preview window. + ;; Tweak the register preview window. ;; This adds thin lines, sorting and hides the mode line of the window. (advice-add #'register-preview :override #'consult-register-window) - ;; Use Consult to select xref locations with preview - (setq xref-show-xrefs-function #'consult-xref - xref-show-definitions-function #'consult-xref) - (add-to-list 'consult-mode-histories '(cider-repl-mode cider-repl-input-history)) + (defvar consult-line-map + (let ((map (make-sparse-keymap))) + (define-key map "\C-s" #'previous-history-element) + map)) + (consult-customize consult-line :keymap consult-line-map) + (defun consult-ripgrep-auto-preview (&optional dir initial) (interactive "P") (consult-ripgrep dir initial)) @@ -269,10 +336,6 @@ DEFS is a plist associating completion categories to commands." (interactive "P") (let ((consult-ripgrep-args (replace-regexp-in-string "\\." "-uu ." consult-ripgrep-args))) (consult-ripgrep dir initial))) - (defun consult-z-ripgrep (&optional dir initial) - (interactive "P") - (let ((consult-ripgrep-args (replace-regexp-in-string "\\." "-z ." consult-ripgrep-args))) - (consult-ripgrep dir initial))) (defun consult-ripgrep-case-sensitive (&optional dir initial) (interactive "P") (let ((consult-ripgrep-args (replace-regexp-in-string "\\." "-s ." consult-ripgrep-args))) @@ -282,25 +345,19 @@ DEFS is a plist associating completion categories to commands." (consult-buffer)) (defun consult-ripgrep-parent (&optional initial) (interactive "P") - (consult-ripgrep (file-name-directory (directory-file-name (persp-current-project-root))) initial)) - - (defalias 'consult-line-thing-at-point 'consult-line) - (defalias 'consult-ripgrep-thing-at-point 'consult-ripgrep) + (consult-ripgrep (file-name-directory + (directory-file-name (or (persp-current-project-root) default-directory))) + initial)) (consult-customize consult-theme :preview-key '(:debounce 0.2 any) ;; For these commands we can use C-N/C-P to scroll and preview, or M-. to preview consult-git-grep consult-grep - consult-ripgrep-parent consult-ripgrep consult-ripgrep-case-sensitive - consult-ripgrep-unrestricted consult-z-ripgrep consult-ripgrep-thing-at-point + consult-ripgrep-parent consult-ripgrep consult-ripgrep-case-sensitive consult-ripgrep-unrestricted consult-bookmark consult-recent-file consult-xref consult-buffer-no-preview - consult--source-recent-file consult--source-project-recent-file consult--source-bookmark - :preview-key '("M-." :debounce 0.2 "C-S-n" :debounce 0.2 "C-S-p") - consult-ripgrep-thing-at-point - :initial (concat "#" (thing-at-point 'symbol)) - consult-line-thing-at-point - :initial (thing-at-point 'symbol)) + consult--source-recent-file consult--source-project-recent-file consult--source-bookmark; + :preview-key '("M-." :debounce 0.2 "C-S-n" :debounce 0.2 "C-S-p")) (defvar-local consult-toggle-preview-orig nil) (defun consult-toggle-preview () @@ -398,12 +455,46 @@ DEFS is a plist associating completion categories to commands." (format "fd --color never -t f -0 . %s" root)) "\0" t)))))))) + (defun remove-leading-hash () + "Remove a # character from the beginning of the current line. + +Designed to be used for consult commands that automatically add a # at the beginning of the minibuffer. +See `+become' and the functions that call it (e.g. `+become-consult-line')." + (interactive) + (save-excursion + (beginning-of-line) + (when (= ?# (char-after)) + (delete-forward-char 1)))) + (defun consult-project-buffer () + "Version of `consult-buffer' that only uses project-related sources." (interactive) (let ((consult-buffer-sources '(consult--project-source-project-buffer consult--project-source-project-file-recentf consult--project-source-project-file-all))) - (consult-buffer)))) + (consult-buffer))) + + ;; https://takeonrules.com/2024/06/08/adding-a-consult-function-for-visualizing-xref/ + (defvar consult--xref-history nil + "History for the `consult-recent-xref' results.") + (defun consult-recent-xref (&optional markers) + "Jump to a marker in MARKERS list (defaults to `xref--history'. + +The command supports preview of the currently selected marker position. +The symbol at point is added to the future history." + (interactive) + (consult--read + (consult--global-mark-candidates + (or markers (flatten-list xref--history))) + :prompt "Go to Xref: " + :annotate (consult--line-prefix) + :category 'consult-location + :sort nil + :require-match t + :lookup #'consult--lookup-location + :history '(:input consult--xref-history) + :add-history (thing-at-point 'symbol) + :state (consult--jump-state)))) (use-package consult-flycheck) @@ -424,6 +515,9 @@ DEFS is a plist associating completion categories to commands." (use-package consult-ls-git :bind ("C-c g f" . consult-ls-git)) +(use-package consult-vc-modified-files + :bind (:map vc-prefix-map ("f" . consult-vc-modified-files))) + (use-package consult-project-extra) (use-package marginalia @@ -435,19 +529,38 @@ DEFS is a plist associating completion categories to commands." (use-package embark :bind (("C-." . embark-act) - ("M-." . embark-dwim) + ([remap xref-find-definitions-current-list-function] . embark-dwim-beginning-of-list) + ([remap xref-find-definitions] . embark-dwim) + ([remap xref-find-definitions-other-window] . embark-dwim-other-window) ("C-c C-o" . embark-export) ("C-h b" . embark-bindings) ("C-h B" . describe-bindings) (:map minibuffer-local-map ("M-." . embark-preview) - ("C-," . embark-become)) + ("C-," . embark-become) + ("C-^" . embark-become-ripgrep-parent) + ("C-S-SPC" . embark-select)) (:map embark-become-file+buffer-map ("e" . consult-project-extra-find) ("E" . project-switch-consult-project-extra-find))) :custom (prefix-help-command 'embark-prefix-help-command) :config + (defun embark-dwim-other-window () + "Like `embark-dwim' but switch to the other window." + (interactive) + (other-window-prefix) + (embark-dwim)) + (defun embark-dwim-beginning-of-list () + "`embark-dwim' at the beginning of the current list. +With a prefix argument, moves up `current-prefix-arg' sexps first." + (interactive) + (progn + (when current-prefix-arg + (sp-backward-up-sexp current-prefix-arg)) + (sp-beginning-of-sexp) + (embark-dwim))) + (defalias 'embark-become-ripgrep-parent (kmacro "C-, ^")) (defun embark-preview () "Previews candidate in vertico buffer, unless it's a consult command" (interactive) @@ -467,10 +580,31 @@ DEFS is a plist associating completion categories to commands." ;; demand, combined with after means that this will load after embark and consult ;; See https://github.com/oantolin/embark/commit/47daded610b245caf01a97d74c940aff91fe14e2#r46010972 :demand t + :config + (defun +become (fn) + "Remove the leading # from the minibuffer, and call `FN'. +Useful with embark-become, when changing from a command that uses # as a separator, to one that doesn't." + (interactive) + (setq unread-command-events (listify-key-sequence "\C-x\C-\M-x")) + (funcall-interactively fn)) + (defun +become-consult-line () + "A version of `consult-line', designed for use with `embark-become'. +The leading # added by other consult commands is removed." + (interactive) + (+become #'consult-line)) + (defun +become-consult-line () + "A version of `consult-imenu', designed for use with `embark-become'. +The leading # added by other consult commands is removed." + (interactive) + (+become #'consult-imenu)) :bind (:map embark-consult-async-search-map + ("l" . +become-consult-line) + ("f" . consult-focus-lines) + ("i" . +become-consult-imenu) ("^" . consult-ripgrep-parent) - ("R" . consult-ripgrep-unrestricted)) + ("u" . consult-ripgrep-unrestricted) + ("c" . consult-ripgrep-case-sensitive)) :hook (embark-collect-mode . consult-preview-at-point-mode)) |