Fork me on GitHub
#lsp
<
2023-03-11
>
lilactown00:03:10

we have a massive monorepo which we define a single .clj-kondo/config.edn at the root for defining rules/hooks/etc. This works great for people who use clj-kondo directly, but people who use clojure-lsp in their editor do not see this config get picked up. is there already an issue tracking this?

ericdallo00:03:04

No, it should work if the project root is the mono repo root

ericdallo00:03:19

Which is what currently works best for clojure-lsp

ericdallo00:03:36

A single clojure-lsp process that understand the whole mono-repo

lilactown00:03:46

how would i determine why that isn't happening?

ericdallo00:03:20

First thing is check if LSP is starting at the mono-repo root

ericdallo00:03:53

What editor do you use? If emacs, lsp-clojure-server-info will tell that

lilactown00:03:33

i use emacs but i don't personally use clojure-lsp, since it was locking up emacs for me in our monorepo last year when i tried it

lilactown00:03:42

most of our devs use vscode i think

lilactown00:03:11

i'll see if i can get someone who can repro to try it

lilactown00:03:40

is the idea that if the "project root" is somewhere else, it doesn't work?

camden00:03:08

I tried using the monorepo root as the project root but I couldn't get any of the language features to work

camden00:03:08

I'll try again next week and come back to this. It may be that I just have to wait a long time for all the code in the monorepo to get indexed. Unsure.

ericdallo00:03:08

The server logs will tell if something is wrong, also not aware of any non working mono-repo, so LMK if need more help with that

ericdallo00:03:46

The first time should take some time, few mins depending on the size, next times should be way faster

camden00:03:22

I'll try that again then, I may have been too impatient.

camden00:03:32

Thanks for helping us debug

ericdallo00:03:56

Also, a .clj-kondo config pointing to a parent folder always work if for some reason you don't want to use the mono repo as root

ericdallo00:03:06

Using :config-paths setting

camden00:03:53

Yeah that's what I've configured which seems to work okay. The only annoying thing is if you goto definition on something in an upstream project in the monorepo it goes to the file inside the jar

camden00:03:08

Instead of going directly to the file in the repo

camden00:03:29

So ideally if the lsp process is running at the monorepo root that wouldn't be an issue anymore.

ericdallo00:03:48

Yes, that's what I expect. You can check clojure-lsp project itself which is a mono-repo as well

ericdallo00:03:26

A structure similar to polylith works best, a root deps.edn pointing all known sub deps.edn

lilactown00:03:31

we use lein-monolith (we built it). i wonder if clojure-lsp needs to understand how that works

ericdallo00:03:00

There was a issue to fully support lein-monolith, let me find it

camden00:03:08

I wonder if clojure-lsp is not able to grab the right set of classpaths at the monorepo root for the lein monolith case

ericdallo00:03:35

Yeah, that is the issue with lein-monolith

lilactown00:03:04

i was looking for stuff about eglot and found this article, which talks about setting up clojure-lsp to work with lein-monolith 😅

🎉 2
ericdallo00:03:13

For deps.edn, you can get the whole classpath just pointing to subfolders, but there is no lein monolith command for that

lilactown00:03:18

> Here's the updated solution! Since https://github.com/clojure-lsp/clojure-lsp/issues/752, clojure-lsp uses the classpath to discover the source code to analyze. The trick is to merge all the classpaths from the monorepo's sub-projects. Conveniently, lein-monolith provides a way to https://github.com/amperity/lein-monolith#merged-source-profile. Therefore we can invoke the command lein monolith with-all classpath instead. Your clojure-lsp configuration file that goes to <monorepo-root>/.lsp/config.edn should look like this: >

{:project-specs [{:project-path "project.clj"
>                   :classpath-cmd ["lein" "monolith" "with-all" "classpath"]}]}
>

camden00:03:42

Yeah lein monolith with-all classpath seems legit

camden00:03:47

Interesting...

camden00:03:29

The only downside is that users of clojure-lsp will have to configure the project path correctly that's sent to the client from their editor but that doesn't seem too hard.

ericdallo00:03:50

Oh I recall, yeah, that was the guy that asked to add that support haha

ericdallo00:03:12

So it should work, good finding, I will add that to my guide for mono repos at clojure-lsp documentation

ericdallo00:03:19

@ULYNWKCNA that's pretty common for LSP users, open the right root, unfortunately there's not much we can do besides tell to open at the right root

ericdallo00:03:59

If all works, you could in the future use clojure-lsp as your linter tool as well ;) As the classpath will be correct, it will give to you findings from kondo, format from cljfmt, clean-ns support

camden00:03:08

Yeah makes total sense. Thanks for talking through this with us!

ericdallo00:03:20

All in a single tool, it's how we are using at Nubank for 99% of the projects

clojure-spin 2
ericdallo00:03:50

You're welcome! LMK if need any help

lilactown16:03:24

after trying this out, the lein monolith with-all classpath command can take minutes to run and it seems to be run every time i try and start the lsp server

lilactown16:03:27

at least, I've tried running clojure-lsp dump and it seemed to generate the cache, but i'm not sure

ericdallo16:03:26

The classpath command is run everytime to check the classpath didn't change, usually a command to retrieve the classpath is fast like lein classpath

camden19:03:38

What if we try using a refresh fingerprint so you only have to do it for projects that changed

ericdallo19:03:07

We already do that for project code, we only analyze files changed, still we need to do if deps changed

camden19:03:58

Yeah but you'll run lein monolith with-all classpathfor each file that changed

camden19:03:22

Instead of only running with the actual projects that had affected changes.

ericdallo19:03:51

No, if the deps file checksum didn't change, we don't run the classpath command again, https://github.com/clojure-lsp/clojure-lsp/blob/master/lib/src/clojure_lsp/startup.clj#L217

ericdallo19:03:10

also, the command is run always in the project root

ericdallo19:03:23

There is no such concept of subprojects for clojure-lsp

ericdallo19:03:32

Only source paths and classpath

camden19:03:38

Oh interesting

camden19:03:43

Okay that's helpful

lilactown22:03:37

we could look into optimizing lein monolith's ability to calculate the classpath in such a way

ericdallo22:03:39

Does it take that long? Usually clojure, shadow-cljs, lein, bb take few seconds

lilactown22:03:04

yeah it takes minutes in our monorepo

lilactown22:03:11

maybe 10s of minutes

ericdallo22:03:16

That's weird.. I don't know too much about lein monolith but AFAICS it should be a lein classpath that only considers the subprojects, probably something could be improved

lilactown00:03:25

does emacs lsp support still block if the lsp server takes awhile?

ericdallo00:03:35

No, should not block

lilactown00:03:02

is there a general preference between eglot and lsp-mode now?

ericdallo00:03:03

I use lsp-mode as I am a lsp-mode maintainer as well, so generally will be more maintained for Clojure probably. eglot support improved recently, but still some features are missing like code lens and call hierarchy

ericdallo00:03:21

Both should work

lilactown00:03:02

I currently use flycheck-mode for clj-kondo. should i disable that?

lukasz15:03:45

If you use eglot it automatically integrates with flymake for errors, so you don't need separate clj-kondo setup, I think I was a flycheck-eglot package that bridges the two

mpenet11:03:20

Both modes work well. Eglot is a bit less ui heavy by default and aims at integrating with emacs defaults, lsp-mode supports more lsp features. I used both and frankly they are quite equivalent. I would say maybe what you use in your config for other modes might drive you to use one or the other

mpenet11:03:15

If you use eglot flymake-diagnostic-at-point is quite nice btw