This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-10-18
Channels
- # announcements (18)
- # babashka (34)
- # beginners (47)
- # biff (1)
- # calva (99)
- # cider (1)
- # clojure (99)
- # clojure-austin (13)
- # clojure-australia (1)
- # clojure-dev (53)
- # clojure-europe (30)
- # clojure-nl (1)
- # clojure-norway (7)
- # clojure-spec (7)
- # clojure-uk (1)
- # clojurescript (50)
- # cursive (11)
- # datahike (20)
- # datomic (10)
- # fulcro (7)
- # graalvm (8)
- # gratitude (1)
- # introduce-yourself (7)
- # jackdaw (1)
- # joyride (1)
- # lambdaisland (7)
- # lsp (2)
- # malli (7)
- # nbb (1)
- # off-topic (1)
- # portal (24)
- # re-frame (8)
- # reagent (13)
- # reitit (7)
- # releases (2)
- # remote-jobs (8)
- # rewrite-clj (3)
- # sci (1)
- # scittle (21)
- # shadow-cljs (2)
- # testing (3)
- # tools-deps (22)
- # web-security (19)
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.
Let's see if I can understand the instructions in https://calva.io/connect-sequences/
I like the idea that VSCode is OSS and really customizable (compared to IntelliJ which is propriority and not so customizable by the developer).
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.
> 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!
Ah, tried that. Nice!
VSCode+Calva is really nice combination for Clojure programming. I wonder why it is not that popular. But hopefully it will.
It is super popular, I'd say. 1 out of 5 Clojure devs use it according to the last Clojure Survey.
Ah, I didn't know!
I live in a Metosin bubble! 🙂
Happy to hear that it is that popular - this means that you have a lot of feedback for future development for Calva! 🙂
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.
When I did that interview I realized how strong feelings people have for their editors.
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.
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.
(and I use VSCode with Emacs keybindings, of course, as IntelliJ also)
Emacs has a lot going for it. VS Code can't compete for someone who knows how to wield Emacs well, I'd say.
Yep. Cursive is really good. But you are going there, I'm sure. 🙂
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?
Aah, with Running REPL server in the project
it do show my connect sequence clojure-backend
.
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)",
}
}
],
Faster to connect to the REPLs now.
Damn. This is good. 🙂
I write a blog post regarding this. 🙂
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
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?Ah, I must try that tomorrow!
But, if I want to give the "connectCode": "(shadow.cljs.devtools.api/repl :app)",
=> I need to pass the object, right?
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.
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.
Ah. Let's try.
> 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.
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.)Damn. It works like that out-of-the-box! I update my blog post regarding that.
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.
Deleted one question. Just read the documentation in more detailed and it answered my question. The Calva documentation is excellent, btw. 🙂

Yep. Just tried without that menu selection - and now it asks about them. Stupid me. One should always read the documentation twice.
I added that new configuration to my blog with compliments to you. Thanks!
In the evening I promise to read the Calva documentation. 🙂
But first my weight lifting exercise at the basement. And sauna, of course. 🙂
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"
}
}
It connect to the clojurescript repl in the terminal but creates the clojure repl jack-in.
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
Ok. I try these later!
@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
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?
oh hold up, i think the issue was that I was trying to load a CLJS namespace in my CLJ repl
Ah, Calva should probably help with that better than saying it can't read properties of null.
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"
}
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.
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
I don't know 😅 not sure vscode allows that, but as a LSP client, it'd make sense to ignore that IMO
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?
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.
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
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. 😃
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.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
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...
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
@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?
This probably isn’t an ideal solution, but we can filter out those messages by overriding vscode.window.showErrorMessage
.
@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).
That's what I figured @UE21H2HHD. Thanks for confirming. Is there an easy way to ask a map node if it's balanced?
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.
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
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.
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?
Good question! Cannot remember at this moment, but am now curious! But time for me to sign off for today! 💤
@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.
> by overriding vscode.window.showErrorMessage
>
Great find @brandon.ringe :the_horns:
@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}"