config

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

corfu-popupinfo.el (22196B)


      1 ;;; corfu-popupinfo.el --- Candidate information popup for Corfu -*- lexical-binding: t -*-
      2 
      3 ;; Copyright (C) 2021-2024 Free Software Foundation, Inc.
      4 
      5 ;; Author: Yuwei Tian <fishtai0@gmail.com>, Daniel Mendler <mail@daniel-mendler.de>
      6 ;; Maintainer: Daniel Mendler <mail@daniel-mendler.de>
      7 ;; Created: 2022
      8 ;; Version: 1.5
      9 ;; Package-Requires: ((emacs "28.1") (compat "30") (corfu "1.5"))
     10 ;; Homepage: https://github.com/minad/corfu
     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 ;; Display an information popup for completion candidate when using
     30 ;; Corfu.  The popup displays either the candidate documentation or the
     31 ;; candidate location.  The `corfu-popupinfo-mode' must be enabled
     32 ;; globally.  Set `corfu-popupinfo-delay' to nil if the info popup should
     33 ;; not update automatically.  If the popup should not appear initially,
     34 ;; but update automatically afterwards, use `(setq corfu-popupinfo-delay
     35 ;; (cons nil 1.0))'.
     36 
     37 ;; For manual toggling the commands `corfu-popupinfo-toggle',
     38 ;; `corfu-popupinfo-location' and `corfu-popupinfo-documentation' are
     39 ;; bound in the `corfu-popupinfo-map'.
     40 
     41 ;;; Code:
     42 
     43 (require 'corfu)
     44 (eval-when-compile
     45   (require 'cl-lib)
     46   (require 'subr-x))
     47 
     48 (defface corfu-popupinfo
     49   '((t :inherit corfu-default))
     50   "Face used for the info popup."
     51   :group 'corfu-faces)
     52 
     53 (defcustom corfu-popupinfo-delay '(2.0 . 1.0)
     54   "Automatically update info popup after that number of seconds.
     55 
     56 The value can be a pair of two floats to specify initial and
     57 subsequent delay.  If the value is non-nil or the car of the pair
     58 is non-nil, the popup will automatically appear for the
     59 preselected candidate.  Otherwise the popup can be requested
     60 manually via `corfu-popupinfo-toggle',
     61 `corfu-popupinfo-documentation' and `corfu-popupinfo-location'.
     62 
     63 It is *not recommended* to use a short delay or even 0, since
     64 this will create high load for Emacs.  Retrieving the
     65 documentation from the backend is usually expensive."
     66   :type '(choice (const :tag "Never" nil)
     67                  (number :tag "Delay in seconds")
     68                  (cons :tag "Two Delays"
     69                        (choice :tag "Initial   "
     70                                (choice (const nil) number))
     71                        (choice :tag "Subsequent"
     72                                (choice (const nil) number))))
     73   :group 'corfu)
     74 
     75 (defcustom corfu-popupinfo-hide t
     76   "Hide the popup during the transition between candidates."
     77   :type 'boolean
     78   :group 'corfu)
     79 
     80 (defcustom corfu-popupinfo-max-width 80
     81   "The maximum width of the info popup in characters."
     82   :type 'natnum
     83   :group 'corfu)
     84 
     85 (defcustom corfu-popupinfo-min-width 30
     86   "The minimum width of the info popup in characters."
     87   :type 'natnum
     88   :group 'corfu)
     89 
     90 (defcustom corfu-popupinfo-max-height 10
     91   "The maximum height of the info popup in characters."
     92   :type 'natnum
     93   :group 'corfu)
     94 
     95 (defcustom corfu-popupinfo-min-height 1
     96   "The minimum height of the info popup in characters."
     97   :type 'natnum
     98   :group 'corfu)
     99 
    100 (defcustom corfu-popupinfo-resize t
    101   "Resize the info popup automatically if non-nil."
    102   :type 'boolean
    103   :group 'corfu)
    104 
    105 (defcustom corfu-popupinfo-direction '(right left vertical)
    106   "Preferred directions for the popup in order."
    107   :type '(repeat
    108           (choice
    109            (const left)
    110            (const right)
    111            (const vertical)
    112            (const force-left)
    113            (const force-right)
    114            (const force-vertical)))
    115   :group 'corfu)
    116 
    117 (defvar-keymap corfu-popupinfo-map
    118   :doc "Additional keymap activated in popupinfo mode."
    119   "M-t" #'corfu-popupinfo-toggle
    120   "<remap> <corfu-info-documentation>" #'corfu-popupinfo-documentation
    121   "<remap> <corfu-info-location>" #'corfu-popupinfo-location
    122   "<remap> <scroll-other-window>" #'corfu-popupinfo-scroll-up
    123   "<remap> <scroll-other-window-down>" #'corfu-popupinfo-scroll-down
    124   "<remap> <end-of-buffer-other-window>" #'corfu-popupinfo-end
    125   "<remap> <beginning-of-buffer-other-window>" #'corfu-popupinfo-beginning)
    126 
    127 (defvar corfu-popupinfo--buffer-parameters
    128   '((truncate-partial-width-windows . nil)
    129     (truncate-lines . nil)
    130     (left-margin-width . 1)
    131     (right-margin-width . 1)
    132     (word-wrap . t)
    133     (fringe-indicator-alist (continuation))
    134     (char-property-alias-alist (face font-lock-face)))
    135   "Buffer parameters.")
    136 
    137 (defvar corfu-popupinfo--frame nil
    138   "Info popup child frame.")
    139 
    140 (defvar corfu-popupinfo--timer nil
    141   "Corfu info popup auto display timer.")
    142 
    143 (defvar corfu-popupinfo--toggle 'init
    144   "Toggle state.")
    145 
    146 (defvar corfu-popupinfo--function
    147   #'corfu-popupinfo--get-documentation
    148   "Function called to obtain documentation string.")
    149 
    150 (defvar corfu-popupinfo--candidate nil
    151   "Completion candidate for the info popup.")
    152 
    153 (defvar corfu-popupinfo--coordinates nil
    154   "Coordinates of the candidate popup.
    155 The coordinates list has the form (LEFT TOP RIGHT BOTTOM) where
    156 all values are in pixels relative to the origin.  See
    157 `frame-edges' for details.")
    158 
    159 (defvar corfu-popupinfo--lock-dir nil
    160   "Locked position direction of the info popup.")
    161 
    162 (defconst corfu-popupinfo--initial-state
    163   (mapcar
    164    (lambda (k) (cons k (symbol-value k)))
    165    '(corfu-popupinfo--candidate
    166      corfu-popupinfo--coordinates
    167      corfu-popupinfo--lock-dir
    168      corfu-popupinfo--toggle
    169      corfu-popupinfo--function))
    170   "Initial state of `corfu-popupinfo-mode'.")
    171 
    172 (defun corfu-popupinfo--visible-p (&optional frame)
    173   "Return non-nil if FRAME is visible."
    174   (setq frame (or frame corfu-popupinfo--frame))
    175   (and (frame-live-p frame) (frame-visible-p frame)))
    176 
    177 (defun corfu-popupinfo--get-location (candidate)
    178   "Get source at location of CANDIDATE."
    179   (save-excursion
    180     (let ((old-buffers (buffer-list)) (buffer nil))
    181       (unwind-protect
    182           (when-let
    183               ((extra (nth 4 completion-in-region--data))
    184                (fun (plist-get extra :company-location))
    185                ;; BUG: company-location may throw errors if location is not found
    186                (loc (ignore-errors (funcall fun candidate)))
    187                ((setq buffer
    188                       (or (and (bufferp (car loc)) (car loc))
    189                           (get-file-buffer (car loc))
    190                           (let ((inhibit-message t)
    191                                 (message-log-max nil)
    192                                 (inhibit-redisplay t)
    193                                 (enable-dir-local-variables nil)
    194                                 (enable-local-variables :safe)
    195                                 (non-essential t)
    196                                 (delay-mode-hooks t)
    197                                 (find-file-hook '(global-font-lock-mode-check-buffers)))
    198                             (find-file-noselect (car loc) t))))))
    199             (with-current-buffer buffer
    200               (save-excursion
    201                 (without-restriction
    202                   (goto-char (point-min))
    203                   (when-let ((pos (cdr loc)))
    204                     (if (bufferp (car loc))
    205                         (goto-char pos)
    206                       (forward-line (1- pos))))
    207                   (let ((beg (point)))
    208                     ;; Support a little bit of scrolling.
    209                     (forward-line (* 10 corfu-popupinfo-max-height))
    210                     (when jit-lock-mode
    211                       (jit-lock-fontify-now beg (point)))
    212                     (let ((res (buffer-substring beg (point))))
    213                       (and (not (string-blank-p res)) res)))))))
    214         (when (and buffer (not (memq buffer old-buffers)))
    215           (kill-buffer buffer))))))
    216 
    217 (defun corfu-popupinfo--get-documentation (candidate)
    218   "Get the documentation for CANDIDATE."
    219   (when-let ((extra (nth 4 completion-in-region--data))
    220              (fun (plist-get extra :company-doc-buffer))
    221              (res (save-excursion
    222                     (let ((inhibit-message t)
    223                           (message-log-max nil)
    224                           (inhibit-redisplay t)
    225                           ;; Reduce print length for elisp backend (#249)
    226                           (print-level 3)
    227                           (print-length (* corfu-popupinfo-max-width
    228                                            corfu-popupinfo-max-height)))
    229                       (funcall fun candidate)))))
    230     (with-current-buffer (or (car-safe res) res)
    231       (setq res (string-trim
    232                  (replace-regexp-in-string
    233                   "[\n\t ]*\\[back\\][\n\t ]*" ""
    234                   (buffer-string))))
    235       (and (not (string-blank-p res)) res))))
    236 
    237 (defun corfu-popupinfo--size ()
    238   "Return popup size as pair."
    239   (let* ((cw (default-font-width))
    240          (lh (default-line-height))
    241          (margin
    242           (* cw (+ (alist-get 'left-margin-width corfu-popupinfo--buffer-parameters)
    243                    (alist-get 'right-margin-width corfu-popupinfo--buffer-parameters))))
    244          (max-height (* lh corfu-popupinfo-max-height))
    245          (max-width (* cw corfu-popupinfo-max-width)))
    246     (or (when corfu-popupinfo-resize
    247           (with-current-buffer " *corfu-popupinfo*"
    248             (cl-letf* (((window-dedicated-p) nil)
    249                        ((window-buffer) (current-buffer))
    250                        (size (window-text-pixel-size
    251                               nil (point-min) (point-max)
    252                               ;; Use 3*max-height as y-limit, to take more text
    253                               ;; into account.
    254                               max-width (* 3 max-height))))
    255               ;; Check that width is not exceeded. Otherwise use full height,
    256               ;; since lines will get wrapped.
    257               (when (<= (car size) max-width)
    258                 (cons (+ margin (car size))
    259                       ;; XXX HACK: Ensure that popup has at least a height of 1,
    260                       ;; which is the minimum frame height (#261). Maybe we
    261                       ;; should ask upstream how smaller frames can be created.
    262                       ;; I only managed to create smaller frames by setting
    263                       ;; `window-safe-min-height' to 0, which feels problematic.
    264                       (min (max (cdr size) lh) max-height))))))
    265         (cons (+ margin max-width) max-height))))
    266 
    267 (defun corfu-popupinfo--frame-geometry (frame)
    268   "Return position and size geometric attributes of FRAME.
    269 
    270 The geometry represents the position and size in pixels
    271 in the form of (X Y WIDTH HEIGHT)."
    272   (pcase-let ((`(,x . ,y) (frame-position frame)))
    273     (list x y (frame-pixel-width frame) (frame-pixel-height frame))))
    274 
    275 (defun corfu-popupinfo--fits-p (size area)
    276   "Check if SIZE fits into the AREA.
    277 
    278 SIZE is in the form (WIDTH . HEIGHT).
    279 AREA is in the form (X Y WIDTH HEIGHT DIR)."
    280   (and (>= (nth 2 area) (car size)) (>= (nth 3 area) (cdr size))))
    281 
    282 (defun corfu-popupinfo--larger-p (area1 area2)
    283   "Check if AREA1 is larger than AREA2.
    284 
    285 AREA1 and AREA2 are both in the form (X Y WIDTH HEIGHT DIR)."
    286   (>= (* (nth 2 area1) (nth 3 area1)) (* (nth 2 area2) (nth 3 area2))))
    287 
    288 (defun corfu-popupinfo--area (ps)
    289   "Calculate the display area for the info popup.
    290 
    291 PS is the pixel size of the popup.  The calculated area is in the
    292 form (X Y WIDTH HEIGHT DIR)."
    293   (pcase-let*
    294       ((cw (default-font-width))
    295        (lh (default-line-height))
    296        (border (alist-get 'internal-border-width corfu--frame-parameters))
    297        (`(,_pfx ,_pfy ,pfw ,pfh)
    298         (corfu-popupinfo--frame-geometry (frame-parent corfu--frame)))
    299        (`(,cfx ,cfy ,cfw ,cfh) (corfu-popupinfo--frame-geometry corfu--frame))
    300        ;; Candidates popup below input
    301        (below (>= cfy (+ lh (cadr (window-inside-pixel-edges))
    302                          (window-tab-line-height)
    303                          (or (cdr (posn-x-y (posn-at-point (point)))) 0))))
    304        ;; Popups aligned at top
    305        (top-aligned (or below (< (cdr ps) cfh)))
    306        ;; Left display area
    307        (ahy (if top-aligned
    308                 cfy
    309               (max 0 (- (+ cfy cfh) border border (cdr ps)))))
    310        (ahh (if top-aligned
    311                 (min (- pfh cfy) (cdr ps))
    312               (min (- (+ cfy cfh) border border) (cdr ps))))
    313        (al (list (max 0 (- cfx (car ps) border)) ahy
    314                  (min (- cfx border) (car ps)) ahh 'left))
    315        ;; Right display area
    316        (arx (+ cfx cfw (- border)))
    317        (ar (list arx ahy (min (- pfw arx border border) (car ps)) ahh 'right))
    318        ;; Vertical display area
    319        (avw (min (car ps) (- pfw cfx border border)))
    320        (av (if below
    321                (list cfx (+ cfy cfh (- border)) avw (min (- pfh cfy cfh border) (cdr ps)) 'vertical)
    322              (let ((h (min (- cfy border border) (cdr ps))))
    323                (list cfx (max 0 (- cfy h border)) avw h 'vertical)))))
    324     (unless (and corfu-popupinfo--lock-dir
    325                  (corfu-popupinfo--fits-p
    326                   (cons (* cw corfu-popupinfo-min-width) (* lh corfu-popupinfo-min-height))
    327                   (pcase corfu-popupinfo--lock-dir ('left al) ('right ar) ('vertical av))))
    328       (setq corfu-popupinfo--lock-dir nil))
    329     (or
    330      (cl-loop for dir in corfu-popupinfo-direction thereis
    331               (pcase dir
    332                 ((or 'force-right (guard (eq corfu-popupinfo--lock-dir 'right))) ar)
    333                 ((or 'force-left (guard (eq corfu-popupinfo--lock-dir 'left))) al)
    334                 ((or 'force-vertical (guard (eq corfu-popupinfo--lock-dir 'vertical))) av)
    335                 ((and 'right (guard (corfu-popupinfo--fits-p ps ar))) ar)
    336                 ((and 'left (guard (corfu-popupinfo--fits-p ps al))) al)
    337                 ((and 'vertical (guard (corfu-popupinfo--fits-p ps av))) av)))
    338      (let ((ah (if (corfu-popupinfo--larger-p ar al) ar al)))
    339        (if (corfu-popupinfo--larger-p av ah) av ah)))))
    340 
    341 (defun corfu-popupinfo--show (candidate)
    342   "Show the info popup for CANDIDATE."
    343   (when corfu-popupinfo--timer
    344     (cancel-timer corfu-popupinfo--timer)
    345     (setq corfu-popupinfo--timer nil))
    346   (when (and (corfu-popupinfo--visible-p corfu--frame))
    347     (let* ((cand-changed
    348             (not (and (corfu-popupinfo--visible-p)
    349                       (corfu--equal-including-properties
    350                        candidate corfu-popupinfo--candidate))))
    351            (new-coords (frame-edges corfu--frame 'inner-edges))
    352            (coords-changed (not (equal new-coords corfu-popupinfo--coordinates))))
    353       (when cand-changed
    354         (if-let ((content (funcall corfu-popupinfo--function candidate)))
    355             (with-current-buffer (corfu--make-buffer " *corfu-popupinfo*")
    356               (with-silent-modifications
    357                 (erase-buffer)
    358                 (insert content)
    359                 (goto-char (point-min)))
    360               (dolist (var corfu-popupinfo--buffer-parameters)
    361                 (set (make-local-variable (car var)) (cdr var)))
    362               (when-let ((m (memq 'corfu-default (alist-get 'default face-remapping-alist))))
    363                 (setcar m 'corfu-popupinfo)))
    364           (corfu-popupinfo--hide)
    365           (setq cand-changed nil coords-changed nil)))
    366       (when (or cand-changed coords-changed)
    367         (pcase-let* ((border (alist-get 'internal-border-width corfu--frame-parameters))
    368                      (`(,area-x ,area-y ,area-w ,area-h ,area-d)
    369                       (corfu-popupinfo--area
    370                        (if cand-changed
    371                            (corfu-popupinfo--size)
    372                          (cons
    373                           (- (frame-pixel-width corfu-popupinfo--frame) border border)
    374                           (- (frame-pixel-height corfu-popupinfo--frame) border border)))))
    375                      (margin-quirk (not corfu-popupinfo--frame)))
    376           (setq corfu-popupinfo--frame
    377                 (corfu--make-frame corfu-popupinfo--frame
    378                                    area-x area-y area-w area-h
    379                                    " *corfu-popupinfo*")
    380                 corfu-popupinfo--toggle t
    381                 corfu-popupinfo--lock-dir area-d
    382                 corfu-popupinfo--candidate candidate
    383                 corfu-popupinfo--coordinates new-coords)
    384           ;; XXX HACK: Force margin update. For some reason, the call to
    385           ;; `set-window-buffer' in `corfu--make-frame' is not effective the
    386           ;; first time. Why does Emacs have all these quirks?
    387           (when margin-quirk
    388             (set-window-buffer
    389              (frame-root-window corfu-popupinfo--frame)
    390              " *corfu-popupinfo*")))))))
    391 
    392 (defun corfu-popupinfo--hide ()
    393   "Clear the info popup buffer content and hide it."
    394   (corfu--hide-frame corfu-popupinfo--frame))
    395 
    396 (defun corfu-popupinfo-end (&optional n)
    397   "Scroll text of info popup window to its end.
    398 
    399 If arg N is omitted or nil, scroll to end.  If a numerical value,
    400 put point N/10 of the way from the end.  If the info popup is not
    401 visible, the other window is moved to beginning or end."
    402   (interactive "P")
    403   (if (corfu-popupinfo--visible-p)
    404       (with-selected-frame corfu-popupinfo--frame
    405         (with-current-buffer " *corfu-popupinfo*"
    406           (with-no-warnings
    407             (end-of-buffer n))))
    408     (end-of-buffer-other-window n)))
    409 
    410 (defun corfu-popupinfo-beginning (&optional n)
    411   "Scroll text of info popup window to beginning of buffer.
    412 
    413 See `corfu-popupinfo-end' for the argument N."
    414   (interactive "P")
    415   (corfu-popupinfo-end (- 10 (if (numberp n) n 0))))
    416 
    417 (defun corfu-popupinfo-scroll-up (&optional n)
    418   "Scroll text of info popup window upward N lines.
    419 
    420 If ARG is omitted or nil, scroll upward by a near full screen.
    421 See `scroll-up' for details.  If the info popup is not visible,
    422 the other window is scrolled."
    423   (interactive "p")
    424   (if (corfu-popupinfo--visible-p)
    425       (with-selected-frame corfu-popupinfo--frame
    426         (with-current-buffer " *corfu-popupinfo*"
    427           (scroll-up n)))
    428     (scroll-other-window n)))
    429 
    430 (defun corfu-popupinfo-scroll-down (&optional n)
    431   "Scroll text of info popup window down N lines.
    432 
    433 See `corfu-popupinfo-scroll-up' for more details."
    434   (interactive "p")
    435   (corfu-popupinfo-scroll-up (- (or n 1))))
    436 
    437 (defun corfu-popupinfo--toggle (fun)
    438   "Set documentation getter FUN and toggle popup."
    439   (when (< corfu--index 0)
    440     (corfu-popupinfo--hide)
    441     (user-error "No candidate selected"))
    442   (setq corfu-popupinfo--toggle
    443         (not (and (corfu-popupinfo--visible-p)
    444                   (eq corfu-popupinfo--function fun))))
    445   (if (not corfu-popupinfo--toggle)
    446       (corfu-popupinfo--hide)
    447     (setq corfu-popupinfo--function fun
    448           corfu-popupinfo--candidate nil)
    449     (let ((cand (nth corfu--index corfu--candidates)))
    450       (corfu-popupinfo--show cand)
    451       (unless (corfu-popupinfo--visible-p)
    452         (user-error "No %s available for `%s'"
    453                     (car (last (split-string (symbol-name fun) "-+")))
    454                     cand)))))
    455 
    456 (defun corfu-popupinfo-documentation ()
    457   "Show or hide documentation in popup.
    458 Behaves like `corfu-popupinfo-toggle'."
    459   (interactive)
    460   (corfu-popupinfo--toggle #'corfu-popupinfo--get-documentation))
    461 
    462 (defun corfu-popupinfo-location ()
    463   "Show or hide location in popup.
    464 Behaves like `corfu-popupinfo-toggle'."
    465   (interactive)
    466   (corfu-popupinfo--toggle #'corfu-popupinfo--get-location))
    467 
    468 (defun corfu-popupinfo-toggle ()
    469   "Toggle the info popup display or hide.
    470 
    471 When using this command to manually hide the info popup, it will
    472 not be displayed until this command is called again, even if
    473 `corfu-popupinfo-delay' is non-nil."
    474   (interactive)
    475   (corfu-popupinfo--toggle corfu-popupinfo--function))
    476 
    477 ;;;###autoload
    478 (define-minor-mode corfu-popupinfo-mode
    479   "Corfu info popup minor mode."
    480   :global t :group 'corfu)
    481 
    482 (cl-defmethod corfu--exhibit :after (&context (corfu-popupinfo-mode (eql t)) &optional _auto)
    483   (when completion-in-region-mode
    484     (setf (alist-get #'corfu-popupinfo-mode minor-mode-overriding-map-alist)
    485           corfu-popupinfo-map)
    486     (when corfu-popupinfo--timer
    487       (cancel-timer corfu-popupinfo--timer)
    488       (setq corfu-popupinfo--timer nil))
    489     (if (and (>= corfu--index 0) (corfu-popupinfo--visible-p corfu--frame))
    490         (let ((cand (nth corfu--index corfu--candidates)))
    491           (if-let ((delay (if (consp corfu-popupinfo-delay)
    492                               (funcall (if (eq corfu-popupinfo--toggle 'init) #'car #'cdr)
    493                                        corfu-popupinfo-delay)
    494                             corfu-popupinfo-delay))
    495                    (corfu-popupinfo--toggle))
    496               (if (or (<= delay 0)
    497                       (and (equal cand corfu-popupinfo--candidate)
    498                            (corfu-popupinfo--visible-p)))
    499                   (corfu-popupinfo--show cand)
    500                 (when (corfu-popupinfo--visible-p)
    501                   (cond
    502                    (corfu-popupinfo-hide
    503                     (corfu-popupinfo--hide))
    504                    (corfu-popupinfo--candidate
    505                     (corfu-popupinfo--show corfu-popupinfo--candidate))))
    506                 (setq corfu-popupinfo--timer
    507                     (run-at-time delay nil #'corfu-popupinfo--show cand)))
    508             (unless (equal cand corfu-popupinfo--candidate)
    509               (corfu-popupinfo--hide))))
    510       (corfu-popupinfo--hide))))
    511 
    512 (cl-defmethod corfu--teardown :before (_buf &context (corfu-popupinfo-mode (eql t)))
    513   (corfu-popupinfo--hide)
    514   (cl-loop for (k . v) in corfu-popupinfo--initial-state do (set k v))
    515   (cl-callf2 assq-delete-all #'corfu-popupinfo-mode minor-mode-overriding-map-alist))
    516 
    517 ;; Do not show Corfu commands with M-X
    518 (dolist (sym '(corfu-popupinfo-scroll-down corfu-popupinfo-scroll-up
    519                corfu-popupinfo-documentation corfu-popupinfo-location
    520                corfu-popupinfo-beginning corfu-popupinfo-end
    521                corfu-popupinfo-toggle))
    522   (put sym 'completion-predicate #'ignore))
    523 
    524 (provide 'corfu-popupinfo)
    525 ;;; corfu-popupinfo.el ends here