swiper icon indicating copy to clipboard operation
swiper copied to clipboard

Prefer matches that start with the target string when sorting

Open betaprior opened this issue 5 years ago • 2 comments

I spent some time looking at ivy-sort-matches-functions-alist and browsing related issues but could not find what I am looking for. Concretely, in counsel-find-file (but probably other Ivy function as well) it would make the most sense to prefer the match that start with the target string. For example, if I am looking for foo here is the desired order:

foobar
fooasdfasdfasdf
zfoo

Note that this is not the same as simply sorting shortest matches first (since foobar must come before zfoo), nor is it the same as placing an implicit ^ in front of the target regex, since I still want to potentially match items where foo is a substring.

Is there a way to make Ivy sort like this?

betaprior avatar Jun 14 '20 08:06 betaprior

ivy--prefix-sort should theoretically do that. But it seems to not work properly at moment (you get Debugger entered--Lisp error: (wrong-type-argument listp "a") if you e.g. press a).

I hope I'll be able to create a PR by the end of the day to fix the issue. After that you should be able use the following in your config:

(add-to-list 'ivy-sort-matches-functions-alist '(counsel-find-file . ivy--prefix-sort))

Melkor333 avatar Jun 22 '20 12:06 Melkor333

ivy--prefix-sort should theoretically do that. But it seems to not work properly at moment (you get Debugger entered--Lisp error: (wrong-type-argument listp "a") if you e.g. press a).

I had the same issue. For me the use of the ivy--regex-ignore-order in ivy-re-builders-alist was the problem causing the mentioned exception. ivy--regex-ignore-order does not return a string like e.g. ivy--regex-plus does, but a list of regex components. You need to turn them to a string using the function ivy-re-to-str.

To fix it you can use something like this:

;; use ivy--prefix-sort (in my case, only for counsel-find-file)
(custom-set-variables
 '(ivy-sort-matches-functions-alist
   (quote
    ((t . nil)
     ;; ...
     (counsel-find-file . ivy--prefix-sort)))))

;; for using ivy--regex-ignore-order:
(setq ivy-re-builders-alist
      ;; Allow input not in order ivy--regex-ignore-order.
      ;; Requires the use of ivy-re-to-str as it does not
      ;; return a string but a list of strings when used with ivy-prefix-sort
      '((counsel-find-file   . (lambda (str) (ivy-re-to-str (ivy--regex-ignore-order str))))
        ;; For other applications keep the normal function
        (t   . ivy--regex-ignore-order))))))

When using ivy--regex-ignore-order without the setup shown above, ivy--prefix-sort crashes, but e.g. ivy--shorter-matches-first does not as that does not use the regex at all.

phuhl avatar Jan 18 '24 10:01 phuhl