|
321 | 321 |
|
322 | 322 | ;; Rendering
|
323 | 323 |
|
324 |
| -(defn render-onto [inspector coll] |
325 |
| - (letfn [(render-one [{:keys [rendered] :as inspector} val] |
326 |
| - ;; Special case: fuse two last strings together. |
327 |
| - (let [lst (peek (or rendered []))] |
328 |
| - (assoc inspector :rendered (if (and (string? lst) (string? val)) |
329 |
| - (conj (pop rendered) (str lst val)) |
330 |
| - (conj rendered val)))))] |
331 |
| - (reduce render-one inspector coll))) |
| 324 | +(defn render |
| 325 | + ([{:keys [rendered] :as inspector} value] |
| 326 | + ;; Special case: fuse two last strings together. |
| 327 | + (let [lst (peek (or rendered []))] |
| 328 | + (assoc inspector :rendered (if (and (string? lst) (string? value)) |
| 329 | + (conj (pop rendered) (.concat ^String lst value)) |
| 330 | + (conj rendered value))))) |
| 331 | + ([inspector value & values] |
| 332 | + (reduce render (render inspector value) values))) |
332 | 333 |
|
333 |
| -(defn render [inspector & values] |
334 |
| - (render-onto inspector values)) |
| 334 | +(defn render-onto [inspector coll] |
| 335 | + (reduce render inspector coll)) |
335 | 336 |
|
336 | 337 | (defn render-ln [inspector & values]
|
337 | 338 | (-> inspector
|
|
350 | 351 |
|
351 | 352 | (defn- padding [{:keys [indentation]}]
|
352 | 353 | (when (and (number? indentation) (pos? indentation))
|
353 |
| - (apply str (repeat indentation " ")))) |
| 354 | + (String. (char-array indentation \space)))) |
354 | 355 |
|
355 | 356 | (defn- render-indent [inspector & values]
|
356 | 357 | (let [padding (padding inspector)]
|
|
505 | 506 | (render-indent-ln ins divider)
|
506 | 507 | (reduce render-row ins pr-rows))))
|
507 | 508 |
|
| 509 | +(defn- leftpad [idx last-idx-len] |
| 510 | + (let [idx-s (str idx) |
| 511 | + idx-len (count idx-s)] |
| 512 | + (if (= idx-len last-idx-len) |
| 513 | + (str idx-s ". ") |
| 514 | + (str (String. (char-array (- last-idx-len idx-len) \space)) idx-s ". ")))) |
| 515 | + |
508 | 516 | (defn- render-indexed-chunk
|
509 | 517 | "Render an indexed chunk of values. Renders all values in `chunk`, so `chunk`
|
510 | 518 | must be finite. If `mark-values?` is true, attach the indices to the values in
|
511 |
| - the index." |
512 |
| - [{:keys [pretty-print] :as inspector} chunk idx-starts-from mark-values?] |
513 |
| - (let [n (count chunk) |
514 |
| - last-idx (+ idx-starts-from n -1) |
515 |
| - last-idx-len (count (str last-idx)) |
516 |
| - idx-fmt (str "%" last-idx-len "s")] |
517 |
| - (loop [ins inspector, chunk (seq chunk), idx idx-starts-from] |
| 519 | + the index. If `skip-nils?` is true, don't render nil values." |
| 520 | + [{:keys [pretty-print] :as inspector} chunk {:keys [start-idx mark-values? skip-nils?]}] |
| 521 | + (let [start-idx (or start-idx 0) |
| 522 | + n (count chunk) |
| 523 | + last-idx (+ start-idx n -1) |
| 524 | + last-idx-len (count (str last-idx))] |
| 525 | + (loop [ins inspector, chunk (seq chunk), idx start-idx] |
518 | 526 | (if chunk
|
519 |
| - (let [header (str (format idx-fmt idx) ". ") |
520 |
| - indentation (if pretty-print (count header) 0)] |
521 |
| - (recur (-> ins |
522 |
| - (render-indent header) |
523 |
| - (indent indentation) |
524 |
| - (render-value (first chunk) |
525 |
| - (when mark-values? |
526 |
| - {:value-role :seq-item, :value-key idx})) |
527 |
| - (unindent indentation) |
528 |
| - (render-ln)) |
| 527 | + (let [header (leftpad idx last-idx-len) |
| 528 | + indentation (if pretty-print (count header) 0) |
| 529 | + item (first chunk)] |
| 530 | + (recur (if-not (and (nil? item) skip-nils?) |
| 531 | + (-> ins |
| 532 | + (render-indent header) |
| 533 | + (indent indentation) |
| 534 | + (render-value item |
| 535 | + (when mark-values? |
| 536 | + {:value-role :seq-item, :value-key idx})) |
| 537 | + (unindent indentation) |
| 538 | + (render-ln)) |
| 539 | + ins) |
529 | 540 | (next chunk) (inc idx)))
|
530 | 541 | ins))))
|
531 | 542 |
|
|
543 | 554 | (unindent))
|
544 | 555 | inspector))
|
545 | 556 |
|
546 |
| -(defn- render-items [inspector items map? start-idx mark-values?] |
| 557 | +(defn- render-items |
| 558 | + [inspector items {:keys [map? start-idx mark-values? skip-nils?] :as opts}] |
547 | 559 | (if map?
|
548 | 560 | (render-map-values inspector items mark-values?)
|
549 | 561 | (if (= (:view-mode inspector) :table)
|
550 |
| - (render-chunk-as-table inspector items start-idx) |
551 |
| - (render-indexed-chunk inspector items start-idx mark-values?)))) |
| 562 | + (render-chunk-as-table inspector items (or start-idx 0)) |
| 563 | + (render-indexed-chunk inspector items opts)))) |
552 | 564 |
|
553 | 565 | (defn- render-value-maybe-expand
|
554 | 566 | "If `obj` is a collection smaller than page-size, then render it as a
|
555 | 567 | collection, otherwise as a compact value."
|
556 | 568 | [{:keys [page-size] :as inspector} obj]
|
557 | 569 | (if (some-> (counted-length obj) (<= page-size))
|
558 |
| - (render-items inspector obj (map? obj) 0 false) |
| 570 | + (render-items inspector obj {:map? (map? obj), :start-idx 0}) |
559 | 571 | (render-indented-value inspector obj)))
|
560 | 572 |
|
561 | 573 | (defn- render-leading-page-ellipsis [{:keys [current-page] :as inspector}]
|
|
575 | 587 | (let [type (object-type value)]
|
576 | 588 | (-> inspector
|
577 | 589 | (render-leading-page-ellipsis)
|
578 |
| - (render-items (or chunk value) (= type :map) (or start-idx 0) |
579 |
| - ;; Set items are not indexed - don't mark. |
580 |
| - (not= type :set)) |
| 590 | + (render-items (or chunk value) |
| 591 | + {:map? (= type :map) |
| 592 | + :start-idx start-idx |
| 593 | + ;; Set items are not indexed - don't mark. |
| 594 | + :mark-values? (not= type :set)}) |
581 | 595 | (render-trailing-page-ellipsis))))
|
582 | 596 |
|
583 | 597 | (defn render-meta-information [inspector obj]
|
|
604 | 618 |
|
605 | 619 | ;;;; Datafy
|
606 | 620 |
|
607 |
| -(defn- datafy-kvs [original-object kvs] |
| 621 | +(defn- datafy-kvs [original-object kvs keep-same?] |
| 622 | + ;; keep-same? should be true for datafying collections that were produced by |
| 623 | + ;; datafying the root, and false if we datafy elements of the original coll. |
608 | 624 | (let [differs? (volatile! false)
|
609 | 625 | result (into {}
|
610 | 626 | (keep (fn [[k v]]
|
611 | 627 | (when-some [dat (some->> (nav original-object k v)
|
612 | 628 | datafy)]
|
613 |
| - (when-not (= dat v) |
614 |
| - (vreset! differs? true)) |
615 |
| - [k dat]))) |
| 629 | + (let [same? (= dat v)] |
| 630 | + (when-not same? |
| 631 | + (vreset! differs? true)) |
| 632 | + (when (or (not same?) keep-same?) |
| 633 | + [k dat]))))) |
616 | 634 | kvs)]
|
617 |
| - (with-meta result {:differs @differs?}))) |
| 635 | + (when-not (empty? result) |
| 636 | + result))) |
618 | 637 |
|
619 |
| -(defn- datafy-seq [s] |
| 638 | +(defn- datafy-seq [s keep-same?] |
620 | 639 | (let [differs? (volatile! false)
|
621 |
| - result (mapv #(let [dat (datafy %)] |
622 |
| - (when-not (= dat %) |
| 640 | + result (mapv #(let [dat (datafy %) |
| 641 | + same? (= dat %)] |
| 642 | + (when-not same? |
623 | 643 | (vreset! differs? true))
|
624 |
| - dat) s)] |
625 |
| - (with-meta result {:differs @differs?}))) |
| 644 | + (when (or (not same?) keep-same?) |
| 645 | + dat)) |
| 646 | + s)] |
| 647 | + (when (or @differs? keep-same?) |
| 648 | + result))) |
626 | 649 |
|
627 | 650 | (defn- datafy-root [obj]
|
628 | 651 | (let [datafied (datafy obj)]
|
|
638 | 661 | ;; If the root value has datafy representation, check if it's a collection.
|
639 | 662 | ;; If so, additionally datafy its items or map values.
|
640 | 663 | (let [datafied (case (object-type datafied)
|
641 |
| - :map (datafy-kvs datafied datafied) |
642 |
| - (:list :set) (datafy-seq datafied) |
| 664 | + :map (datafy-kvs datafied datafied true) |
| 665 | + (:list :set) (datafy-seq datafied true) |
643 | 666 | datafied)]
|
644 | 667 | ;; Only render the datafy section if the datafied version of the object is
|
645 | 668 | ;; different than object, since we don't want to show the same data twice.
|
|
650 | 673 | ;; If the value is a type that can be paged, then only datafy the
|
651 | 674 | ;; displayed chunk.
|
652 | 675 | (let [chunk (or chunk value)
|
653 |
| - map? (= (object-type value) :map) |
654 |
| - datafied (if map? |
655 |
| - (datafy-kvs value chunk) |
656 |
| - (datafy-seq chunk))] |
657 |
| - ;; Only return the datafied representation if at least one value is |
658 |
| - ;; different from the original. |
659 |
| - (when (:differs (meta datafied)) |
| 676 | + datafied (if (= (object-type value) :map) |
| 677 | + (datafy-kvs value chunk false) |
| 678 | + (datafy-seq chunk false))] |
| 679 | + (when datafied |
660 | 680 | [datafied true])))))
|
661 | 681 |
|
662 | 682 | (defn- render-datafy [{:keys [start-idx] :as inspector}]
|
|
670 | 690 | ;; using the same pagination rules as the main chunk.
|
671 | 691 | (-> ins
|
672 | 692 | (render-leading-page-ellipsis)
|
673 |
| - (render-items datafied (map? datafied) (or start-idx 0) false) |
| 693 | + (render-items datafied {:map? (map? datafied) |
| 694 | + :start-idx start-idx |
| 695 | + :skip-nils? true}) |
674 | 696 | (render-trailing-page-ellipsis))
|
675 | 697 | ;; Otherwise, render datafied representation as a collection if it is
|
676 | 698 | ;; small enough, or as a single value.
|
|
978 | 1000 | (unindent ins)
|
979 | 1001 | (render-section-header ins "Trace")
|
980 | 1002 | (indent ins)
|
981 |
| - (render-items ins (.getStackTrace root-cause) false 0 false) |
| 1003 | + (render-items ins (.getStackTrace root-cause) {}) |
982 | 1004 | (unindent ins)
|
983 | 1005 | (render-datafy ins))))
|
984 | 1006 |
|
|
987 | 1009 | (render-labeled-value "Class" (class obj))
|
988 | 1010 | (render-section-header "Contents")
|
989 | 1011 | (indent)
|
990 |
| - (render-items (StackTraceElement->vec obj) false 0 false))) |
| 1012 | + (render-items (StackTraceElement->vec obj) {}))) |
991 | 1013 |
|
992 | 1014 | (defmethod inspect :aref [inspector ^clojure.lang.ARef obj]
|
993 | 1015 | (let [val (deref obj)]
|
|
1086 | 1108 | (inspect value)
|
1087 | 1109 | (render-path)
|
1088 | 1110 | (render-view-mode)
|
1089 |
| - (update :rendered seq)))) |
1090 |
| - ([inspector value] |
1091 |
| - (inspect-render (-> (assoc inspector :value value) |
1092 |
| - (dissoc :value-analysis))))) |
| 1111 | + (update :rendered seq))))) |
1093 | 1112 |
|
1094 | 1113 | ;; Public entrypoints
|
1095 | 1114 |
|
|
1102 | 1121 | (-> default-inspector-config
|
1103 | 1122 | (merge (validate-config config))
|
1104 | 1123 | (assoc :stack [], :path [], :pages-stack [], :current-page 0,
|
1105 |
| - :view-modes-stack [], :view-mode :normal) |
1106 |
| - (inspect-render value)))) |
| 1124 | + :view-modes-stack [], :view-mode :normal, :value value) |
| 1125 | + (inspect-render)))) |
1107 | 1126 |
|
1108 | 1127 | (defn ^:deprecated clear
|
1109 | 1128 | "If necessary, use `(start inspector nil) instead.`"
|
|
0 commit comments