-
Notifications
You must be signed in to change notification settings - Fork 219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Setup JDT LS extension to provide Java + Kotlin interoperability #334
Conversation
Very nice, thanks a lot for tackling this issue and the writeup, looks pretty good at first glance! I hope to find some time to review this in detail soon. Similar to |
@fwcd Sure, I'm fine either way. If you want, you can create the new repo and I can make a separate PR there with the vscode + JDT part. And we can keep this PR for the changes to the KLS only. Whatever you prefer. |
@fwcd FYI, I found some more time and added gradle support as well. |
I have moved the |
@@ -95,6 +98,10 @@ class CompilerClassPath(private val config: CompilerConfiguration) : Closeable { | |||
workspaceRoots.add(root) | |||
javaSourcePath.addAll(findJavaSourceFiles(root)) | |||
|
|||
val outputDir = Paths.get(root.toString(), "kls").toFile() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefix that directory with a dot, e.g. .kls
, also perhaps a less generic name? Alternatively, could we perhaps use the storagePath
introduced in #337, so we don't have to put custom build outputs into the user's project?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Your second suggestion would be perfect, but unfortunately it'll be tricky to implement (although doable).
The problem is that the JDT LS extension needs to know where to find the build outputs. A directory inside the user's project is an easy solution, because the JDT LS extension can know about this without any help. If we use a different directory, we will need to establish communication between the JDT LS extension and the kotlin language server. This is obviously doable and ideal, but it is trickier to implement.
I would suggest using .kls
for now (your first suggestion) and in a later PR we could implement the other approach. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey. So I thought a little more about this and I think I might have an alternative approach to this that would make things a lot cleaner.
Instead of using custom project importers on the JDT LS extension, we could have a delegateCommandHandler that adds the build output location to the java project classpath. With this approach, the java project would be imported using the normal JDT project importers but we would change the classpath as soon as the KLS is setup. In order for this to work, the KLS would need to be able to call the delegateCommandHandler
once it knows where it will store the build outputs. This call would probably need to go through the vscode extensions, since a direct communication between the language servers is tricky. The cool thing about this approach is that the JDT LS would just work normally at first and as soon as the KLS starts, it would be notified to update its project. This approach would also allow us to use temp directories as a default build output location, which is a lot cleaner (especially for people who are not even working on a Java + Kotlin project)
@@ -263,6 +266,7 @@ class KotlinTextDocumentService( | |||
fun lintAll() { | |||
debounceLint.submitImmediately { | |||
sp.compileAllFiles() | |||
sp.saveAllFiles() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does separately emitting compilation outputs have a non-negligible performance impact?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, the tests I've done were fine, but they were not exhaustive. With that said, this particular part of the code is done async, so I don't think it should be too problematic. I suggest you check it yourself just in case.
Besides this, the only other time we emit code is on file save (which doesn't happen that often, and only for one file at once).
@fwcd I updated the PR to use the approach I described in a previous comment (i.e., use a fwcd/vscode-kotlin#89 This approach is now a lot cleaner, since it uses temp directories for the build outputs (thus no longer polluting the user workspace) |
Hey @fwcd |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, looks mostly good, just some minor things.
server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensions.kt
Outdated
Show resolved
Hide resolved
Thank you! |
Fixes #192
Sets up a VSCode extension to allow Java code to see Kotlin code. The extension depends on both
vscode-java
andvscode-kotlin
. It uses the JDT LS extension mechanism, through a custom JDT LS extension that provides kotlin project importers for maven and gradle.This seems to work reasonably well for small projects at least. I don't know how well it performs on bigger projects, but I think the concept looks valid and we can always improve that later.
Some notes:
javaExtensions
contribution point to providevscode-java
with the JAR for the JDT LS extension. The JDT LS uses the jar to find the kotlin project importers. The importers have higher priority than the default ones provided by the JDT LS itself.MavenProjectImporter
andGradleProjectImporter
provided by the JDT LS. As such, pretty much all the importing logic is done by the JDT LS. Once the core java project is imported (byMavenProjectImporter
orGradleProjectImporter
) we add the compiled kotlin files to the project's classpath. This is how the java code is then able to see the kotlin code.kls
at the root of the workspace. I chose this because the JDT LS messes with the default maven and gradle output paths (and we should try to isolate the language servers as much as possible). The code generation is only triggered on file save for performance reasons.How to test this for now:
On the
vscode-java-kotlin
folder, run thebuild.sh
script to build the JDT LS extension. Afterwards, runnpm install
to install the VSCode extension dependencies. Once this is done, you can either debug it (using F5 on VSCode), or package it and install it from a VSIX.Important: The JDT LS extension will only work with the latest kotlin language server code (i.e, the one in this PR), so you should install the language server locally and setup your
vscode-kotlin
to use that (through thekotlin.languageServer.path
configuration property)This is very experimental (I cannot stress this enough). This is literally the first thing I wrote involving Eclipse PDE and the JDT LS API. With that said, I think the concept at least seems to work, so I'm guessing we can improve this more over time.
Feedback welcome :)