Fork me on GitHub
#calva
<
2022-10-22
>
Kari Marttila09:10:42

Calva: Connect to a Running REPL Server in the Project question in 🧵

Kari Marttila09:10:33

I have the following calva connection settings in VSCode settings.json file:

"calva.replConnectSequences": [
      {
        "name": "clojure-backend",
        "nReplPortFile": [".nrepl-port"],
        "projectType": "deps.edn",
        "cljsType": "none"
      },   
      {
        "name": "clojurescript-frontend",
        "projectType": "shadow-cljs",
        "cljsType": {
            "dependsOn": "shadow-cljs",
            "connectCode": "(shadow.cljs.devtools.api/repl :app)",
        }
      }
    ],

Kari Marttila09:10:52

... then I connect to backend and frontend REPLs...

Kari Marttila09:10:39

For a while everything is ok. But occasionally I see in the backend terminal REPL:

ERROR: Unhandled REPL handler exception processing message {:op close, :session 5136a91c-6071-4bba-80a6-21184505df0a}
java.net.SocketException: Socket closed
	at java.base/java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
	at java.base/java.net.SocketOutputStream.write(SocketOutputStream.java:150)
	at java.base/java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:81)
	at java.base/java.io.BufferedOutputStream.flush(BufferedOutputStream.java:142)
	at nrepl.transport$bencode$fn__716.invoke(transport.clj:131)
	at nrepl.transport.FnTransport.send(transport.clj:34)
	at nrepl.middleware.session$close_session.invokeStatic(session.clj:285)
	at nrepl.middleware.session$close_session.invoke(session.clj:279)
	at nrepl.middleware.session$session$fn__1381.invoke(session.clj:322)
	at nrepl.middleware$wrap_conj_descriptor$fn__942.invoke(middleware.clj:16)
	at nrepl.server$default_handler$fn__1949.invoke(server.clj:141)
	at nrepl.server$handle_STAR_.invokeStatic(server.clj:24)
	at nrepl.server$handle_STAR_.invoke(server.clj:21)
	at nrepl.server$handle$fn__1917.invoke(server.clj:41)
	at clojure.core$binding_conveyor_fn$fn__5823.invoke(core.clj:2047)
	at clojure.lang.AFn.call(AFn.java:18)
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at java.base/java.lang.Thread.run(Thread.java:829)
After this error, Calva seems to be working just fine in the editor (i.e. I can evaluate forms). E.g. In namespace misc1 I have a form (def foo 1) which in the editor evaluates to 1 . But in the terminal repl:
misc1/foo
Syntax error compiling at (REPL:0:0).
No such var: misc1/foo
I.e. the terminal repl does not see the evaluations that was done in the Calva editor. I wonder what is the reason for this and am I doing something in a wrong way?

Kari Marttila09:10:43

I examined this a bit more and it seems to happen when I connect to the frontend repl.

Kari Marttila09:10:58

Yep. Exactly then.

Kari Marttila09:10:36

I think it might be the shadow-cljs configuration. I examine this a bit myself.

alekszelark09:10:43

It’s because Calva cannot connect to two repls simultaneously.

alekszelark09:10:59

As your shadow-cljs config is managed by tools.deps {:deps …} you can only connect to shadow-cljs repl to get both cljs and clj repls working

Kari Marttila09:10:37

Ah, I didn't know that. Thanks!

pez09:10:01

> As your shadow-cljs config is managed by tools.deps {:deps …} you can only connect to shadow-cljs repl to get both cljs and clj repls working In fact, that’s what is happening. When you connect to what you have named “frontend”, the previous repl is disconnected and you have both backend and frontend provided by the “frontend” connection. That’s why I renamed it to “backend + frontend" in my suggestion.

Kari Marttila09:10:54

Ah, ok. Let's try that.

Kari Marttila10:10:19

... and I need to update my blog post regarding this. Good channel - very fast help. Thanks! 🙂

pez10:10:14

And you should post it as a separate post in #C8NUSGWG6, I think. It did not make it to this week's Clojure Deref when you hid it in a thread there.

Kari Marttila10:10:34

One more question.

Kari Marttila10:10:06

So, if I have this configuration in my settings.json:

"calva.replConnectSequences": [
      {
        "name": "backend + frontend",
        "projectType": "shadow-cljs",
        "cljsType": "shadow-cljs",
        "menuSelections": {
          "cljsLaunchBuilds": [
            ":app",
            ":test",
          ],
          "cljsDefaultBuild": ":app"
        }
      }
    ]
=> I connect to the frontend REPL running in my terminal, but not to the backend REPL running in my terminal? I.e., is the backend REPL actually started by Calva as Jack-in?

Kari Marttila10:10:12

Hm. Maybe I have to continue reading the Calva documentation to fully understand this. 🙂

alekszelark10:10:04

> is the backend REPL actually started by Calva as Jack-in? No, it’s started by shadow-cljs, as shadow-cljs started nREPL, and has all the dependencies needed for running backend code.

alekszelark10:10:53

Calva Jack-in only starts shadow-cljs repl in this case

Kari Marttila10:10:27

Hm. In Cursive you can start the backend and frontend REPLs separately in terminals, and then have two separate connections to those two REPLs. So, I guess in Calva, this means that I need to setup also the needed backend aliases in shadow-cljs.edn ?

alekszelark10:10:13

Not exactly, look at how it’s sorted out in Luminus template:

alekszelark10:10:21

"calva.replConnectSequences": [
        {
            "name": "my-luminus-shadow Server",
            "projectType": "Leiningen",
            "afterCLJReplJackInCode": "(in-ns 'user) (start) (println \"Access the server at \")",
            "cljsType": "none",
            "menuSelections": {
                "leinProfiles": [
                    "dev"
                ]
            }
        },
        {
            "name": "my-luminus-shadow Server + Client",
            "projectType": "shadow-cljs",
            "afterCLJReplJackInCode": "(in-ns 'user) (start) (println \"Access the server at \")",
            "cljsType": "shadow-cljs",
            "menuSelections": {
                "cljsLaunchBuilds": [
                    "app",
                    "test"
                ],
                "cljsDefaultBuild": "app"
            }
        }

Kari Marttila10:10:35

Hm. Maybe I need to find some example that uses both frontend and backend REPLs and deps.edn and shadow-cljs and Calva. And then study the example and read the Calva documentation once more. I really want to understand this part properly if I start using Calva.

Kari Marttila10:10:26

E.g. using that backend + frontend I can't navigate to the clojure functions any more using ctrl+mouse.

Kari Marttila10:10:55

Ok. ctrl+mouse works now => I need to put all required aliases to shadow-cljs.

alekszelark10:10:06

Yeah, it should work

pez10:10:10

If you haven't read https://blog.agical.se/en/posts/shadow-cljs-clojure-cljurescript-calva-nrepl-basics/ I think that could clear things up. When you tell shadow-cljs to use deps, what really happens is that shadow-cljs uses the clojure command to start the REPL. It will use the :aliases to create this command line.

alekszelark10:10:54

What a nice blogpost, I haven’t seen it before, but it could save me a lot of time a couple years ago if it’d be written then ^_^

pez11:10:06

Thanks! Yeah, I was a bit late to respond to the clues I got by all the questions about this. Check the video out as well. And the comments to that video. There is a comment there with a very nice summary of the gist of the message.

Kari Marttila17:10:21

Thanks for the excellent documentation and blog post. I read those in more detail and I think I have a better understanding of these pieces now.