Open aiguofer opened 1 year ago
Thanks for looking into this! That's a neat idea, though generating files in the user's project directory is something I'm trying to use sparingly. Ideally we could use the Gradle tooling API to get the dependencies from Gradle directly, see
The tooling API offers an EclipseModel
which effectively should provide the same information that is generated for the .classpath
.
@fwcd thanks for the link and context! I agree with your assessment on the other thread... it seems like a lot of work to create a whole new IDE plugin for LSP. I imagine most of what is needed to generate the classpath can be obtained from the EclipseModel
or EclipseProject
.
I did think about the files in the user project, which is why I delete the .classpath
file at the end of the operation. That being said, it might be more performant if we skip the whole xml serialization/deserialization. I'll see if I can modify this to create a task that instantiates an EclipseProject
and prints out the dependencies similar to how it's currently done.
@fwcd figured out how to use the EclipseModel
directly. Since some of the dependencies might be resolved more than once with different methods, I first build a map of path -> source
(and prefer entries with source
) then print out the individual items.
There are 2 major problems I'm still having (happy to create issues if needed) with go-to-definition. I'm currentyl using {"externalSources":{"autoConvertToKotlin":false,"useKlsScheme":false}}
(with useKlsScheme=true
none of the go-to-def work, and autoConvertToKotlin=true
fails for most files):
async2 Go-to-definition at .../flight/SlFlightServer.kt 36:38
async2 Found declaration descriptor public final fun logger(func: () -> kotlin.Unit): mu.KLogger defined in mu.KotlinLogging[DeserializedSimpleFunctionDescriptor@686ee9]
async2 Couldn't find definition at .../flight/SlFlightServer.kt 36:38
Internal error: java.lang.IllegalArgumentException: Unable to find script compilation configuration for the script KtFile: /var/folders/6x/nmdbvc9d15d93v99zh7nqgym0000gp/T/kotlinlangserver10938469402867462880/JsonProperty1664481689349846736.java
Nice! What I had in mind would be to go a step further and resolve the EclipseModel
directly from within the language server (ideally so we could drop the xyzClasspathFinder.gradle
eventually). This would require using the Gradle tooling API.
@fwcd so I've been playing around a bit with the Tooling API. It's pretty straightforward to get the EclipseProject and the classes from that, but I haven't found how to get project.android
, project.sourceSets
, or the kotlin
extension. We might need to include the jars for those plugins explicitly and figure out how gradle resolves those internally.
Here's a function showing how to get the sources using the tooling api:
private fun getDepsWithSources(): Set<ClassPathEntry> {
val connector = GradleConnector.newConnector().forProjectDirectory(projectDirectory.toFile())
val classpaths = mutableSetOf<ClassPathEntry>()
connector.connect().use { connection ->
try {
val eclipseModel = connection.getModel(EclipseProject::class.java)
classpaths.addAll(
eclipseModel.classpath.map {
LOG.info { "Adding path from tools API: ${it.file.path}" }
ClassPathEntry(it.file.toPath(), it.file?.toPath()) }.toSet()
)
} catch(e: Exception) {
LOG.error("Error: $e")
}
}
return classpaths
}
Its been a 2+ years since I last used the eclipse model, but I remember back when using it with https://github.com/sourcegraph/scip-java that it was pretty suboptimal and often missed things when tested across a number of repositories across github (at one point i took the union of the eclipse + IDEA models + an init script from this repo as they both missed some that the other didnt). We're currently using this custom task, id be interested in knowing whether you know of how this compares to it off-hand (from my experience it worked better than the eclipse model, but again its been a long while so my memory may be very fuzzy)
@Strum355 Interesting! honestly I have no idea how it compares. I've just started using Kotlin at work in the past 6 months and hate using IntelliJ; I've been trying to use Emacs but I can't seem to get anywhere near the ability to explore dependencies using the language server so I figured I'd take a stab at this. I don't really get much time to mess around with it though.
I've been trying to find com.sourcegraph.gradle.semanticdb.SemanticdbGradlePlugin
but can't find the code for it... what exactly is that doing?
Do you think it would make sense for kotlin-language-server
to use the same plugin? Alternatively, do you think the approach from https://github.com/sourcegraph/scip-java/pull/74/files worked well?
@Strum355 Interesting! honestly I have no idea how it compares. I've just started using Kotlin at work in the past 6 months and hate using IntelliJ; I've been trying to use Emacs but I can't seem to get anywhere near the ability to explore dependencies using the language server so I figured I'd take a stab at this. I don't really get much time to mess around with it though.
I've been trying to find
com.sourcegraph.gradle.semanticdb.SemanticdbGradlePlugin
but can't find the code for it... what exactly is that doing?
I should've pinned the link to a specific commit, our gradle work just underwent some changes that Im not a part of :grimacing: we're not using init scripts anymore, but rather a gradle plugin itself
From what I can grok, this is the gradle task that we now use to gather the set of dependencies. I hope your scala-fu is up to scratch :sweat_smile: (mine isnt) We abandoned EclipseProject
and IdeaProject
long ago fwiw
I dont believe we have explicit tested support for Android as well, which may throw a spanner in the works here
ahh thanks @Strum355! One of the issues is that we're trying to get the source jars to add to the classpath entries, but only the EclipseProject
and IdeaProject
resolve those AFAIK.
I had originally created #410. The ability to navigate to sources is pretty crucial for me. This PR uses the built in Eclipse Gradle plugin to generate the Classpath with sources. The plugin creates a
.classpath
file, which we read and parse to generate the set ofClassPathEntry
for Gradle.This PR would still need some cleanup, but figured I'd put it out to see what others think of it.
There is still an issue when you navigate to a source where it tries to load it as a kotlin script and fails with something like: