branch: externals/vertico commit b06348be7a48ca02cd75f7fc1587b1cce9ebebb9 Author: Daniel Mendler <m...@daniel-mendler.de> Commit: Daniel Mendler <m...@daniel-mendler.de>
Add Vertico extensions --- extensions/vertico-buffer.el | 97 +++++++++++++++++++++++++++++++++++++++++++ extensions/vertico-repeat.el | 81 ++++++++++++++++++++++++++++++++++++ extensions/vertico-reverse.el | 72 ++++++++++++++++++++++++++++++++ 3 files changed, 250 insertions(+) diff --git a/extensions/vertico-buffer.el b/extensions/vertico-buffer.el new file mode 100644 index 0000000..dab789b --- /dev/null +++ b/extensions/vertico-buffer.el @@ -0,0 +1,97 @@ +;;; vertico-buffer.el --- Display Vertico in a buffer instead of the minibuffer -*- lexical-binding: t -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This package is a Vertico extension, which allows to display Vertico +;; in a buffer instead of the minibuffer. The buffer display can be enabled +;; by the `vertico-buffer-mode'. + +;;; Code: + +(require 'vertico) + +(defvar-local vertico-buffer--overlay nil) + +(defcustom vertico-buffer-hide-prompt nil + "Hide the prompt in the minibuffer." + :type 'boolean + :group 'vertico) + +(defvar vertico-buffer-action + `(display-buffer-in-side-window + (window-parameters + (mode-line-format . mode-line-buffer-identification) + (header-line-format . (:eval (vertico-buffer--prompt)))) + (window-height . ,(+ 3 vertico-count)) + (side . bottom) + (slot . -1)) + "Display action for the Vertico buffer.") + +(defun vertico-buffer--prompt () + "Return minibuffer prompt string, to be used as `header-line-format'." + (with-selected-window (active-minibuffer-window) + (let ((str (buffer-string)) + (pt (point))) + (if (= pt (point-max)) + (concat str #(" " 0 1 (face (:inverse-video t)))) + (setq pt (max (minibuffer-prompt-end) pt)) + (put-text-property (1- pt) pt 'face '(:inverse-video t) str) + str)))) + +(defun vertico-buffer--display (lines) + "Display LINES in buffer." + (let ((buffer (get-buffer-create + (if (= 1 (recursion-depth)) + " *Vertico*" + (format " *Vertico [%s]*" (1- (recursion-depth))))))) + (with-current-buffer buffer + (setq-local display-line-numbers nil + truncate-lines nil + show-trailing-whitespace nil + inhibit-modification-hooks t) + (erase-buffer) + (insert (string-join lines)) + (goto-char (point-min))) + (display-buffer buffer vertico-buffer-action))) + +(defun vertico-buffer--setup () + "Setup minibuffer overlay, which pushes the minibuffer content down." + (when vertico-buffer-hide-prompt + (setq vertico-buffer--overlay (make-overlay (point-max) (point-max) nil t t)) + (overlay-put vertico-buffer--overlay 'window (selected-window)) + (overlay-put vertico-buffer--overlay 'priority 1000) + (overlay-put vertico-buffer--overlay 'after-string "\n\n") + (set-window-vscroll nil 100) + (window-resize nil (- (window-height))))) + +;;;###autoload +(define-minor-mode vertico-buffer-mode + "Display Vertico in a buffer instead of the minibuffer." + :global t + (cond + (vertico-buffer-mode + (advice-add #'vertico--display-candidates :override #'vertico-buffer--display) + (advice-add #'vertico--setup :after #'vertico-buffer--setup)) + (t + (advice-remove #'vertico--display-candidates #'vertico-buffer--display) + (advice-remove #'vertico--setup #'vertico-buffer--setup)))) + +(provide 'vertico-buffer) +;;; vertico-buffer.el ends here diff --git a/extensions/vertico-repeat.el b/extensions/vertico-repeat.el new file mode 100644 index 0000000..5cce094 --- /dev/null +++ b/extensions/vertico-repeat.el @@ -0,0 +1,81 @@ +;;; vertico-repeat.el --- Repeat the last Vertico session -*- lexical-binding: t -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This package is a Vertico extension, which allows to repeat the last +;; Vertico session via the `vertico-repeat' command. + +;;; Code: + +(require 'vertico) + +(defvar vertico-repeat--input nil) +(defvar vertico-repeat--command nil) +(defvar vertico-repeat--candidate nil) + +(defun vertico-repeat--save-input () + "Save current minibuffer content for `vertico-repeat'." + (setq vertico-repeat--input (minibuffer-contents))) + +(defun vertico-repeat--save-candidate () + "Save currently selected candidate for `vertico-repeat'." + (setq vertico-repeat--candidate + (and vertico--lock-candidate + (>= vertico--index 0) + (nth vertico--index vertico--candidates)))) + +(defun vertico-repeat--save () + "Save Vertico status for `vertico-repeat'." + (unless (eq real-this-command #'vertico-repeat) + (setq vertico-repeat--command (if (boundp 'minibuffer-current-command) + minibuffer-current-command + this-command) + vertico-repeat--input "" + vertico-repeat--candidate nil)) + (add-hook 'post-command-hook #'vertico-repeat--save-input nil 'local) + (add-hook 'minibuffer-exit-hook #'vertico-repeat--save-candidate nil 'local)) + +(defun vertico-repeat--restore () + "Restore Vertico status for `vertico-repeat'." + (delete-minibuffer-contents) + (insert vertico-repeat--input) + (when vertico-repeat--candidate + (run-at-time 0 nil + (lambda () + (when-let (idx (seq-position vertico--candidates vertico-repeat--candidate)) + (setq vertico--index idx + vertico--lock-candidate t) + (vertico--exhibit)))))) + +;;;###autoload +(defun vertico-repeat () + "Repeat last Vertico completion session." + (interactive) + (unless vertico-repeat--command + (user-error "No repeatable Vertico session")) + (minibuffer-with-setup-hook + #'vertico-repeat--restore + (command-execute (setq this-command vertico-repeat--command)))) + +;;;###autoload +(advice-add #'vertico--setup :after #'vertico-repeat--save) + +(provide 'vertico-repeat) +;;; vertico-repeat.el ends here diff --git a/extensions/vertico-reverse.el b/extensions/vertico-reverse.el new file mode 100644 index 0000000..0c51cec --- /dev/null +++ b/extensions/vertico-reverse.el @@ -0,0 +1,72 @@ +;;; vertico-reverse.el --- Reverse the Vertico display -*- lexical-binding: t -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; This program is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see <http://www.gnu.org/licenses/>. + +;;; Commentary: + +;; This package is a Vertico extension, which reverses the list of candidates. + +;;; Code: + +(require 'vertico) + +(defvar vertico-reverse-map + (let ((map (make-composed-keymap nil vertico-map))) + (define-key map [remap beginning-of-buffer] #'vertico-last) + (define-key map [remap minibuffer-beginning-of-buffer] #'vertico-last) + (define-key map [remap end-of-buffer] #'vertico-first) + (define-key map [remap scroll-down-command] #'vertico-scroll-up) + (define-key map [remap scroll-up-command] #'vertico-scroll-down) + (define-key map [remap next-line] #'vertico-previous) + (define-key map [remap previous-line] #'vertico-next) + (define-key map [remap next-line-or-history-element] #'vertico-previous) + (define-key map [remap previous-line-or-history-element] #'vertico-next) + (define-key map [remap backward-paragraph] #'vertico-next-group) + (define-key map [remap forward-paragraph] #'vertico-previous-group) + map) + "Vertico keymap adapted to reversed candidate order.") + +(defun vertico-reverse--display (lines) + "Display LINES in reverse." + (move-overlay vertico--candidates-ov (point-min) (point-min)) + (let ((string (concat + (unless (eq vertico-resize t) + (make-string (- vertico-count (length lines)) ?\n)) + (apply #'concat (nreverse lines))))) + (add-face-text-property 0 (length string) 'default 'append string) + (overlay-put vertico--candidates-ov 'before-string string)) + (vertico--resize-window (length lines))) + +(defun vertico-reverse--setup () + "Setup reverse keymap." + (use-local-map vertico-reverse-map)) + +;;;###autoload +(define-minor-mode vertico-reverse-mode + "Reverse the Vertico display." + :global t + (cond + (vertico-reverse-mode + (advice-add #'vertico--display-candidates :override #'vertico-reverse--display) + (advice-add #'vertico--setup :after #'vertico-reverse--setup)) + (t + (advice-remove #'vertico--display-candidates #'vertico-reverse--display) + (advice-remove #'vertico--setup #'vertico-reverse--setup)))) + +(provide 'vertico-reverse) +;;; vertico-reverse.el ends here