Skip to content

Commit 67518a5

Browse files
authored
Observe thread interruption status for cancellable tasks (#319)
Otherwise `future-cancel` wouldn't do much - at least from what I can infer reading the code. Fixes #316
1 parent b78e354 commit 67518a5

File tree

5 files changed

+52
-22
lines changed

5 files changed

+52
-22
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
* This increases the chances that a namespace will be found, which in turns makes refactor-nrepl more complete/accurate.
1313
* Replace Cheshire with `clojure.data.json`
1414
* Build ASTs more robustly (by using locks and ruling out certain namespaces like refactor-nrepl itself)
15+
* Honor internal `future-cancel` calls, improving overall responsiveness and stability.
1516

1617
### Bugs fixed
1718
* [#289](https://github.com/clojure-emacs/refactor-nrepl/issues/289): Fix an edge-case with involving keywords that caused find-symbol to crash.

src/refactor_nrepl/find/find_macros.clj

+12-4
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@
5555
opts {:read-cond :allow :features #{:clj} :eof :eof}]
5656
(loop [macros [], form (reader/read opts rdr)]
5757
(cond
58-
(= form :eof) macros
58+
(or (= form :eof)
59+
(util/interrupted?)) macros
5960
(and (sequential? form) (= (first form) 'defmacro))
6061
(recur (conj macros (build-macro-meta form f))
6162
(reader/read opts rdr))
@@ -82,7 +83,8 @@
8283
"Finds all macros that are defined in the project."
8384
[ignore-errors?]
8485
(->> (core/find-in-project (util/with-suppressed-errors
85-
(some-fn core/cljc-file? core/clj-file?)
86+
(every-pred (complement util/interrupted?)
87+
(some-fn core/cljc-file? core/clj-file?))
8688
ignore-errors?))
8789
(mapcat #(try
8890
(get-macro-definitions-in-file-with-caching %)
@@ -217,14 +219,20 @@
217219
(when (fully-qualified-name? fully-qualified-name)
218220
(let [all-defs (find-macro-definitions-in-project ignore-errors?)
219221
macro-def (first (filter #(= (:name %) fully-qualified-name) all-defs))
220-
tracker (tracker/build-tracker (util/with-suppressed-errors tracker/default-file-filter-predicate ignore-errors?))
222+
tracker (tracker/build-tracker (util/with-suppressed-errors
223+
(every-pred (complement util/interrupted?)
224+
tracker/default-file-filter-predicate)
225+
ignore-errors?))
221226
origin-ns (symbol (core/prefix fully-qualified-name))
222227
dependents (tracker/get-dependents tracker origin-ns)]
223228
(some->> macro-def
224229
^String (:file)
225230
File.
226231
(conj dependents)
227-
(mapcat (partial find-usages-in-file [macro-def]))
232+
(keep (fn [x]
233+
(when-not (util/interrupted?)
234+
(find-usages-in-file [macro-def] x))))
235+
(apply concat)
228236
(into #{})
229237
(remove nil?)
230238
(sort-by :line-beg)))))

src/refactor_nrepl/find/find_symbol.clj

+24-16
Original file line numberDiff line numberDiff line change
@@ -137,21 +137,28 @@
137137
(str/join "/" [namespace var-name]))
138138
referred-syms (libspecs/referred-syms-by-file&fullname ignore-errors)]
139139
(->> (core/dirs-on-classpath)
140-
(mapcat (partial core/find-in-dir (util/with-suppressed-errors
141-
(every-pred (some-fn core/clj-file? core/cljc-file?)
142-
(fn [f]
143-
(try
144-
(let [n (some-> f
145-
core/read-ns-form
146-
parse/name-from-ns-decl)]
147-
(if-not n
148-
false
149-
(not (self-referential? n))))
150-
(catch Exception e
151-
(util/maybe-log-exception e)
152-
false))))
153-
ignore-errors)))
154-
(mapcat (partial find-symbol-in-file fully-qualified-name ignore-errors referred-syms)))))
140+
(keep (fn [x]
141+
(when-not (util/interrupted?)
142+
(core/find-in-dir (util/with-suppressed-errors
143+
(every-pred (some-fn core/clj-file? core/cljc-file?)
144+
(fn [f]
145+
(try
146+
(let [n (some-> f
147+
core/read-ns-form
148+
parse/name-from-ns-decl)]
149+
(if-not n
150+
false
151+
(not (self-referential? n))))
152+
(catch Exception e
153+
(util/maybe-log-exception e)
154+
false))))
155+
ignore-errors)
156+
x))))
157+
(apply concat)
158+
(keep (fn [x]
159+
(when-not (util/interrupted?)
160+
(find-symbol-in-file fully-qualified-name ignore-errors referred-syms x))))
161+
(apply concat))))
155162

156163
(defn- get&read-enclosing-sexps
157164
[file-content {:keys [^long line-beg ^long col-beg]}]
@@ -249,7 +256,8 @@
249256
macros (future (find-macro (core/fully-qualify ns name) ignore-errors?))
250257
globals (->> (find-global-symbol file ns name ignore-errors?)
251258
distinct
252-
(remove find-util/spurious?)
259+
(remove (some-fn util/interrupted?
260+
find-util/spurious?))
253261
future)]
254262

255263
(or

src/refactor_nrepl/ns/tracker.clj

+4-2
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,11 @@
5353
"Get the dependent files for ns from tracker."
5454
[tracker my-ns]
5555
(let [deps (dep/immediate-dependents (:clojure.tools.namespace.track/deps tracker)
56-
(symbol my-ns))]
56+
(symbol my-ns))
57+
deps-set (set deps)]
5758
(for [[file ns] (:clojure.tools.namespace.file/filemap tracker)
58-
:when ((set deps) ns)]
59+
:when (and (not (util/interrupted?))
60+
(deps-set ns))]
5961
file)))
6062

6163
(defn- in-refresh-dirs? [refresh-dirs file]

src/refactor_nrepl/util.clj

+11
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,14 @@
8888
(maybe-log-exception e)
8989
;; return false, because `with-suppressed-errors` is oriented for predicate usage
9090
false)))))
91+
92+
(defn interrupted?
93+
"Has the current thread been interrupted?
94+
95+
Observing this condition helps `future-cancel` effectively cancel `future`s."
96+
([]
97+
(interrupted? ::_))
98+
;; The arity with a "useless" arg is there so that this can be used as a predicate
99+
;; in other places that already are using `some-fn`, `every-pred`, etc
100+
([_]
101+
(.isInterrupted (Thread/currentThread))))

0 commit comments

Comments
 (0)