oantolin / orderless

Emacs completion style that matches multiple regexps in any order

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.