Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cider-pprint-eval-last-sexp from a cljs repl on a value which contains a #js literal formats eveything on one line. #3534

Open
dmg46664 opened this issue Oct 17, 2023 · 20 comments

Comments

@dmg46664
Copy link

dmg46664 commented Oct 17, 2023

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

@vemv
Copy link
Member

vemv commented Oct 17, 2023

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 :)

Announcement.

Cheers - V

@dmg46664
Copy link
Author

Thanks, but I'm not quite sure how to upgrade to a particular version making peace with spacemacs... 🤷

@vemv
Copy link
Member

vemv commented Oct 17, 2023

Thanks for the hint! After a new round of bugfixes I'll ping the Doom and Spacemacs maintainers.

@aiba
Copy link
Contributor

aiba commented Feb 24, 2024

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

@vemv
Copy link
Member

vemv commented Feb 24, 2024

Is it a problem because the long lines slow down emacs?

@aiba
Copy link
Contributor

aiba commented Feb 24, 2024

No, it's quite fast. It's a problem because it makes it hard to see and understand the *cider-result* data.

@aiba
Copy link
Contributor

aiba commented Feb 24, 2024

Possibly related:

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?

@vemv
Copy link
Member

vemv commented Feb 25, 2024

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

@vemv
Copy link
Member

vemv commented Feb 25, 2024

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.

@aiba
Copy link
Contributor

aiba commented Feb 25, 2024

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):

image

Whereas, evaluating {:a (js/Object.) :b (range 20) :c (range 20)} puts this in the cider result buffer (no pretty printing!):

image

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):

image

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.

@vemv
Copy link
Member

vemv commented Feb 25, 2024

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:

(defcustom cider-print-fn 'pprint

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.

@aiba
Copy link
Contributor

aiba commented Feb 25, 2024

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.

@vemv
Copy link
Member

vemv commented Feb 25, 2024

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.

@vemv
Copy link
Member

vemv commented Feb 25, 2024

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")
)

@vemv
Copy link
Member

vemv commented Feb 25, 2024

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.

@aiba
Copy link
Contributor

aiba commented Feb 25, 2024

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.

@vemv
Copy link
Member

vemv commented Feb 25, 2024

Cheers, yes, I think the same

@aiba
Copy link
Contributor

aiba commented Feb 25, 2024

@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 :).

@vemv
Copy link
Member

vemv commented Feb 25, 2024

Awesome, that was quick!

I'll verify it works + document the new min expected Shadow version, then close.

Cheers - V

@dmg46664
Copy link
Author

Great work both 🙌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants