Skip to content

Commit

Permalink
Merge pull request #126 from clj-commons/hls/20240821-deeply-nested-fns
Browse files Browse the repository at this point in the history
Abbreviated repeated names in a Clojure function name
  • Loading branch information
hlship authored Aug 21, 2024
2 parents cacd749 + 1f347cd commit 99d118b
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 11 deletions.
14 changes: 12 additions & 2 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
## 3.1.0 - UNRELEASED

In a Clojure stack frame, repeated elements may be abbreviated; for example,
what was output in 3.0.0 as
`integration.diplomat.components.github-api-test/fn/fn/fn/fn/fn/fn/fn/fn/fn/fn/fn/fn/fn/fn`
will be output in 3.1.0 as `integration.diplomat.components.github-api-test/fn{x14}`
(this is an actual test case!)
These crazily nested functions occur when using macro-intensive libraries such as
[nubank/state-flow](https://github.com/nubank/state-flow) and [funcool/cats](https://github.com/funcool/cats).

## 3.0.0 - 7 Jun 2024

**BREAKING CHANGES**:

Moved the io.aviso/pretty compatibility layer to new library
Moved the io.aviso/pretty compatibility layer (introduced in 2.5.0) to new library
[org.clj-commons/pretty-aviso-bridge](https://github.com/clj-commons/pretty-aviso-bridge).

Other changes:
Expand Down Expand Up @@ -30,7 +40,7 @@ Minor bug fixes.
*BREAKING CHANGES*

- The function `clojure.core/apply` is now omitted (in formatted stack traces)
- Properties inside exceptions are now pretty-printed to a default depth of 2; previously, the depth was unlimited
- Properties inside exceptions are now pretty-printed to a default depth of 2; previously, the depth was unlimited

Other changes:

Expand Down
52 changes: 43 additions & 9 deletions src/clj_commons/format/exceptions.clj
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,45 @@
*app-frame-names*))
:clojure-frame))

(defn- counted-terms
[terms]
(if-not (seq terms)
[]
(loop [acc-term (first terms)
acc-count 1
ts (next terms)
result []]
(if (nil? ts)
(conj result [acc-term acc-count])
(let [t (first ts)
ts' (next ts)]
(if (= acc-term t)
(recur acc-term (inc acc-count) ts' result)
(recur t 1 ts' (conj result [acc-term acc-count]))))))))

(defn- counted-frame-name
[[name count]]
(if (= count 1)
name
(str name "{x" count "}")))

(defn- format-clojure-frame-base
[frame]
(let [names' (->> frame
:names
counted-terms
(map counted-frame-name))
width (->> names'
(map length)
(reduce + 0)
(+ (count names')) ;; each name has a trailing slash
dec)] ;; except the last
{:name-width width
:name [(get *fonts* (clj-frame-font-key frame))
(->> names' drop-last (str/join "/"))
"/"
[(:function-name *fonts*) (last names')]]}))

(defn format-stack-frame
"Transforms an expanded stack frame (see [[transform-stack-trace]])
into a formatted stack frame:
Expand Down Expand Up @@ -387,15 +426,10 @@
:repeats repeats})

:else
(let [formatted-name [(get *fonts* (clj-frame-font-key frame))
(->> names drop-last (str/join "/"))
"/"
[(:function-name *fonts*) (last names)]]]
{:name formatted-name
:name-width (-> frame :name length)
:file file
:line (str line)
:repeats repeats})))
(assoc (format-clojure-frame-base frame)
:file file
:line (str line)
:repeats repeats)))

(defn filter-stack-trace-maps
"Filters the stack trace maps (from [[transform-stack-trace]], removing unnecessary frames and
Expand Down
16 changes: 16 additions & 0 deletions test/playground.clj
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@
[]
(my-deprecated-fn))

(defn deep
[x]
((fn [x1]
((fn [x2]
((fn [x3]
((fn inner [x4]
(/ x4 0)) x3))
x2))
x1))
x))

(comment
(caller)

(deep 10)

(clojure.repl/pst)

)

0 comments on commit 99d118b

Please sign in to comment.