Orderless never returns a sole match for `switch-to-buffer`
mm-- opened this issue · comments
If you try to use orderless for switch-to-buffer
, for example using
(setf (alist-get 'buffer completion-category-overrides)
(list '(styles orderless)))
you'll notice it'll never complete buffer names fully, even if there's only one possible candidate.
This has to do with the fact that switch-to-buffer
uses a completion table constructed with completion-table-with-predicate
.
You'll see the issue in the following code:
(setq example-unfiltered-table '("Hello one" "Test two" "Test Filtered"))
(setq my-filtered-example "Test Filtered")
(defun example-predicate (name)
(not (equal (if (consp name) (car name) name) my-filtered-example)))
(setq example-filtered-table
(apply-partially #'completion-table-with-predicate
example-unfiltered-table
#'example-predicate
nil))
(completion-pcm-try-completion "Hel" example-unfiltered-table nil 0) ;; => ("Hello one" . 9)
(orderless-try-completion "Hel" example-unfiltered-table nil 0);; => ("Hello one" . 9)
(completion-pcm-try-completion "Hel" example-filtered-table nil 0);; => ("Hello one" . 9)
;; This is incorrect, it should return the same thing above.
(orderless-try-completion "Hel" example-filtered-table nil 0);; => ("Hel" . 0)
It turns out that completion-table-with-predicate
can call a predicate twice when its STRICT
argument is nil
. The lambda
used in orderless-try-completion
is stateful, and upon being run again will incorrectly throw orderless--many
, even when there's only one unique match.
This should be fixed by comparing the candidate to one
and only throw orderless--many
if they are actually different. Furthermore we should probably return t from our "predicate" to avoid interfering with completion tables which rely on the filtered list of candidates (like the or
in this case). This will still be efficient since for more than one candidate we will still throw orderless--many
.
(There is the chance that some tables are broken by our filtering method, namely the ones which call the predicate before filtering the candidates against the patterns. But that's inefficient and tables shouldn't do this.)
Thanks for reporting this! I agree with @minad's suggestion to fix this and will get on it when I get the chance, probably this weekend.