From bf6a4cde442620f7a8a9cc00af11be7cbc9fb3b4 Mon Sep 17 00:00:00 2001 From: Phil Brown Date: Wed, 7 Apr 2021 15:02:17 -0700 Subject: [PATCH] [Inspector] Configure truncation limits The limits after which the inspector truncates collection members are now configurable. Previously they were hardcoded to 5 and 150 for collection and atom (non-collection) members. --- CHANGELOG.md | 6 ++++ src/orchard/inspect.clj | 60 ++++++++++++++++++++++++----------- test/orchard/inspect_test.clj | 35 ++++++++++++++++++-- 3 files changed, 80 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e36d07fc9..8c9e5f9bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## master (unreleased) +### New features + +* [#111](https://github.com/clojure-emacs/orchard/pull/111): [Inspector] Configure truncation limits + +### Changes + * The _class info cache_ is now initialized silently by default. This results in less confusing output. * You can now `@orchard.java/cache-initializer` for deterministically waiting for this cache workload to complete. * You can control its verbosity by setting `"-Dorchard.initialize-cache.silent=false"` (or `[...]=true`). diff --git a/src/orchard/inspect.clj b/src/orchard/inspect.clj index 79dbe946f..88ed59f09 100644 --- a/src/orchard/inspect.clj +++ b/src/orchard/inspect.clj @@ -129,6 +129,18 @@ :page-size new-page-size :current-page 0))) +(defn set-max-atom-length + "Set the maximum length of atomic collection members before they're truncated." + [inspector max-atom-length] + {:pre [(integer? max-atom-length)]} + (inspect-render (assoc inspector :max-atom-length max-atom-length))) + +(defn set-max-coll-size + "Set the maximum number of nested collection members to print before truncating." + [inspector max-coll-size] + {:pre [(integer? max-coll-size)]} + (inspect-render (assoc inspector :max-coll-size max-coll-size))) + (defn eval-and-inspect "Evaluate the given expression where `v` is bound to the currently inspected value. Open the evaluation result in the inspector." @@ -167,16 +179,22 @@ (s/join sep) (format fmt)))) -(defn- short? [coll] - (<= (count coll) 5)) +(def ^:private ^:dynamic *max-atom-length* 150) +(def ^:private ^:dynamic *max-coll-size* 5) -(def ^:private truncate-max-length 150) +(defn- short? [coll] + ;; Prefer `bounded-count` if available (clojure 1.9+) or fall back to `count`. + (let [len (if-let [bounded-count (some-> (resolve 'clojure.core/bounded-count) + (var-get))] + (bounded-count (inc *max-coll-size*) coll) + (count coll))] + (<= len *max-coll-size*))) (defn- truncate-string [s] (when s (let [len (count s)] - (if (> len truncate-max-length) - (str (subs s 0 (- truncate-max-length 2)) "...") + (if (> len *max-atom-length*) + (str (subs s 0 (max (- *max-atom-length* 3) 0)) "...") s)))) (defn value-types [value] @@ -228,25 +246,26 @@ (safe-pr-seq value "[ %s ]")) (defmethod inspect-value :vector-long [value] - (safe-pr-seq (take 5 value) "[ %s ... ]")) + (safe-pr-seq (take *max-coll-size* value) "[ %s ... ]")) (defmethod inspect-value :lazy-seq [value] - (let [first-six (take 6 value)] - (if (= (count first-six) 6) - (safe-pr-seq (take 5 value) "( %s ... )") - (safe-pr-seq first-six "( %s )")))) + (let [prefix-length (inc *max-coll-size*) + prefix (take prefix-length value)] + (if (= (count prefix) prefix-length) + (safe-pr-seq (take *max-coll-size* value) "( %s ... )") + (safe-pr-seq prefix "( %s )")))) (defmethod inspect-value :list [value] (safe-pr-seq value "( %s )")) (defmethod inspect-value :list-long [value] - (safe-pr-seq (take 5 value) "( %s ... )")) + (safe-pr-seq (take *max-coll-size* value) "( %s ... )")) (defmethod inspect-value :set [value] (safe-pr-seq value "#{ %s }")) (defmethod inspect-value :set-long [value] - (safe-pr-seq (take 5 value) "#{ %s ... }")) + (safe-pr-seq (take *max-coll-size* value) "#{ %s ... }")) (defmethod inspect-value :array [value] (let [ct (.getName (or (.getComponentType (class value)) Object))] @@ -254,7 +273,7 @@ (defmethod inspect-value :array-long [value] (let [ct (.getName (or (.getComponentType (class value)) Object))] - (safe-pr-seq (take 5 value) ", " (str ct "[] { %s ... }")))) + (safe-pr-seq (take *max-coll-size* value) ", " (str ct "[] { %s ... }")))) (defmethod inspect-value java.lang.Class [value] (pr-str value)) @@ -531,12 +550,15 @@ (defn inspect-render ([inspector] (inspect-render inspector (:value inspector))) - ([inspector value] (-> (reset-index inspector) - (assoc :rendered []) - (assoc :value value) - (render-reference) - (inspect value) - (render-path)))) + ([inspector value] + (binding [*max-atom-length* (or (:max-atom-length inspector) *max-atom-length*) + *max-coll-size* (or (:max-coll-size inspector) *max-coll-size*)] + (-> (reset-index inspector) + (assoc :rendered []) + (assoc :value value) + (render-reference) + (inspect value) + (render-path))))) ;; Get a human readable printout of rendered sequence (defmulti inspect-print-component first) diff --git a/test/orchard/inspect_test.clj b/test/orchard/inspect_test.clj index 5b6159cd8..17be71a2c 100644 --- a/test/orchard/inspect_test.clj +++ b/test/orchard/inspect_test.clj @@ -17,6 +17,8 @@ (def inspect-result-with-nil ["(\"Class\" \": \" (:value \"clojure.lang.PersistentVector\" 0) (:newline) \"Contents: \" (:newline) \" \" \"0\" \". \" (:value \"1\" 1) (:newline) \" \" \"1\" \". \" (:value \"2\" 2) (:newline) \" \" \"2\" \". \" (:value \"nil\" 3) (:newline) \" \" \"3\" \". \" (:value \"3\" 4) (:newline))"]) +(def inspect-result-configure-length ["(\"Class\" \": \" (:value \"clojure.lang.PersistentVector\" 0) (:newline) \"Contents: \" (:newline) \" \" \"0\" \". \" (:value \"[ 1... 2222 333 ... ]\" 1) (:newline))"]) + (def eval-and-inspect-result ["(\"Class\" \": \" (:value \"java.lang.String\" 0) (:newline) \"Value: \" \"\\\"1001\\\"\")"]) (def java-hashmap-inspect-result ["(\"Class\" \": \" (:value \"java.util.HashMap\" 0) (:newline) \"Contents: \" (:newline) \" \" (:value \":b\" 1) \" = \" (:value \"2\" 2) (:newline) \" \" (:value \":c\" 3) \" = \" (:value \"3\" 4) (:newline) \" \" (:value \":a\" 5) \" = \" (:value \"1\" 6) (:newline))"]) @@ -27,7 +29,7 @@ (def long-vector (vec (range 70))) (def long-map (zipmap (range 70) (range 70))) (def long-nested-coll (vec (map #(range (* % 10) (+ (* % 10) 80)) (range 200)))) -(def truncated-string (str "\"" (apply str (repeat 147 "a")) "...")) +(def truncated-string (str "\"" (apply str (repeat 146 "a")) "...")) (defn inspect [value] @@ -264,13 +266,42 @@ "{ :a 1, :b 2 }" (java.util.HashMap. {:a 1 :b 2}) "long[] { 1, 2, 3, 4 }" (long-array [1 2 3 4]) "java.lang.Long[] { 0, 1, 2, 3, 4 ... }" (into-array Long (range 10)) - "#" (MyTestType. "test1")))) + "#" (MyTestType. "test1"))) + + (testing "inspect-value adjust length and size" + (binding [inspect/*max-atom-length* 6 + inspect/*max-coll-size* 2] + (are [result form] (= result (inspect/inspect-value form)) + "1" 1 + "nil" nil + "\"2\"" "2" + ":ab..." :abc/def + "( :a :b )" '(:a :b) + "[ 1 2 ... ]" [1 2 3] + "{ :a 1, :b 2 }" {:a 1 :b 2} + "( 1 1 ... )" (repeat 1) + "[ ( 1 1 ... ) ]" [(repeat 1)] + "{ :a { ( 0 1 ... ) \"ab..., ... } }" {:a {(range 10) "abcdefg", 2 3, 4 5, 6 7, 8 9, 10 11}} + "java.lang.Long[] { 0, 1 ... }" (into-array Long (range 10)))) + (binding [inspect/*max-coll-size* 6] + (are [result form] (= result (inspect/inspect-value form)) + "[ ( 1 1 1 1 1 1 ... ) ]" [(repeat 1)] + "{ :a { ( 0 1 2 3 4 5 ... ) 1, 2 3, 4 5, 6 7, 8 9, 10 11 } }" {:a {(range 10) 1, 2 3, 4 5, 6 7, 8 9, 10 11}})))) (deftest inspect-coll-test (testing "inspect :coll prints contents of the coll" (is (= inspect-result-with-nil (render (inspect/start (inspect/fresh) [1 2 nil 3])))))) +(deftest inspect-configure-length-test + (testing "inspect respects :max-atom-length and :max-coll-size configuration" + (is (= inspect-result-configure-length + (render (-> (inspect/fresh) + (assoc :max-atom-length 4 + :max-coll-size 3) + (inspect/start [[111111 2222 333 44 5]]))))))) + + (deftest inspect-java-hashmap-test (testing "inspecting java.util.Map descendendants prints a key-value coll" (is (= java-hashmap-inspect-result