Skip to content

Commit c64754e

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

File tree

5 files changed

+278
-88
lines changed

5 files changed

+278
-88
lines changed

src/cljs_tooling/complete.clj

+160-38
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,128 @@
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 type]
9+
{:candidate (name candidate)
10+
:ns (symbol ns)
11+
:type type})
12+
13+
(defn- var->type
14+
"Returns the candidate type corresponding to the given metadata map."
15+
[var]
16+
(condp #(get %2 %1) var
17+
:protocol :protocol-fn
18+
:fn-var :fn
19+
:record :record
20+
:protocols :type
21+
:protocol-symbol :protocol
22+
:var))
23+
624
(def special-forms
725
'#{& . case* catch def defrecord* deftype* do finally fn* if js* let*
826
letfn* loop* new ns quote recur set! throw try})
927

10-
(defn prefix-completions
11-
[prefix completions]
12-
(map #(symbol (str prefix "/" %)) completions))
28+
(def special-form-candidates
29+
"Candidate data for all special forms."
30+
(for [form special-forms]
31+
(candidate-data form 'cljs.core :special-form)))
32+
33+
(defn all-ns-candidates
34+
"Returns candidate data for all namespaces in the environment."
35+
[env]
36+
(for [[ns _] (a/all-ns env)]
37+
(candidate-data ns ns :ns)))
38+
39+
(defn ns-candidates
40+
"Returns candidate data for all referred namespaces (and their aliases) in context-ns."
41+
[env context-ns]
42+
(for [[alias ns] (a/ns-aliases env context-ns)]
43+
(candidate-data alias ns :ns)))
44+
45+
(defn macro-ns-candidates
46+
"Returns candidate data for all referred macro namespaces (and their aliases) in
47+
context-ns."
48+
[env context-ns]
49+
(for [[alias ns] (a/macro-ns-aliases env context-ns)]
50+
(candidate-data alias ns :ns)))
51+
52+
(defn referred-var-candidates
53+
"Returns candidate data for all referred vars in context-ns."
54+
[env context-ns]
55+
(for [[refer qualified-name] (a/referred-vars env context-ns)
56+
:let [ns (namespace qualified-name)
57+
type (var->type (a/find-var env qualified-name))]]
58+
(candidate-data refer ns type)))
59+
60+
(defn referred-macro-candidates
61+
"Returns candidate data for all referred macros in context-ns."
62+
[env context-ns]
63+
(for [[refer qualified-name] (a/referred-macros env context-ns)
64+
:let [ns (namespace qualified-name)]]
65+
(candidate-data refer ns :macro)))
66+
67+
(defn- var-candidates
68+
[vars]
69+
(for [[name meta] vars
70+
:let [qualified-name (:name meta)
71+
ns (namespace qualified-name)
72+
type (var->type meta)]]
73+
(candidate-data name ns type)))
74+
75+
(defn ns-var-candidates
76+
"Returns candidate data for all vars defined in ns."
77+
[env ns]
78+
(var-candidates (a/ns-vars env ns)))
1379

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))))
80+
(defn core-var-candidates
81+
"Returns candidate data for all cljs.core vars visible in context-ns."
82+
[env context-ns]
83+
(var-candidates (a/core-vars env context-ns)))
84+
85+
(defn macro-candidates
86+
[macros]
87+
(for [[name var] macros
88+
:let [var-meta (meta var)
89+
ns (ns-name (:ns var-meta))]]
90+
(candidate-data name ns :macro)))
91+
92+
(defn core-macro-candidates
93+
[env ns]
94+
"Returns candidate data for all cljs.core macros visible in ns."
95+
(macro-candidates (a/core-macros env ns)))
96+
97+
(defn import-candidates
98+
"Returns candidate data for all imports in context-ns."
99+
[env context-ns]
100+
(flatten
101+
(for [[import qualified-name] (a/imports env context-ns)]
102+
[(candidate-data import qualified-name :import)
103+
(candidate-data qualified-name qualified-name :import)])))
104+
105+
(defn unscoped-candidates
106+
"Returns all non-namespace-qualified potential candidates in context-ns."
107+
[env context-ns]
108+
(concat special-form-candidates
109+
(all-ns-candidates env)
110+
(ns-candidates env context-ns)
111+
(macro-ns-candidates env context-ns)
112+
(referred-var-candidates env context-ns)
113+
(referred-macro-candidates env context-ns)
114+
(ns-var-candidates env context-ns)
115+
(core-var-candidates env context-ns)
116+
(core-macro-candidates env context-ns)
117+
(import-candidates env context-ns)))
18118

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))))
119+
(defn- prefix-candidate
120+
[prefix candidate-data]
121+
(let [candidate (:candidate candidate-data)
122+
prefixed-candidate (str prefix "/" candidate)]
123+
(assoc candidate-data :candidate prefixed-candidate)))
124+
125+
(defn- prefix-candidates
126+
[prefix candidates]
127+
(map #(prefix-candidate prefix %) candidates))
23128

24129
(defn- scope->ns
25130
[env scope context-ns]
@@ -33,41 +138,58 @@
33138
scope
34139
(a/to-macro-ns env scope context-ns)))
35140

36-
(defn scoped-completions
141+
(defn ns-public-var-candidates
142+
"Returns candidate data for all public vars defined in ns."
143+
[env ns]
144+
(var-candidates (a/public-vars env ns)))
145+
146+
(defn ns-macro-candidates
147+
"Returns candidate data for all macros defined in ns."
148+
[env ns]
149+
(macro-candidates (a/public-macros ns)))
150+
151+
(defn scoped-candidates
152+
"Returns all candidates for the namespace of sym. Sym must be
153+
namespace-qualified. Macro candidates are included if the namespace has its
154+
macros required in context-ns."
37155
[env sym context-ns]
38156
(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))))
157+
ns (scope->ns env scope context-ns)
158+
macro-ns (scope->macro-ns env scope context-ns)]
159+
(mapcat #(prefix-candidates scope %)
160+
[(ns-public-var-candidates env ns)
161+
(ns-macro-candidates env macro-ns)])))
43162

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
163+
(defn potential-candidates
164+
"Returns all candidates for sym. If sym is namespace-qualified, the candidates
165+
for that namespace will be returned (including macros if the namespace has its
166+
macros required in context-ns). Otherwise, all non-namespace-qualified
167+
candidates for context-ns will be returned."
58168
[env sym context-ns]
59169
(if (namespace sym)
60-
(scoped-completions env sym context-ns)
61-
(unscoped-completions env context-ns)))
170+
(scoped-candidates env sym context-ns)
171+
(unscoped-candidates env context-ns)))
172+
173+
(defn- distinct-candidates
174+
"Filters candidates to have only one entry for each value of :candidate. If
175+
multiple such entries do exist, the first occurrence is used."
176+
[candidates]
177+
(map first (vals (group-by :candidate candidates))))
178+
179+
(defn- candidate-match?
180+
[candidate prefix]
181+
(.startsWith ^String (:candidate candidate) (str prefix)))
62182

63183
(defn completions
64-
"Return a sequence of matching completions given current namespace and a prefix string"
184+
"Returns a sequence of candidate data for completions matching the given
185+
prefix string and (optionally) the current namespace."
65186
([env prefix] (completions env prefix nil))
66187
([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)))
188+
(let [prefix (u/as-sym prefix)
189+
context-ns (u/as-sym context-ns)]
190+
(->> (potential-candidates env prefix context-ns)
191+
distinct-candidates
192+
(filter #(candidate-match? % prefix))
193+
(sort-by :candidate)))))
72194

73195

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)