Subject: bug#74561: [PATCH] Allow limiting the size of *Completions*

From: Spencer Baugh <[email-masked]>
Date: Fri, 29 Nov 2024 09:45:33 -0500

Stefan Monnier <[email-masked]> writes:

>> From profiling, the main bottleneck in completion over large
>> completion sets is display-completion-list, when there are many
>> available candidates.
>
> Hmm... interesting.  I expected it would be the computation of faces
> from things like `completion-pcm--hilit-commonality`.
>
> Do you happen to know which part of `display-completion-list` is the
> most costly?  is it the actual insertion into the buffer?

A simple way to profile this is:
(progn
  (require 'profiler)
  (profiler-reset)
  (profiler-cpu-start 10000)
  (completing-read ":" (mapcar #'number-to-string (number-sequence 0 100000)))
  (profiler-cpu-stop)
  (setq profiler-cpu-log (profiler-cpu-log))
  (profiler-report-cpu))

The biggest individual contributors of runtime are
set/add-text-properties and insert.

> I think we should try and fill the buffer lazily.  We don't have much
> experience with "jit" populating a buffer (the closest I can think of is
> the `vlf` package, which doesn't do "jit", IIRC), so it may take some
> trial-and-error until we have something that works, but it
> seems worthwhile.

Yes, I think filling the *Completions* buffer lazily would be way better
than limiting the size of the buffer, thanks everyone for your comments.

I think it would be sufficient to do something simple, and just split
filling the *Completions* buffer into two parts:

- In minibuffer-completion-help, insert only enough completion
candidates that the part of the *Completions* buffer that's displayed in
a window initially looks normal.  Save the rest of the completions in a
buffer-local in *Completions*.

- Upon any kind of interaction with the *Completions* buffer, insert all
the rest of the completion candidates in completions--finish-populate.

We could be lazier than this, but this is probably sufficient to give a
big speedup, since I think *Completions* is rendered much more often
than it's interacted with.

So to do this, all we need is a way to do completions--finish-populate
at the right time.

I'm not sure when to do that.  Maybe we could just call it in
window-selection-change-functions and with-minibuffer-completions-window
and maybe a few other places?