Fork me on GitHub
#calva
<
2022-10-18
>
Kari Marttila16:10:47

I got an idea for the part 3 of my Calva blog post series. I try to configure a keyboard shortcut to connect to the Clojure REPL, Clojurescript REPL and start the REPL output window in one shot.

Kari Marttila16:10:03

Let's see if I can understand the instructions in https://calva.io/connect-sequences/

pez16:10:17

Let's see. 😃

Kari Marttila16:10:46

I like the idea that VSCode is OSS and really customizable (compared to IntelliJ which is propriority and not so customizable by the developer).

pez16:10:40

The keyboard shortcut will be defined for you once you have configured, it will be ctrl+alt+c ctrl+alt+j enter. To get it shorter than that (not having to select in the sequence using enter, I think you would need to use Joyride, and it will be a bit of work. You can look at the Calva integration-tests for inspiration.

pez16:10:41

> I like the idea that VSCode is OSS and really customizable (compared to IntelliJ which is propriority and not so customizable by the developer). I've contributed a few things to VS Code. The most important one is the Screencast Mode options to show command names together with the keystrokes. I use that all the time!

Kari Marttila16:10:57

Ah, tried that. Nice!

Kari Marttila16:10:37

VSCode+Calva is really nice combination for Clojure programming. I wonder why it is not that popular. But hopefully it will.

pez16:10:56

It is super popular, I'd say. 1 out of 5 Clojure devs use it according to the last Clojure Survey.

Kari Marttila16:10:13

Ah, I didn't know!

Kari Marttila16:10:22

I live in a Metosin bubble! 🙂

Kari Marttila16:10:46

Happy to hear that it is that popular - this means that you have a lot of feedback for future development for Calva! 🙂

pez16:10:47

There are some issues that stops some professional users from switching. @UEFE6JWG4 knows more about that. The pattern at Metosin might be partly because of this. We should probably spend some time investigating and see what we can do about it.

Kari Marttila16:10:45

When I did that interview I realized how strong feelings people have for their editors.

pez16:10:52

Indeed. Calva makes no attempt whatsoever in trying to lure someone away from their favorite editor. It is meant to be there for people who like VS Code.

Kari Marttila16:10:11

E.g. some of our clojurians are hard-core Emacs users. I also use Emacs, but as an IDE I prefer a real GUI editor like IntelliJ or VSCode.

Kari Marttila16:10:44

(and I use VSCode with Emacs keybindings, of course, as IntelliJ also)

pez16:10:05

Emacs has a lot going for it. VS Code can't compete for someone who knows how to wield Emacs well, I'd say.

pez16:10:00

And Cursive is amazingly well built. Calva has a lot of ground to cover! 😃

Kari Marttila16:10:33

Yep. Cursive is really good. But you are going there, I'm sure. 🙂

Kari Marttila17:10:03

Ok. I think I had some misunderstanding. So: https://calva.io/connect-sequences/ => provides instructions how to create a Jack-in connect sequence (i.e. Calva starts a REPL and connects to it). But: I'd like to create a connect sequence for connecting to a "Running REPL server in the project". I.e. => I'd like to have a connect sequence for Running REPL server in the project + deps.edn + use .nrepl-port file instead of needing to click those options with a mouse every time. Is this possible?

Kari Marttila17:10:08

Aah, with Running REPL server in the project it do show my connect sequence clojure-backend.

pez17:10:33

Yes, maybe not obvious, but that’s what connect means in the feature name.

Kari Marttila17:10:28

Cool. I think I did basic connect sequences for myself:

"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 Marttila17:10:43

Faster to connect to the REPLs now.

Kari Marttila17:10:46

Damn. This is good. 🙂

Kari Marttila17:10:54

I write a blog post regarding this. 🙂

Kari Marttila18:10:39

Didn't streamline the keyboard shortcuts all the way, but it is pretty fast to connect to the repls like this. https://www.karimarttila.fi/clojure/2022/10/18/clojure-calva-part3.html

Kari Marttila18:10:53

Just in time: Sauna is ready!

1
pez19:10:45

I think you should get away

"cljsType": "shadow-cljs",
Instead of providing an object. Iirc the built in type does the same as your custom one. But maybe you tried that and it didn't work?

Kari Marttila19:10:52

Ah, I must try that tomorrow!

Kari Marttila06:10:25

But, if I want to give the "connectCode": "(shadow.cljs.devtools.api/repl :app)", => I need to pass the object, right?

Kari Marttila06:10:13

BTW. This worked:

"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)",
        }
      }
    ],
But this didn't work:
"name": "clojurescript-frontend",
        "projectType": "shadow-cljs",
        "nReplPortFile": [".shadow-cljs/nrepl-port"],     => I tried to give the shadow-cljs nrepl port file explicitely.

pez06:10:25

You don't need to do that, but I am guess you know this. Anyway, could be a bug. However, the path is expected to be a vector of segments, so maybe [".shadow-cljs", "nrepl-port"] works.

Kari Marttila06:10:00

Ah. Let's try.

pez06:10:33

> But, if I want to give the "connectCode": "(shadow.cljs.devtools.api/repl :app)", => I need to pass the object, right? No. If you configure menuSelections (launch and default cljs builds) the built in project type should work.

pez07:10:34

I think something like this should work:

{
      "name": "backend + frontend",
      "projectType": "shadow-cljs",
      "cljsType": "shadow-cljs",
      "menuSelections": {
        "cljsLaunchBuilds": [
          ":app",
          ":test",
        ],
        "cljsDefaultBuild": ":app"
      }
    }
(”backend +” holds true if you configure shadow to use deps.)

Kari Marttila15:10:14

Damn. It works like that out-of-the-box! I update my blog post regarding that.

Kari Marttila15:10:08

BTW. Now that I have get used to one REPL output window both for the backend Clojure REPL and frontend Clojurescript REPL, it is pretty neat. Compared to Cursive, in which you have to manually select the REPL, in Calva you just open what ever file Clojure and Clojurescript and it automatically uses the right REPL.

🙏 1
Kari Marttila17:10:06

Deleted one question. Just read the documentation in more detailed and it answered my question. The Calva documentation is excellent, btw. 🙂

calva 1
Kari Marttila17:10:04

Yep. Just tried without that menu selection - and now it asks about them. Stupid me. One should always read the documentation twice.

Kari Marttila17:10:34

I added that new configuration to my blog with compliments to you. Thanks!

Kari Marttila17:10:57

In the evening I promise to read the Calva documentation. 🙂

Kari Marttila17:10:21

But first my weight lifting exercise at the basement. And sauna, of course. 🙂

Kari Marttila16:10:44

Ah, just realized. This solution does not actually connect to the backend repl running in the terminal:

{
      "name": "backend + frontend",
      "projectType": "shadow-cljs",
      "cljsType": "shadow-cljs",
      "menuSelections": {
        "cljsLaunchBuilds": [
          ":app",
          ":test",
        ],
        "cljsDefaultBuild": ":app"
      }
    }

Kari Marttila16:10:52

It connect to the clojurescript repl in the terminal but creates the clojure repl jack-in.

pez17:10:01

It assumes that you start your backend repl with shadow-cljs. Something like

shadow-cljs -d cider/cider-nrepl:0.27.4 clj-repl
might work You can instead start the cljs watcher from there, I think...
shadow-cljs -d cider/cider-nrepl:0.27.4 watch :app :test

Kari Marttila17:10:46

Ok. I try these later!

Kari Marttila17:10:05

Damn, I'm beginning to fall in love with VSCode and Calva. 🙂

❤️ 1
calva 1
Stephen Young16:10:48

@pez @brandon.ringe i've just created a PR that will show stacktraces on test errors in the repl: https://github.com/BetterThanTomorrow/calva/pull/1903 please take a look and let me know what you think

❤️ 3
🙏 1
🎉 1
pez16:10:51

AMAZING! Thanks! 🙏 I'll try to find time to test it tonight.

yedi19:10:45

hey yall, I've been using Calva for a while now and just restarted my computer this morning. Now when I spin up a REPL in calva, I'm unable to do basic REPL operations. Trying to switch namespaces results in Cannot read properties of null (reading 'switchNS') Also when loading a file or running all tests within a file seem to hang. Anyone know what might be going on?

pez19:10:58

Not good! How do you spin up your REPL?

yedi20:10:40

the built in REPL for calva, using Leiningen

yedi20:10:01

and my project's dev profile, the same as what i've been doing for months

yedi20:10:21

(sorry for the late reply, Slack didn't notify me 😅 )

yedi20:10:56

oh hold up, i think the issue was that I was trying to load a CLJS namespace in my CLJ repl facepalm

pez20:10:07

Ah, Calva should probably help with that better than saying it can't read properties of null.

pez20:10:30

That means things are working, I hope?

yedi22:10:21

yep, all set now

clojure-spin 1
skylize20:10:38

Here is a workaround until problem with LSP exception popups can be solved. Adding this to your keybindings.json provides a Shift+Esc shortcut to dismiss all notifications, whenever any are visible, regardless of focus.

{
    "key": "shift+escape",
    "command": "notifications.clearAll",
    "when": "notificationToastsVisible || notificationCenterVisible"
  }

ericdallo20:10:25

Is that problem frequent like that? I thought was only for corner cases

skylize20:10:06

I get the one related to unbalance maps all the time.

ericdallo20:10:21

that's weird.. do you have a quick simple repro?

skylize20:10:59

Simplest possible repro I have found is ({}) in a new file, then type : between brackets, as if to make type in a key name. See https://github.com/BetterThanTomorrow/calva/issues/1889#issuecomment-1274812901 for a bit more depth on that.

ericdallo20:10:13

Right I can repro that on Calva, even so, seems like corner cases, I'd suggest making calva ignore that notification like it used to do since beginning

ericdallo21:10:10

I don't know 😅 not sure vscode allows that, but as a LSP client, it'd make sense to ignore that IMO

ericdallo21:10:34

One quick fix we could do on clojure-lsp is to try catch on code actions handler, log as error and return empty code actions, WDYT @U07M2C8TT?

pez21:10:46

We have tried making Calva ignore it. It doesn't seem possible. There has never been any code in Calva that does this. And yes, this happens All. The. Time. Not a corner case thing at all.

1
ericdallo21:10:46

So we should prioritize that, I was not aware that was affecting most calva users

ericdallo21:10:59

If we can't make calva supress the log or control that, which is weird, we could • fix the root cause on clojure-lsp which I suspect is not that easy • meanwhile do the quickfix I proposed with the try-catch

pez21:10:08

Sorry for not making that clear. It actually doesn't bother me, personally, a lot. I just ignore it. But for some users it is different. 😃

skylize21:10:13

Best we can work out at the moment (as was discussed in a recent thread you were @-ed into) Calva's involvement in this particular event seems to be limited to configuration. We give this little function to LSP, requesting support for Code Actions.

function provideCodeActions(document, range, context, token, next) {
  return next(document, range, context, token);
}
Then as far as I can tell, all communication from there is directly between LSP and Code, with nowhere for Calva to interject.

ericdallo21:10:59

I don't know how vscode created the spec but its vscode-language-client library seems limited in multiple ways compared with other LSP packages of other editors 😅 I know it's not calva's fault

pez21:10:05

It's pretty strange that the LSP client doesn't get a say on what to do with the error, but it really doesn't seem to get that...

ericdallo21:10:12

I'll try to prioritize that issue this week

ericdallo21:10:18

Yeah, I wonder if that popup was added accidentally on the vscode LSP library, I bet other LSP servers/clients are having the same headache

jacob.maine22:10:49

@UKFSJSM38 the try/catch quickfix sounds reasonable. I agree... fixing the root cause involves a pretty extensive change. The basic problem (in the case of ({:})) is that rewrite-clj will parse unbalanced maps {:} or {:foo}. Those map nodes are z/sexpr-able?, but z/sexpr throws an error. So clojure-lsp should be more defensive whenever it calls z/sexpr. I doubt this is new behavior in rewrite-clj, but @UE21H2HHD—perhaps you have more insight?

👍 1
bringe23:10:19

This probably isn’t an ideal solution, but we can filter out those messages by overriding vscode.window.showErrorMessage.

👀 1
bringe23:10:08

It does intercept the lsp error messages.

ericdallo23:10:49

sounds good to me

jacob.maine23:10:56

Ah JavaScript. Mutable slots everywhere. What could go wrong? 😈

😂 2
bringe00:10:43

To be fair, we can redef functions in Clojure, although, maybe not so globally? lol

bringe00:10:40

@pez Should we just do the above in Calva? :man-shrugging:

1
lread03:10:01

@U07M2C8TT > The basic problem (in the case of ({:})) is that rewrite-clj will parse unbalanced maps {:} or {:foo}. Those map nodes are z/sexpr-able?, but z/sexpr throws an error. So clojure-lsp should be more defensive whenever it calls z/sexpr. I doubt this is new behavior in rewrite-clj, but @UE21H2HHD—perhaps you have more insight? Yup, this is how rewrite-clj behaves. The unbalanced maps have been parse-able since v0. The sexpr-able? fn, which is a v1 addition, isn't about unbalanced maps, etc, but if the node type is sexpr-able (e.g. not whitespace, comment or reader discard).

jacob.maine03:10:36

That's what I figured @UE21H2HHD. Thanks for confirming. Is there an easy way to ask a map node if it's balanced?

lread03:10:03

Nothing exposed currently. Could count the children (skipping unevals) and check if even. See docs for other https://cljdoc.org/d/rewrite-clj/rewrite-clj/1.1.45/doc/user-guide#_parsing_peculiarities.

jacob.maine03:10:48

Ha, the https://cljdoc.org/d/rewrite-clj/rewrite-clj/1.1.45/doc/user-guide#unbalanced-maps section defines this clojure-lsp bug exactly. Anyway, sounds like something to fix on the clojure-lsp side

lread03:10:52

I was thinking of adding a valid? fn at one point for such things as unbalanced maps, but then decided against it. I didn't want rewrite-clj potentially answering that question wrong for some node types. The ultimate trick is to try not to use sexpr, and instead work with the rewrite-clj nodes instead. But I realize sexpr can be worthwhile/convenient.

jacob.maine03:10:50

That's a good perspective to keep in mind as we're fixing this. Perhaps we can remove some of the uses of sexpr. What do z/get and friends do with unbalanced maps?

lread03:10:40

Good question! Cannot remember at this moment, but am now curious! But time for me to sign off for today! 💤

pez10:10:43

@brandon.ringe, sounds good to me to intercept it for now. Then the clojure-lsp team can chill with it and solve thee root cause instead of hacking in a try/catch for the sake of VS Code only.

👍 2
skylize15:10:51

> by overriding vscode.window.showErrorMessage > Great find @brandon.ringe :the_horns:

1
lread18:10:44

@U07M2C8TT follow up from yesterday, unbalanced maps in rewrite-clj work as we might have expected:

(-> "{:a}"
      z/of-string
      (z/get :a))
  ;; => nil

  (-> "{:a}"
      z/of-string
      (z/assoc :b 2)
      z/root-string)
  ;; => "{:a :b 2}"

jacob.maine18:10:52

👍 thanks @UE21H2HHD. Makes sense.

👍 1