-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathrepl.cljs
199 lines (182 loc) · 6.82 KB
/
repl.cljs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
(ns clj-refactor.repl
(:require
[cljs.reader :as reader]
[clojure.string :as string]
[rewrite-clj.parser :as parser]
[clj-refactor.util :refer [echo-err]]
[clj-refactor.transform :as transform]
[cljs.core.async :refer [close! chan <!]])
(:require-macros
[cljs.core.async.macros :refer [go]]))
(def ^{:private true :doc "vim list type hint for fireplace#message"} v:t_list 3)
(defn handle-fireplace
[done-ch nvim args cb results]
(js/console.log "First debug of handle-fireplace" (pr-str args) (pr-str results))
(cond
(not results)
(throw (ex-info "Unable to get results"
{:message (str (pr-str args) "=>" (pr-str results))}))
(aget (first results) "error")
(throw (ex-info "Error during fireplace#message: "
{:message (aget (first results) "error")}))
:else
(do
(js/console.log (:op args) results)
(cb (first results)))))
(defn fireplace-message
([nvim args cb]
(fireplace-message true (chan) nvim args cb))
([done-ch nvim args cb]
(fireplace-message true done-ch nvim args cb))
([save? done-ch nvim args cb]
(-> (if save?
(.command nvim "w")
(js/Promise.resolve 0))
(.then (fn [_]
(.callFunction nvim "fireplace#message" (clj->js [(clj->js args) v:t_list]))))
(.catch (fn [err]
(js/console.log (pr-str args) err)
(echo-err nvim (str "Error: " err))
(close! done-ch)))
(.then (partial handle-fireplace done-ch nvim args cb))
(.catch (fn [err]
(echo-err nvim (str "Error: " (str (.-message err) (-> err ex-data :message))))
(close! done-ch))))))
(defn nrepl-resolve-missing
"Try to add a ns libspec based on whatever the middleware thinks."
[done-ch run-transform nvim sym cursor]
(fireplace-message
false
done-ch
nvim
{:op "resolve-missing" :symbol (str sym)}
(fn [result]
(let [cstr (aget result "candidates")]
(if (seq cstr)
(let [candidates (reader/read-string cstr)]
(when (> (count candidates) 1)
(js/console.log "More than one candidate!" candidates))
;; take first one for now - maybe can get input() choice
(if-let [{:keys [name type]} (first candidates)]
(run-transform done-ch transform/add-candidate nvim [name type (namespace sym)] cursor)
(close! done-ch))))
(do
(.command nvim "echo 'No candidates'")
(close! done-ch))))))
(defn nrepl-namespace-aliases
"Try to add a ns libspec based on already used aliases.
Falls back to `resolve-missing`."
[done-ch run-transform nvim sym cursor]
(fireplace-message
false
done-ch
nvim
{:op "namespace-aliases"}
(fn [result]
(let [cstr (aget result "namespace-aliases")
aliases (reader/read-string cstr)
sym-ns (namespace sym)]
(if-let [missing (first (get-in aliases [:clj (symbol sym-ns)]))]
(run-transform done-ch transform/add-candidate nvim [missing :ns sym-ns] cursor)
(nrepl-resolve-missing done-ch run-transform nvim sym cursor))))))
(defn add-missing-libspec
"Asks repl for the missing libspec.
When the repl comes back with response, run transform to add to ns"
[done-ch run-transform nvim _ [cursor word]]
(let [sym (symbol word)]
(if (namespace sym)
(nrepl-namespace-aliases done-ch run-transform nvim sym cursor)
(nrepl-resolve-missing done-ch run-transform nvim sym cursor))))
(defn clean-ns
"Asks repl for the missing libspec.
When the repl comes back with response, run transform to add to ns"
[done-ch run-transform nvim _ [cursor path prune-ns-form prefix-rewriting]]
(fireplace-message
done-ch
nvim
{:op "clean-ns"
:path path
:prefix-rewriting (if (pos? prefix-rewriting) "true" "false")
:prune-ns-form (if (pos? prune-ns-form) "true" "false")}
(fn [result]
(let [ns-str (aget result "ns")]
(if (string? ns-str)
(run-transform
done-ch transform/replace-ns nvim [(parser/parse-string ns-str)] cursor)
(close! done-ch))))))
(defn rename-file
[nvim [new-file] current-file]
(fireplace-message
nvim
{:op "rename-file-or-dir" :old-path current-file :new-path new-file}
(fn [result]
(let [touched (aget result "touched")]
(.command nvim (str "e " new-file " | silent! bp | bd"))))))
(defn rename-dir
[nvim [new-dir] current-dir]
(fireplace-message
nvim
{:op "rename-file-or-dir" :old-path current-dir :new-path new-dir}
(fn [result]
(let [touched (aget result "touched")]
(.command nvim (str "e " new-dir " | silent! bp | bd"))))))
(defn extract-definition
[transform-fn nvim args [project-dir buffer-file buffer-ns word info [_ row col _]]]
(let [ns (or (aget info "ns") buffer-ns)
name (or (aget info "name") word)]
(fireplace-message
nvim
{:op "extract-definition"
:file buffer-file
:dir project-dir
:ns ns
:name name
:line row
:column col}
(fn [result]
(let [edn (aget result "definition")
defs (reader/read-string edn)]
(apply transform-fn nvim ns name defs args))))))
(defn rename-symbol
[nvim sym-ns sym-name defs new-symbol]
(go
;; TODO look at clj-refactor.el for safer impl
(let [wait-ch (chan)]
(let [{:keys [line-beg col-beg file name]} (:definition defs)]
(.command nvim (str "e " file " | "
"call cursor(" line-beg "," col-beg ") | "
"exe \"normal! w/" sym-name "\ncw" new-symbol "\" | "
"w")))
(doseq [occurrence (conj (:occurrences defs))
:let [{:keys [line-beg col-beg file name]} occurrence]]
(.command nvim (str "e " file " | "
"call cursor(" line-beg "," col-beg ") | "
"exe \"normal! cw" new-symbol "\" | "
"w")
(fn [err]
(close! wait-ch)))
(<! wait-ch)))))
(defn find-used-locals
[run-transform transform-fn nvim args [file [_ row col _]]]
(fireplace-message
nvim
{:op "find-used-locals"
:file file
:line row
:column col}
(fn [result]
(let [used-locals (seq (js->clj (aget result "used-locals")))]
(run-transform transform-fn nvim (conj (js->clj args) used-locals) [0 row col 0])))))
(defn magic-requires
[done-ch run-transform nvim args [cursor path word]]
(go
(let [cram-ch (chan)
clean-ch (chan)]
(add-missing-libspec cram-ch run-transform nvim args [cursor word])
(js/console.log "waiting on cram")
(<! cram-ch)
(clean-ns clean-ch run-transform nvim args [cursor path])
(js/console.log "waiting on clean")
(<! clean-ch)
(js/console.log "closing magic")
(close! done-ch))))