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: Eli Zaretskii <eliz <at> gnu.org>
To: Chris Roberts <frayedultrasonicaligator <at> disroot.org>, João Távora <joaotavora <at> gmail.com>
Cc: 79420 <at> debbugs.gnu.org
Subject: bug#79420: 30.2; icomplete-vertical-mode flashes horizontal minibuffer prompt before expanding
Date: Sat, 13 Sep 2025 13:01:04 +0300
> Date: Wed, 10 Sep 2025 11:48:18 +0200
> From:  Chris Roberts via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <bug-gnu-emacs <at> gnu.org>
> 
> 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?

Thanks.

João, any comments or suggestions?




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.