Fork me on GitHub
#lsp
<
2022-11-14
>
lispers-anonymous14:11:13

I was trying out the scala lsp server "metals" today, and noticed that their way of handling scala source files in jars is similar to how clojure-lsp handles compiled ".class" files in jars. They unzip the files into a directory managed by the language server (something similar to .lsp/.cache ) and return a normal file: URI pointing to it. Is that something that could be considered as an option for clojure-lsp? That option is much friendlier for clients and doesn't require the use of language extensions or handling special URIs.

lispers-anonymous14:11:35

I had a much WORSE experience trying out a java language server called "jdtls" which uses some kind of bespoke URI scheme invented just for the language server that looks like this

I requires the use of a lsp language extension to decompile the class and use it. I am not a fan. I'm at least happy that the JAR scheme clojure lsp uses is something that can be parsed and worked with.

ericdallo14:11:12

IMO this should be supported by the LSP spec itself, it's not clear what servers and clients should do, but IMO server should only return a canonical URI and clients extract or handle the way they know which should be similar for each editor

ericdallo14:11:05

clojure-lsp ATM also decompiles .class automatically, especially if finds a pom.xml decompiling the whole jar for smoother navigation https://clojure-lsp.io/settings/#java-support

lispers-anonymous15:11:23

From the perspective of a server-agnostic lsp client, that seems like a tall order. How many langauges package source/bytecode into archive files like this? Java and C# both have two different approaches that every client would then need to understand. The language server itself is meant to abstract away language specific things like that. The only way I could see the lsp spec solving this is to suggest that servers do something like what clojure-lsp does with java sources: prefer the loose .java source files if possible, else decompile the bytecode into a temp file somewhere. The LSP spec suggesting something like using zipfile URIs (not jar , since it's specific to the JVM) might make some sense since zipfiles are a pretty universally understood format. Idk though, just thinking outloud.

ericdallo15:11:30

yeah, I understand your point, and I agree there are tradeoffs, I think we should start a issue on the spec, you and @U07M2C8TT have good points

lispers-anonymous15:11:53

Yeah, that’s probably a good next move. Looking at the different jvm language servers today I didn’t realize how many different approaches there would be. I can look into writing up a ticket to send them when I get a big chunk of free time (sometime this week probably). I will probably come up with a draft and show it here for yall to weigh in.

ericdallo15:11:46

Yeah, from my experience, if the spec didn't say anything, there will be lots of different behaviors between clients and servers naturally That sounds really helpful, thanks!

catjam 1
jacob.maine02:11:20

@UDVJE9RE3 let me see if I can summarize your suggestion in clojure-lsp terms. In the normal course of business, sometimes clojure-lsp wants to tell the client about a “jar file”. It constructs a special jar file URI and gives the client the URI. It doesn’t really say what the client should do with the URI. Up until now, that responsibility has been up to the clients. If they understand the URI format, they can open the file. But it’s actually a bit tricky for clients to do this right. Not only do they have to understand the format of the URI, but they also have to know how to unzip archives. We, clojure-lsp, already acknowledge that not all clients will be able to do this, so we provide clojure/dependencyContents, which a client can use to exchange a URI for the contents of a file. If clients use this, they still have to decide how to handle the file contents. In Emac’s lsp-mode, the contents is put in a temp directory. (I’m not sure what else happens. Things may or may not be set up so that a Java LSP server is started for it.) Your suggestion is to move some of this server-side, removing the need for clojure/dependencyContents. If a client requested it, clojure-lsp would automatically unzip all jar files somewhere in the filesystem. Instead of returning special jar file URIs, it would return a regular file URI. I think this is a nice idea. It would shield clients from some of the insanity of jar files. I’d be curious, if the jars aren’t unzipped in the current directory, will clients still struggle to treat them correctly? Will they be able to open LSP servers for them? To complicate things, we also have one special case we’ve been trying to support. Some users want to be able to edit the jar files that are opened via LSP. I think this basically only works in coc.nvim, using some special config that converts the jar file URIs into “zipfile” URIs. These zipfile URIs have a special construction that nvim understands. They point to the user’s .m2 directory, and nvim knows how to open the jar, edit the file, and write the changes back into the zipped jar. When these users restart their code, the jar patches are applied.

ericdallo12:11:43

We should not forget the LSP spec supports remote clients, so server could be running in another machine and won't be able to unzip jars in that case.

lispers-anonymous14:11:56

> Your suggestion is to move some of this server-side, removing the need for clojure/dependencyContents. If a client requested it, clojure-lsp would automatically unzip all jar files somewhere in the filesystem. Instead of returning special jar file URIs, it would return a regular file URI. I think this is a nice idea. It would shield clients from some of the insanity of jar files. That's the suggestion. It removes the hassle of handling jars and removes the non standard server method that clients have to know about. > I’d be curious, if the jars aren’t unzipped in the current directory, will clients still struggle to treat them correctly? Will they be able to open LSP servers for them? I think this depends on the client. For eglot the user can configure it to open it under the current project's lsp server, or start a new lsp server. I imagine other clients would have similar configurations. > To complicate things, we also have one special case we’ve been trying to support. Some users want to be able to edit the jar files that are opened via LSP. I think this basically only works in coc.nvim, using some special config that converts the jar file URIs into “zipfile” URIs. These zipfile URIs have a special construction that nvim understands. They point to the user’s .m2 directory, and nvim knows how to open the jar, edit the file, and write the changes back into the zipped jar. When these users restart their code, the jar patches are applied. (edited) This is a really interesting thing to want. I had the option of making this available in my jarchive package but chose not to. I may add it later, but not enable it by default. It's just asking for trouble. There was a user in the github issue that said it is probably the cause of them needing to periodically wipe out their .m2 folder. From the perspective of a clojure developer, an alternative is once the file is unzipped and opened, the user can write a copy of it to their project's source directory. That's what I would do right now in Emacs if I wanted this for whatever reason. Opening hiccup.page out of the jar, I would write it to project-root/src/hiccup/page.clj and start editing. An even better alternative is to use a local dependency coordinate with deps.edn... Maybe it's just more configuration though. Right now clojure-lsp has dependency-scheme where they can set "zip" or "jar" . If those stay in place, there couple be a third (ideally the default) that does this behavior I described: "temp" or "unzip" something to that effect. I realize that is asking to add even more baggage to clojure-lsp. "No" is a perfectly reasonable response. > We should not forget the LSP spec supports remote clients, so server could be running in another machine and won't be able to unzip jars in that case. Would the source not also be on the remote machine at that point? If the directory the jar'd files are extracted to is in the project, which I would argue it should be, then this would still be okay. I don't know though. I only use clojure-lsp locally.

jacob.maine17:11:19

> [editing .m2 is] just asking for trouble. I agree. I've been discouraging this practice and the use of the "zipfile" scheme that supports it. Someday I'd like to deprecate it. > Opening hiccup.page out of the jar, I would write it to project-root/src/hiccup/page.clj and start editing. An even better alternative is to use a local dependency coordinate with deps.edn... Those are both good alternatives. I hadn't thought of the first one—pretty friction-less. I'll propose that as another alternative to the users who like this feature. > "temp" or "unzip" something to that effect Perhaps this config could be melded into dependency-scheme, but to me that suggests that the URIs might be temp://... which isn't what we'd be implying. I think I'd rather have a separate section of the config for this feature: either clients ask the server to unzip everything, in which case they get file: URIs, or they don't, in which case they get jar: URIs. If possible, I'd like to deprecate dependency-scheme entirely someday, removing support for zipfile: URIs. >> We should not forget the LSP spec supports remote clients > If the directory the jar'd files are extracted to is in the project, which I would argue it should be, then this would still be okay. @UKFSJSM38 I think what you're saying is that when a server is running remotely, it doesn't have access to a local filesystem to which it can write an unzipped archive (or to be more precise, it probably does have a local filesystem, just not one which the client can necessarily access). And you're pointing out that clojure/dependencyContents might be a workaround for that kind of problem. And @UDVJE9RE3 I think what you're saying is that it wouldn't be a problem if the server put the unzipped archive at a public URI that the client could read from. However, stepping back a bit, this is all very theoretical. Though the LSP spec says servers should support remote clients, clojure-lsp does not. At the moment it has several pieces that assume a shared local filesystem, many of which are much more critical than navigating in jars. If we ever get around to supporting remote clients, we'd need to figure out how to address those problems. It's possible that something like clojure/dependencyContents (or some other operations that act like a remote filesystem) would be required, but I don't think that's a reason to keep clojure/dependencyContents around now. And, since the server will maintain tools for unzipping jars and generating URIs for those files, it shouldn't be so hard to re-implement clojure/dependencyContents on top of those tools, if we decide we need it. Anyway, I've lost track... do we have a Github Issue in clojure-lsp for discussing this further? If not, @UDVJE9RE3 will you make one?

ericdallo17:11:38

Agreed with everything you said @U07M2C8TT. A issue would be very helpful on clojure-lsp, but I still think we should focus first on open a issue on the lsp SPEC though to understand if they recommend anything or should start to recommend

lispers-anonymous17:11:22

Yeah, I have “writing up something to submit to the lsp spec” for this problem on my todo list. I can open one up on clojure-lsp too. I’d prefer that over slack tbh

👍 2
jacob.maine18:11:56

Thanks for doing so much legwork on this @UDVJE9RE3... I appreciate it.

lispers-anonymous18:11:23

Happy to help! I appreciate yall giving this consideration.

jacob.maine20:11:12

Very thorough. Thanks @UDVJE9RE3

👍 1