config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

vertico-suspend.el (4720B)


      1 ;;; vertico-suspend.el --- Suspend the current Vertico session -*- lexical-binding: t -*-
      2 
      3 ;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
      4 
      5 ;; Author: Daniel Mendler <mail@daniel-mendler.de>
      6 ;; Maintainer: Daniel Mendler <mail@daniel-mendler.de>
      7 ;; Created: 2023
      8 ;; Version: 1.8
      9 ;; Package-Requires: ((emacs "27.1") (compat "29.1.4.4") (vertico "1.8"))
     10 ;; Homepage: https://github.com/minad/vertico
     11 
     12 ;; This file is part of GNU Emacs.
     13 
     14 ;; This program is free software: you can redistribute it and/or modify
     15 ;; it under the terms of the GNU General Public License as published by
     16 ;; the Free Software Foundation, either version 3 of the License, or
     17 ;; (at your option) any later version.
     18 
     19 ;; This program is distributed in the hope that it will be useful,
     20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     22 ;; GNU General Public License for more details.
     23 
     24 ;; You should have received a copy of the GNU General Public License
     25 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
     26 
     27 ;;; Commentary:
     28 
     29 ;; This package is a Vertico extension providing the `vertico-suspend'
     30 ;; command to suspend the current Vertico completion session.  If
     31 ;; `vertico-suspend' is called from within the currently active
     32 ;; Vertico minibuffer, the completion session is suspended.  Otherwise
     33 ;; the last session is restored.  It is possible to suspend multiple
     34 ;; nested Vertico sessions.  Note that `vertico-suspend' requires that
     35 ;; recursive minibuffers are enabled by setting the customizable
     36 ;; variable `enable-recursive-minibuffers' to t.
     37 ;;
     38 ;; (keymap-global-set "M-S" #'vertico-suspend)
     39 ;;
     40 ;; See also the related extension `vertico-repeat', which uses a
     41 ;; different technique, storing a completion session history.
     42 ;;
     43 ;; There exists a small issue with `vertico-suspend'.  The setting
     44 ;; `echo-keystrokes' does not work.  Unfortunately this cannot be
     45 ;; fixed without modifying the C source of Emacs, since Emacs forcibly
     46 ;; disables echo if a minibuffer is active.
     47 
     48 ;;; Code:
     49 
     50 (require 'vertico)
     51 
     52 (defvar vertico-buffer--restore)
     53 (declare-function vertico-buffer-mode "ext:vertico-buffer")
     54 (defvar-local vertico-suspend--ov nil)
     55 
     56 ;;;###autoload
     57 (defun vertico-suspend ()
     58   "Suspend the current completion session.
     59 If the command is invoked from within the Vertico minibuffer, the
     60 current session is suspended.  If the command is invoked from
     61 outside the minibuffer, the active minibuffer is either selected
     62 or the latest completion session is restored."
     63   (interactive)
     64   (unless enable-recursive-minibuffers
     65     (user-error "Recursive minibuffers must be enabled"))
     66   (advice-add #'set-minibuffer-message :around #'vertico-suspend--message)
     67   (if-let ((win (active-minibuffer-window))
     68            (buf (window-buffer win))
     69            ((buffer-local-value 'vertico--input buf)))
     70       (cond
     71        ((minibufferp)
     72         (add-hook 'pre-redisplay-functions #'vertico-suspend--unselect nil 'local)
     73         (setq vertico-suspend--ov (make-overlay (point-min) (point-max) nil t t))
     74         (overlay-put vertico-suspend--ov 'invisible t)
     75         (overlay-put vertico-suspend--ov 'priority 1000)
     76         (overlay-put vertico--candidates-ov 'before-string nil)
     77         (overlay-put vertico--candidates-ov 'after-string nil)
     78         (set-window-parameter win 'no-other-window t)
     79         (when (bound-and-true-p vertico-buffer-mode)
     80           (vertico-buffer-mode -1)
     81           (setq vertico-buffer--restore #'ignore))
     82         (vertico-suspend--unselect))
     83        (t
     84         (select-window win)
     85         (set-window-parameter win 'no-other-window nil)
     86         (remove-hook 'pre-redisplay-functions #'vertico-suspend--unselect 'local)
     87         (when vertico-suspend--ov
     88           (delete-overlay vertico-suspend--ov)
     89           (setq vertico-suspend--ov nil))
     90         (when (eq #'ignore (bound-and-true-p vertico-buffer--restore))
     91           (setq vertico-buffer--restore nil)
     92           (vertico-buffer-mode 1))))
     93     (user-error "No Vertico session to suspend or resume")))
     94 
     95 (defun vertico-suspend--unselect (&rest _)
     96   "Ensure that suspended minibuffer is not selected."
     97   (let ((win (get-buffer-window)))
     98     (when (eq win (selected-window))
     99       (unless (frame-root-window-p win)
    100         (window-resize win (- (window-pixel-height win)) nil nil 'pixelwise))
    101       (select-window (minibuffer-selected-window) t))))
    102 
    103 (defun vertico-suspend--message (&rest app)
    104   "Apply APP in non-suspended minibuffers, otherwise bail out."
    105   (when-let ((win (active-minibuffer-window))
    106              ((not (buffer-local-value 'vertico-suspend--ov (window-buffer win)))))
    107     (apply app)))
    108 
    109 (provide 'vertico-suspend)
    110 ;;; vertico-suspend.el ends here