calva

Fahd El Mazouni 2026-05-05T13:08:09.734429Z

Hello peeps this https://github.com/clojure-lsp/clojure-lsp/pull/2283 for clojure-lsp just got merged, mind if I make a pr for calva to support the new code actions ? also while I was working on that I hacked around calva to make code action discovery dynamic, should I pursue that or just add the commands the same way the others are ?

ericdallo 2026-05-05T13:08:36.374079Z

dynamic code actions would be nice!

❤️ 2
Fahd El Mazouni 2026-05-05T13:09:02.807969Z

cool ! I'll clean it up and submit it for review asap

pez 2026-05-05T13:11:06.808599Z

I don’t quite recall why we have manual code action. Seems there could be a reason…

Fahd El Mazouni 2026-05-05T13:11:40.469829Z

the only thing I have in mind is a step that handles renames (I think my memory is really spotty)

ericdallo 2026-05-05T13:18:54.822819Z

the reason is that was not easy to have dynamic ones IIRC

Fahd El Mazouni 2026-05-05T13:19:14.528499Z

oh it basically allows the user to choose the binding name instead of the generic one colure-lsp puts in

Fahd El Mazouni 2026-05-05T13:20:10.341539Z

oh that's not the only thing indeed

pez 2026-05-05T13:20:44.924339Z

The suspense, @fahd.elmazouni! 😃

Fahd El Mazouni 2026-05-05T13:21:14.433499Z

the commands an extension exposes should be in its "manifest" ?

pez 2026-05-05T13:22:14.258769Z

I don’t recognize/recall that as a reason…

pez 2026-05-05T13:22:52.800669Z

Can you git blame the relevant file and see who we can ping in here?

pez 2026-05-05T13:23:57.861699Z

I am of course for this being as dynamic as we possibly can get it. Just need to gain a fuller picture…

Fahd El Mazouni 2026-05-05T13:24:06.976789Z

I'll have a deeper look once I get some time, I'll report back with findings and/or a pr

🙏 1
Fahd El Mazouni 2026-05-05T13:25:55.797009Z

for now, I made claude dig the git history and it came up with this

Root cause: multi-project support broke it.

  1. Before Jan 2023 — Single LSP client per workspace. clojure-lsp auto-registered all commands via standard LSP client/registerCapability. Worked fine.
  2. Jan 10, 2023 (bc34181b6, Julien Vincent, PR #2020) — Multi-project support landed. Multiple LSP clients in same VS Code window. Auto-registration disabled because multiple clients registering same command names = conflicts.
  3. Hidden regression — Nobody realized VS Code internally binds operations like "Organize Imports" and "Add Missing Import" to these LSP commands. With registration disabled, those silently broke. No errors, just nothing happening.
  4. Jan 30, 2023 (f80217a90, fixes #2040, #2041) — Manual static registration added as fix. All commands hardcoded with logic to pick correct LSP client per file. Comment in code explains exactly this:

  ▎ "The built-in behaviour resulted in command registration conflicts. There are several vscode operations (such as organise-imports) which are bound to execute these internal lsp commands which would no longer function if these commands are not
  correctly registered.

ericdallo 2026-05-05T13:29:35.417609Z

Interesting, even so all clojure-lsp clients we always had to manually hardcode all commands, but would be nice to have that dynamically configured, only code actions work like that

pez 2026-05-05T13:36:57.450399Z

Multiproject support is way more expensive than I realized when we went for it. It is very fancy and probably nice for some people who need it, but generally it is better to just run one server and configure it to support all sub projects. But that ship have sailed, I guess… Do we specify all these actions in the manifest, @fahd.elmazouni?

pez 2026-05-05T13:38:01.637349Z

In any case, I suggest hard coding to match current clojure-lsp and we create an issue for looking at what we can do about making it dynamic.

ericdallo 2026-05-05T13:40:18.140419Z

TBH if a client can dynamically get the avaialble commands, I'd say that's better than hardcode

pez 2026-05-05T13:44:47.838599Z

Yes, we all agree about that, @ericdallo 😃

ericdallo 2026-05-05T13:49:08.743099Z

it seems https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#executeCommandOptions in initialize result the known commands, so that's 100% possible to do!

seancorfield 2026-05-05T13:58:44.891439Z

I guess at this point adding an option to disable multi-project support wouldn't help provide a simpler path since you'd still need to support command registration and selection for multiple LSP servers? It just seems like it added a lot of complexity and breakage (and additional subsequent complexity to fix it). Maybe it isn't worth the support involved?

ericdallo 2026-05-05T14:01:15.569339Z

I can't see why this is a big deal with multiple projects, we could prefix the command with the project name or so dynamically

pez 2026-05-05T14:05:10.607079Z

@seancorfield And multi-project support is still a bit broken. An option for disabling it could probably stop it from messing with projects where it is not used. It’s a separate issue from the current one though, since as long as we do have the support, we will need to account for it in code action registration.

seancorfield 2026-05-05T14:23:58.873839Z

Yeah... sometimes "good ideas" prove to not be so good once they're implemented 🙂

Fahd El Mazouni 2026-05-05T14:24:59.372109Z

isn't that the story of our lives ? can't wait to sit down and have a look at this hehe

JR 2026-05-07T12:23:10.915739Z

Oops, there were some new lsp code actions that I wanted, so I submitted this PR to calva to enable them: https://github.com/BetterThanTomorrow/calva/pull/3205. Does this still make sense or will everything be dynamic soon?

ericdallo 2026-05-07T12:23:51.093769Z

until we have dynamic, we might need to open PRs like that, so np to me

pez 2026-05-07T12:25:22.486069Z

Ah, that’s you, @john.t.richardson.dev, I was about to ask. 😃

😶‍🌫️ 1
pez 2026-05-07T12:26:27.035779Z

I think it’s good to handle the dynamism in a separate issue. Less blockage. https://clojurians.slack.com/archives/CBE668G4R/p1777988281637349?thread_ts=1777986489.734429&cid=CBE668G4R

👍 2
seancorfield 2026-05-05T22:42:43.711089Z

Question about exception reporting in Calva. When I eval an expression with an error, Calva shows the first line inline, and then shows the two lines in the REPL output -- where exactly do those error messages come from and what, if any, hooks into preprocessing those errors does/could Calva provide?

neumann 2026-05-06T07:10:10.058869Z

If anyone works on that sort of thing, could it be put in its own mini library? I’d love for that to be useful for other tools. Or maybe a renewed effort on the existing library?

🤘 1
seancorfield 2026-05-06T13:21:19.066109Z

Yeah, I've toyed with this a few times over the years, and never quite figured out how/where to fit it into the ecosystem, but the recent (long) thread in #off-topic made me think again about doing this. I think nREPL middleware might make the most sense but, yes, as a library where the core of it could be used standalone. I just haven't dug into nREPL enough to understand all the message/response stuff.

seancorfield 2026-05-07T02:35:56.571539Z

I have a nascent nREPL middleware that rephrases / cleans up some exceptions. Example:

user=> (* 42 :x)
Execution error (UnexpectedType) at user/eval2593 (REPL:1).
Expected Number but got Keyword

1
seancorfield 2026-05-07T02:39:55.625269Z

It uses modified versions of clojure.main's repl-caught and err->msg -- so you could start a REPL with :caught -- and an nREPL middleware function that installs that as the ::caught-fn.

seancorfield 2026-05-05T22:47:29.405279Z

I'm asking because I'm wondering if Calva could rewrite exception messages to provide something more beginner-friendly? For example, class <source> cannot be cast to class <expected> (<source> is in unnamed module...) could be regex-mapped to something like Found <source> but expected <expected> perhaps with some class names shortened, e.g., Found Keyword but expected Number for the case I posted above (with all the module stuff suppressed). And perhaps that could be what is shown inline as well. Users can always eval *e (might be nice if there was a default Calva command and key binding for that) to get the full details?

pez 2026-05-06T05:16:18.242379Z

Sweet idea! There was a project started some years ago, mapping known error messages to more beginner friendly messages. It never took off, but it was a very interesting approach. There are no hooks in Calva for doing things like that. But there could be. The messages come in via nrepl. You can enable the nrepl log and see what they look like. We do some processing on them, so that we can print the stacktrace on demand. There could be some nrepl middleware that does things like this, btw.