I’m having troubles fixing an issue with println not printing newlines in the released Joyride extension. The newline prints fine in the development build. I’ve added some debug logging on this branch: https://github.com/BetterThanTomorrow/joyride/blob/253-trailing-newlines-take-2/src/joyride/sci.cljs
From the debug logging I note:
• There is some default printing somewhere, that also prints to the console
◦ This is probably fine, or at least not causing the problem I am trying to understand
• When it works:
◦ The trailing newline is a separate print (which is lacking from the release build)
◦ The default console printer is not printing this newline
Joyride is using a pretty ancient SCI, so maybe this problem goes away if I upgrade. The problem with that is that I have tried a few times and failed getting a working Joyride extension with latest SCI. But maybe I now have the compelling reason to solve that problem… (I don’t remember right now what broke.)
I do remember fixing something like this in SCI so worth a try
Thanks. Then that’ll be my next step and I’ll probably come back with refreshed memory of the hurdle with that. 😃
I have bad news and bad news. 😃
• Upgrading SCI doesn’t fix the println problem
• Upgrading SCI breaks the E2E tests where we use Joyride for running tests. Specifically it is tests using the deftest-async macro (nicked from nbb, iirc) that break with Could not find instance method: catch$
I created a new thread for the upgrading issue: https://clojurians.slack.com/archives/C03DPCLCV9N/p1761856709212499
this commit fixes it https://github.com/babashka/sci/commit/b6dc7f3b76e83990ac25bf2d935ba3b60c007df4
which is on the master branch
the println error might be in the nrepl server
does the code go through nrepl or not?
Ah, “it” was the test macro thing. I can confirm it fixed it!
"it"?
> this commit fixes it
yeah
ok
println issue… Not nrepl. I get it also when just evaluating code on the Joyride SCI repl.
also in a script, not in REPL?
That too. Anything that uses our eval-string function.
can you reproduce it on this SCI playground? it has the same println config as joyride. https://babashka.org/scittle/codemirror.html if so, please copy/paste the repro
oh I see now the screenshot in the initial message with the wrapfn
I. can't remember adding this
The wrapfn? It’s pretty new.
well isn't that the issue then?
The wrapfn never gets called with the trailing newline.
In release builds. In the dev host we get the trailing newline call.
In SCI println is this:
https://github.com/babashka/sci/blob/f40ee1a6cf6c53b8271b41c101c3391773d67e76/src/sci/impl/io.cljc#L239
It just called CLJS println.
And CLJS println prints the newline separately through *print-fn*
Perhaps shadow or so sets print-newline differently in production mode, don't know
You could try to print it (not in SCI, but in CLJS) on startup or so for debugging (it being *print-newline* )
I was digging around a bit with this yesterday, without making much sense from it.
The initial value of SCI's print newline is inherited from the host: https://github.com/babashka/sci/blob/f40ee1a6cf6c53b8271b41c101c3391773d67e76/src/sci/impl/io.cljc#L63 You could also just set it manually by evaluating:
(alter-var-root #'*print-new-line* (constantly true))
and see if that helpsFrom a packaged VSIX:
> [Extension Host] print-newline false
And it is true in the dev extension host.
aha
then that explains it
maybe ask shadow why this is
So the alter-var-root at start of Joyride?
Yesterday, I was thinking that maybe I should do something like this with *print-newline* yesterday when I found my way there via SCI. But then I thought that maybe it would make print behave funny. But that’s not how this variable works?
This fixes the issue:
(defn eval-string [s]
(sci/binding [sci/ns @!last-ns
sci/print-newline true
sci/print-fn (wrap-print-fn "stdout" @sci/print-fn output/append-eval-out!)
sci/print-err-fn (wrap-print-fn "stderr" @sci/print-err-fn output/append-eval-err!)]
(let [code (str s)
reader (sci/reader code)]
(loop [res nil]
(let [form (sci/parse-next (store/get-ctx) reader)]
(if (= :sci.core/eof form)
(do
(vreset! !last-ns @sci/ns)
(output/append-eval-result! (pr-str res) {:ns (str @sci/ns)})
res)
(let [result (try
(sci/eval-form (store/get-ctx) form)
(catch js/Error e
(let [message (or (.-message e) (str e))]
(output/append-line-eval-err! message)
(throw e))))]
(recur result))))))))
WDYT?ah yes. you could also just do:
(sci/alter-var-root sci/print-newline (constantly true))
once at the top
(I didn't remember I exposed it)
also: don't forget to bug shadow about this because this behavior seems a bit funnyPerhaps shadow evaluates enable console print for you:
(defn enable-console-print!
"Set *print-fn* to console.log"
[]
(set! *print-newline* false)
(set-print-fn!
(fn []
(let [xs (js-arguments)]
(.apply (.-log js/console) js/console (garray/clone xs)))))
(set-print-err-fn!
(fn []
(let [xs (js-arguments)]
(.apply (.-error js/console) js/console (garray/clone xs)))))
nil)but in release it does not?
or SCI is loaded in a different order than when this is evaluated, something like that
if you want SCI to behave as with enable-console-print! just evaluate it before inheriting *print-fn* with alter-var-root
The stack trace :
Error: Error: Could not find instance method: catch$
at /Users/pez/Projects/joyride/out/js/cljs-runtime/joyride/extension.cljs:49:26
at /Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/core.cljc:325:45
at Object.reject (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl.cljc:113:41)
at processNextTick (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:288:25)
at transition (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:360:12)
at PromiseImpl.reject (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:154:9)
at Object.complete (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:251:18)
at Object.complete (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:327:18)
at resolveTask (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:305:12)
at processNextTick (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:296:7)
at transition (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:360:12)
at PromiseImpl.reject (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:154:9)
at Object.complete (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:251:18)
at resolveTask (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:305:12)
at processNextTick (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:296:7)
at transition (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:360:12)
at PromiseImpl.reject (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl/promise.js:154:9)
at PromiseImpl.promesa$protocols$ICompletable$_reject_BANG_$arity$2 (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/impl.cljc:128:21)
at Object.promesa$protocols$_reject_BANG_ [as _reject_BANG_] (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/protocols.cljc:50:14)
at promesa$core$reject_BANG_ (/Users/pez/Projects/joyride/out/js/cljs-runtime/promesa/core.cljc:497:4)
at /Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/analyzer.cljc:1372:1
at Object.sci$impl$types$eval [as eval] (/Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/types.cljc:86:8)
at /Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/evaluator.cljc:99:30
at /Users/pez/Projects/joyride/out/js/cljs-runtime/sci.impl.evaluator.js:106:3
at /Users/pez/Projects/joyride/out/js/cljs-runtime/cljs/core.cljs:5776:36
at /Users/pez/Projects/joyride/out/js/cljs-runtime/cljs.core.js:20740:3
at Object.cljs$core$IReduce$_reduce$arity$3 (/Users/pez/Projects/joyride/out/js/cljs-runtime/cljs.core.js:20755:3)
at cljs$core$reduce.cljs$core$IFn$_invoke$arity$3 (/Users/pez/Projects/joyride/out/js/cljs-runtime/cljs/core.cljs:2619:17)
at Object.sci$impl$evaluator$eval_try [as eval_try] (/Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/evaluator.cljc:88:9)
at /Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/analyzer.cljc:916:7
at Object.sci$impl$types$eval [as eval] (/Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/types.cljc:86:8)
at /Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/analyzer.cljc:80:21
at Object.sci$impl$types$eval [as eval] (/Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/types.cljc:86:8)
at /Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/analyzer.cljc:578:17
at Object.sci$impl$types$eval [as eval] (/Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/types.cljc:86:8)
at /Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/analyzer.cljc:813:27
at Object.sci$impl$types$eval [as eval] (/Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/types.cljc:86:8)
at sci$impl$fns$arity_1 (/Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/fns.cljc:109:18)
at /Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/analyzer.cljc:1372:1
at Object.sci$impl$types$eval [as eval] (/Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/types.cljc:86:8)
at Timeout.sci$impl$fns$arity_0 [as _onTimeout] (/Users/pez/Projects/joyride/out/js/cljs-runtime/sci/impl/fns.cljc:108:18)
at listOnTimeout (node:internal/timers:588:17)
at processTimers (node:internal/timers:523:7)The macro:
(defmacro deftest-async [name opts & body]
(let [[opts body]
(if (map? opts)
[opts body]
[nil (cons opts body)])]
`(cljs.test/deftest ~name
~@(when-let [pre (:before opts)]
[pre])
(cljs.test/async
~'done
(-> (do ~@body)
(.catch (fn [err#]
(cljs.test/is (= 1 0) (str err# (.-stack err#)))))
(.finally
(fn []
~@(when-let [post (:after opts)]
[post])
(~'done))))))))If I rewrite the tests so that they use regular deftest and cljs.test/async directly, they do not crash.