Skip to content

Commit 2c6ee6b

Browse files
committed
Better formatter for exceptions
1 parent 9e67362 commit 2c6ee6b

File tree

6 files changed

+65
-19
lines changed

6 files changed

+65
-19
lines changed

README.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,11 @@ If your evaluation runs too long and you want to interrupt it, run `Clojure REPL
122122

123123
If your evaluation failed, put your cursor inside failed region and run `Clojure REPL: Toggle Stacktrace`:
124124

125-
<img src="https://raw.github.com/tonsky/sublime-clojure/master/screenshots/toggle_stacktrace.png" width="594" height="165" alt="Toggle Stacktrace">
125+
<img src="https://raw.github.com/tonsky/sublime-clojure/master/screenshots/toggle_stacktrace.png" width="553" height="146" alt="Toggle Stacktrace">
126+
127+
Sublime Clojure will display stacktraces in a Clojure-friendly way. Compare with the default REPL:
128+
129+
<img src="https://raw.github.com/tonsky/sublime-clojure/master/screenshots/stacktraces.png" width="806" height="390" alt="Stacktraces">
126130

127131
To show symbol info, run `Clojure REPL: Toggle Symbol Info`:
128132

@@ -140,10 +144,10 @@ To edit settings, run `Preferences: Sublime Clojure Settings` command.
140144
Command | macOS | Windows/Linux | Mnemonic
141145
------------------------------|----------------------------------|-------------------------------------------------| -----------------------
142146
Evaluate | <kbd>Ctrl</kbd> <kbd>Enter</kbd> | <kbd>Ctrl</kbd> <kbd>Alt</kbd> <kbd>Enter</kbd> |
143-
Evaluate Buffer | <kbd>Ctrl</kbd> <kbd>B</kbd> | <kbd>Ctrl</kbd> <kbd>Alt</kbd> <kbd>B</kbd> | <kbd>B</kbd>uffer
144-
Interrupt Pending Evaluations | <kbd>Ctrl</kbd> <kbd>C</kbd> | <kbd>Ctrl</kbd> <kbd>Alt</kbd> <kbd>C</kbd> | <kbd>C</kbd>ancel
145-
Toggle Info | <kbd>Ctrl</kbd> <kbd>I</kbd> | <kbd>Ctrl</kbd> <kbd>Alt</kbd> <kbd>I</kbd> | <kbd>I</kbd>nfo
146-
Clear Evaluation Results | <kbd>Ctrl</kbd> <kbd>L</kbd> | <kbd>Ctrl</kbd> <kbd>Alt</kbd> <kbd>L</kbd> | C<kbd>l</kbd>ear
147+
Evaluate Buffer | <kbd>Ctrl</kbd> <kbd>B</kbd> | <kbd>Ctrl</kbd> <kbd>Alt</kbd> <kbd>B</kbd> | [B]uffer
148+
Interrupt Pending Evaluations | <kbd>Ctrl</kbd> <kbd>C</kbd> | <kbd>Ctrl</kbd> <kbd>Alt</kbd> <kbd>C</kbd> | [C]ancel
149+
Toggle Info | <kbd>Ctrl</kbd> <kbd>I</kbd> | <kbd>Ctrl</kbd> <kbd>Alt</kbd> <kbd>I</kbd> | [I]nfo
150+
Clear Evaluation Results | <kbd>Ctrl</kbd> <kbd>L</kbd> | <kbd>Ctrl</kbd> <kbd>Alt</kbd> <kbd>L</kbd> | c[L]ear
147151

148152
To change key bindings, run `Preferences: Sublime Clojure Key Bindings` command.
149153

screenshots/stacktraces.png

354 KB
Loading

screenshots/toggle_stacktrace.png

-22.5 KB
Loading

src/middleware.clj

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,55 @@
1111
[nrepl.transport Transport]))
1212

1313
(defn- root-cause [^Throwable t]
14-
(when t
15-
(loop [t t]
16-
(if-some [cause (.getCause t)]
17-
(recur cause)
18-
t))))
14+
(if-some [cause (some-> t .getCause)]
15+
(recur cause)
16+
t))
1917

2018
(defn print-root-trace [^Throwable t]
2119
(stacktrace/print-stack-trace (root-cause t)))
2220

23-
(defn trace [^Throwable t]
24-
(let [trace (with-out-str
25-
(.printStackTrace t (java.io.PrintWriter. *out*)))]
26-
(if-some [idx (str/index-of trace "\n\tat clojure.lang.Compiler.eval(Compiler.java:")]
27-
(subs trace 0 idx)
28-
trace)))
21+
(defn- duplicate? [^StackTraceElement prev-el ^StackTraceElement el]
22+
(and
23+
(= (.getClassName prev-el) (.getClassName el))
24+
(= (.getFileName prev-el) (.getFileName el))
25+
(= "invokeStatic" (.getMethodName prev-el))
26+
(#{"invoke" "doInvoke"} (.getMethodName el))))
27+
28+
(defn- clear-duplicates [els]
29+
(for [[prev-el el] (map vector (cons nil els) els)
30+
:when (or (nil? prev-el) (not (duplicate? prev-el el)))]
31+
el))
32+
33+
(defn- trace-element-str [^StackTraceElement el]
34+
(let [file (.getFileName el)
35+
clojure? (and file
36+
(or (.endsWith file ".clj")
37+
(.endsWith file ".cljc")
38+
(= file "NO_SOURCE_FILE")))]
39+
(str
40+
"\t"
41+
(if clojure?
42+
(clojure.lang.Compiler/demunge (.getClassName el))
43+
(str (.getClassName el) "." (.getMethodName el)))
44+
" ("
45+
(.getFileName el)
46+
":"
47+
(.getLineNumber el)
48+
")")))
49+
50+
(defn- trace-str [^Throwable t]
51+
(str
52+
(.getSimpleName (class t))
53+
": "
54+
(.getMessage t)
55+
(when-some [data (ex-data t)] (str " " (pr-str data)))
56+
"\n"
57+
(->> (.getStackTrace t)
58+
(take-while #(not= "clojure.lang.Compiler" (.getClassName ^StackTraceElement %)))
59+
(remove #(#{"clojure.lang.RestFn" "clojure.lang.AFn"} (.getClassName ^StackTraceElement %)))
60+
(clear-duplicates)
61+
(map trace-element-str)
62+
(str/join "\n"))))
2963

3064
(defn- caught-transport [{:keys [transport] :as msg}]
3165
(reify Transport
@@ -44,7 +78,7 @@
4478
root (assoc
4579
::root-ex-msg (.getMessage root)
4680
::root-ex-class (.getSimpleName (class root))
47-
::trace (trace root))
81+
::trace (trace-str root))
4882
loc (merge loc)
4983
data (update ::print/keys (fnil conj []) ::root-ex-data)
5084
data (assoc ::root-ex-data data))]

test_repl/error_syntax.clj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,6 @@
44
(let [x 1
55
y 2]]))
66

7-
(defn h [])
7+
(defn h [])
8+
9+
(let [x])

test_repl/stacktraces.cljc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@
99
(defn h []
1010
(g))
1111

12+
(h)
13+
1214
(meta #'h)
1315

14-
(h)
16+
(try
17+
(h)
18+
(catch Exception e
19+
(with-out-str
20+
(.printStackTrace e))))
1521

1622
(defn -main [& args]
1723
(h))

0 commit comments

Comments
 (0)