|
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?] :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