Skip to content

Instantly share code, notes, and snippets.

@PythonNut
Last active December 29, 2016 01:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save PythonNut/0538505e5aac87ea1d620dd32f9dcf12 to your computer and use it in GitHub Desktop.
Save PythonNut/0538505e5aac87ea1d620dd32f9dcf12 to your computer and use it in GitHub Desktop.
Ivy smart flx sorting
(defun nadvice/ivy--flx-sort (name cands)
"Sort according to closeness to string NAME the string list CANDS."
(condition-case nil
(let* (;; an optimized regex for fuzzy matching
;; "abc" → "\\`[^a]*a[^b]*b[^c]*c"
(fuzzy-regex (if (= (elt name 0) ?^)
(concat "^"
(regexp-quote (substring name 1 2))
(mapconcat
(lambda (x)
(setq x (string x))
(concat "[^" x "]*" (regexp-quote x)))
(substring name 2)
""))
(concat "^"
(mapconcat
(lambda (x)
(setq x (string x))
(concat "[^" x "]*" (regexp-quote x)))
name
""))))
(flx-name (if (string-match "^\\^" name)
(substring name 1)
name))
(cands-left)
(cands-to-sort))
;; filter out non-matching candidates
(dolist (cand cands)
(when (string-match fuzzy-regex cand)
(push cand cands-left)))
;; pre-sort the candidates by length before partitioning
(setq cands-left (sort cands-left
(lambda (c1 c2)
(< (length c1)
(length c2)))))
;; partition the candidates into sorted and unsorted groups
(dotimes (_n (min (length cands-left) ivy-flx-limit))
(push (pop cands-left) cands-to-sort))
(append
;; compute all of the flx scores in one pass and sort
(mapcar #'car
(sort (mapcar
(lambda (cand)
(cons cand
(car (flx-score cand
flx-name
ivy--flx-cache))))
cands-to-sort)
(lambda (c1 c2)
(if (/= (cdr c1) (cdr c2))
(> (cdr c1)
(cdr c2))
(< (length (car c1))
(length (car c2)))))))
;; add the unsorted candidates
cands-left))
(error
cands)))
(advice-add 'ivy--flx-sort :override #'nadvice/ivy--flx-sort)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment