`cider-pprint-eval-last-sexp` from a `cljs` repl on a value which contains a #js literal formats eveything on one line.
Expected behavior
Pretty printing should work even when #js literal is included.
Actual behavior
Whenever I run cider-pprint-eval-last-sexp from a cljs repl on a value which contains a #js literal everything is formatted on one line.
Steps to reproduce the problem
Connect to shadow-cljs repl.
{"K" 75,
"L" 76,
"G" 71,
"J" 74,
"M" 77,
"H" 72,
"E" 69,
"C" 67,
"F" 70,
"I" 73,
"D" 68
"Z" #js [1]}
produces
{"K" 75, "L" 76, "G" 71, "J" 74, "M" 77, "Z" #js [1], "H" 72, "E" 69, "C" 67, "F" 70, "I" 73, "D" 68}
Environment & Version information
CIDER version information
;; Connected to nREPL server - nrepl://localhost:53978
;; CIDER 1.8.0-snapshot (package: 20230707.640), nREPL 1.0.0
yarn run v1.22.19
warning package.json: No license field
...
shadow-cljs - starting via "clojure"
shadow-cljs - HTTP server available at http://localhost:8082
shadow-cljs - server version: 2.25.5 running at http://localhost:9630
shadow-cljs - nREPL server started on port 53978
Lein / Clojure CLI version
;; Clojure 1.11.1, Java 17.0.2
Emacs version
GNU Emacs 28.2 (build 1, aarch64-apple-darwin21.1.0, NS appkit-2113.00 Version 12.0.1 (Build 21A559)) of 2022-09-12
Operating system
Mac OS 13.0.1 (22A400)
JDK distribution
openjdk 17.0.2 2022-01-18 LTS
OpenJDK Runtime Environment Zulu17.32+13-CA (build 17.0.2+8-LTS)
OpenJDK 64-Bit Server VM Zulu17.32+13-CA (build 17.0.2+8-LTS, mixed mode, sharing)
https://clojurians.slack.com/archives/C0617A8PQ/p1674417453437479
Thanks! I'll investigate.
Btw, 20230707.640 is a few months behind - if you intend to get eventually use this bugfix, better to de-risk the upgrade in advance :)
Cheers - V
Thanks, but I'm not quite sure how to upgrade to a particular version making peace with spacemacs... 🤷
Thanks for the hint! After a new round of bugfixes I'll ping the Doom and Spacemacs maintainers.
Hi, I'm experiencing this behavior as well. I've been experiencing this behavior for at least a year, but only recently has it become a big problem as I've been dealing with a lot of #js data.
My versions:
CIDER
;; CIDER 1.14.0-snapshot (package: 1.14.0-snapshot), nREPL 1.0.0
;; ClojureScript REPL type: shadow-select
;; ClojureScript REPL init form: (do (require '[shadow.cljs.devtools.api :as shadow]) (shadow/nrepl-select :web-client-dev))
Emacs
GNU Emacs 29.2 (build 2, aarch64-apple-darwin23.2.0, NS appkit-2487.30 Version 14.2.1 (Build 23C71)) of 2024-01-19
Is it a problem because the long lines slow down emacs?
No, it's quite fast. It's a problem because it makes it hard to see and understand the *cider-result* data.
Possibly related:
- https://github.com/BetterThanTomorrow/calva/issues/1259
- https://github.com/thheller/shadow-cljs/issues/510
I tried all the suggestions noted in both of these issues, and I still can't get emacs/cider to pretty-print results with shadow-cljs when there is a "#js" in the output. When there is not a "#js" in the output, it pretty-prints fine.
I'd love to help debug this, but I don't understand the responsibilities of the different tools involved: emacs cider, nrepl, shadow-cljs, etc.
When using cider-connect-sibling-cljs with :cljs-repl-type 'shadow-select, whose responsibility is it to pretty-print the results into the *cider-result* buffer. Does this happen by cider, nrepl, or shadow-cljs?
Thanks for the hints!
A bare clj -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "RELEASE" } }}' -m cljs.main -re node --repl will show that (js-obj {}) will print #js {} ootb
I've asked here where in cljs is that defined: https://clojurians.slack.com/archives/C07UQ678E/p1708856848465549
If it is something like a print-method, it should be simpler to override as we already do with other print-methods https://github.com/clojure-emacs/cider-nrepl/blob/3824d72f9ba1a14f9ce9910500db0885f6b39c23/src/cider/nrepl/print_method.clj
It's https://github.com/clojure/clojurescript/blob/8a4f8d1025151ae1281185ed9d101c389661554d/src/main/cljs/cljs/core.cljs#L10517
...I reckon that we can't/shouldn't change or override cljs behavior globally.
But probably, somewhere in cider code we perform a prn or pr-str. We could avoid that if we detected that the object is a js object, and use a custom impl instead.
We want js objects to be printed as #js {}. The problem is that the entire containing object is not pretty printed for some reason when any of the deeply nested data is a js object.
For example, evaluating {:a (range 20), :b (range 20), :c (range 20)} puts this in the cider result (correct pretty-printing):
Whereas, evaluating {:a (js/Object.) :b (range 20) :c (range 20)} puts this in the cider result buffer (no pretty printing!):
However, evaluating (still in cljs): (cljs.pprint/pprint {:a (js/Object.) :b (range 20) :c (range 20)}) prints this to the terminal (correct pretty printing):
So for some reason, when cider evaluates the expression, it doesn't pprint it to the cider-result buffer, whereas when you explicitly call cljs.pprint from the repl, it pprints fine.
Note that our default pprint option is: https://github.com/clojure-emacs/cider-nrepl/blob/3824d72f9ba1a14f9ce9910500db0885f6b39c23/src/cider/nrepl/pprint.clj#L42-L47
Many nrepl messages attach these k-vs:
nrepl.middleware.print/buffer-size 4096
nrepl.middleware.print/options (dict
right-margin 70)
nrepl.middleware.print/print "cider.nrepl.pprint/pprint"
nrepl.middleware.print/quota 1048576
nrepl.middleware.print/stream? "1"
You can customize these Elisp side with:
https://github.com/clojure-emacs/cider/blob/dc58ed1a411e6fe6f0350435aa4c56ec6edf59bf/cider-client.el#L280
I hope these give you a baseline to play with! Best-case, you'd be able to detect what's wrong with our pprint and either fix it locally, or propose a PR.
In the case where the result has a tagged literal in it, I don't think either cider.nrepl.pprint/pprint nor my defcustom cider-print-fn is getting called! I have tried fipp, puget, zprint, etc.... all have the same issue. If the evaluation result contains a tagged literal, then for some reason the cider-print-fn is bypassed and the result is not pretty printed.
Note I have observed that this happens with any tagged literal, not just #js.
Thanks! We'd have to check how shadow-cljs integrates with cider-nrepl which is bit of a dense area.
It's mainly implemented in https://github.com/thheller/shadow-cljs/blob/a496c6febd36a7e9e6919180796f9ace81ff98e0/src/main/shadow/cljs/devtools/server/nrepl.clj
defn make-middleware-stack is one of the most relevant defns there - the final computed middleware can easily affect how things get eval'ed/printed.
For posterity, here's the nrepl-level interaction:
(-->
id "25"
op "eval"
session "779f9d6d-cb46-43c9-8753-aaadaced9882"
time-stamp "2024-02-25 15:24:45.928430000"
code "{:a (js/Object.) :b (range 20) :c (range 20)}"
column 1
file "/Users/vemv/icd.scroll/src/icd/scroll/db.cljs"
line 11
nrepl.middleware.print/buffer-size 4096
nrepl.middleware.print/options (dict
right-margin 70)
nrepl.middleware.print/print "cider.nrepl.pprint/pprint"
nrepl.middleware.print/quota 1048576
nrepl.middleware.print/stream? "1"
ns #("icd.scroll.db" 0 13 (fontified t cider-locals nil cider-block-dynamic-font-lock t face font-lock-type-face))
)
(<--
id "25"
session "779f9d6d-cb46-43c9-8753-aaadaced9882"
time-stamp "2024-02-25 15:24:45.968621000"
ns "icd.scroll.db"
printed-value 1
value "{:a #js {}, :b (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19), :c (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19)}"
)
(<--
id "25"
session "779f9d6d-cb46-43c9-8753-aaadaced9882"
time-stamp "2024-02-25 15:24:45.968937000"
status ("done")
)
One last note, shadow-based nrepl eval is defined here https://github.com/thheller/shadow-cljs/blob/a496c6febd36a7e9e6919180796f9ace81ff98e0/src/main/shadow/cljs/devtools/server/nrepl_impl.clj#L322
It may be that that bespoke eval doesn't happen to listen to the nrepl.middleware.print/print option.
Oooooooo I think you got it! In that file, it tries to call read-string, and if that fails it returns the unread string:
https://github.com/thheller/shadow-cljs/blob/a496c6febd36a7e9e6919180796f9ace81ff98e0/src/main/shadow/cljs/devtools/server/nrepl_impl.clj#L186
Indeed, read-string fails for all the same tagged literals that also cause pretty-printing to fail!
I'm fairly certain this is the issue. THANK YOU! I'll file an issue on shadow-cljs.
Cheers, yes, I think the same
@vemv my PR was accepted to shadow, you can close this issue. Thank you again for the help! Locating that nrepl_impl.clj file was the key :).
Awesome, that was quick!
I'll verify it works + document the new min expected Shadow version, then close.
Cheers - V
Great work both 🙌