Skip to content
This repository was archived by the owner on Oct 21, 2022. It is now read-only.

Commit d04030a

Browse files
committed
Improve doc search sorting with Levenshtein distance implemented by @carocad
1 parent f35e730 commit d04030a

File tree

1 file changed

+46
-12
lines changed
  • lein-light-nrepl/src/lighttable/nrepl

1 file changed

+46
-12
lines changed

lein-light-nrepl/src/lighttable/nrepl/doc.clj

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,33 @@
99
[cljs.analyzer :as ana])
1010
(:import java.net.URL java.io.File))
1111

12-
(defn clean-meta [m]
12+
(defn- next-row
13+
"Computes the value of the next row of the distance matrix, based on the
14+
values from the previous row."
15+
[pre-row char1 str2]
16+
(let [init-val [(inc (first pre-row))]
17+
row (fn [crow [diagonal above char2]]
18+
(let [dist (if (= char2 char1) diagonal
19+
(inc (min diagonal above (peek crow))))]
20+
(conj crow dist)))]
21+
(reduce row init-val (map vector pre-row (rest pre-row) str2))))
22+
23+
24+
;; Author: PLIQUE Guillaume (Yomguithereal)
25+
;; Source: https://gist.github.com/vishnuvyas/958488
26+
(defn levenshtein
27+
"Compute the levenshtein distance (a.k.a edit distance) between two strings.
28+
Informally, the Levenshtein distance between two words is the minimum number
29+
of single-character edits (i.e. insertions, deletions or substitutions)
30+
required to change one word into the other"
31+
[str1 str2]
32+
(let [first-row (range (inc (count str2)))]
33+
(peek (reduce #(next-row %1 %2 str2) first-row str1))))
34+
35+
(defn clean-meta
36+
"returns a hash-map with only these keys: :ns :name :doc :arglists
37+
:file :line :macro and updates :ns to a string"
38+
[m]
1339
(when m
1440
(-> m
1541
(select-keys [:ns :name :doc :arglists :file :line :macro])
@@ -19,7 +45,10 @@
1945
(defn str-contains? [orig search]
2046
(> (.indexOf orig search) -1))
2147

22-
(defn format-result [m]
48+
(defn format-result
49+
"Returns a hash-map with `:args` as the original `:arglists` value. `:args` is converted to
50+
a string and dissociated from `:arglists`."
51+
[m]
2352
(when m
2453
(-> m
2554
(assoc :args (-> m :arglists str))
@@ -34,16 +63,21 @@
3463
(dissoc :arglists)
3564
)))
3665

37-
(defn find-doc [search]
38-
(let [ms (concat (mapcat #(sort-by :name (map meta (vals (ns-interns %))))
39-
(all-ns)))]
40-
(for [m ms
41-
:when (and (:doc m)
42-
(not (:private m))
43-
(or (str-contains? (:doc m) search)
44-
(str-contains? (str (:ns m)) search)
45-
(str-contains? (str (:name m)) search)))]
46-
(format-result (clean-meta m)))))
66+
(defn find-doc
67+
"Look for a var with name `search` among all namespaces. Only public
68+
vars with docstring are returned.
69+
70+
Returns a list of metadata (max 30) hash-maps sorted by their levenshtein
71+
distance with the `search` input."
72+
[search]
73+
(let [with-dist #(hash-map :dist (levenshtein search (str (:name %)))
74+
:meta %)
75+
all-vars (vals (apply merge (map ns-interns (all-ns))))
76+
dist-metas (into [] (comp (map meta) (filter :doc) (remove :private)
77+
(map clean-meta) (map format-result)
78+
(map with-dist))
79+
all-vars)]
80+
(take 30 (map :meta (sort-by :dist dist-metas)))))
4781

4882
(def jar-temp-files
4983
"Maps jar-url paths to temp files"

0 commit comments

Comments
 (0)