Skip to content

Commit 3feb4eb

Browse files
[print] Make orchard.print more consistent with CIDER printing
1 parent 6be9993 commit 3feb4eb

File tree

3 files changed

+61
-31
lines changed

3 files changed

+61
-31
lines changed

src/orchard/print.clj

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
(:refer-clojure :exclude [print print-str])
1111
(:import
1212
(clojure.core Eduction)
13-
(clojure.lang AFunction Compiler IDeref IPending IPersistentMap
14-
IPersistentSet IPersistentVector IRecord Keyword Symbol
15-
TaggedLiteral Var)
13+
(clojure.lang AFunction Compiler IDeref IPending IPersistentMap MultiFn
14+
IPersistentSet IPersistentVector IRecord Keyword Namespace
15+
Symbol TaggedLiteral Var)
16+
(java.io Writer)
1617
(java.util List Map Map$Entry)
1718
(mx.cider.orchard TruncatingStringWriter
1819
TruncatingStringWriter$TotalLimitExceeded))
@@ -50,7 +51,7 @@
5051
(defn- print-coll-item
5152
"Print an item in the context of a collection. When printing a map, don't print
5253
`[]` characters around map entries."
53-
[^TruncatingStringWriter w, x, map?]
54+
[^Writer w, x, map?]
5455
(if (and map? (instance? Map$Entry x))
5556
(do (print (.getKey ^Map$Entry x) w)
5657
(.write w " ")
@@ -60,7 +61,7 @@
6061
(defn- print-coll
6162
([w x sep prefix suffix]
6263
(print-coll w x sep prefix suffix false))
63-
([^TruncatingStringWriter w, ^Iterable x, ^String sep, ^String prefix,
64+
([^Writer w, ^Iterable x, ^String sep, ^String prefix,
6465
^String suffix, map?]
6566
(let [level *print-level*]
6667
(when-not (nil? level)
@@ -89,10 +90,10 @@
8990
(finally (when-not (nil? level)
9091
(set! *print-level* level)))))))
9192

92-
(defmethod print nil [_ ^TruncatingStringWriter w]
93+
(defmethod print nil [_ ^Writer w]
9394
(.write w "nil"))
9495

95-
(defmethod print :string [^String x, ^TruncatingStringWriter w]
96+
(defmethod print :string [^String x, ^Writer w]
9697
(let [len (.length x)
9798
max-len *max-atom-length*
9899
truncate? (and max-len (< max-len len))
@@ -106,7 +107,7 @@
106107
(.write w "..."))
107108
(.append w \")))
108109

109-
(defmethod print :scalar [^Object x, ^TruncatingStringWriter w]
110+
(defmethod print :scalar [^Object x, ^Writer w]
110111
(.write w (.toString x)))
111112

112113
(defmethod print :persistent-map [x w]
@@ -132,29 +133,33 @@
132133
(defmethod print :map [^Map x, w]
133134
(print-map x w))
134135

135-
(defmethod print :record [x, ^TruncatingStringWriter w]
136+
(defmethod print :record [x, ^Writer w]
136137
(.write w "#")
137138
(.write w (.getSimpleName (class x)))
138139
(print-map x w))
139140

140-
(defmethod print :array [x, ^TruncatingStringWriter w]
141+
(defmethod print :array [x, ^Writer w]
141142
(let [ct (.getName (or (.getComponentType (class x)) Object))
142143
as-seq (seq x)]
143144
(.write w ct)
144145
(if as-seq
145146
(print-coll w as-seq ", " "[] {" "}")
146147
(.write w "[] {}"))))
147148

148-
(defmethod print IDeref [^IDeref x, ^TruncatingStringWriter w]
149+
(defmethod print IDeref [^IDeref x, ^Writer w]
149150
(let [pending (and (instance? IPending x)
150151
(not (.isRealized ^IPending x)))
151152
[ex val]
152153
(when-not pending
153154
(try [false (deref x)]
154155
(catch Throwable e
155-
[true e])))]
156+
[true e])))
157+
full-name (.getName (class x))
158+
name (cond (str/starts-with? full-name "clojure.core$future_call") "future"
159+
(str/starts-with? full-name "clojure.core$promise") "promise"
160+
:else (str/lower-case (.getSimpleName (class x))))]
156161
(.write w "#")
157-
(.write w (.getSimpleName (class x)))
162+
(.write w name)
158163
(print [(cond (or ex
159164
(and (instance? clojure.lang.Agent x)
160165
(agent-error x)))
@@ -168,16 +173,36 @@
168173
(defmethod print Class [x w]
169174
(print-method x w))
170175

171-
(defmethod print AFunction [x, ^TruncatingStringWriter w]
176+
(defmethod print AFunction [x, ^Writer w]
172177
(.write w "#function[")
173178
(.write w (Compiler/demunge (.getName (class x))))
174179
(.write w "]"))
175180

181+
(def ^:private multifn-name-field
182+
(delay (doto (.getDeclaredField MultiFn "name")
183+
(.setAccessible true))))
184+
185+
(defn- multifn-name [^MultiFn mfn]
186+
(try (.get ^java.lang.reflect.Field @multifn-name-field mfn)
187+
(catch SecurityException _ "_")))
188+
189+
(defmethod print MultiFn [x, ^Writer w]
190+
(.write w "#multifn[")
191+
(.write w (multifn-name x))
192+
;; MultiFn names are not unique so we keep the identity to ensure it's unique.
193+
(.write w (format " 0x%x]" (System/identityHashCode x))))
194+
176195
(defmethod print TaggedLiteral [x w]
177196
(print-method x w))
178197

179-
(defmethod print Throwable [^Throwable x, ^TruncatingStringWriter w]
180-
(.write w "#Error[")
198+
(defmethod print Namespace [x, ^Writer w]
199+
(.write w "#namespace[")
200+
(.write w (str (ns-name x)))
201+
;; MultiFn names are not unique so we keep the identity to ensure it's unique.
202+
(.write w "]"))
203+
204+
(defmethod print Throwable [^Throwable x, ^Writer w]
205+
(.write w "#error[")
181206
(.write w (str (.getName (class x)) " "))
182207
(loop [cause x, msg nil]
183208
(if cause
@@ -191,7 +216,7 @@
191216
(print (str first-frame) w))
192217
(.write w "]"))
193218

194-
(defmethod print :default [^Object x, ^TruncatingStringWriter w]
219+
(defmethod print :default [^Object x, ^Writer w]
195220
(.write w (.toString x)))
196221

197222
(defn print-str

test/orchard/inspect_test.clj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@
168168
[:newline]
169169
" " [:value ":name" pos?] " = " [:value "any-var" pos?]
170170
[:newline]
171-
" " [:value ":ns" pos?] " = " [:value "orchard.inspect-test" pos?]
171+
" " [:value ":ns" pos?] " = " [:value "#namespace[orchard.inspect-test]" pos?]
172172
[:newline]
173173
[:newline]]
174174
(section "Meta Information" rendered)))
@@ -1147,7 +1147,7 @@
11471147
(is+ ["--- Refer from:"
11481148
[:newline]
11491149
" "
1150-
[:value "clojure.core" pos?]
1150+
[:value "#namespace[clojure.core]" pos?]
11511151
" = "
11521152
[:value #=(str "[#'clojure.core/primitives-classnames #'clojure.core/+' #'clojure.core/decimal? "
11531153
"#'clojure.core/restart-agent #'clojure.core/sort-by ...]") pos?]

test/orchard/print_test.clj

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -83,14 +83,19 @@
8383
"java.lang.Long[] {0, 1, 2, 3, 4}" (into-array Long (range 5))
8484
"java.lang.Long[] {}" (into-array Long [])
8585
"#<MyTestType test1>" (MyTestType. "test1")
86-
"#Atom[1]" (atom 1)
87-
"#Delay[<pending>]" (delay 1)
88-
"#Delay[1]" (doto (delay 1) deref)
89-
"#Delay[<failed>]" (let [d (delay (/ 1 0))] (try @d (catch Exception _)) d)
90-
#"#Error\[clojure.lang.ExceptionInfo \"Boom\" \"orchard.print_test.+\"\]" (ex-info "Boom" {})
91-
#"#Error\[clojure.lang.ExceptionInfo \"Boom\" \{:a 1\} \"orchard.print_test.+\"\]" (ex-info "Boom" {:a 1})
92-
#"#Error\[java.lang.RuntimeException \"Runtime!\" \"orchard.print_test.+\"\]" (RuntimeException. "Runtime!")
93-
#"#Error\[java.lang.RuntimeException \"Outer: Inner\" \"orchard.print_test.+\"\]" (RuntimeException. "Outer"
86+
"#atom[1]" (atom 1)
87+
"#delay[<pending>]" (delay 1)
88+
"#delay[1]" (doto (delay 1) deref)
89+
"#delay[<failed>]" (let [d (delay (/ 1 0))] (try @d (catch Exception _)) d)
90+
"#promise[<pending>]" (promise)
91+
"#promise[1]" (doto (promise) (deliver 1))
92+
"#future[<pending>]" (future (Thread/sleep 10000))
93+
"#future[1]" (doto (future 1) deref)
94+
"#agent[1]" (agent 1)
95+
#"#error\[clojure.lang.ExceptionInfo \"Boom\" \"orchard.print_test.+\"\]" (ex-info "Boom" {})
96+
#"#error\[clojure.lang.ExceptionInfo \"Boom\" \{:a 1\} \"orchard.print_test.+\"\]" (ex-info "Boom" {:a 1})
97+
#"#error\[java.lang.RuntimeException \"Runtime!\" \"orchard.print_test.+\"\]" (RuntimeException. "Runtime!")
98+
#"#error\[java.lang.RuntimeException \"Outer: Inner\" \"orchard.print_test.+\"\]" (RuntimeException. "Outer"
9499
(RuntimeException. "Inner"))
95100
"#function[clojure.core/str]" str))
96101

@@ -134,10 +139,10 @@
134139

135140
(are [result lvl] (= result (binding [*print-level* lvl]
136141
(sut/print-str (atom {:a (range 10)}))))
137-
"#Atom[...]" 0
138-
"#Atom[{...}]" 1
139-
"#Atom[{:a (...)}]" 2
140-
"#Atom[{:a (0 1 2 3 4 5 6 7 8 9)}]" 3))
142+
"#atom[...]" 0
143+
"#atom[{...}]" 1
144+
"#atom[{:a (...)}]" 2
145+
"#atom[{:a (0 1 2 3 4 5 6 7 8 9)}]" 3))
141146

142147
(deftest print-non-iterable
143148
(is (= "#{1 2 3}" (sut/print-str (reify clojure.lang.IPersistentSet

0 commit comments

Comments
 (0)