Fork me on GitHub
#squint
<
2023-11-10
>
borkdude15:11:08

First sign of nREPL life!

‼️ 13
pez17:11:00

I get errors trying to clone the repo:

Cloning into 'squint'...
remote: Enumerating objects: 6637, done.
remote: Counting objects: 100% (1860/1860), done.
remote: Compressing objects: 100% (530/530), done.
error: object 3ebf8cb9f283e531f511a78f3198bd0050b452f8: zeroPaddedFilemode: contains zero-padded file modes
fatal: fsck error in packed object
fatal: fetch-pack: invalid index-pack output
Tried updating to latest git, but that doesn’t help.

pez17:11:01

I could clone by disabling fsck checks.

borkdude17:11:20

I might have seen it before but not sure what it is

borkdude18:11:00

@U0ETXRFEW Pushed an improvement for printing JS objects

borkdude18:11:13

I'm very happy you're giving this an early try

pez18:11:02

Before pulling your improvement I have this:

❯ node node_cli.js nrepl-server :port 1888
nREPL server started on port 1888 on host 127.0.0.1 - 
Connection accepted
request {:op "eval", :code "*ns*", :id "1"}
:ns nil
:v "(async function () {\nvar squint_core = await import('squint-cljs/core.js');\nglobalThis.user = globalThis.user || {};\nreturn _STAR_ns_STAR_;;\n\n}) ()"
ReferenceError: _STAR_ns_STAR_ is not defined
    at eval (eval at <anonymous> (file:///Users/pez/Projects/squint/lib/cli.js:33:13), <anonymous>:4:1)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
response {"err" "_STAR_ns_STAR_ is not defined\n", "id" "1"}
response {"ex" "ReferenceError: _STAR_ns_STAR_ is not defined", "ns" "user", "id" "1"}
response {"ns" "user", "status" ["done"], "id" "1"}
request {:op "clone", :id "2"}
response {"new-session" "0c3acf9a-5811-4a04-aba5-93ac99b6afd0", "status" ["done"], "id" "2"}
request {:op "describe", :id "3", :verbose 1, :session "0c3acf9a-5811-4a04-aba5-93ac99b6afd0"}
response {"versions" {"nbb-nrepl" {"major" "TODO", "version-string" "TODO"}, "node" {"major" "v20", "minor" "6", "incremental" "1", "version-string" "v20.6.1"}}, "aux" {}, "ops" {"complete" {}, "info" {}, "lookup" {}, "eval" {}, "load-file" {}, "describe" {}, "close" {}, "clone" {}, "eldoc" {}}, "status" ["done"], "id" "3", "session" "0c3acf9a-5811-4a04-aba5-93ac99b6afd0"}
request {:file "/Users/pez/Projects/squint/.calva/output-window/output.calva-repl", :nrepl.middleware.print/print "cider.nrepl.pprint/pprint", :op "eval", :column 1, :line 91, :id "4", :code "(when-let [requires (resolve 'clojure.main/repl-requires)] (clojure.core/apply clojure.core/require @requires))", :stderr {}, :pprint 1, :stdout {}, :nrepl.middleware.print/options {:right-margin 80, :length 150}, :session "0c3acf9a-5811-4a04-aba5-93ac99b6afd0"}
:ns nil
:v "(async function () {\nvar squint_core = await import('squint-cljs/core.js');\nglobalThis.user = globalThis.user || {};\nreturn (await (async function () {\n let temp__23934__auto__1 = resolve(symbol(\"clojure.main/repl-requires\"));\nif (temp__23934__auto__1 != null && temp__23934__auto__1 !== false) {\nlet requires2 = temp__23934__auto__1;\nreturn squint_core.apply(globalThis.user.clojure.core.require, squint_core.deref(requires2));}\n})());\n\n}) ()"
ReferenceError: resolve is not defined
    at eval (eval at <anonymous> (file:///Users/pez/Projects/squint/lib/cli.js:33:13), <anonymous>:5:29)
    at eval (eval at <anonymous> (file:///Users/pez/Projects/squint/lib/cli.js:33:13), <anonymous>:9:3)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
response {"err" "resolve is not defined\n", "id" "4", "session" "0c3acf9a-5811-4a04-aba5-93ac99b6afd0"}
response {"ex" "ReferenceError: resolve is not defined", "ns" "user", "id" "4", "session" "0c3acf9a-5811-4a04-aba5-93ac99b6afd0"}
response {"ns" "user", "status" ["done"], "id" "4", "session" "0c3acf9a-5811-4a04-aba5-93ac99b6afd0"}
request {:op "clone", :session "0c3acf9a-5811-4a04-aba5-93ac99b6afd0", :id "6"}
response {"new-session" "8d05650b-843e-40ac-9039-473394923c8c", "status" ["done"], "id" "6", "session" "0c3acf9a-5811-4a04-aba5-93ac99b6afd0"}
request {:id "7", :op "eval", :session "8d05650b-843e-40ac-9039-473394923c8c", :code ":fake-it", :stdout {}, :stderr {}, :pprint 0}
:ns nil
:v "(async function () {\nvar squint_core = await import('squint-cljs/core.js');\nglobalThis.user = globalThis.user || {};\nreturn \"fake-it\";;\n\n}) ()"
response {"ns" "user", "value" "fake-it", "id" "7", "session" "8d05650b-843e-40ac-9039-473394923c8c"}
response {"ns" "user", "status" ["done"], "id" "7", "session" "8d05650b-843e-40ac-9039-473394923c8c"}
And Calva gives up. Connecting as a nbb type project type, but I don’t think that matters, because for Calva that just means it should treat the first session connected as a cljs repl and not try promote it. Will add a squint project type to make it less confusing for users.

borkdude18:11:15

can you test commit f86ac57a8b42e3776e50fc9669a87ce4e3d94d1f so we are on equal situations?

👍 1
pez18:11:59

my process is

bb build
node node_cli.js nrepl-server :port 1888

pez18:11:32

I get the same error on that commit.

borkdude18:11:34

you can simply run bb dev I guess, this is faster

pez18:11:09

It looked like that started a shadow-cljs nrepl server. But maybe I read that wrong?

pez18:11:01

I will go afk soon and probably without notice. Just a heads up so that I don’t seem rude. 😃

borkdude18:11:04

yes, but that doesn't really hurt

pez18:11:17

❯ bb dev  
shadow-cljs - config: /Users/pez/Projects/squint/shadow-cljs.edn
shadow-cljs - starting via "clojure"
[2023-11-10 19:32:30.166 - WARNING] TCP Port 9630 in use.
shadow-cljs - server version: 2.20.15 running at 
shadow-cljs - nREPL server started on port 60543
shadow-cljs - watching build :squint
[:squint] Configuring build.
[:squint] Compiling ...
[:squint] Build completed. (141 files, 131 compiled, 0 warnings, 5.00s)
It’s unclear on which port the squint nrepl server is started.

borkdude18:11:43

you have to start the nrepl server in another terminal with:

node node_cli.js nrepl-server :port 1888

pez18:11:10

Ah, so it’s mainly that I don’t need to keep running bb build. Gotcha!

borkdude18:11:13

but you can just pull the branch and shadow will rebuild, without you having to fully build bb

pez18:11:20

I see what I could try to make Calva connect. But will be later tonight because now I have to run.

borkdude18:11:58

no probs, could very well be a bug in the nREPL server, which I just made work today

pez20:11:41

For very stupid reasons, Calva treats these CLJS-only repls as if they were CLJ repls. By default Calva starts a CLJ session by evaluating:

(when-let [requires (resolve 'clojure.main/repl-requires)] (clojure.core/apply clojure.core/require @requires))
This is configurable, though, so I now tried first to replace that expression with nothing. I still can’t connect, unsure what Calva is unsatisfied with, but I also see an error in the log:
nREPL server started on port 1888 on host 127.0.0.1 - 
Connection accepted
request {:op "eval", :code "*ns*", :id "1"}
:ns nil
ReferenceError: _STAR_ns_STAR_ is not defined
    at eval (eval at <anonymous> (file:///Users/pez/Projects/squint/lib/cljs-runtime/squint.repl.nrepl_server.js:215:8), <anonymous>:4:1)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
response {"err" "_STAR_ns_STAR_ is not defined\n", "id" "1"}
response {"ex" "ReferenceError: _STAR_ns_STAR_ is not defined", "ns" "user", "id" "1"}
response {"ns" "user", "status" ["done"], "id" "1"}
request {:op "clone", :id "2"}
response {"new-session" "365ebe4e-417b-471f-ba5f-304a3426bd27", "status" ["done"], "id" "2"}
request {:op "describe", :id "3", :verbose 1, :session "365ebe4e-417b-471f-ba5f-304a3426bd27"}
response {"versions" {"nbb-nrepl" {"major" "TODO", "version-string" "TODO"}, "node" {"major" "v20", "minor" "6", "incremental" "1", "version-string" "v20.6.1"}}, "aux" {}, "ops" {"complete" {}, "info" {}, "lookup" {}, "eval" {}, "load-file" {}, "describe" {}, "close" {}, "clone" {}, "eldoc" {}}, "status" ["done"], "id" "3", "session" "365ebe4e-417b-471f-ba5f-304a3426bd27"}
request {:op "clone", :session "365ebe4e-417b-471f-ba5f-304a3426bd27", :id "5"}
response {"new-session" "277c7b91-e21e-4de8-8316-b51fb700221c", "status" ["done"], "id" "5", "session" "365ebe4e-417b-471f-ba5f-304a3426bd27"}
request {:id "6", :op "eval", :session "277c7b91-e21e-4de8-8316-b51fb700221c", :code ":fake-it", :stdout {}, :stderr {}, :pprint 0}
:ns nil
response {"ns" "user", "value" "\"fake-it\"", "id" "6", "session" "277c7b91-e21e-4de8-8316-b51fb700221c"}
response {"ns" "user", "status" ["done"], "id" "6", "session" "277c7b91-e21e-4de8-8316-b51fb700221c"}

borkdude20:11:41

maybe the describe map is wrong or so

borkdude20:11:47

dunno, emacs works though

borkdude20:11:58

I released 0.4.39

pez20:11:41

Yeah, clearly Calva is unnecessary picky about something. I will try to figure out what it is. But it is also that Calva can connect with a lot of nREPL servers.

borkdude20:11:51

try lein repl :connect 1888

borkdude20:11:07

basically only the eval op is implemented right now

pez20:11:22

I now also tries with making the initial evaluation be the one that Calva uses for cljs repls:

(try (require '[cljs.repl :refer [apropos dir doc find-doc print-doc pst source]]) (catch :default e (js/console.warn \"Failed to require cljs.repl utilities:\" (.-message e))))
That also fails. With a third kind of error thrown, or two actually:
nREPL server started on port 1888 on host 127.0.0.1 - 
Connection accepted
request {:op "eval", :code "*ns*", :id "1"}
:ns nil
ReferenceError: _STAR_ns_STAR_ is not defined
    at eval (eval at <anonymous> (file:///Users/pez/Projects/squint/lib/cljs-runtime/squint.repl.nrepl_server.js:215:8), <anonymous>:4:1)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
response {"err" "_STAR_ns_STAR_ is not defined\n", "id" "1"}
response {"ex" "ReferenceError: _STAR_ns_STAR_ is not defined", "ns" "user", "id" "1"}
response {"ns" "user", "status" ["done"], "id" "1"}
request {:op "clone", :id "2"}
response {"new-session" "db576da1-cd1b-4d04-a23a-f0d06203891e", "status" ["done"], "id" "2"}
request {:op "describe", :id "3", :verbose 1, :session "db576da1-cd1b-4d04-a23a-f0d06203891e"}
response {"versions" {"nbb-nrepl" {"major" "TODO", "version-string" "TODO"}, "node" {"major" "v20", "minor" "6", "incremental" "1", "version-string" "v20.6.1"}}, "aux" {}, "ops" {"complete" {}, "info" {}, "lookup" {}, "eval" {}, "load-file" {}, "describe" {}, "close" {}, "clone" {}, "eldoc" {}}, "status" ["done"], "id" "3", "session" "db576da1-cd1b-4d04-a23a-f0d06203891e"}
request {:file "/Users/pez/Projects/squint/.calva/output-window/output.calva-repl", :nrepl.middleware.print/print "cider.nrepl.pprint/pprint", :op "eval", :column 1, :line 186, :id "4", :code "(try (require '[cljs.repl :refer [apropos dir doc find-doc print-doc pst source]]) (catch :default e (js/console.warn \"Failed to require cljs.repl utilities:\" (.-message e))))", :stderr {}, :pprint 1, :stdout {}, :nrepl.middleware.print/options {:right-margin 80, :length 150}, :session "db576da1-cd1b-4d04-a23a-f0d06203891e"}
:ns nil
SyntaxError: Cannot use import statement outside a module
    at file:///Users/pez/Projects/squint/lib/cljs-runtime/squint.repl.nrepl_server.js:215:13
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
response {"err" "Cannot use import statement outside a module\n", "id" "4", "session" "db576da1-cd1b-4d04-a23a-f0d06203891e"}
response {"ex" "SyntaxError: Cannot use import statement outside a module", "ns" "user", "id" "4", "session" "db576da1-cd1b-4d04-a23a-f0d06203891e"}
response {"ns" "user", "status" ["done"], "id" "4", "session" "db576da1-cd1b-4d04-a23a-f0d06203891e"}
request {:op "clone", :session "db576da1-cd1b-4d04-a23a-f0d06203891e", :id "6"}
response {"new-session" "19b45adf-c246-4e9b-a784-9ee069dac14e", "status" ["done"], "id" "6", "session" "db576da1-cd1b-4d04-a23a-f0d06203891e"}
request {:id "7", :op "eval", :session "19b45adf-c246-4e9b-a784-9ee069dac14e", :code ":fake-it", :stdout {}, :stderr {}, :pprint 0}
:ns nil
response {"ns" "user", "value" "\"fake-it\"", "id" "7", "session" "19b45adf-c246-4e9b-a784-9ee069dac14e"}
response {"ns" "user", "status" ["done"], "id" "7", "session" "19b45adf-c246-4e9b-a784-9ee069dac14e"}

borkdude20:11:40

AFAIK that also fails with regular CLJS on Node:

$ clj -M:cljs -m cljs.main -re node
ClojureScript 1.11.60
cljs.user=> (try (require '[cljs.repl :refer [apropos dir doc find-doc print-doc pst source]]) (catch :default e (js/console.warn \"Failed to require cljs.repl utilities:\" (.-message e))))
Syntax error reading source at (REPL:1).
<NO_SOURCE_FILE> [line 1, col 159] Invalid symbol: utilities:.

pez21:11:02

Leiningen nrepl client can connect.

borkdude21:11:41

oh no I was wrong, that expression works, but probably only because cljs.repl already exists

borkdude21:11:55

anyway, that won't work in squint

pez21:11:35

Not expecting it to work. Just tried it to see if it might.

pez21:11:39

I think the most interesting case is when I replace this initial eval with nothing.

pez21:11:10

I will now try to find where Calva gives up, because that seems unrelated to the error being thrown.

borkdude21:11:24

You can also try one expression on the command line:

$ bb -Sdeps '{:deps {io.github.babashka/nrepl-client {:git/sha "c83b15906d224b67a67951343b05623c4c00cdcf"}}}' -e "((requiring-resolve 'babashka.nrepl-client/eval-expr) {:port 1888 :expr \"(vec (frequencies [1 1 1 2 2 2 ]))\"})"

{:vals ["[ [ '1', 3 ], [ '2', 3 ] ]"]}

pez21:11:34

It’s cool that the server works with a lot of clients. Even if it doesn’t exactly help Calva.

pez21:11:21

Found a clue. When Calva connects to a cljs repl it considers the cljs repl connected when the result of an evaluation (different for different cljs type of repls) matches a regexp (similarly varying) with a cljs-only repl, we short-circuit this by evaluating the keyword :fake-it and check if the result is :fake-it. With squint it isn’t. The result is "fake-it" , and the connection is considered failed.

pez21:11:16

The easiest fix in Calva is to expect evaluating :fake-it results in "fake-it". But seems a bit risky?

borkdude21:11:38

or use another expression: (-> {:a 1} :a)

pez21:11:03

I could also evaluate something else. Yes.

pez21:11:32

Will squint continue to evaluate keywords like this?

pez21:11:04

OK. So then we need to fix this in Calva. Will try to get around to it this weekend. I don’t like a situation with a cool new nrepl server and Calva can’t connect to it.

borkdude21:11:20

that's the spirit :)

pez21:11:52

The proper fix is to stop the fake nonsense and realize that standalone cljs is a thing again.

pez21:11:08

But I can’t get that done anytime soon.

borkdude21:11:33

no worries, the squint nREPL is far from complete either :)

pez21:11:02

It’s an ergonomic necessity in order for me to get started porting Calva to squint.

pez21:11:26

You’ll notice on X when I get Calva to connect. Now it’s off to bed for me. TTFN!

borkdude21:11:45

what is the TS feedback loop like? Just batch programming, write, compile, run, repeat?

pez21:11:33

Yes. I think that for some setups, like React people enjoy some hotreloading, but I haven’t tried it. For the Calva build it is what you described, even if the time it takes is very quick, and things are pretty much stateless so the restart doesn’t feel all that awful. Still there is a considerable difference from when hacking on the cljs parts of Calva.

pez21:11:50

I demoed interactive programming to a TypeScript team today and their jaws where on the floor, so I think that tells us something about what their feedback loop is like.

pez21:11:49

They got very interested in my js-repl script 😃

pez11:11:15

Now I can connect. But I can’t evaluate things, because Calva starts evaluations in a new namspace with (in-ns …), and that fails:

request {:id "27", :op "eval", :session "4c9c2641-9cfd-487c-9615-529246b376f2", :code "(in-ns 'wordle)", :pprint 0}
:ns nil
ReferenceError: in_ns is not defined
    at eval (eval at <anonymous> (file:///Users/pez/Projects/squint/lib/cljs-runtime/squint.repl.nrepl_server.js:215:8), <anonymous>:4:1)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
response {"err" "in_ns is not defined\n", "id" "27", "session" "4c9c2641-9cfd-487c-9615-529246b376f2"}
response {"ex" "ReferenceError: in_ns is not defined", "ns" "user", "id" "27", "session" "4c9c2641-9cfd-487c-9615-529246b376f2"}
response {"ns" "wordle", "status" ["done"], "id" "27", "session" "4c9c2641-9cfd-487c-9615-529246b376f2"}
I think Calva can be made a bit more resilient to the error and use the ns in the done message, but anyway, that’s where I am now.

borkdude11:11:24

you don't have to do in-ns with nREPL, nREPL has a "ns" field

borkdude11:11:50

maybe I could support that with squint for the REPL, please make an issue so I won't forget, if you think this is important

pez11:11:20

I don’t know if it is important yet. I’ll try to see if I can convince Calva to deal without it. We are already populating the ns field…

borkdude20:11:37

Released v0.4.39 with squint nrepl-server :port 1888 - note that this is an incomplete implementation but if you're adventurous, try it out and come back with issues

🚀 6
seancorfield20:11:04

My mind is officially blown! 🤯 So this does a compile-on-demand to JS for each form sent over the nREPL connection but retains the evaluation history (because node.js has the JS execution), and then it turns the JS result back into cljs data when it sends it back?

borkdude20:11:18

> So this does a compile-on-demand to JS for each form sent over the nREPL connection Yes > but retains the evaluation history (because node.js has the JS execution) Yes > and then it turns the JS result back into cljs data when it sends it back? No, it just prints the result using node:util/inspect

seancorfield21:11:10

Ah, I misread what I saw in the screencap...

seancorfield21:11:01

I am hoping to try out squint at work so I can write React components in cljs but integrate them with our JS codebase... at some point... 🙂

borkdude21:11:35

sounds like a great fit for squint. setting up a project has become easier now with squint.edn and squint watch

seancorfield21:11:40

I'll probably pester you for guidance when it actually happens... 🙂

lemuel14:11:34

Thanks. I’ll give this a spin with Next.js

borkdude14:11:33

@U017AGUF30R sure, let me know how that goes

👍 1
borkdude19:11:00

@U04V70XH6 now it does print as CLJS-like data structure {:a 1} is evaluated to a JS object which prints as #js {:a 1}

1
lemuel22:11:04

I’ve not got far with my experiments yet but having nrepl is so useful. Thank you!

👍 1