Skip to content

Commit 3f9d238

Browse files
committed
Merge pull request #15 from cichli/completion-metadata
Completion metadata
2 parents c670637 + 161506f commit 3f9d238

File tree

5 files changed

+309
-109
lines changed

5 files changed

+309
-109
lines changed

src/cljs_tooling/complete.clj

+171-50
Original file line numberDiff line numberDiff line change
@@ -3,72 +3,193 @@
33
(:require [cljs-tooling.util.analysis :as a]
44
[cljs-tooling.util.misc :as u]))
55

6-
;;; TODO
7-
(defn ns-classes
8-
"Returns a list of potential class name completions for a given namespace"
9-
[env ns]
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})
1012

11-
;;(map name (keys (ns-imports ns)))
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-function
18+
:fn-var :function
19+
:record :record
20+
:protocols :type
21+
:protocol-symbol :protocol
22+
:var))
1323

1424
(def special-forms
1525
'#{& . case* catch def defrecord* deftype* do finally fn* if js* let*
1626
letfn* loop* new ns quote recur set! throw try})
1727

18-
(defn prefix-completions
19-
[prefix completions]
20-
(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 :namespace)))
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 :namespace)))
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 :namespace)))
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)))
79+
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)))
2191

22-
(defn ns-completions
23-
"Returns a list of public vars in the given namespace."
24-
([env ns] (keys (a/public-vars env ns)))
25-
([env ns prefix] (prefix-completions prefix (ns-completions env ns))))
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)))
118+
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))
128+
129+
(defn- scope->ns
130+
[env scope context-ns]
131+
(if (a/find-ns env scope)
132+
scope
133+
(a/to-ns env scope context-ns)))
26134

27-
(defn macro-ns-completions
28-
"Returns a list of macro names in the given namespace."
29-
([ns] (keys (a/public-macros ns)))
30-
([ns prefix] (prefix-completions prefix (macro-ns-completions ns))))
135+
(defn- scope->macro-ns
136+
[env scope context-ns]
137+
(if (= scope 'cljs.core)
138+
scope
139+
(a/to-macro-ns env scope context-ns)))
31140

32-
(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."
33155
[env sym context-ns]
34156
(let [scope (symbol (namespace sym))
35-
ns (if (a/find-ns env scope)
36-
scope
37-
(a/to-ns env scope context-ns))
38-
macro-ns (if (= scope 'cljs.core)
39-
scope
40-
(a/to-macro-ns env scope context-ns))]
41-
(concat (ns-completions env ns scope)
42-
(macro-ns-completions macro-ns scope))))
43-
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-
(ns-classes env context-ns)))
57-
58-
(defn potential-completions
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)])))
162+
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."
59168
[env sym context-ns]
60169
(if (namespace sym)
61-
(scoped-completions env sym context-ns)
62-
(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)))
63182

64183
(defn completions
65-
"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."
66186
([env prefix] (completions env prefix nil))
67187
([env prefix context-ns]
68-
(->> (potential-completions env (u/as-sym prefix) (u/as-sym context-ns))
69-
distinct
70-
(map str)
71-
(filter #(.startsWith % prefix))
72-
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)))))
73194

74195

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

+27-25
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
(:require [cljs-tooling.util.misc :as u])
33
(:refer-clojure :exclude [find-ns find-var all-ns ns-aliases]))
44

5-
65
(def NSES :cljs.analyzer/namespaces)
76

87
(defn all-ns
@@ -23,11 +22,20 @@
2322

2423
;; Code adapted from clojure-complete (http://github.com/ninjudd/clojure-complete)
2524

25+
(defn imports
26+
"Returns a map of [import-name] to [ns-qualified-import-name] for all imports
27+
in the given namespace."
28+
[env ns]
29+
(:imports (find-ns env ns)))
2630

2731
(defn ns-aliases
2832
"Returns a map of [ns-name-or-alias] to [ns-name] for the given namespace."
2933
[env ns]
30-
(:requires (find-ns env ns)))
34+
(let [imports (imports env ns)]
35+
(->> (find-ns env ns)
36+
:requires
37+
(filter #(not (contains? imports (key %))))
38+
(into {}))))
3139

3240
(defn macro-ns-aliases
3341
"Returns a map of [macro-ns-name-or-alias] to [macro-ns-name] for the given namespace."
@@ -54,12 +62,6 @@
5462
:use-macros
5563
expand-refer-map))
5664

57-
(defn imports
58-
"Returns a map of [import-name] to [ns-qualified-import-name] for all imports
59-
in the given namespace."
60-
[env ns]
61-
(:imports (find-ns env ns)))
62-
6365
(defn to-ns
6466
"If sym is an alias to, or the name of, a namespace referred to in ns, returns
6567
the name of the namespace; else returns nil."
@@ -80,22 +82,32 @@
8082
[var]
8183
((complement :anonymous) (val var)))
8284

83-
(defn public-vars
84-
"Returns a list of the public vars declared in the ns."
85-
[env ns]
86-
(let [vars (:defs (find-ns env ns))]
87-
(into {} (filter (every-pred public? named?) vars))))
88-
8985
(defn- macro?
9086
[var]
9187
(-> (val var)
9288
meta
9389
:macro))
9490

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+
95107
(defn public-macros
96108
"Returns a list of the public macros declared in the ns."
97109
[ns]
98-
(if (and ns (clojure.core/find-ns ns))
110+
(when (and ns (clojure.core/find-ns ns))
99111
(->> (ns-publics ns)
100112
(filter macro?)
101113
(into {}))))
@@ -107,16 +119,6 @@
107119
excludes (:excludes (find-ns env ns))]
108120
(apply dissoc vars excludes)))
109121

110-
(defn ns-vars
111-
"Vars visible to the ns"
112-
([env ns] (ns-vars env ns false))
113-
([env ns include-core?]
114-
(merge (->> (find-ns env ns)
115-
:defs
116-
(filter named?)
117-
(into {}))
118-
(if include-core? (core-vars env ns)))))
119-
120122
(defn core-macros
121123
"Returns a list of cljs.core macros visible to the ns."
122124
[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)