Skip to content

Commit 30e1783

Browse files
committed
Return candidate metadata along with completions
Fixes #12.
1 parent 4c35870 commit 30e1783

File tree

5 files changed

+397
-87
lines changed

5 files changed

+397
-87
lines changed

src/cljs_tooling/complete.clj

+183-38
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,131 @@
33
(:require [cljs-tooling.util.analysis :as a]
44
[cljs-tooling.util.misc :as u]))
55

6+
(defn- candidate-data
7+
"Returns a map of candidate data for the given arguments."
8+
[candidate ns qualified-name type]
9+
{:candidate (name candidate)
10+
:ns (symbol ns)
11+
:name (symbol qualified-name)
12+
:type type})
13+
14+
(defn- var->type
15+
"Returns the candidate type corresponding to the given metadata map."
16+
[var]
17+
(condp #(get %2 %1) var
18+
:protocol :protocol-fn
19+
:fn-var :fn
20+
:record :record
21+
:protocols :type
22+
:protocol-symbol :protocol
23+
:var))
24+
625
(def special-forms
726
'#{& . case* catch def defrecord* deftype* do finally fn* if js* let*
827
letfn* loop* new ns quote recur set! throw try})
928

10-
(defn prefix-completions
11-
[prefix completions]
12-
(map #(symbol (str prefix "/" %)) completions))
29+
(def special-form-candidates
30+
"Candidate data for all special forms."
31+
(for [form special-forms
32+
:let [qualified-name (symbol "cljs.core" (name form))]]
33+
(candidate-data form qualified-name 'cljs.core :special)))
34+
35+
(defn all-ns-candidates
36+
"Returns candidate data for all namespaces in the environment."
37+
[env]
38+
(for [[ns _] (a/all-ns env)]
39+
(candidate-data ns ns ns :ns)))
40+
41+
(defn ns-candidates
42+
"Returns candidate data for all referred namespaces (and their aliases) in context-ns."
43+
[env context-ns]
44+
(for [[alias ns] (a/ns-aliases env context-ns)]
45+
(candidate-data alias ns ns :ns)))
46+
47+
(defn macro-ns-candidates
48+
"Returns candidate data for all referred macro namespaces (and their aliases) in
49+
context-ns."
50+
[env context-ns]
51+
(for [[alias ns] (a/macro-ns-aliases env context-ns)]
52+
(candidate-data alias ns ns :ns)))
53+
54+
(defn referred-var-candidates
55+
"Returns candidate data for all referred vars in context-ns."
56+
[env context-ns]
57+
(for [[refer qualified-name] (a/referred-vars env context-ns)
58+
:let [ns (namespace qualified-name)
59+
type (var->type (a/find-var env qualified-name))]]
60+
(candidate-data refer ns qualified-name type)))
61+
62+
(defn referred-macro-candidates
63+
"Returns candidate data for all referred macros in context-ns."
64+
[env context-ns]
65+
(for [[refer qualified-name] (a/referred-macros env context-ns)
66+
:let [ns (namespace qualified-name)]]
67+
(candidate-data refer ns qualified-name :macro)))
68+
69+
(defn- var-candidates
70+
[vars]
71+
(for [[name meta] vars
72+
:let [qualified-name (:name meta)
73+
ns (namespace qualified-name)
74+
type (var->type meta)]]
75+
(candidate-data name ns qualified-name type)))
76+
77+
(defn ns-var-candidates
78+
"Returns candidate data for all vars defined in ns."
79+
[env ns]
80+
(var-candidates (a/ns-vars env ns)))
81+
82+
(defn core-var-candidates
83+
"Returns candidate data for all cljs.core vars visible in context-ns."
84+
[env context-ns]
85+
(var-candidates (a/core-vars env context-ns)))
86+
87+
(defn macro-candidates
88+
[macros]
89+
(for [[name var] macros
90+
:let [var-meta (meta var)
91+
ns (ns-name (:ns var-meta))
92+
qualified-name (:name var-meta)]]
93+
(candidate-data name ns qualified-name :macro)))
94+
95+
(defn core-macro-candidates
96+
[env ns]
97+
"Returns candidate data for all cljs.core macros visible in ns."
98+
(macro-candidates (a/core-macros env ns)))
99+
100+
(defn import-candidates
101+
"Returns candidate data for all imports in context-ns."
102+
[env context-ns]
103+
(flatten
104+
(for [[import qualified-name] (a/imports env context-ns)]
105+
[(candidate-data import qualified-name qualified-name :import)
106+
(candidate-data qualified-name qualified-name qualified-name :import)])))
107+
108+
(defn unscoped-candidates
109+
"Returns all non-namespace-qualified potential candidates in context-ns."
110+
[env context-ns]
111+
(concat special-form-candidates
112+
(all-ns-candidates env)
113+
(ns-candidates env context-ns)
114+
(macro-ns-candidates env context-ns)
115+
(referred-var-candidates env context-ns)
116+
(referred-macro-candidates env context-ns)
117+
(ns-var-candidates env context-ns)
118+
(core-var-candidates env context-ns)
119+
(core-macro-candidates env context-ns)
120+
(import-candidates env context-ns)))
13121

14-
(defn ns-completions
15-
"Returns a list of public vars in the given namespace."
16-
([env ns] (keys (a/public-vars env ns)))
17-
([env ns prefix] (prefix-completions prefix (ns-completions env ns))))
122+
(defn- prefix-candidate
123+
[prefix candidate-data]
124+
(let [candidate (:candidate candidate-data)
125+
prefixed-candidate (str prefix "/" candidate)]
126+
(assoc candidate-data :candidate prefixed-candidate)))
18127

19-
(defn macro-ns-completions
20-
"Returns a list of macro names in the given namespace."
21-
([ns] (keys (a/public-macros ns)))
22-
([ns prefix] (prefix-completions prefix (macro-ns-completions ns))))
128+
(defn- prefix-candidates
129+
[prefix candidates]
130+
(map #(prefix-candidate prefix %) candidates))
23131

24132
(defn- scope->ns
25133
[env scope context-ns]
@@ -33,41 +141,78 @@
33141
scope
34142
(a/to-macro-ns env scope context-ns)))
35143

36-
(defn scoped-completions
144+
(defn ns-public-var-candidates
145+
"Returns candidate data for all public vars defined in ns."
146+
[env ns]
147+
(var-candidates (a/public-vars env ns)))
148+
149+
(defn ns-macro-candidates
150+
"Returns candidate data for all macros defined in ns."
151+
[env ns]
152+
(macro-candidates (a/public-macros ns)))
153+
154+
(defn scoped-candidates
155+
"Returns all candidates for the namespace of sym. Sym must be
156+
namespace-qualified. Macro candidates are included if the namespace has its
157+
macros required in context-ns."
37158
[env sym context-ns]
38159
(let [scope (symbol (namespace sym))
39-
ns (scope->ns scope)
40-
macro-ns (scope->macro-ns scope)]
41-
(concat (ns-completions env ns scope)
42-
(macro-ns-completions macro-ns scope))))
160+
ns (scope->ns env scope context-ns)
161+
macro-ns (scope->macro-ns env scope context-ns)]
162+
(mapcat #(prefix-candidates scope %)
163+
[(ns-public-var-candidates env ns)
164+
(ns-macro-candidates env macro-ns)])))
43165

44-
(defn unscoped-completions
45-
[env context-ns]
46-
(concat special-forms
47-
(keys (a/all-ns env))
48-
(keys (a/ns-aliases env context-ns))
49-
(keys (a/macro-ns-aliases env context-ns))
50-
(keys (a/referred-vars env context-ns))
51-
(keys (a/referred-macros env context-ns))
52-
(keys (a/ns-vars env context-ns true))
53-
(keys (a/core-macros env context-ns))
54-
(keys (a/imports env context-ns))
55-
(vals (a/imports env context-ns))))
56-
57-
(defn potential-completions
166+
(defn potential-candidates
167+
"Returns all candidates for sym. If sym is namespace-qualified, the candidates
168+
for that namespace will be returned (including macros if the namespace has its
169+
macros required in context-ns). Otherwise, all non-namespace-qualified
170+
candidates for context-ns will be returned."
58171
[env sym context-ns]
59172
(if (namespace sym)
60-
(scoped-completions env sym context-ns)
61-
(unscoped-completions env context-ns)))
173+
(scoped-candidates env sym context-ns)
174+
(unscoped-candidates env context-ns)))
175+
176+
(def ^:private type-ranking
177+
[:special
178+
:ns
179+
:fn
180+
:protocol-fn
181+
:record
182+
:type
183+
:protocol
184+
:var
185+
:macro
186+
:import])
187+
188+
(defn- candidate-rank
189+
[candidate types]
190+
(.indexOf (vec types) (:type candidate)))
191+
192+
(defn- distinct-candidates
193+
"Filters candidates to have only one entry for each value of :candidate. If
194+
multiple such entries do exist, the one with the earliest appearing value
195+
of :type in types will be used."
196+
[candidates types]
197+
(let [grouped-candidates (group-by :candidate candidates)]
198+
(for [[candidate group] grouped-candidates]
199+
(first (sort-by #(candidate-rank % types) group)))))
200+
201+
(defn- candidate-match?
202+
[candidate prefix]
203+
(.startsWith ^String (:candidate candidate) (str prefix)))
62204

63205
(defn completions
64-
"Return a sequence of matching completions given current namespace and a prefix string"
206+
"Returns a sequence of matching completions given current namespace and a
207+
prefix string."
65208
([env prefix] (completions env prefix nil))
66209
([env prefix context-ns]
67-
(->> (potential-completions env (u/as-sym prefix) (u/as-sym context-ns))
68-
distinct
69-
(map str)
70-
(filter #(.startsWith % prefix))
71-
sort)))
210+
(let [prefix (u/as-sym prefix)
211+
context-ns (u/as-sym context-ns)
212+
candidates (potential-candidates env prefix context-ns)]
213+
(as-> candidates $
214+
(distinct-candidates $ type-ranking)
215+
(filter #(candidate-match? % prefix) $)
216+
(sort-by :candidate $)))))
72217

73218

src/cljs_tooling/info.clj

+4-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@
8888
[macro (get (a/referred-macros env context-ns) sym)] (format-macro (-> macro find-var meta))
8989

9090
;; var in ns
91-
[context-var (get (a/ns-vars env context-ns true) sym)] (format-var context-ns context-var)
91+
[context-var (get (a/ns-vars env context-ns) sym)] (format-var context-ns context-var)
92+
93+
;; var in cljs.core
94+
[var (get (a/core-vars env context-ns) sym)] (format-var context-ns var)
9295

9396
;; macro in cljs.core
9497
[macro (get (a/public-macros 'cljs.core) sym)] (format-macro (meta macro))

src/cljs_tooling/util/analysis.clj

+16-16
Original file line numberDiff line numberDiff line change
@@ -82,18 +82,28 @@
8282
[var]
8383
((complement :anonymous) (val var)))
8484

85-
(defn public-vars
86-
"Returns a list of the public vars declared in the ns."
87-
[env ns]
88-
(let [vars (:defs (find-ns env ns))]
89-
(into {} (filter (every-pred public? named?) vars))))
90-
9185
(defn- macro?
9286
[var]
9387
(-> (val var)
9488
meta
9589
:macro))
9690

91+
(defn ns-vars
92+
"Returns a list of the vars declared in the ns."
93+
[env ns]
94+
(->> (find-ns env ns)
95+
:defs
96+
(filter named?)
97+
(into {})))
98+
99+
(defn public-vars
100+
"Returns a list of the public vars declared in the ns."
101+
[env ns]
102+
(->> (find-ns env ns)
103+
:defs
104+
(filter (every-pred named? public?))
105+
(into {})))
106+
97107
(defn public-macros
98108
"Returns a list of the public macros declared in the ns."
99109
[ns]
@@ -109,16 +119,6 @@
109119
excludes (:excludes (find-ns env ns))]
110120
(apply dissoc vars excludes)))
111121

112-
(defn ns-vars
113-
"Returns a list of vars visible to the ns."
114-
([env ns] (ns-vars env ns false))
115-
([env ns include-core?]
116-
(merge (->> (find-ns env ns)
117-
:defs
118-
(filter named?)
119-
(into {}))
120-
(if include-core? (core-vars env ns)))))
121-
122122
(defn core-macros
123123
"Returns a list of cljs.core macros visible to the ns."
124124
[env ns]

test-resources/test_ns.cljs

+2
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@
33
(:require [cljs.core.async :refer [sliding-buffer]]
44
[clojure.string]
55
[om.core]))
6+
7+
(defrecord TestRecord [a b c])

0 commit comments

Comments
 (0)