Subject: bug#74019: [PATCH] Optionally preserve selected candidate across *Completions* update

From: Eli Zaretskii <[email-masked]>
Date: Sat, 26 Oct 2024 09:45:14 +0300

> Cc: Juri Linkov <[email-masked]>
> Date: Fri, 25 Oct 2024 17:32:38 -0400
> From:  Spencer Baugh via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <[email-masked]>
> 
> Add completion-preserve-selection, a defcustom which allows keeping the
> same selected candidate after *Completions* is updated by
> minibuffer-completion-help.

Shouldn't we stop complicating the completion machinery at some point?
It is already basically impenetrable, and if someone still can reason
about what it does in any specific case, my hat's off to them; I have
long ago reached the point where the _only_ way of understanding
what's going on is to step with a debugger through the code -- and it
doesn't help that some of the code is in Lisp and some in C, so Lisp
calls into C, which calls back into Lisp, etc., thus one needs to
interrupt the stepping, fire up a different debugger, then go back.

Stefan, WDYT?  Should we close completion to further development and
accept only bugfixes?

What do Stefan Kangas and Andrea think?

> +(defcustom completion-preserve-selection nil
> +  "If non-nil, `minibuffer-completion-help' preserves the selected completion candidate.

This doc-string line is too long.

I also don't like the name: "selection" could be confused to mean the
X selection.  I'd use "selected-candidates" instead.

> +If non-nil, and point is on a completion candidate in the displayed
> +*Completions* window, `minibuffer-completion-help' will put point on the
> +same candidate after updating *Completions*."

This is completely unclear: what does minibuffer-completion-help have
to do with updating *Completions*?

> +             (current-candidate-and-offset
> +              (when-let* ((window (get-buffer-window "*Completions*" 0)))
> +                (with-selected-window window
> +                  (when-let* ((beg (completions--start-of-candidate-at (point))))
> +
> +                    (cons (get-text-property beg 'completion--string) (- (point) beg))))))

Why is this done unconditionally?  with-selected-window is not a cheap
function.

> @@ -4905,8 +4928,6 @@ minibuffer-next-completion
>    (interactive "p")
>    (let ((auto-choose minibuffer-completion-auto-choose))
>      (with-minibuffer-completions-window
> -      (when completions-highlight-face
> -        (setq-local cursor-face-highlight-nonselected-window t))

Why is this being moved to a different place?