Skip to content

Commit a0f1dcf

Browse files
authored
Pretty view mode (#335)
* Add pretty printer * Add pretty printer tests * Add :pretty view mode
1 parent e202e81 commit a0f1dcf

File tree

7 files changed

+1143
-34
lines changed

7 files changed

+1143
-34
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## master (unreleased)
44

5+
* [#335](https://github.com/clojure-emacs/orchard/pull/335) Add `orchard.pp` and pretty view mode.
6+
57
## 0.33.0 (2025-04-08)
68

79
* [#333](https://github.com/clojure-emacs/orchard/pull/333): Add `orchard.profile`.

src/orchard/inspect.clj

+94-33
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,22 @@
4444
:max-coll-size 5
4545
:max-nested-depth nil
4646
:display-analytics-hint nil
47-
:analytics-size-cutoff 100000})
47+
:analytics-size-cutoff 100000
48+
:pretty-print false})
4849

4950
(defn- reset-render-state [inspector]
5051
(-> inspector
5152
(assoc :counter 0, :index [], :indentation 0, :rendered [])
5253
(dissoc :chunk :start-idx :last-page)))
5354

55+
(defn- print-string
56+
"Print or pretty print the string `value`, depending on the view mode
57+
of the inspector."
58+
[{:keys [indentation pretty-print]} value]
59+
(if pretty-print
60+
(print/pprint-str value {:indentation (or indentation 0)})
61+
(print/print-str value)))
62+
5463
(defn- array? [obj]
5564
(some-> (class obj) .isArray))
5665

@@ -211,7 +220,7 @@
211220

212221
(defn- validate-config [{:keys [page-size max-atom-length max-value-length
213222
max-coll-size max-nested-depth display-analytics-hint
214-
analytics-size-cutoff]
223+
analytics-size-cutoff pretty-print]
215224
:as config}]
216225
(when (some? page-size) (pre-ex (pos-int? page-size)))
217226
(when (some? max-atom-length) (pre-ex (pos-int? max-atom-length)))
@@ -220,6 +229,7 @@
220229
(when (some? max-nested-depth) (pre-ex (pos-int? max-nested-depth)))
221230
(when (some? display-analytics-hint) (pre-ex (= display-analytics-hint "true")))
222231
(when (some? analytics-size-cutoff) (pre-ex (pos-int? analytics-size-cutoff)))
232+
(when (some? pretty-print) (pre-ex (contains? #{true false} pretty-print)))
223233
(select-keys config (keys default-inspector-config)))
224234

225235
(defn refresh
@@ -294,11 +304,15 @@
294304
(render-onto values)
295305
(render '(:newline))))
296306

297-
(defn- indent [inspector]
298-
(update inspector :indentation + 2))
307+
(defn- indent
308+
"Increment the `:indentation` of `inspector` by `n` or 2."
309+
[inspector & [n]]
310+
(update inspector :indentation + (or n 2)))
299311

300-
(defn- unindent [inspector]
301-
(update inspector :indentation - 2))
312+
(defn- unindent
313+
"Decrement the `:indentation` of `inspector` by `n` or 2."
314+
[inspector & [n]]
315+
(indent inspector (- (or n 2))))
302316

303317
(defn- padding [{:keys [indentation]}]
304318
(when (and (number? indentation) (pos? indentation))
@@ -325,7 +339,7 @@
325339
([inspector value] (render-value inspector value nil))
326340
([inspector value {:keys [value-role value-key display-value]}]
327341
(let [{:keys [counter]} inspector
328-
display-value (or display-value (print/print-str value))
342+
display-value (or display-value (print-string inspector value))
329343
expr (list :value display-value counter)]
330344
(-> inspector
331345
(update :index conj {:value value
@@ -340,11 +354,15 @@
340354
(render-value value value-opts)
341355
(render-ln)))
342356

343-
(defn render-labeled-value [inspector label value & [value-opts]]
344-
(-> inspector
345-
(render-indent (str label ": "))
346-
(render-value value value-opts)
347-
(render-ln)))
357+
(defn render-labeled-value [{:keys [pretty-print] :as inspector} label value & [value-opts]]
358+
(let [formatted-label (str label ": ")
359+
indentation (if pretty-print (count formatted-label) 0)]
360+
(-> inspector
361+
(render-indent formatted-label)
362+
(indent indentation)
363+
(render-value value value-opts)
364+
(unindent indentation)
365+
(render-ln))))
348366

349367
(defn- render-class-name [inspector obj]
350368
(render-labeled-value inspector "Class" (class obj)))
@@ -356,18 +374,52 @@
356374
(render-ln))
357375
inspector))
358376

377+
(defn- long-map-key?
378+
"Returns true of `s` is a long string, more than 20 character or
379+
containing newlines."
380+
[^String s]
381+
(or (.contains s "\n") (> (count s) 20)))
382+
383+
(defn- render-map-separator
384+
"Render the map separator according to `rendered-key`. If
385+
`rendered-key` is long or contains newlines the key and value will
386+
be rendered on separate lines."
387+
[{:keys [pretty-print] :as inspector} long-key?]
388+
(if (and pretty-print long-key?)
389+
(-> (render-ln inspector)
390+
(render-indent "=")
391+
(render-ln))
392+
(render inspector " = ")))
393+
394+
(defn- render-map-value
395+
"Render a map value. If `mark-values?` is true, attach the keys to the
396+
values in the index."
397+
[{:keys [pretty-print] :as inspector} key val mark-values? rendered-key long-key?]
398+
(if pretty-print
399+
(let [indentation (if long-key? 0 (+ 3 (count rendered-key)))]
400+
(-> (indent inspector indentation)
401+
(render (if (zero? indentation) " " ""))
402+
(render-value val
403+
(when mark-values?
404+
{:value-role :map-value, :value-key key}))
405+
(unindent indentation)
406+
((if (long-map-key? rendered-key) render-ln identity))))
407+
(render-value inspector val
408+
(when mark-values?
409+
{:value-role :map-value, :value-key key}))))
410+
359411
(defn- render-map-values
360412
"Render associative key-value pairs. If `mark-values?` is true, attach the keys
361413
to the values in the index."
362414
[inspector mappable mark-values?]
363415
(reduce (fn [ins [key val]]
364-
(-> ins
365-
(render-indent)
366-
(render-value key)
367-
(render " = ")
368-
(render-value val (when mark-values?
369-
{:value-role :map-value, :value-key key}))
370-
(render-ln)))
416+
(let [rendered-key (print-string ins key)
417+
long-key? (long-map-key? rendered-key)]
418+
(-> (render-indent ins)
419+
(render-value key {:display-value rendered-key})
420+
(render-map-separator long-key?)
421+
(render-map-value key val mark-values? rendered-key long-key?)
422+
(render-ln))))
371423
inspector
372424
mappable))
373425

@@ -426,20 +478,24 @@
426478
"Render an indexed chunk of values. Renders all values in `chunk`, so `chunk`
427479
must be finite. If `mark-values?` is true, attach the indices to the values in
428480
the index."
429-
[inspector chunk idx-starts-from mark-values?]
481+
[{:keys [pretty-print] :as inspector} chunk idx-starts-from mark-values?]
430482
(let [n (count chunk)
431483
last-idx (+ idx-starts-from n -1)
432484
last-idx-len (count (str last-idx))
433485
idx-fmt (str "%" last-idx-len "s")]
434486
(loop [ins inspector, chunk (seq chunk), idx idx-starts-from]
435487
(if chunk
436-
(recur (-> ins
437-
(render-indent (format idx-fmt idx) ". ")
438-
(render-value (first chunk)
439-
(when mark-values?
440-
{:value-role :seq-item, :value-key idx}))
441-
(render-ln))
442-
(next chunk) (inc idx))
488+
(let [header (str (format idx-fmt idx) ". ")
489+
indentation (if pretty-print (count header) 0)]
490+
(recur (-> ins
491+
(render-indent header)
492+
(indent indentation)
493+
(render-value (first chunk)
494+
(when mark-values?
495+
{:value-role :seq-item, :value-key idx}))
496+
(unindent indentation)
497+
(render-ln))
498+
(next chunk) (inc idx)))
443499
ins))))
444500

445501
(declare known-types)
@@ -656,7 +712,7 @@
656712

657713
(defmethod inspect :string [inspector ^java.lang.String obj]
658714
(-> (render-class-name inspector obj)
659-
(render "Value: " (print/print-str obj))
715+
(render "Value: " (print-string inspector obj))
660716
(render-ln)
661717
(render-section-header "Print")
662718
(indent)
@@ -714,9 +770,7 @@
714770
(shorten-member-string (str obj) (.getDeclaringClass ^Method obj))
715771

716772
(instance? Field obj)
717-
(shorten-member-string (str obj) (.getDeclaringClass ^Field obj))
718-
719-
:else (print/print-str obj))]
773+
(shorten-member-string (str obj) (.getDeclaringClass ^Field obj)))]
720774
(letfn [(render-fields [inspector section-name field-values]
721775
(if (seq field-values)
722776
(-> inspector
@@ -924,12 +978,19 @@
924978
(unindent)))))
925979

926980
(defn inspect-render
927-
([{:keys [max-atom-length max-value-length max-coll-size max-nested-depth value]
981+
([{:keys [max-atom-length max-value-length max-coll-size max-nested-depth value pretty-print]
928982
:as inspector}]
929983
(binding [print/*max-atom-length* max-atom-length
930984
print/*max-total-length* max-value-length
931985
*print-length* max-coll-size
932-
*print-level* max-nested-depth]
986+
*print-level* (cond-> max-nested-depth
987+
;; In pretty mode a higher *print-level*
988+
;; leads to better results, otherwise we
989+
;; render a ton of # characters when
990+
;; there is still enough screen estate
991+
;; in most cases.
992+
(and pretty-print (number? max-nested-depth))
993+
(* 2))]
933994
(-> inspector
934995
(reset-render-state)
935996
(decide-if-paginated)

0 commit comments

Comments
 (0)