emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] master dc693c3 280/348: Make ivy--flx-sort more intelligent


From: Oleh Krehel
Subject: [elpa] master dc693c3 280/348: Make ivy--flx-sort more intelligent
Date: Sat, 8 Apr 2017 11:04:15 -0400 (EDT)

branch: master
commit dc693c37dae89e9a4302a5cce42f5321f83946c8
Author: PythonNut <address@hidden>
Commit: PythonNut <address@hidden>

    Make ivy--flx-sort more intelligent
---
 ivy.el | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 62 insertions(+), 20 deletions(-)

diff --git a/ivy.el b/ivy.el
index 85d1c4a..2eb5292 100644
--- a/ivy.el
+++ b/ivy.el
@@ -2703,26 +2703,68 @@ no sorting is done.")
 (defun ivy--flx-sort (name cands)
   "Sort according to closeness to string NAME the string list CANDS."
   (condition-case nil
-      (if (and cands
-               (< (length cands) ivy-flx-limit))
-          (let* ((flx-name (if (string-match "^\\^" name)
-                               (substring name 1)
-                             name))
-                 (cands-with-score
-                  (delq nil
-                        (mapcar
-                         (lambda (x)
-                           (let ((score (flx-score x flx-name ivy--flx-cache)))
-                             (and score
-                                  (cons score x))))
-                         cands))))
-            (if cands-with-score
-                (mapcar #'cdr
-                        (sort cands-with-score
-                              (lambda (x y)
-                                (> (caar x) (caar y)))))
-              cands))
-        cands)
+      (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
+                                     ""))))
+
+             ;; strip off the leading "^" for flx matching
+             (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)
+                         ;; break ties by length
+                         (if (/= (cdr c1) (cdr c2))
+                             (> (cdr c1)
+                                (cdr c2))
+                           (< (length (car c1))
+                              (length (car c2)))))))
+
+         ;; add the unsorted candidates
+         cands-left))
     (error
      cands)))
 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]