config

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

corfu-popupinfo.el (22175B)


      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 ;; Package-Requires: ((emacs "28.1") (compat "30") (corfu "1.5"))
      9 ;; URL: https://github.com/minad/corfu
     10 
     11 ;; This file is part of GNU Emacs.
     12 
     13 ;; This program is free software: you can redistribute it and/or modify
     14 ;; it under the terms of the GNU General Public License as published by
     15 ;; the Free Software Foundation, either version 3 of the License, or
     16 ;; (at your option) any later version.
     17 
     18 ;; This program is distributed in the hope that it will be useful,
     19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
     20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     21 ;; GNU General Public License for more details.
     22 
     23 ;; You should have received a copy of the GNU General Public License
     24 ;; along with this program.  If not, see <https://www.gnu.org/licenses/>.
     25 
     26 ;;; Commentary:
     27 
     28 ;; Display an information popup for completion candidate when using
     29 ;; Corfu.  The popup displays either the candidate documentation or the
     30 ;; candidate location.  The `corfu-popupinfo-mode' must be enabled
     31 ;; globally.  Set `corfu-popupinfo-delay' to nil if the info popup should
     32 ;; not update automatically.  If the popup should not appear initially,
     33 ;; but update automatically afterwards, use `(setq corfu-popupinfo-delay
     34 ;; (cons nil 1.0))'.
     35 
     36 ;; For manual toggling the commands `corfu-popupinfo-toggle',
     37 ;; `corfu-popupinfo-location' and `corfu-popupinfo-documentation' are
     38 ;; bound in the `corfu-popupinfo-map'.
     39 
     40 ;;; Code:
     41 
     42 (require 'corfu)
     43 (eval-when-compile
     44   (require 'cl-lib)
     45   (require 'subr-x))
     46 
     47 (defface corfu-popupinfo
     48   '((t :inherit corfu-default))
     49   "Face used for the info popup."
     50   :group 'corfu-faces)
     51 
     52 (defcustom corfu-popupinfo-delay '(2.0 . 1.0)
     53   "Automatically update info popup after that number of seconds.
     54 
     55 The value can be a pair of two floats to specify initial and
     56 subsequent delay.  If the value is non-nil or the car of the pair
     57 is non-nil, the popup will automatically appear for the
     58 preselected candidate.  Otherwise the popup can be requested
     59 manually via `corfu-popupinfo-toggle',
     60 `corfu-popupinfo-documentation' and `corfu-popupinfo-location'.
     61 
     62 It is *not recommended* to use a short delay or even 0, since
     63 this will create high load for Emacs.  Retrieving the
     64 documentation from the backend is usually expensive."
     65   :type '(choice (const :tag "Never" nil)
     66                  (number :tag "Delay in seconds")
     67                  (cons :tag "Two Delays"
     68                        (choice :tag "Initial   "
     69                                (choice (const nil) number))
     70                        (choice :tag "Subsequent"
     71                                (choice (const nil) number))))
     72   :group 'corfu)
     73 
     74 (defcustom corfu-popupinfo-hide t
     75   "Hide the popup during the transition between candidates."
     76   :type 'boolean
     77   :group 'corfu)
     78 
     79 (defcustom corfu-popupinfo-max-width 80
     80   "The maximum width of the info popup in characters."
     81   :type 'natnum
     82   :group 'corfu)
     83 
     84 (defcustom corfu-popupinfo-min-width 30
     85   "The minimum width of the info popup in characters."
     86   :type 'natnum
     87   :group 'corfu)
     88 
     89 (defcustom corfu-popupinfo-max-height 10
     90   "The maximum height of the info popup in characters."
     91   :type 'natnum
     92   :group 'corfu)
     93 
     94 (defcustom corfu-popupinfo-min-height 1
     95   "The minimum height of the info popup in characters."
     96   :type 'natnum
     97   :group 'corfu)
     98 
     99 (defcustom corfu-popupinfo-resize t
    100   "Resize the info popup automatically if non-nil."
    101   :type 'boolean
    102   :group 'corfu)
    103 
    104 (defcustom corfu-popupinfo-direction '(right left vertical)
    105   "Preferred directions for the popup in order."
    106   :type '(repeat
    107           (choice
    108            (const left)
    109            (const right)
    110            (const vertical)
    111            (const force-left)
    112            (const force-right)
    113            (const force-vertical)))
    114   :group 'corfu)
    115 
    116 (defvar-keymap corfu-popupinfo-map
    117   :doc "Additional keymap activated in popupinfo mode."
    118   "M-t" #'corfu-popupinfo-toggle
    119   "<remap> <corfu-info-documentation>" #'corfu-popupinfo-documentation
    120   "<remap> <corfu-info-location>" #'corfu-popupinfo-location
    121   "<remap> <scroll-other-window>" #'corfu-popupinfo-scroll-up
    122   "<remap> <scroll-other-window-down>" #'corfu-popupinfo-scroll-down
    123   "<remap> <end-of-buffer-other-window>" #'corfu-popupinfo-end
    124   "<remap> <beginning-of-buffer-other-window>" #'corfu-popupinfo-beginning)
    125 
    126 (defvar corfu-popupinfo--buffer-parameters
    127   '((truncate-partial-width-windows . nil)
    128     (truncate-lines . nil)
    129     (left-margin-width . 1)
    130     (right-margin-width . 1)
    131     (word-wrap . t)
    132     (fringe-indicator-alist (continuation))
    133     (char-property-alias-alist (face font-lock-face)))
    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                       (corfu--equal-including-properties
    349                        candidate corfu-popupinfo--candidate))))
    350            (new-coords (frame-edges corfu--frame 'inner-edges))
    351            (coords-changed (not (equal new-coords corfu-popupinfo--coordinates))))
    352       (when cand-changed
    353         (if-let ((content (funcall corfu-popupinfo--function candidate)))
    354             (with-current-buffer (corfu--make-buffer " *corfu-popupinfo*")
    355               (with-silent-modifications
    356                 (erase-buffer)
    357                 (insert content)
    358                 (goto-char (point-min)))
    359               (dolist (var corfu-popupinfo--buffer-parameters)
    360                 (set (make-local-variable (car var)) (cdr var)))
    361               (when-let ((m (memq 'corfu-default (alist-get 'default face-remapping-alist))))
    362                 (setcar m 'corfu-popupinfo)))
    363           (corfu-popupinfo--hide)
    364           (setq cand-changed nil coords-changed nil)))
    365       (when (or cand-changed coords-changed)
    366         (pcase-let* ((border (alist-get 'internal-border-width corfu--frame-parameters))
    367                      (`(,area-x ,area-y ,area-w ,area-h ,area-d)
    368                       (corfu-popupinfo--area
    369                        (if cand-changed
    370                            (corfu-popupinfo--size)
    371                          (cons
    372                           (- (frame-pixel-width corfu-popupinfo--frame) border border)
    373                           (- (frame-pixel-height corfu-popupinfo--frame) border border)))))
    374                      (margin-quirk (not corfu-popupinfo--frame)))
    375           (setq corfu-popupinfo--frame
    376                 (corfu--make-frame corfu-popupinfo--frame
    377                                    area-x area-y area-w area-h
    378                                    " *corfu-popupinfo*")
    379                 corfu-popupinfo--toggle t
    380                 corfu-popupinfo--lock-dir area-d
    381                 corfu-popupinfo--candidate candidate
    382                 corfu-popupinfo--coordinates new-coords)
    383           ;; XXX HACK: Force margin update. For some reason, the call to
    384           ;; `set-window-buffer' in `corfu--make-frame' is not effective the
    385           ;; first time. Why does Emacs have all these quirks?
    386           (when margin-quirk
    387             (set-window-buffer
    388              (frame-root-window corfu-popupinfo--frame)
    389              " *corfu-popupinfo*")))))))
    390 
    391 (defun corfu-popupinfo--hide ()
    392   "Clear the info popup buffer content and hide it."
    393   (corfu--hide-frame corfu-popupinfo--frame))
    394 
    395 (defun corfu-popupinfo-end (&optional n)
    396   "Scroll text of info popup window to its end.
    397 
    398 If arg N is omitted or nil, scroll to end.  If a numerical value,
    399 put point N/10 of the way from the end.  If the info popup is not
    400 visible, the other window is moved to beginning or end."
    401   (interactive "P")
    402   (if (corfu-popupinfo--visible-p)
    403       (with-selected-frame corfu-popupinfo--frame
    404         (with-current-buffer " *corfu-popupinfo*"
    405           (with-no-warnings
    406             (end-of-buffer n))))
    407     (end-of-buffer-other-window n)))
    408 
    409 (defun corfu-popupinfo-beginning (&optional n)
    410   "Scroll text of info popup window to beginning of buffer.
    411 
    412 See `corfu-popupinfo-end' for the argument N."
    413   (interactive "P")
    414   (corfu-popupinfo-end (- 10 (if (numberp n) n 0))))
    415 
    416 (defun corfu-popupinfo-scroll-up (&optional n)
    417   "Scroll text of info popup window upward N lines.
    418 
    419 If ARG is omitted or nil, scroll upward by a near full screen.
    420 See `scroll-up' for details.  If the info popup is not visible,
    421 the other window is scrolled."
    422   (interactive "p")
    423   (if (corfu-popupinfo--visible-p)
    424       (with-selected-frame corfu-popupinfo--frame
    425         (with-current-buffer " *corfu-popupinfo*"
    426           (scroll-up n)))
    427     (scroll-other-window n)))
    428 
    429 (defun corfu-popupinfo-scroll-down (&optional n)
    430   "Scroll text of info popup window down N lines.
    431 
    432 See `corfu-popupinfo-scroll-up' for more details."
    433   (interactive "p")
    434   (corfu-popupinfo-scroll-up (- (or n 1))))
    435 
    436 (defun corfu-popupinfo--toggle (fun)
    437   "Set documentation getter FUN and toggle popup."
    438   (when (< corfu--index 0)
    439     (corfu-popupinfo--hide)
    440     (user-error "No candidate selected"))
    441   (setq corfu-popupinfo--toggle
    442         (not (and (corfu-popupinfo--visible-p)
    443                   (eq corfu-popupinfo--function fun))))
    444   (if (not corfu-popupinfo--toggle)
    445       (corfu-popupinfo--hide)
    446     (setq corfu-popupinfo--function fun
    447           corfu-popupinfo--candidate nil)
    448     (let ((cand (nth corfu--index corfu--candidates)))
    449       (corfu-popupinfo--show cand)
    450       (unless (corfu-popupinfo--visible-p)
    451         (user-error "No %s available for `%s'"
    452                     (car (last (split-string (symbol-name fun) "-+")))
    453                     cand)))))
    454 
    455 (defun corfu-popupinfo-documentation ()
    456   "Show or hide documentation in popup.
    457 Behaves like `corfu-popupinfo-toggle'."
    458   (interactive)
    459   (corfu-popupinfo--toggle #'corfu-popupinfo--get-documentation))
    460 
    461 (defun corfu-popupinfo-location ()
    462   "Show or hide location in popup.
    463 Behaves like `corfu-popupinfo-toggle'."
    464   (interactive)
    465   (corfu-popupinfo--toggle #'corfu-popupinfo--get-location))
    466 
    467 (defun corfu-popupinfo-toggle ()
    468   "Toggle the info popup display or hide.
    469 
    470 When using this command to manually hide the info popup, it will
    471 not be displayed until this command is called again, even if
    472 `corfu-popupinfo-delay' is non-nil."
    473   (interactive)
    474   (corfu-popupinfo--toggle corfu-popupinfo--function))
    475 
    476 ;;;###autoload
    477 (define-minor-mode corfu-popupinfo-mode
    478   "Corfu info popup minor mode."
    479   :global t :group 'corfu)
    480 
    481 (cl-defmethod corfu--exhibit :after (&context (corfu-popupinfo-mode (eql t)) &optional _auto)
    482   (when completion-in-region-mode
    483     (setf (alist-get #'corfu-popupinfo-mode minor-mode-overriding-map-alist)
    484           corfu-popupinfo-map)
    485     (when corfu-popupinfo--timer
    486       (cancel-timer corfu-popupinfo--timer)
    487       (setq corfu-popupinfo--timer nil))
    488     (if (and (>= corfu--index 0) (corfu-popupinfo--visible-p corfu--frame))
    489         (let ((cand (nth corfu--index corfu--candidates)))
    490           (if-let ((delay (if (consp corfu-popupinfo-delay)
    491                               (funcall (if (eq corfu-popupinfo--toggle 'init) #'car #'cdr)
    492                                        corfu-popupinfo-delay)
    493                             corfu-popupinfo-delay))
    494                    (corfu-popupinfo--toggle))
    495               (if (or (<= delay 0)
    496                       (and (equal cand corfu-popupinfo--candidate)
    497                            (corfu-popupinfo--visible-p)))
    498                   (corfu-popupinfo--show cand)
    499                 (when (corfu-popupinfo--visible-p)
    500                   (cond
    501                    (corfu-popupinfo-hide
    502                     (corfu-popupinfo--hide))
    503                    (corfu-popupinfo--candidate
    504                     (corfu-popupinfo--show corfu-popupinfo--candidate))))
    505                 (setq corfu-popupinfo--timer
    506                     (run-at-time delay nil #'corfu-popupinfo--show cand)))
    507             (unless (equal cand corfu-popupinfo--candidate)
    508               (corfu-popupinfo--hide))))
    509       (corfu-popupinfo--hide))))
    510 
    511 (cl-defmethod corfu--teardown :before (_buf &context (corfu-popupinfo-mode (eql t)))
    512   (corfu-popupinfo--hide)
    513   (cl-loop for (k . v) in corfu-popupinfo--initial-state do (set k v))
    514   (cl-callf2 assq-delete-all #'corfu-popupinfo-mode minor-mode-overriding-map-alist))
    515 
    516 ;; Do not show Corfu commands with M-X
    517 (dolist (sym '(corfu-popupinfo-scroll-down corfu-popupinfo-scroll-up
    518                corfu-popupinfo-documentation corfu-popupinfo-location
    519                corfu-popupinfo-beginning corfu-popupinfo-end
    520                corfu-popupinfo-toggle))
    521   (put sym 'completion-predicate #'ignore))
    522 
    523 (provide 'corfu-popupinfo)
    524 ;;; corfu-popupinfo.el ends here