|
9 | 9 | [orchard.java :as java]
|
10 | 10 | [orchard.misc :as u]
|
11 | 11 | [orchard.meta :as m]
|
| 12 | + [orchard.info :as clj-info] |
| 13 | + [orchard.eldoc :as eldoc] |
12 | 14 | [cljs-tooling.info :as cljs-info]
|
13 | 15 | [orchard.spec :as spec]))
|
14 | 16 |
|
15 |
| -(defn- resource-full-path [relative-path] |
16 |
| - (io/resource relative-path (class-loader))) |
| 17 | +(declare format-response) |
17 | 18 |
|
18 |
| -(def see-also-data |
19 |
| - (edn/read-string (slurp (io/resource "see-also.edn")))) |
| 19 | +(defn format-nested |
| 20 | + "Apply response formatting to nested `:candidates` info for Java members." |
| 21 | + [info] |
| 22 | + (if-let [candidates (:candidates info)] |
| 23 | + (assoc info :candidates |
| 24 | + (zipmap (keys candidates) |
| 25 | + (->> (vals candidates) (map format-response)))) |
| 26 | + info)) |
20 | 27 |
|
21 |
| -(defn info-clj |
22 |
| - [ns sym] |
23 |
| - (or |
24 |
| - ;; it's a special (special-symbol?) |
25 |
| - (m/special-sym-meta sym) |
26 |
| - ;; it's a var |
27 |
| - (m/var-meta (m/resolve-var ns sym)) |
28 |
| - ;; sym is an alias for another ns |
29 |
| - (m/ns-meta (get (m/resolve-aliases ns) sym)) |
30 |
| - ;; it's simply a full ns |
31 |
| - (m/ns-meta (find-ns sym)) |
32 |
| - ;; it's a Java class/member symbol...or nil |
33 |
| - (java/resolve-symbol ns sym))) |
| 28 | +(defn blacklist |
| 29 | + "Remove anything that might contain arbitrary EDN, metadata can hold anything" |
| 30 | + [info] |
| 31 | + (let [blacklisted #{:arglists :forms}] |
| 32 | + (apply dissoc info blacklisted))) |
| 33 | + |
| 34 | +(defn format-response |
| 35 | + [info] |
| 36 | + (letfn [(forms-join [forms] |
| 37 | + (->> (map pr-str forms) |
| 38 | + (str/join \newline)))] |
| 39 | + (when info |
| 40 | + (-> info |
| 41 | + (merge (when-let [ns (:ns info)] |
| 42 | + {:ns (str ns)}) |
| 43 | + (when-let [args (:arglists info)] |
| 44 | + {:arglists-str (forms-join args)}) |
| 45 | + (when-let [forms (:forms info)] |
| 46 | + {:forms-str (forms-join forms)}) |
| 47 | + (when-let [file (:file info)] |
| 48 | + (clj-info/file-info file)) |
| 49 | + (when-let [path (:javadoc info)] |
| 50 | + (clj-info/javadoc-info path))) |
| 51 | + format-nested |
| 52 | + blacklist |
| 53 | + u/transform-value)))) |
34 | 54 |
|
35 | 55 | (defn info-cljs
|
36 | 56 | [env symbol ns]
|
|
58 | 78 | f))
|
59 | 79 | f)))))
|
60 | 80 |
|
61 |
| -(defn info-java |
62 |
| - [class member] |
63 |
| - (java/member-info class member)) |
64 |
| - |
65 | 81 | (defn info
|
66 | 82 | [{:keys [ns symbol class member] :as msg}]
|
67 | 83 | (let [[ns symbol class member] (map u/as-sym [ns symbol class member])]
|
68 | 84 | (if-let [cljs-env (cljs/grab-cljs-env msg)]
|
69 | 85 | (info-cljs cljs-env symbol ns)
|
70 |
| - (let [var-info (cond (and ns symbol) (info-clj ns symbol) |
71 |
| - (and class member) (info-java class member) |
| 86 | + (let [var-info (cond (and ns symbol) (clj-info/info ns symbol) |
| 87 | + (and class member) (clj-info/info-java class member) |
72 | 88 | :else (throw (Exception.
|
73 | 89 | "Either \"symbol\", or (\"class\", \"member\") must be supplied")))
|
74 |
| - var-key (str (:ns var-info) "/" (:name var-info)) |
75 |
| - see-also (->> (get see-also-data var-key) |
76 |
| - (filter (comp resolve u/as-sym)))] |
| 90 | + see-also (clj-info/see-also ns symbol)] |
77 | 91 | (if (seq see-also)
|
78 | 92 | (merge {:see-also see-also} var-info)
|
79 | 93 | var-info)))))
|
80 | 94 |
|
81 |
| -(defn resource-path |
82 |
| - "If it's a resource, return a tuple of the relative path and the full resource path." |
83 |
| - [x] |
84 |
| - (or (if-let [full (resource-full-path x)] |
85 |
| - [x full]) |
86 |
| - (if-let [[_ relative] (re-find #".*jar!/(.*)" x)] |
87 |
| - (if-let [full (resource-full-path relative)] |
88 |
| - [relative full])) |
89 |
| - ;; handles load-file on jar resources from a cider buffer |
90 |
| - (if-let [[_ relative] (re-find #".*jar:(.*)" x)] |
91 |
| - (if-let [full (resource-full-path relative)] |
92 |
| - [relative full])))) |
93 |
| - |
94 |
| -(defn file-path |
95 |
| - "For a file path, return a URL to the file if it exists and does not |
96 |
| - represent a form evaluated at the REPL." |
97 |
| - [x] |
98 |
| - (when (seq x) |
99 |
| - (let [f (io/file x)] |
100 |
| - (when (and (.exists f) |
101 |
| - (not (-> f .getName (.startsWith "form-init")))) |
102 |
| - (io/as-url f))))) |
103 |
| - |
104 |
| -(defn file-info |
105 |
| - [path] |
106 |
| - (let [[resource-relative resource-full] (resource-path path)] |
107 |
| - (merge {:file (or (file-path path) resource-full path)} |
108 |
| - ;; Classpath-relative path if possible |
109 |
| - (if resource-relative |
110 |
| - {:resource resource-relative})))) |
111 |
| - |
112 |
| -(defn javadoc-info |
113 |
| - "Resolve a relative javadoc path to a URL and return as a map. Prefer javadoc |
114 |
| - resources on the classpath; then use online javadoc content for core API |
115 |
| - classes. If no source is available, return the relative path as is." |
116 |
| - [path] |
117 |
| - {:javadoc |
118 |
| - (or (resource-full-path path) |
119 |
| - ;; [bug#308] `*remote-javadocs*` is outdated WRT Java |
120 |
| - ;; 8, so we try our own thing first. |
121 |
| - (when (re-find #"^(java|javax|org.omg|org.w3c.dom|org.xml.sax)/" path) |
122 |
| - (format "http://docs.oracle.com/javase/%d/docs/api/%s" |
123 |
| - u/java-api-version path)) |
124 |
| - ;; If that didn't work, _then_ we fallback on `*remote-javadocs*`. |
125 |
| - (some (let [classname (.replaceAll path "/" ".")] |
126 |
| - (fn [[prefix url]] |
127 |
| - (when (.startsWith classname prefix) |
128 |
| - (str url path)))) |
129 |
| - @javadoc/*remote-javadocs*) |
130 |
| - path)}) |
131 |
| - |
132 |
| -;; TODO: Seems those were hardcoded here accidentally - we should |
133 |
| -;; probably provide a simple API to register remote JavaDocs. |
134 |
| -(javadoc/add-remote-javadoc "com.amazonaws." "http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/") |
135 |
| -(javadoc/add-remote-javadoc "org.apache.kafka." "https://kafka.apache.org/090/javadoc/index.html?") |
136 |
| - |
137 |
| -(declare format-response) |
138 |
| - |
139 |
| -(defn format-nested |
140 |
| - "Apply response formatting to nested `:candidates` info for Java members." |
141 |
| - [info] |
142 |
| - (if-let [candidates (:candidates info)] |
143 |
| - (assoc info :candidates |
144 |
| - (zipmap (keys candidates) |
145 |
| - (->> (vals candidates) (map format-response)))) |
146 |
| - info)) |
147 |
| - |
148 |
| -(defn blacklist |
149 |
| - "Remove anything that might contain arbitrary EDN, metadata can hold anything" |
150 |
| - [info] |
151 |
| - (let [blacklisted #{:arglists :forms}] |
152 |
| - (apply dissoc info blacklisted))) |
153 |
| - |
154 |
| -(defn format-response |
155 |
| - [info] |
156 |
| - (letfn [(forms-join [forms] |
157 |
| - (->> (map pr-str forms) |
158 |
| - (str/join \newline)))] |
159 |
| - (when info |
160 |
| - (-> info |
161 |
| - (merge (when-let [ns (:ns info)] |
162 |
| - {:ns (str ns)}) |
163 |
| - (when-let [args (:arglists info)] |
164 |
| - {:arglists-str (forms-join args)}) |
165 |
| - (when-let [forms (:forms info)] |
166 |
| - {:forms-str (forms-join forms)}) |
167 |
| - (when-let [file (:file info)] |
168 |
| - (file-info file)) |
169 |
| - (when-let [path (:javadoc info)] |
170 |
| - (javadoc-info path))) |
171 |
| - format-nested |
172 |
| - blacklist |
173 |
| - u/transform-value)))) |
174 |
| - |
175 | 95 | (defn info-reply
|
176 | 96 | [msg]
|
177 | 97 | (if-let [var-info (format-response (info msg))]
|
178 | 98 | var-info
|
179 | 99 | {:status :no-info}))
|
180 | 100 |
|
181 |
| -(defn extract-arglists |
182 |
| - [info] |
183 |
| - (cond |
184 |
| - (:special-form info) (->> (:forms info) |
185 |
| - ;; :forms contains a vector of sequences or symbols |
186 |
| - ;; which we have to convert the format employed by :arglists |
187 |
| - (map #(if (coll? %) (vec %) (vector %)))) |
188 |
| - (:candidates info) (->> (:candidates info) |
189 |
| - vals |
190 |
| - (mapcat :arglists) |
191 |
| - distinct |
192 |
| - (sort-by count)) |
193 |
| - :else (:arglists info))) |
194 |
| - |
195 |
| -(defn format-arglists [raw-arglists] |
196 |
| - (map #(mapv str %) raw-arglists)) |
197 |
| - |
198 |
| -(defn extract-ns-or-class |
199 |
| - [{:keys [ns class candidates] :as info}] |
200 |
| - (cond |
201 |
| - ns {:ns (str ns)} |
202 |
| - class {:class [(str class)]} |
203 |
| - candidates {:class (map key candidates)})) |
204 |
| - |
205 |
| -(defn extract-name-or-member |
206 |
| - [{:keys [name member candidates]}] |
207 |
| - (cond |
208 |
| - name {:name (str name)} |
209 |
| - member {:member (str member)} |
210 |
| - candidates {:member (->> candidates vals (map :member) first str)})) |
211 |
| - |
212 |
| -(defn extract-eldoc |
213 |
| - [info] |
214 |
| - (if-let [arglists (seq (-> info extract-arglists format-arglists))] |
215 |
| - {:eldoc arglists :type "function"} |
216 |
| - {:type "variable"})) |
217 |
| - |
218 | 101 | (defn eldoc-reply
|
219 | 102 | [msg]
|
220 | 103 | (if-let [info (info msg)]
|
221 |
| - (merge (extract-ns-or-class info) |
222 |
| - (extract-name-or-member info) |
223 |
| - (extract-eldoc info) |
224 |
| - {:docstring (:doc info)}) |
| 104 | + (eldoc/eldoc info) |
225 | 105 | {:status :no-eldoc}))
|
226 | 106 |
|
227 | 107 | (defn eldoc-datomic-query-reply
|
228 |
| - [msg] |
| 108 | + [{:keys [ns symbol] :as msg}] |
229 | 109 | (try
|
230 |
| - (let [ns (read-string (:ns msg)) |
231 |
| - sym (read-string (:symbol msg)) |
232 |
| - query (if (symbol? sym) |
233 |
| - (deref (ns-resolve ns sym)) |
234 |
| - (eval sym)) |
235 |
| - inputs (if (map? query) |
236 |
| - ;; query as map |
237 |
| - (or (:in query) "$") |
238 |
| - ;; query as vector |
239 |
| - (let [partitioned (partition-by keyword? query) |
240 |
| - index (.indexOf partitioned '(:in))] |
241 |
| - (if (= index -1) |
242 |
| - "$" |
243 |
| - (nth partitioned (+ 1 index)))))] |
244 |
| - {:inputs (format-arglists [inputs])}) |
| 110 | + (eldoc/datomic-query ns symbol) |
245 | 111 | (catch Throwable _ {:status :no-eldoc})))
|
246 | 112 |
|
247 | 113 | (defn handle-info [handler msg]
|
|
0 commit comments