Package: emacs;
Reported by: Spencer Baugh <sbaugh <at> janestreet.com>
Date: Wed, 27 Nov 2024 20:26:02 UTC
Severity: wishlist
Tags: patch
Done: Stefan Monnier <monnier <at> iro.umontreal.ca>
Bug is archived. No further changes may be made.
View this message in rfc822 format
From: Spencer Baugh <sbaugh <at> janestreet.com> To: Eli Zaretskii <eliz <at> gnu.org> Cc: sbaugh <at> catern.com, juri <at> linkov.net, dmitry <at> gutov.dev, joaotavora <at> gmail.com, 74561 <at> debbugs.gnu.org, monnier <at> iro.umontreal.ca Subject: bug#74561: [PATCH] Allow limiting the size of *Completions* Date: Tue, 11 Feb 2025 14:44:46 -0500
[Message part 1 (text/plain, inline)]
Eli Zaretskii <eliz <at> gnu.org> writes: >> Cc: João Távora <joaotavora <at> gmail.com>, >> dmitry <at> gutov.dev, 74561 <at> debbugs.gnu.org, >> Stefan Monnier <monnier <at> iro.umontreal.ca>, juri <at> linkov.net >> From: sbaugh <at> catern.com >> Date: Tue, 11 Feb 2025 15:03:31 +0000 (UTC) >> >> +(defcustom completions-insert-lazily 200 >> + "If non-nil, completions are inserted lazily. > > Does the default value mean a change in user-facing behavior of > completion commands? Nope, no user-facing behavior changes. In fact, this probably shouldn't be user-customizable at all, since it's an internal optimization with essentially no cost. So I've changed this into a defvar completions--insert-lazily. >> +When a number, only that many completions are inserted, and the > > Please use "If", not "When". The latter could be misinterpreted as > meaning some time-related condition, which is not what you mean here. Done. > Also, what about the :version tag? No longer a defcustom. > And this user option needs a NEWS entry. Added a NEWS entry for the change in general. Updated patch:
[0001-Lazily-highlight-and-insert-candidates-in-Completion.patch (text/x-patch, inline)]
From fd4ca55084fa24998c09cabbb6e7dd2a88164abd Mon Sep 17 00:00:00 2001 From: Spencer Baugh <sbaugh <at> catern.com> Date: Mon, 13 Jan 2025 14:32:18 -0500 Subject: [PATCH] Lazily highlight and insert candidates in *Completions* From profiling, the main bottleneck in completion over large completion sets is display-completion-list, when there are many available candidates. For example, in my large monorepo, when completing over the 589196 files or the 73897 branches, even with the candidates narrowed down by typing some prefix to complete, TAB (when it shows *Completions*) or ? is slow, mostly in display-completion-list. However, rendering all the completion candidates is unnecessary if the *Completions* window is never scrolled to see those candiates. By eagerly inserting only some candidates and lazily highlighting and inserting the remaining candidates only when necessary, performance is much improved. * lisp/minibuffer.el (completion--insert-strings): Insert completions lazily. (bug#74561) (completion--lazy-insert-strings) (completions--insert-lazily) (completions--lazy-insert-button) Add. (minibuffer-completion-help): Set completion-lazy-hilit. (with-minibuffer-completions-window): Call completion--lazy-insert-strings. * lisp/simple.el (completion-setup-function): Preserve buffer-locals required for lazy completion insertion. (switch-to-completions): Call completion--lazy-insert-strings. --- etc/NEWS | 10 ++++++++++ lisp/minibuffer.el | 47 ++++++++++++++++++++++++++++++++++++++++++++-- lisp/simple.el | 5 ++++- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 9fe46d818bd..61a6d9a3319 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -176,6 +176,16 @@ will still be on that candidate after "*Completions*" is updated with a new list of completions. The candidate is automatically deselected when the "*Completions*" buffer is hidden. +--- +*** "*Completions*" is displayed faster with many completion candidates. +The "*Completions*" buffer is now created and displayed faster when it +contains many completion candidates. When intially created and +displayed in a window, only enough completion candidates are inserted +into the "*Completions*" buffer to fill the window. The remaining +completion candidates are inserted automatically if you run a command +which interacts with "*Completions*" buffer, such as +'switch-to-completions'. + ** Windows +++ diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index b401e4a920c..d08874f1cbb 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -2230,6 +2230,14 @@ completions-header-format (string :tag "Format string for heading line")) :version "29.1") +(defvar completions--insert-lazily 200 + "If non-nil, completions are inserted lazily. + +Only this many completions are inserted, and the rest are inserted +lazily by `completion--lazy-insert-strings'.") + +(defvar-local completions--lazy-insert-button nil) + (defun completion--insert-strings (strings &optional group-fun) "Insert a list of STRINGS into the current buffer. The candidate strings are inserted into the buffer depending on the @@ -2257,8 +2265,41 @@ completion--insert-strings ;; Align to tab positions for the case ;; when the caller uses tabs inside prefix. (setq colwidth (- colwidth (mod colwidth completion-tab-width)))) - (funcall (intern (format "completion--insert-%s" completions-format)) - strings group-fun length wwidth colwidth columns)))) + (let ((truncated-strings + (and completions--insert-lazily + (< completions--insert-lazily (length strings)) + (take completions--insert-lazily strings))) + (start (point))) + (funcall (intern (format "completion--insert-%s" completions-format)) + (mapcar (lambda (candidate) + (if (consp candidate) + (setcar candidate (completion-lazy-hilit (car candidate))) + (completion-lazy-hilit candidate))) + (or truncated-strings strings)) + group-fun length wwidth colwidth columns) + (when truncated-strings + (newline) + (setq-local completions--lazy-insert-button + (insert-button "[Completions truncated, click here to insert the rest.]" + 'action #'completion--lazy-insert-strings)) + (button-put completions--lazy-insert-button 'group-fun group-fun) + (button-put completions--lazy-insert-button 'completions-start (copy-marker start)) + (button-put completions--lazy-insert-button 'completion-strings strings)))))) + +(defun completion--lazy-insert-strings (&optional button) + (setq button (or button completions--lazy-insert-button)) + (when button + (let ((completions--insert-lazily nil) + (completion-lazy-hilit t) + (standard-output (current-buffer)) + (inhibit-read-only t) + (group-fun (button-get button 'group-fun)) + (strings (button-get button 'completion-strings))) + (save-excursion + (goto-char (button-get button 'completions-start)) + (delete-region (point) (button-end button)) + (setq-local completions--lazy-insert-button nil) + (completion--insert-strings strings group-fun))))) (defun completion--insert-horizontal (strings group-fun length wwidth @@ -2644,6 +2685,7 @@ minibuffer-completion-help (end (or end (point-max))) (string (buffer-substring start end)) (md (completion--field-metadata start)) + (completion-lazy-hilit completions--insert-lazily) (completions (completion-all-completions string minibuffer-completion-table @@ -4986,6 +5028,7 @@ with-minibuffer-completions-window (get-buffer-window "*Completions*" 0))))) (when window (with-selected-window window + (completion--lazy-insert-strings) ,@body)))) (defcustom minibuffer-completion-auto-choose t diff --git a/lisp/simple.el b/lisp/simple.el index e1c0dd4a092..57553343c04 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -10455,10 +10455,12 @@ completion-setup-function (buffer-substring (minibuffer-prompt-end) (point))))))) (with-current-buffer standard-output (let ((base-position completion-base-position) - (insert-fun completion-list-insert-choice-function)) + (insert-fun completion-list-insert-choice-function) + (lazy-button completion--lazy-insert-button)) (completion-list-mode) (when completions-highlight-face (setq-local cursor-face-highlight-nonselected-window t)) + (setq-local completion--lazy-insert-button lazy-button) (setq-local completion-base-position base-position) (setq-local completion-list-insert-choice-function insert-fun)) (setq-local completion-reference-buffer mainbuf) @@ -10504,6 +10506,7 @@ switch-to-completions (progn (minibuffer-completion-help) (get-buffer-window "*Completions*" 0))))) (select-window window) + (completion--lazy-insert-strings) (when (bobp) (cond ((and (memq this-command '(completion-at-point minibuffer-complete)) -- 2.39.3
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.