GNU bug report logs - #79420
30.2; icomplete-vertical-mode flashes horizontal minibuffer prompt before expanding

Previous Next

Package: emacs;

Reported by: Chris Roberts <frayedultrasonicaligator <at> disroot.org>

Date: Wed, 10 Sep 2025 10:52:01 UTC

Severity: normal

Found in version 30.2

Full log


View this message in rfc822 format

From: Chris Roberts <frayedultrasonicaligator <at> disroot.org>
To: 79420 <at> debbugs.gnu.org
Subject: bug#79420: 30.2; icomplete-vertical-mode flashes horizontal minibuffer prompt before expanding
Date: Wed, 10 Sep 2025 11:48:18 +0200
1. emacs -Q
2. Evaluate the following:

(setq icomplete-show-matches-on-no-input t)
(icomplete-vertical-mode +1)

3. M-x

Looking at the minibuffer, you will see the text "M-x" flash
momentarily, before the minibuffer window expands vertically. This can
be made more apparent by setting `icomplete-compute-delay' to a higher
value (0.15 by default.)

This is caused by the call to `sit-for' inside of the
`icomplete-exhibit' function. The wait obviously causes the issue,
because the function pauses the setup, including all of the necessary
vertical code, and waits for `icomplete-compute-delay' seconds. But
even if we set `icomplete-compute-delay' to 0, the prompt will still
flash, because redisplay is triggered. In other words, the only way to
call `sit-for' that doesn't cause an issue is:

(sit-for x t)

where x <= 0.

Following are my thoughts on how to fix this.

The piece of code from `icomplete-exhibit' that we are interested in is
the following:

(and (or icomplete-show-matches-on-no-input
         (not (equal (icomplete--field-string)
                     icomplete--initial-input)))
     (or
      ;; Don't bother with delay after certain number of chars:
      (> (- (point) (icomplete--field-beg))
         icomplete-max-delay-chars)
      ;; Don't delay if the completions are known.
      completion-all-sorted-completions
      ;; Don't delay if alternatives number is small enough:
      (and (sequencep (icomplete--completion-table))
           (< (length (icomplete--completion-table))
              icomplete-delay-completions-threshold))
      ;; Delay - give some grace time for next keystroke, before
      ;; embarking on computing completions:
      (sit-for icomplete-compute-delay)))

We see that `sit-for' will only execute if all the preceding forms
return nil (since it's inside `and'). We also see that setting
`icomplete-delay-completions-threshold' to a high value, like maybe
`most-positive-fixnum' should help us avoid the call to `sit-for' in
most situations. Except it doesn't, because
`(icomplete--completion-table)' does not return `sequencep'! This can
be verified by overriding the function via advice, and capturing the
value returned by `icomplete--completion-table':

;; Don't delay if alternatives number is small enough:
(progn ;; Important that we return nil to avoid exiting early
  (setq reimu (icomplete--completion-table))
  nil)
(and (sequencep (icomplete--completion-table))
     (< (length (icomplete--completion-table))
        icomplete-delay-completions-threshold))

Repeat the reproduction steps including this advice, press C-g after
M-x, and finally C-x C-e `(sequencep reimu)' in the buffer (it's
important that we don't do something that reads from the minibuffer,
to not change the value), and you will get nil. In fact, `(type-of
reimu)' shows that it's a compiled function.

After debugging `icomplete--completion-table', I verified that this
compiled function is in fact the value of the
minibuffer-completion-table at the time. I believe this might be
another bug, because the docstring of `minibuffer-completion-table'
says:

"Alist or obarray used for completion in the minibuffer."

But it's evidently neither alist nor obarray (I assume, since
`(sequencep obarray)' returns t).

Thus, my ideas of fixing the original problem with the flashing prompt
are following, from easiest to hardest:

1. Add a check for `icomplete-compute-delay)' <= 0, before the call to
`sit-for', like so:

;; Don't delay if the wait is <= 0, to avoid redisplay
;; and prompt flashing in vertical mode.
(<= icomplete-compute-delay 0)
;; Delay - give some grace time for next keystroke, before
;; embarking on computing completions:
(sit-for icomplete-compute-delay)))

2. Force `sit-for' to never redisplay. This could also be
conditionalized on `ido-vertical-mode' variable, to not affect the
existing code. I think this is a tricky option, because this line is
really ancient (at least 30 years old) and changing it might have
unintended consequences, perhaps?

3. Fix the presumed bug with minibuffer-completion-table and adjust the
`sequencep' check in `icomplete-exhibit' to compare with
`icomplete-delay-completions-threshold' correctly.

And finally, as mentioned earlier, this line of code is ancient. Maybe
some deliberation is in order on whether it's actually still needed
nowadays?

-----------------------------------------------------------------------

In GNU Emacs 30.2 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.33,
 cairo version 1.16.0) of 2025-09-10 built on cdr
Windowing system distributor 'The X.Org Foundation', version
11.0.12101004
System Description: Linux Mint 21.2

Configured using:
 'configure --with-cairo --with-x-toolkit=gtk3'

Configured features:
CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GSETTINGS HARFBUZZ JPEG LCMS2
LIBSELINUX LIBXML2 MODULES NOTIFY INOTIFY PDUMPER PNG SECCOMP SOUND
SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS WEBP X11 XDBE XIM XINPUT2 XPM
GTK3 ZLIB




This bug report was last modified today.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.