config

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

corfu-popupinfo.el (22107B)


      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.3
      9 ;; Package-Requires: ((emacs "27.1") (compat "29.1.4.4") (corfu "1.3"))
     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   "Buffer parameters.")
    135 
    136 (defvar corfu-popupinfo--frame nil
    137   "Info popup child frame.")
    138 
    139 (defvar corfu-popupinfo--timer nil
    140   "Corfu info popup auto display timer.")
    141 
    142 (defvar corfu-popupinfo--toggle 'init
    143   "Toggle state.")
    144 
    145 (defvar corfu-popupinfo--function
    146   #'corfu-popupinfo--get-documentation
    147   "Function called to obtain documentation string.")
    148 
    149 (defvar corfu-popupinfo--candidate nil
    150   "Completion candidate for the info popup.")
    151 
    152 (defvar corfu-popupinfo--coordinates nil
    153   "Coordinates of the candidate popup.
    154 The coordinates list has the form (LEFT TOP RIGHT BOTTOM) where
    155 all values are in pixels relative to the origin.  See
    156 `frame-edges' for details.")
    157 
    158 (defvar corfu-popupinfo--lock-dir nil
    159   "Locked position direction of the info popup.")
    160 
    161 (defconst corfu-popupinfo--initial-state
    162   (mapcar
    163    (lambda (k) (cons k (symbol-value k)))
    164    '(corfu-popupinfo--candidate
    165      corfu-popupinfo--coordinates
    166      corfu-popupinfo--lock-dir
    167      corfu-popupinfo--toggle
    168      corfu-popupinfo--function))
    169   "Initial state of `corfu-popupinfo-mode'.")
    170 
    171 (defun corfu-popupinfo--visible-p (&optional frame)
    172   "Return non-nil if FRAME is visible."
    173   (setq frame (or frame corfu-popupinfo--frame))
    174   (and (frame-live-p frame) (frame-visible-p frame)))
    175 
    176 (defun corfu-popupinfo--get-location (candidate)
    177   "Get source at location of CANDIDATE."
    178   (save-excursion
    179     (let ((old-buffers (buffer-list)) (buffer nil))
    180       (unwind-protect
    181           (when-let
    182               ((extra (nth 4 completion-in-region--data))
    183                (fun (plist-get extra :company-location))
    184                ;; BUG: company-location may throw errors if location is not found
    185                (loc (ignore-errors (funcall fun candidate)))
    186                ((setq buffer
    187                       (or (and (bufferp (car loc)) (car loc))
    188                           (get-file-buffer (car loc))
    189                           (let ((inhibit-message t)
    190                                 (message-log-max nil)
    191                                 (inhibit-redisplay t)
    192                                 (enable-dir-local-variables nil)
    193                                 (enable-local-variables :safe)
    194                                 (non-essential t)
    195                                 (delay-mode-hooks t)
    196                                 (find-file-hook '(global-font-lock-mode-check-buffers)))
    197                             (find-file-noselect (car loc) t))))))
    198             (with-current-buffer buffer
    199               (save-excursion
    200                 (without-restriction
    201                   (goto-char (point-min))
    202                   (when-let ((pos (cdr loc)))
    203                     (if (bufferp (car loc))
    204                         (goto-char pos)
    205                       (forward-line (1- pos))))
    206                   (let ((beg (point)))
    207                     ;; Support a little bit of scrolling.
    208                     (forward-line (* 10 corfu-popupinfo-max-height))
    209                     (when jit-lock-mode
    210                       (jit-lock-fontify-now beg (point)))
    211                     (let ((res (buffer-substring beg (point))))
    212                       (and (not (string-blank-p res)) res)))))))
    213         (when (and buffer (not (memq buffer old-buffers)))
    214           (kill-buffer buffer))))))
    215 
    216 (defun corfu-popupinfo--get-documentation (candidate)
    217   "Get the documentation for CANDIDATE."
    218   (when-let ((extra (nth 4 completion-in-region--data))
    219              (fun (plist-get extra :company-doc-buffer))
    220              (res (save-excursion
    221                     (let ((inhibit-message t)
    222                           (message-log-max nil)
    223                           (inhibit-redisplay t)
    224                           ;; Reduce print length for elisp backend (#249)
    225                           (print-level 3)
    226                           (print-length (* corfu-popupinfo-max-width
    227                                            corfu-popupinfo-max-height)))
    228                       (funcall fun candidate)))))
    229     (with-current-buffer (or (car-safe res) res)
    230       (setq res (string-trim
    231                  (replace-regexp-in-string
    232                   "[\n\t ]*\\[back\\][\n\t ]*" ""
    233                   (buffer-string))))
    234       (and (not (string-blank-p res)) res))))
    235 
    236 (defun corfu-popupinfo--size ()
    237   "Return popup size as pair."
    238   (let* ((cw (default-font-width))
    239          (lh (default-line-height))
    240          (margin
    241           (* cw (+ (alist-get 'left-margin-width corfu-popupinfo--buffer-parameters)
    242                    (alist-get 'right-margin-width corfu-popupinfo--buffer-parameters))))
    243          (max-height (* lh corfu-popupinfo-max-height))
    244          (max-width (* cw corfu-popupinfo-max-width)))
    245     (or (when corfu-popupinfo-resize
    246           (with-current-buffer " *corfu-popupinfo*"
    247             (cl-letf* (((window-dedicated-p) nil)
    248                        ((window-buffer) (current-buffer))
    249                        (size (window-text-pixel-size
    250                               nil (point-min) (point-max)
    251                               ;; Use 3*max-height as y-limit, to take more text
    252                               ;; into account.
    253                               max-width (* 3 max-height))))
    254               ;; Check that width is not exceeded. Otherwise use full height,
    255               ;; since lines will get wrapped.
    256               (when (<= (car size) max-width)
    257                 (cons (+ margin (car size))
    258                       ;; XXX HACK: Ensure that popup has at least a height of 1,
    259                       ;; which is the minimum frame height (#261). Maybe we
    260                       ;; should ask upstream how smaller frames can be created.
    261                       ;; I only managed to create smaller frames by setting
    262                       ;; `window-safe-min-height' to 0, which feels problematic.
    263                       (min (max (cdr size) lh) max-height))))))
    264         (cons (+ margin max-width) max-height))))
    265 
    266 (defun corfu-popupinfo--frame-geometry (frame)
    267   "Return position and size geometric attributes of FRAME.
    268 
    269 The geometry represents the position and size in pixels
    270 in the form of (X Y WIDTH HEIGHT)."
    271   (pcase-let ((`(,x . ,y) (frame-position frame)))
    272     (list x y (frame-pixel-width frame) (frame-pixel-height frame))))
    273 
    274 (defun corfu-popupinfo--fits-p (size area)
    275   "Check if SIZE fits into the AREA.
    276 
    277 SIZE is in the form (WIDTH . HEIGHT).
    278 AREA is in the form (X Y WIDTH HEIGHT DIR)."
    279   (and (>= (nth 2 area) (car size)) (>= (nth 3 area) (cdr size))))
    280 
    281 (defun corfu-popupinfo--larger-p (area1 area2)
    282   "Check if AREA1 is larger than AREA2.
    283 
    284 AREA1 and AREA2 are both in the form (X Y WIDTH HEIGHT DIR)."
    285   (>= (* (nth 2 area1) (nth 3 area1)) (* (nth 2 area2) (nth 3 area2))))
    286 
    287 (defun corfu-popupinfo--area (ps)
    288   "Calculate the display area for the info popup.
    289 
    290 PS is the pixel size of the popup.  The calculated area is in the
    291 form (X Y WIDTH HEIGHT DIR)."
    292   (pcase-let*
    293       ((cw (default-font-width))
    294        (lh (default-line-height))
    295        (border (alist-get 'internal-border-width corfu--frame-parameters))
    296        (`(,_pfx ,_pfy ,pfw ,pfh)
    297         (corfu-popupinfo--frame-geometry (frame-parent corfu--frame)))
    298        (`(,cfx ,cfy ,cfw ,cfh) (corfu-popupinfo--frame-geometry corfu--frame))
    299        ;; Candidates popup below input
    300        (below (>= cfy (+ lh (cadr (window-inside-pixel-edges))
    301                          (window-tab-line-height)
    302                          (or (cdr (posn-x-y (posn-at-point (point)))) 0))))
    303        ;; Popups aligned at top
    304        (top-aligned (or below (< (cdr ps) cfh)))
    305        ;; Left display area
    306        (ahy (if top-aligned
    307                 cfy
    308               (max 0 (- (+ cfy cfh) border border (cdr ps)))))
    309        (ahh (if top-aligned
    310                 (min (- pfh cfy) (cdr ps))
    311               (min (- (+ cfy cfh) border border) (cdr ps))))
    312        (al (list (max 0 (- cfx (car ps) border)) ahy
    313                  (min (- cfx border) (car ps)) ahh 'left))
    314        ;; Right display area
    315        (arx (+ cfx cfw (- border)))
    316        (ar (list arx ahy (min (- pfw arx border border) (car ps)) ahh 'right))
    317        ;; Vertical display area
    318        (avw (min (car ps) (- pfw cfx border border)))
    319        (av (if below
    320                (list cfx (+ cfy cfh (- border)) avw (min (- pfh cfy cfh border) (cdr ps)) 'vertical)
    321              (let ((h (min (- cfy border border) (cdr ps))))
    322                (list cfx (max 0 (- cfy h border)) avw h 'vertical)))))
    323     (unless (and corfu-popupinfo--lock-dir
    324                  (corfu-popupinfo--fits-p
    325                   (cons (* cw corfu-popupinfo-min-width) (* lh corfu-popupinfo-min-height))
    326                   (pcase corfu-popupinfo--lock-dir ('left al) ('right ar) ('vertical av))))
    327       (setq corfu-popupinfo--lock-dir nil))
    328     (or
    329      (cl-loop for dir in corfu-popupinfo-direction thereis
    330               (pcase dir
    331                 ((or 'force-right (guard (eq corfu-popupinfo--lock-dir 'right))) ar)
    332                 ((or 'force-left (guard (eq corfu-popupinfo--lock-dir 'left))) al)
    333                 ((or 'force-vertical (guard (eq corfu-popupinfo--lock-dir 'vertical))) av)
    334                 ((and 'right (guard (corfu-popupinfo--fits-p ps ar))) ar)
    335                 ((and 'left (guard (corfu-popupinfo--fits-p ps al))) al)
    336                 ((and 'vertical (guard (corfu-popupinfo--fits-p ps av))) av)))
    337      (let ((ah (if (corfu-popupinfo--larger-p ar al) ar al)))
    338        (if (corfu-popupinfo--larger-p av ah) av ah)))))
    339 
    340 (defun corfu-popupinfo--show (candidate)
    341   "Show the info popup for CANDIDATE."
    342   (when corfu-popupinfo--timer
    343     (cancel-timer corfu-popupinfo--timer)
    344     (setq corfu-popupinfo--timer nil))
    345   (when (and (corfu-popupinfo--visible-p corfu--frame))
    346     (let* ((cand-changed
    347             (not (and (corfu-popupinfo--visible-p)
    348                       (equal candidate corfu-popupinfo--candidate))))
    349            (new-coords (frame-edges corfu--frame 'inner-edges))
    350            (coords-changed (not (equal new-coords corfu-popupinfo--coordinates))))
    351       (when cand-changed
    352         (if-let ((content (funcall corfu-popupinfo--function candidate)))
    353             (with-current-buffer (corfu--make-buffer " *corfu-popupinfo*")
    354               (with-silent-modifications
    355                 (erase-buffer)
    356                 (insert content)
    357                 (goto-char (point-min)))
    358               (dolist (var corfu-popupinfo--buffer-parameters)
    359                 (set (make-local-variable (car var)) (cdr var)))
    360               (when-let ((m (memq 'corfu-default (alist-get 'default face-remapping-alist))))
    361                 (setcar m 'corfu-popupinfo)))
    362           (corfu-popupinfo--hide)
    363           (setq cand-changed nil coords-changed nil)))
    364       (when (or cand-changed coords-changed)
    365         (pcase-let* ((border (alist-get 'internal-border-width corfu--frame-parameters))
    366                      (`(,area-x ,area-y ,area-w ,area-h ,area-d)
    367                       (corfu-popupinfo--area
    368                        (if cand-changed
    369                            (corfu-popupinfo--size)
    370                          (cons
    371                           (- (frame-pixel-width corfu-popupinfo--frame) border border)
    372                           (- (frame-pixel-height corfu-popupinfo--frame) border border)))))
    373                      (margin-quirk (not corfu-popupinfo--frame)))
    374           (setq corfu-popupinfo--frame
    375                 (corfu--make-frame corfu-popupinfo--frame
    376                                    area-x area-y area-w area-h
    377                                    " *corfu-popupinfo*")
    378                 corfu-popupinfo--toggle t
    379                 corfu-popupinfo--lock-dir area-d
    380                 corfu-popupinfo--candidate candidate
    381                 corfu-popupinfo--coordinates new-coords)
    382           ;; XXX HACK: Force margin update. For some reason, the call to
    383           ;; `set-window-buffer' in `corfu--make-frame' is not effective the
    384           ;; first time. Why does Emacs have all these quirks?
    385           (when margin-quirk
    386             (set-window-buffer
    387              (frame-root-window corfu-popupinfo--frame)
    388              " *corfu-popupinfo*")))))))
    389 
    390 (defun corfu-popupinfo--hide ()
    391   "Clear the info popup buffer content and hide it."
    392   (corfu--hide-frame corfu-popupinfo--frame))
    393 
    394 (defun corfu-popupinfo-end (&optional n)
    395   "Scroll text of info popup window to its end.
    396 
    397 If arg N is omitted or nil, scroll to end.  If a numerical value,
    398 put point N/10 of the way from the end.  If the info popup is not
    399 visible, the other window is moved to beginning or end."
    400   (interactive "P")
    401   (if (corfu-popupinfo--visible-p)
    402       (with-selected-frame corfu-popupinfo--frame
    403         (with-current-buffer " *corfu-popupinfo*"
    404           (with-no-warnings
    405             (end-of-buffer n))))
    406     (end-of-buffer-other-window n)))
    407 
    408 (defun corfu-popupinfo-beginning (&optional n)
    409   "Scroll text of info popup window to beginning of buffer.
    410 
    411 See `corfu-popupinfo-end' for the argument N."
    412   (interactive "P")
    413   (corfu-popupinfo-end (- 10 (if (numberp n) n 0))))
    414 
    415 (defun corfu-popupinfo-scroll-up (&optional n)
    416   "Scroll text of info popup window upward N lines.
    417 
    418 If ARG is omitted or nil, scroll upward by a near full screen.
    419 See `scroll-up' for details.  If the info popup is not visible,
    420 the other window is scrolled."
    421   (interactive "p")
    422   (if (corfu-popupinfo--visible-p)
    423       (with-selected-frame corfu-popupinfo--frame
    424         (with-current-buffer " *corfu-popupinfo*"
    425           (scroll-up n)))
    426     (scroll-other-window n)))
    427 
    428 (defun corfu-popupinfo-scroll-down (&optional n)
    429   "Scroll text of info popup window down N lines.
    430 
    431 See `corfu-popupinfo-scroll-up' for more details."
    432   (interactive "p")
    433   (corfu-popupinfo-scroll-up (- (or n 1))))
    434 
    435 (defun corfu-popupinfo--toggle (fun)
    436   "Set documentation getter FUN and toggle popup."
    437   (when (< corfu--index 0)
    438     (corfu-popupinfo--hide)
    439     (user-error "No candidate selected"))
    440   (setq corfu-popupinfo--toggle
    441         (not (and (corfu-popupinfo--visible-p)
    442                   (eq corfu-popupinfo--function fun))))
    443   (if (not corfu-popupinfo--toggle)
    444       (corfu-popupinfo--hide)
    445     (setq corfu-popupinfo--function fun
    446           corfu-popupinfo--candidate nil)
    447     (let ((cand (nth corfu--index corfu--candidates)))
    448       (corfu-popupinfo--show cand)
    449       (unless (corfu-popupinfo--visible-p)
    450         (user-error "No %s available for `%s'"
    451                     (car (last (split-string (symbol-name fun) "-+")))
    452                     cand)))))
    453 
    454 (defun corfu-popupinfo-documentation ()
    455   "Show or hide documentation in popup.
    456 Behaves like `corfu-popupinfo-toggle'."
    457   (interactive)
    458   (corfu-popupinfo--toggle #'corfu-popupinfo--get-documentation))
    459 
    460 (defun corfu-popupinfo-location ()
    461   "Show or hide location in popup.
    462 Behaves like `corfu-popupinfo-toggle'."
    463   (interactive)
    464   (corfu-popupinfo--toggle #'corfu-popupinfo--get-location))
    465 
    466 (defun corfu-popupinfo-toggle ()
    467   "Toggle the info popup display or hide.
    468 
    469 When using this command to manually hide the info popup, it will
    470 not be displayed until this command is called again, even if
    471 `corfu-popupinfo-delay' is non-nil."
    472   (interactive)
    473   (corfu-popupinfo--toggle corfu-popupinfo--function))
    474 
    475 ;;;###autoload
    476 (define-minor-mode corfu-popupinfo-mode
    477   "Corfu info popup minor mode."
    478   :global t :group 'corfu)
    479 
    480 (cl-defmethod corfu--exhibit :after (&context (corfu-popupinfo-mode (eql t)) &optional _auto)
    481   (when completion-in-region-mode
    482     (setf (alist-get #'corfu-popupinfo-mode minor-mode-overriding-map-alist)
    483           corfu-popupinfo-map)
    484     (when corfu-popupinfo--timer
    485       (cancel-timer corfu-popupinfo--timer)
    486       (setq corfu-popupinfo--timer nil))
    487     (if (and (>= corfu--index 0) (corfu-popupinfo--visible-p corfu--frame))
    488         (let ((cand (nth corfu--index corfu--candidates)))
    489           (if-let ((delay (if (consp corfu-popupinfo-delay)
    490                               (funcall (if (eq corfu-popupinfo--toggle 'init) #'car #'cdr)
    491                                        corfu-popupinfo-delay)
    492                             corfu-popupinfo-delay))
    493                    (corfu-popupinfo--toggle))
    494               (if (or (<= delay 0)
    495                       (and (equal cand corfu-popupinfo--candidate)
    496                            (corfu-popupinfo--visible-p)))
    497                   (corfu-popupinfo--show cand)
    498                 (when (corfu-popupinfo--visible-p)
    499                   (cond
    500                    (corfu-popupinfo-hide
    501                     (corfu-popupinfo--hide))
    502                    (corfu-popupinfo--candidate
    503                     (corfu-popupinfo--show corfu-popupinfo--candidate))))
    504                 (setq corfu-popupinfo--timer
    505                     (run-at-time delay nil #'corfu-popupinfo--show cand)))
    506             (unless (equal cand corfu-popupinfo--candidate)
    507               (corfu-popupinfo--hide))))
    508       (corfu-popupinfo--hide))))
    509 
    510 (cl-defmethod corfu--teardown :before (_buf &context (corfu-popupinfo-mode (eql t)))
    511   (corfu-popupinfo--hide)
    512   (cl-loop for (k . v) in corfu-popupinfo--initial-state do (set k v))
    513   (cl-callf2 assq-delete-all #'corfu-popupinfo-mode minor-mode-overriding-map-alist))
    514 
    515 ;; Emacs 28: Do not show Corfu commands with M-X
    516 (dolist (sym '(corfu-popupinfo-scroll-down corfu-popupinfo-scroll-up
    517                corfu-popupinfo-documentation corfu-popupinfo-location
    518                corfu-popupinfo-beginning corfu-popupinfo-end
    519                corfu-popupinfo-toggle))
    520   (put sym 'completion-predicate #'ignore))
    521 
    522 (provide 'corfu-popupinfo)
    523 ;;; corfu-popupinfo.el ends here