Skip to content

Commit 3b6809a

Browse files
authored
Merge pull request #142 from clj-commons/hls/20250630-deps-main
Add `clj-commons.pretty.repl/main` and describe use w/ clj tool
2 parents dd6a429 + 48c75cf commit 3b6809a

File tree

4 files changed

+85
-4
lines changed

4 files changed

+85
-4
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
- Default style for `print-table` can be overridden via a dynamic var
44
- Use a vertical bar (│) not a pipe character (|) as column separator in binary output
55
- New `clj-commons.pretty.nrepl` namespace to set up pretty inside nREPL
6+
- Function `clj-commons.pretty.repl/main` meant for use with `clj -X` to wrap another function
67

78
## 3.4.1 -- 23 Jun 2025
89

README.md

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,76 @@ Or, same thing, but with Pretty enabled:
2626

2727
![With Pretty](docs/images/pedestal-with-pretty.png)
2828

29-
The point is, you can scan down to see things in chronological order; the important parts are highlighted, the names are the same (or closer) to your source code, unnecessary details are omitted, and it's much easier to pick out the most important parts, such as file names and line numbers.
29+
The point is, you can scan down to see things in chronological order; the important parts are highlighted, the names are the same (or closer) to your source code, unnecessary details are omitted, and it's much easier to pick out other essential parts easily, such as file names and line numbers.
3030

31-
## Pretty and nREPL
31+
### Enabling Pretty
32+
33+
Pretty exceptions are enabled by invoking the fucntion `clj-commons.pretty.repl/install-pretty-exceptions`. This
34+
redefines a number of Vars to replace the default implementations with prettier ones. This is something you could
35+
set up in your `user.clj` namespace.
36+
37+
### Pretty with Leiningen
38+
39+
In shared projects, many people have different ideas about what's best when it comes to error reporting.
40+
If you want to be able to use Pretty but have your project's dependencies be "clean", you can use
41+
a [Leiningen](https://leiningen.org/) profile for this purpose.
42+
43+
For example, create a file `~/.lein/profiles.d/debug.clj`:
44+
45+
```clojure
46+
{:dependencies
47+
[[org.clj-commons/pretty "3.4.1"]]
48+
:injections
49+
[(require '[clj-commons.pretty.repl :as repl])
50+
(repl/install-pretty-exceptions)]}
51+
```
52+
You can then run your REPL as `lein with-profiles +debug` and have your pretty
53+
exceptions without adding pretty-specific code or dependencies to your project.
54+
55+
TIP: I also set up other tools I depend on, such as
56+
[clj-reload](https://github.com/tonsky/clj-reload), in the same profile.
57+
58+
### Pretty with clj
59+
60+
```clojure
61+
{:aliases
62+
{ :debug
63+
{:extra-deps {org.clj-commons/pretty {:mvn/version "3.4.1"}}
64+
:main-opts ["--main" "clj-commons.pretty-repl"]}}}
65+
```
66+
Executing `clj -M:debug` will run the function `clj-commons.pretty-repl/-main` which will set up
67+
pretty exceptions before passing any remaining command line argments to `clojure.main/main`.
68+
69+
Alternately,
70+
71+
```clojure
72+
{:aliases
73+
{:debug
74+
{:extra-deps {org.clj-commons/pretty {:mvn/version "3.4.1"}}
75+
:exec-fn clj-commons.pretty.repl/main}
76+
77+
:test
78+
{:extra-paths ["test"]
79+
:extra-deps {io.github.cognitect-labs/test-runner
80+
{:git/tag "v0.5.1" :git/sha "dfb30dd"}}
81+
:exec-fn cognitect.test-runner.api/test
82+
:exec-args {:fn cognitect.test-runner.api/test}}}}
83+
```
84+
85+
This allows testing with pretty as `clj -X:test:debug`.
86+
87+
`clj -X:test` is normal execution, and the `clj` tools will directly invoke the `cognitect.test-runner.api/test` function.
88+
`clj -X:test:debug` will overwrite the :exec-fn to invoke the `clj-commons.pretty.repl/main` function, which will
89+
set up pretty exceptions before delegating to the function specified with the :fn option.
90+
91+
Both of these approaches are doable but clumsy, so a solution involving nREPL directly will likely be better.
92+
93+
94+
### Pretty with nREPL
3295

3396
[nREPL](https://nrepl.org) is the framework that allows an IDE such as [Emacs](https://cider.mx/)
3497
or [Cursive](https://cursive-ide.com/), or even a CLI such as
35-
[Leiningen](https://leiningen.org/), to interoperate with a running REPL in a subprocess.
98+
Leiningen, to interoperate with a running REPL in a subprocess.
3699

37100
Pretty includes an nREPL middleware function, `clj-commons.pretty.nrepl/wrap-pretty`, that will install pretty exception reporting into the REPL.
38101

deps.edn

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
nrepl/nrepl {:mvn/version "1.3.1"}
1010
org.clojure/core.async {:mvn/version "1.8.741"}
1111
nubank/matcher-combinators {:mvn/version "3.9.1"}
12-
io.github.tonsky/clj-reload {:mvn/version "0.9.7"}
12+
io.github.tonsky/clj-reload {:mvn/version "0.9.8"}
1313
io.github.cognitect-labs/test-runner {:git/tag "v0.5.1"
1414
:git/sha "dfb30dd"}}
1515
:jvm-opts ["-Dclj-commons.ansi.enabled=true"]
16+
:exec-args {:fn cognitect.test-runner.api/test} ; for :debug
1617
:exec-fn cognitect.test-runner.api/test}
1718

1819
;; clj -T:build <command>
@@ -21,6 +22,10 @@
2122
{:git/tag "0.11.0" :git/sha "8c67d11"}}
2223
:ns-default build}
2324

25+
:debug
26+
{:exec-fn clj-commons.pretty.repl/main
27+
:exec-args {:fn missing/bad-wolf}}
28+
2429
:1.11
2530
{:override-deps {org.clojure/clojure {:mvn/version "1.12.1"}}}
2631

src/clj_commons/pretty/repl.clj

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,15 @@
8585
[& args]
8686
(install-pretty-exceptions)
8787
(apply main/main args))
88+
89+
(defn main
90+
"Entrypoint compatible with tools.build. The :fn argument is a symbol that's resolved to
91+
a function to invoke, and is passed the argument map."
92+
{:added "3.5.0"}
93+
[arg-map]
94+
(install-pretty-exceptions)
95+
(let [{delegate-fn :fn} arg-map
96+
f (or (requiring-resolve delegate-fn)
97+
(throw (ex-info (str "Could not resolve function to invoke: " delegate-fn)
98+
arg-map)))]
99+
(f (dissoc arg-map :fn))))

0 commit comments

Comments
 (0)