brandonbloom / fipp

Fast Idiomatic Pretty Printer for Clojure
525 stars 44 forks source link

ClojureScript: fipp interacts badly with console.log as default print strategy #84

Open eauc opened 1 year ago

eauc commented 1 year ago

So I apologize if this is a silly question, but I'm trying to use fipp in clojurescript and it prints a single character per line, with options like width having no effect.

Funily enough, if I capture the output in a string and print it, everything is fine :sweat_smile:

(ns test-fipp.core
  (:require [fipp.edn]))

(defn main
  []
  (fipp.edn/pprint [1 2 3] {:width 100})
  (cljs.core/*print-fn*
   (with-out-str
     (fipp.edn/pprint [1 2 3] {:width 100}))))

outputs

[
1

2

3
]

[1 2 3]

I tried this in node and my browser, using shadow-cljs to build the project

I've setup a basic projet to show this behaviour https://github.com/eauc/test-fipp

any idea what I'm doing wrong ? thanks in advance :pray:

brandonbloom commented 1 year ago

If you print [123 456 789] do you get a number per line or still a single character per line? Assuming the former, this smells to me like you're seeing each individual print call as a separate console.log or similar.

What javascript environment are you running in?

eauc commented 1 year ago

first of all thanks for taking the time to answer :pray:

(fipp.edn/pprint [123 234 345] {:width 100})
(cljs.core/*print-fn*
 (with-out-str
   (fipp.edn/pprint [123 234 345] {:width 100})))

outputs


[
123

234

345
]

[123 234 345]

so it looks like I get one "token" per line ?

I suspected it might be a problem with shadow-cljs so I tried a basic deps.edn build (added the setup to the test repo) the behaviour is the same :sweat_smile:

I run the JS with node v16.14.2 and chrome v105.0.5195.125 on Debian

brandonbloom commented 1 year ago

The second call appears to be working, which implies to me that something is wrong with the default print-fn. What does (do (pr 123) (pr 456)) print?

Is it:

123
456

Or is it 123456 on a single line?

If the former, this is because the default print function is likely set to something like console.log instead of something like stdout.write.

eauc commented 1 year ago

alright thanks for pointing me in this direction if I do (do (pr 123) (pr 456)) it prints

123
456

I looked at cljs.core/*print-fn* and it's pointing to a shadow-cljs print function. Investigating this I don't think it's my problem since eventually it just prints the string using the original print-fn

however, reading the implementation of cljs.core/enable-console-print! https://cljs.github.io/api/cljs.core/enable-console-printBANG and the documentation of *print-newline* https://cljs.github.io/api/cljs.core/STARprint-newlineSTAR I think it's pretty much intended that console.log is the default print function in clojurescript... thus adding a new line to each printed string

brandonbloom commented 1 year ago

it's pretty much intended that console.log is the default print function in clojurescript... thus adding a new line to each printed string

This must have changed over the years, since it used to use process.stdout.write in Node.js, iirc.

The workaround is simple:

(defn pp [x]
  (println (with-out-str (fipp.edn/pprint x))))

I've renamed this issue to capture the broader problem.

Fundamentally, fipp is intended to be streamable, and so ultimately does (run! print strings) where strings is a lazy sequence. I'd argue that print is broken in ClojureScript when based on console.log, but if that's known/expected/intended, then I'd entertain a fix in Fipp. In order to recover the correct behavior with console.log, but preserving the streaming, you'd have to detect line breaks and batch up line output (which is what I'd expect ClojureScript to do internally!)

I'm not super involved in the community anymore, so I'm not going to spearhead this investigation/fix, but happy to receive feedback/guidance and code here.

eauc commented 1 year ago

hello again,

first of all thanks for your time on this issue :pray:

I continued my own developement using fipp with with-out-str indeed, it works and overall is no big hassle.

I'm a bit of a noob in clojure(script) myself so probably not the best person to drive a fix over this :sweat_smile: but I agree with your assessment, and from what I understand Clojurescript must do something along those line with their *print-newline* setting :thinking:

Maybe the issue will be useful in case someone stumble on this behaviour too.

See you, and thanks for ~all the fish~ the lib :wave: