From c17d2b72d183bb5f9787c8365957cbbd0b7145fd Mon Sep 17 00:00:00 2001 From: daplf Date: Sun, 6 Mar 2022 16:41:47 +0000 Subject: [PATCH 01/34] Setup JDT LS extension --- .../kotlin/org/javacs/kt/CompilerClassPath.kt | 11 +- .../javacs/kt/KotlinTextDocumentService.kt | 4 + .../main/kotlin/org/javacs/kt/SourcePath.kt | 35 +- .../kotlin/org/javacs/kt/compiler/Compiler.kt | 47 +- vscode-java-kotlin/.gitignore | 9 + vscode-java-kotlin/.vscode/launch.json | 21 + vscode-java-kotlin/.vscodeignore | 8 + vscode-java-kotlin/README.md | 11 + vscode-java-kotlin/build.sh | 7 + vscode-java-kotlin/javaConfig.json | 6 + .../META-INF/MANIFEST.MF | 16 + .../build.properties | 5 + .../org.javacs.kt.jdt.ls.extension/plugin.xml | 13 + .../org.javacs.kt.jdt.ls.extension/pom.xml | 18 + .../jdt/ls/extension/KotlinMavenImporter.java | 183 +++ vscode-java-kotlin/jdt-ls-extension/pom.xml | 79 ++ .../jdt-ls-extension/target.target | 17 + vscode-java-kotlin/package-lock.json | 1158 +++++++++++++++++ vscode-java-kotlin/package.json | 46 + vscode-java-kotlin/src/extension.ts | 7 + vscode-java-kotlin/tsconfig.json | 21 + 21 files changed, 1706 insertions(+), 16 deletions(-) create mode 100644 vscode-java-kotlin/.gitignore create mode 100644 vscode-java-kotlin/.vscode/launch.json create mode 100644 vscode-java-kotlin/.vscodeignore create mode 100644 vscode-java-kotlin/README.md create mode 100644 vscode-java-kotlin/build.sh create mode 100644 vscode-java-kotlin/javaConfig.json create mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/META-INF/MANIFEST.MF create mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/build.properties create mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/plugin.xml create mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/pom.xml create mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinMavenImporter.java create mode 100644 vscode-java-kotlin/jdt-ls-extension/pom.xml create mode 100644 vscode-java-kotlin/jdt-ls-extension/target.target create mode 100644 vscode-java-kotlin/package-lock.json create mode 100644 vscode-java-kotlin/package.json create mode 100644 vscode-java-kotlin/src/extension.ts create mode 100644 vscode-java-kotlin/tsconfig.json diff --git a/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt b/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt index 9d3805e1..450edabe 100644 --- a/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt +++ b/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt @@ -5,8 +5,10 @@ import org.javacs.kt.classpath.defaultClassPathResolver import org.javacs.kt.compiler.Compiler import org.javacs.kt.util.AsyncExecutor import java.io.Closeable +import java.io.File import java.nio.file.FileSystems import java.nio.file.Path +import java.nio.file.Paths /** * Manages the class path (compiled JARs, etc), the Java source path @@ -17,6 +19,7 @@ class CompilerClassPath(private val config: CompilerConfiguration) : Closeable { private val javaSourcePath = mutableSetOf() private val buildScriptClassPath = mutableSetOf() val classPath = mutableSetOf() + private var outputDirectory: File? = null var compiler = Compiler(javaSourcePath, classPath.map { it.compiledJar }.toSet(), buildScriptClassPath) private set @@ -66,7 +69,7 @@ class CompilerClassPath(private val config: CompilerConfiguration) : Closeable { if (refreshCompiler) { LOG.info("Reinstantiating compiler") compiler.close() - compiler = Compiler(javaSourcePath, classPath.map { it.compiledJar }.toSet(), buildScriptClassPath) + compiler = Compiler(javaSourcePath, classPath.map { it.compiledJar }.toSet(), buildScriptClassPath, outputDirectory) updateCompilerConfiguration() } @@ -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() + outputDirectory = outputDir + compiler.outputDirectory = outputDir + return refresh() } @@ -103,6 +110,8 @@ class CompilerClassPath(private val config: CompilerConfiguration) : Closeable { workspaceRoots.remove(root) javaSourcePath.removeAll(findJavaSourceFiles(root)) + outputDirectory = null + compiler.outputDirectory = null return refresh() } diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt b/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt index 72174f50..937da459 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt @@ -179,6 +179,9 @@ class KotlinTextDocumentService( // Lint after saving to prevent inconsistent diagnostics val uri = parseURI(params.textDocument.uri) lintNow(uri) + debounceLint.schedule { + sp.save(uri) + } } override fun signatureHelp(position: SignatureHelpParams): CompletableFuture = async.compute { @@ -263,6 +266,7 @@ class KotlinTextDocumentService( fun lintAll() { debounceLint.submitImmediately { sp.compileAllFiles() + sp.saveAllFiles() sp.refreshDependencyIndexes() } } diff --git a/server/src/main/kotlin/org/javacs/kt/SourcePath.kt b/server/src/main/kotlin/org/javacs/kt/SourcePath.kt index 67c63b03..99b4cc57 100644 --- a/server/src/main/kotlin/org/javacs/kt/SourcePath.kt +++ b/server/src/main/kotlin/org/javacs/kt/SourcePath.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.CompositeBindingContext import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter +import java.lang.Exception import kotlin.concurrent.withLock import java.nio.file.Path import java.nio.file.Paths @@ -50,7 +51,8 @@ class SourcePath( var compiledContext: BindingContext? = null, var compiledContainer: ComponentProvider? = null, val language: Language? = null, - val isTemporary: Boolean = false // A temporary source file will not be returned by .all() + val isTemporary: Boolean = false, // A temporary source file will not be returned by .all() + var lastSavedFile: KtFile? = null, ) { val extension: String? = uri.fileExtension ?: "kt" // TODO: Use language?.associatedFileType?.defaultExtension again val isScript: Boolean = extension == "kts" @@ -162,7 +164,10 @@ class SourcePath( } fun delete(uri: URI) { - files[uri]?.let { refreshWorkspaceIndexes(listOf(it), listOf()) } + files[uri]?.let { + refreshWorkspaceIndexes(listOf(it), listOf()) + cp.compiler.removeGeneratedCode(listOfNotNull(it.lastSavedFile)) + } files.remove(uri) } @@ -250,10 +255,34 @@ class SourcePath( // TODO: Investigate the possibility of compiling all files at once, instead of iterating here // At the moment, compiling all files at once sometimes leads to an internal error from the TopDownAnalyzer files.keys.forEach { - compileFiles(listOf(it)) + // If one of the files fails to compile, we compile the others anyway + try { + compileFiles(listOf(it)) + } catch (ex: Exception) { + LOG.printStackTrace(ex) + } } } + /** + * Saves a file. This generates code for the file and deletes previously generated code for this file. + */ + fun save(uri: URI) { + files[uri]?.let { + cp.compiler.removeGeneratedCode(listOfNotNull(it.lastSavedFile)) + it.compiledContainer?.let { container -> + it.compiledContext?.let { context -> + cp.compiler.generateCode(container, context, listOfNotNull(it.compiledFile)) + it.lastSavedFile = it.compiledFile + } + } + } + } + + fun saveAllFiles() { + files.keys.forEach { save(it) } + } + fun refreshDependencyIndexes() { compileAllFiles() diff --git a/server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt b/server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt index 4bff8995..56cb0ccf 100644 --- a/server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt +++ b/server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt @@ -1,15 +1,12 @@ package org.javacs.kt.compiler -import com.intellij.codeInsight.NullableNotNullManager import com.intellij.lang.Language -import com.intellij.openapi.Disposable import com.intellij.openapi.util.Disposer import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.openapi.vfs.VirtualFileSystem import com.intellij.psi.PsiFile import com.intellij.psi.PsiFileFactory -import com.intellij.mock.MockProject import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback import org.jetbrains.kotlin.cli.jvm.compiler.CliBindingTrace @@ -18,7 +15,6 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoots import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots -import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration as KotlinCompilerConfiguration import org.jetbrains.kotlin.config.JVMConfigurationKeys @@ -39,26 +35,20 @@ import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer import org.jetbrains.kotlin.resolve.TopDownAnalysisMode import org.jetbrains.kotlin.resolve.calls.components.InferenceSession import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo -import org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar import org.jetbrains.kotlin.scripting.compiler.plugin.definitions.CliScriptDefinitionProvider import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys -import org.jetbrains.kotlin.scripting.definitions.ScriptCompilationConfigurationFromDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider -import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider -import org.jetbrains.kotlin.scripting.definitions.StandardScriptDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition // Legacy import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition import org.jetbrains.kotlin.scripting.definitions.getEnvironment -import org.jetbrains.kotlin.scripting.extensions.ScriptExtraImportsProviderExtension import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices import org.jetbrains.kotlin.util.KotlinFrontEndException -import org.jetbrains.kotlin.utils.PathUtil import java.io.Closeable import java.io.File import java.nio.file.Path @@ -69,7 +59,6 @@ import kotlin.concurrent.withLock import kotlin.script.dependencies.Environment import kotlin.script.dependencies.ScriptContents import kotlin.script.experimental.dependencies.ScriptDependencies -import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult import kotlin.script.experimental.host.ScriptingHostConfiguration @@ -80,6 +69,12 @@ import org.javacs.kt.LOG import org.javacs.kt.CompilerConfiguration import org.javacs.kt.util.KotlinLSException import org.javacs.kt.util.LoggingMessageCollector +import org.jetbrains.kotlin.cli.common.output.writeAllTo +import org.jetbrains.kotlin.codegen.ClassBuilderFactories +import org.jetbrains.kotlin.codegen.KotlinCodegenFacade +import org.jetbrains.kotlin.codegen.state.GenerationState +import org.jetbrains.kotlin.container.getService +import org.jetbrains.kotlin.descriptors.ModuleDescriptor private val GRADLE_DSL_DEPENDENCY_PATTERN = Regex("^gradle-(?:kotlin-dsl|core).*\\.jar$") @@ -445,7 +440,7 @@ enum class CompilationKind { * Incrementally compiles files and expressions. * The basic strategy for compiling one file at-a-time is outlined in OneFilePerformance. */ -class Compiler(javaSourcePath: Set, classPath: Set, buildScriptClassPath: Set = emptySet()) : Closeable { +class Compiler(javaSourcePath: Set, classPath: Set, buildScriptClassPath: Set = emptySet(), var outputDirectory: File? = null) : Closeable { private var closed = false private val localFileSystem: VirtualFileSystem @@ -553,6 +548,34 @@ class Compiler(javaSourcePath: Set, classPath: Set, buildScriptClass } } + fun removeGeneratedCode(files: Collection) { + files.forEach { file -> + file.declarations.forEach { declaration -> + outputDirectory?.resolve( + file.packageFqName.asString().replace(".", File.separator) + File.separator + declaration.name + ".class" + )?.delete() + } + } + } + + fun generateCode(container: ComponentProvider, bindingContext: BindingContext, files: Collection) { + outputDirectory?.let { + compileLock.withLock { + val compileEnv = compileEnvironmentFor(CompilationKind.DEFAULT) + val state = GenerationState.Builder( + project = compileEnv.environment.project, + builderFactory = ClassBuilderFactories.BINARIES, + module = container.getService(ModuleDescriptor::class.java), + bindingContext = bindingContext, + files = files.toList(), + configuration = compileEnv.environment.configuration + ).build() + KotlinCodegenFacade.compileCorrectFiles(state) + state.factory.writeAllTo(it) + } + } + } + override fun close() { if (!closed) { defaultCompileEnvironment.close() diff --git a/vscode-java-kotlin/.gitignore b/vscode-java-kotlin/.gitignore new file mode 100644 index 00000000..c862d8ce --- /dev/null +++ b/vscode-java-kotlin/.gitignore @@ -0,0 +1,9 @@ +node_modules +target +*.vsix +.idea +*.iml +.DS_Store +**/.DS_Store +jars +.vscode/settings.json \ No newline at end of file diff --git a/vscode-java-kotlin/.vscode/launch.json b/vscode-java-kotlin/.vscode/launch.json new file mode 100644 index 00000000..4faa2ec5 --- /dev/null +++ b/vscode-java-kotlin/.vscode/launch.json @@ -0,0 +1,21 @@ +// A launch configuration that compiles the extension and then opens it inside a new window +// Use IntelliSense to learn about possible attributes. +// Hover to view descriptions of existing attributes. +// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}" + ], + "outFiles": [ + "${workspaceFolder}/out/**/*.js" + ] + } + ] +} diff --git a/vscode-java-kotlin/.vscodeignore b/vscode-java-kotlin/.vscodeignore new file mode 100644 index 00000000..e6ba7467 --- /dev/null +++ b/vscode-java-kotlin/.vscodeignore @@ -0,0 +1,8 @@ +.vscode/** +.idea/** +*.iml +javaConfig.json +tsconfig.json +org.javacs.kt.jdt.ls.extension +build.sh +.gitignore \ No newline at end of file diff --git a/vscode-java-kotlin/README.md b/vscode-java-kotlin/README.md new file mode 100644 index 00000000..dc66223b --- /dev/null +++ b/vscode-java-kotlin/README.md @@ -0,0 +1,11 @@ +# VSCode Extension for Java + Kotlin + +A VSCode extension that enchances [vscode-java](https://github.com/redhat-developer/vscode-java) and [vscode-kotlin](https://github.com/fwcd/vscode-kotlin) with java + kotlin interoperability. This uses a JDT LS extension with a custom project importer to allow Java code to have access to Kotlin code. + +**Disclaimer**: This is very experimental, but it seems to work for small maven projects at least. + +## Setup (for now) + +For now, to set this up, you need to run the `build.sh` script in this directory to package the JDT LS extension. Afterwards, you should run `npm install` to install the extension dependencies. + +To debug, you can use F5 on VSCode, as with any other extension. To package the extension you can use `vsce package`. \ No newline at end of file diff --git a/vscode-java-kotlin/build.sh b/vscode-java-kotlin/build.sh new file mode 100644 index 00000000..a186860a --- /dev/null +++ b/vscode-java-kotlin/build.sh @@ -0,0 +1,7 @@ +#!/bin/bash +rm -fr jars +mkdir -p jars + +cd jdt-ls-extension +mvn clean package +cp org.javacs.kt.jdt.ls.extension/target/org.javacs.kt.jdt.ls.extension-1.0.0-SNAPSHOT.jar ../jars/jdt-ls-extension.jar \ No newline at end of file diff --git a/vscode-java-kotlin/javaConfig.json b/vscode-java-kotlin/javaConfig.json new file mode 100644 index 00000000..5e886918 --- /dev/null +++ b/vscode-java-kotlin/javaConfig.json @@ -0,0 +1,6 @@ +{ + "projects": [ + "./jdt-ls-extension/org.javacs.kt.jdt.ls.extension" + ], + "targetPlatform": "./jdt-ls-extension/target.target" + } \ No newline at end of file diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/META-INF/MANIFEST.MF b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/META-INF/MANIFEST.MF new file mode 100644 index 00000000..d2178539 --- /dev/null +++ b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/META-INF/MANIFEST.MF @@ -0,0 +1,16 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: org.javacs.kt.jdt.ls.extension +Bundle-SymbolicName: org.javacs.kt.jdt.ls.extension;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Vendor: VMware, Inc. +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Require-Bundle: org.eclipse.jdt.ls.core, + org.eclipse.core.runtime, + org.eclipse.jdt.core, + org.eclipse.core.resources, + org.eclipse.m2e.core;resolution:=optional, + org.eclipse.m2e.jdt;resolution:=optional, + org.eclipse.m2e.maven.runtime;resolution:=optional, + org.eclipse.lsp4j, + org.eclipse.lsp4j.jsonrpc diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/build.properties b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/build.properties new file mode 100644 index 00000000..e9863e28 --- /dev/null +++ b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/build.properties @@ -0,0 +1,5 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/plugin.xml b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/plugin.xml new file mode 100644 index 00000000..a14dc180 --- /dev/null +++ b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/plugin.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/pom.xml b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/pom.xml new file mode 100644 index 00000000..05c95656 --- /dev/null +++ b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/pom.xml @@ -0,0 +1,18 @@ + + 4.0.0 + eclipse-plugin + org.javacs.kt + org.javacs.kt.jdt.ls.extension + 1.0.0-SNAPSHOT + org.javacs.kt.jdt.ls.extension + + + org.javacs.kt + jdt-ls-extension-parent + 1.0.0-SNAPSHOT + ../pom.xml + + diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinMavenImporter.java b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinMavenImporter.java new file mode 100644 index 00000000..5094dcb3 --- /dev/null +++ b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinMavenImporter.java @@ -0,0 +1,183 @@ +package org.javacs.kt.jdt.ls.extension; + +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; +import org.eclipse.jdt.ls.core.internal.managers.MavenBuildSupport; +import org.eclipse.jdt.ls.core.internal.managers.MavenProjectImporter; +import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager.CHANGE_TYPE; +import org.eclipse.m2e.core.MavenPlugin; +import org.eclipse.m2e.core.project.IMavenProjectFacade; + +/** + * Custom importer for kotlin maven projects. + * This relies on the JDT LS MavenProjectImporter to actually import the base project. + * It then updates the classpath to include the kotlin compiled classes. + */ +@SuppressWarnings("restriction") +public class KotlinMavenImporter extends MavenProjectImporter { + + /** + * Checks if this is a maven kotlin project. + * For now, we rely on MavenProjectImporter.applies to check if this is a maven project. + * On top of that, we check if we have any kotlin files in the workspace. + * If we do, we assume this is a kotlin maven project. + * TODO: We should make this more robust in the future. + */ + @Override + public boolean applies(IProgressMonitor monitor) throws CoreException { + if (super.applies(monitor)) { + try (Stream files = Files.walk(rootFolder.toPath())) { + return files.anyMatch(f -> f.getFileName().toString().endsWith(".kt")); + } catch (IOException ex) { + return false; + } + } else { + return false; + } + } + + @Override + public void reset() { + super.reset(); + } + + /** + * This imports the project. It relies on the MavenProjectImporter.importToWorkspace to do most of the work. + * Once the base maven project is imported, we add the kls folder to the classpath as a library. + * The kls folder is the folder used by the kotlin language server to output classfiles. + */ + @Override + public void importToWorkspace(IProgressMonitor monitor) throws CoreException { + super.importToWorkspace(monitor); + + for (IMavenProjectFacade mavenProject : MavenPlugin.getMavenProjectRegistry().getProjects()) { + IProject project = mavenProject.getProject(); + java.nio.file.Path path = Paths.get(project.getLocation().toOSString(), "kls"); + setKlsClasspathEntry(project, path, monitor); + registerKlsWatcher(path); + } + } + + /** + * Registers a watcher for the kls directory. + * Any file change leads to an update in the classpath. + */ + private void registerKlsWatcher(java.nio.file.Path path) { + new Thread(() -> { + try { + Files.createDirectories(path); + Map keys = new HashMap<>(); + // Create the watcher and watch all directories under the base kls directory. + WatchService watcher = FileSystems.getDefault().newWatchService(); + keys.putAll(watchDirectory(watcher, path)); + + // Wair for file related events. + // When a file is added or deleted, we update the classpath (we remove and re-add the kls classpath entry) + while (true) { + WatchKey key; + if ((key = watcher.take()) != null) { + java.nio.file.Path dir = keys.get(key); + if (dir != null) { + key.pollEvents().forEach(event -> { + @SuppressWarnings("unchecked") + WatchEvent ev = (WatchEvent) event; + + java.nio.file.Path name = ev.context(); + java.nio.file.Path child = dir.resolve(name); + + // If a new directory was created, we need to watch it as well. + if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { + if (Files.isDirectory(child, LinkOption.NOFOLLOW_LINKS)) { + keys.putAll(watchDirectory(watcher, dir)); + } + } + }); + Job job = new Job("Updating kotlin classpath entry") { + @Override + protected IStatus run(IProgressMonitor monitor) { + try { + for (IMavenProjectFacade mavenProject : MavenPlugin.getMavenProjectRegistry().getProjects()) { + IProject project = mavenProject.getProject(); + setKlsClasspathEntry(project, path, monitor); + } + + return Status.OK_STATUS; + } catch (CoreException ex) { + JavaLanguageServerPlugin.logException(ex); + return Status.error("An error occurred while updating the kotlin classpath entry"); + } + } + }; + job.schedule(); + job.join(); + key.reset(); + } + } + } + } catch (IOException | InterruptedException ex) { + JavaLanguageServerPlugin.logException(ex); + } + }).start(); + } + + private Map watchDirectory(WatchService watcher, java.nio.file.Path path) { + Map keys = new HashMap<>(); + + try { + Files.walkFileTree(path, new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { + WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); + keys.put(key, dir); + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException ex) { + JavaLanguageServerPlugin.logException(ex); + } + + return keys; + } + + private void setKlsClasspathEntry(IProject project, java.nio.file.Path path, IProgressMonitor monitor) throws CoreException { + IJavaProject javaProject = JavaCore.create(project); + + List entries = new ArrayList<>(Arrays.asList(javaProject.getRawClasspath())); + IPath klsPath = Path.fromOSString(path.toString()); + + entries.removeIf(entry -> entry.getPath().equals(klsPath)); + IClasspathEntry classpathEntry = JavaCore.newLibraryEntry(klsPath, null, null); + entries.add(classpathEntry); + + javaProject.setRawClasspath(entries.toArray(new IClasspathEntry[0]), monitor); + new MavenBuildSupport().refresh(project, CHANGE_TYPE.CHANGED, monitor); + } +} diff --git a/vscode-java-kotlin/jdt-ls-extension/pom.xml b/vscode-java-kotlin/jdt-ls-extension/pom.xml new file mode 100644 index 00000000..f3c84b7d --- /dev/null +++ b/vscode-java-kotlin/jdt-ls-extension/pom.xml @@ -0,0 +1,79 @@ + + 4.0.0 + + org.javacs.kt + jdt-ls-extension-parent + pom + 1.0.0-SNAPSHOT + jdt-ls-extension-parent + + + org.javacs.kt.jdt.ls.extension + + + + 11 + 1.7.0 + + + + + + eclipse + p2 + https://download.eclipse.org/releases/2022-03 + + + + JDT.LS + p2 + https://download.eclipse.org/jdtls/snapshots/repository/latest/ + + + + jboss + p2 + https://download.jboss.org/jbosstools/updates/m2e-extensions/m2e-apt/1.5.3-2019-11-08_11-04-22-H22/ + + + + + + org.eclipse.tycho.extras + tycho-source-feature-plugin + ${tycho-version} + + + source-feature + package + + source-feature + + + + + + + org.eclipse.tycho + tycho-source-plugin + ${tycho-version} + + + plugin-source + + plugin-source + + + + + + + org.eclipse.tycho + tycho-maven-plugin + ${tycho-version} + true + + + + diff --git a/vscode-java-kotlin/jdt-ls-extension/target.target b/vscode-java-kotlin/jdt-ls-extension/target.target new file mode 100644 index 00000000..e850b17b --- /dev/null +++ b/vscode-java-kotlin/jdt-ls-extension/target.target @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vscode-java-kotlin/package-lock.json b/vscode-java-kotlin/package-lock.json new file mode 100644 index 00000000..f0725d9b --- /dev/null +++ b/vscode-java-kotlin/package-lock.json @@ -0,0 +1,1158 @@ +{ + "name": "vscode-java-kotlin", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/node": { + "version": "12.20.46", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.46.tgz", + "integrity": "sha512-cPjLXj8d6anFPzFvOPxS3fvly3Shm5nTfl6g8X5smexixbuGUf7hfr21J5tX9JW+UPStp/5P5R8qrKL5IyVJ+A==", + "dev": true + }, + "@types/vscode": { + "version": "1.65.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.65.0.tgz", + "integrity": "sha512-wQhExnh2nEzpjDMSKhUvnNmz3ucpd3E+R7wJkOhBNK3No6fG3VUdmVmMOKD0A8NDZDDDiQcLNxe3oGmX5SjJ5w==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "azure-devops-node-api": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.1.tgz", + "integrity": "sha512-XDG91XzLZ15reP12s3jFkKS8oiagSICjnLwxEYieme4+4h3ZveFOFRA4iYIG40RyHXsiI0mefFYYMFIJbMpWcg==", + "dev": true, + "requires": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cheerio": { + "version": "1.0.0-rc.10", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", + "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", + "dev": true, + "requires": { + "cheerio-select": "^1.5.0", + "dom-serializer": "^1.3.2", + "domhandler": "^4.2.0", + "htmlparser2": "^6.1.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "tslib": "^2.2.0" + } + }, + "cheerio-select": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", + "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", + "dev": true, + "requires": { + "css-select": "^4.1.3", + "css-what": "^5.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0", + "domutils": "^2.7.0" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "css-select": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", + "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^5.1.0", + "domhandler": "^4.3.0", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", + "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "dev": true + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "requires": { + "mimic-response": "^3.1.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "denodeify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", + "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=", + "dev": true + }, + "detect-libc": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "dev": true + }, + "dom-serializer": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", + "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true + }, + "domhandler": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", + "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", + "dev": true + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "dev": true, + "requires": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "linkify-it": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", + "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", + "dev": true, + "requires": { + "uc.micro": "^1.0.1" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "markdown-it": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", + "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "entities": "~2.0.0", + "linkify-it": "^2.0.0", + "mdurl": "^1.0.1", + "uc.micro": "^1.0.5" + }, + "dependencies": { + "entities": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", + "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", + "dev": true + } + } + }, + "mdurl": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", + "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", + "dev": true + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "dev": true + }, + "node-abi": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.8.0.tgz", + "integrity": "sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==", + "dev": true, + "requires": { + "semver": "^7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", + "dev": true, + "requires": { + "semver": "^5.1.0" + } + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "prebuild-install": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.0.1.tgz", + "integrity": "sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg==", + "dev": true, + "requires": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "npmlog": "^4.0.1", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", + "dev": true, + "requires": { + "mute-stream": "~0.0.4" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true + }, + "simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "requires": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "requires": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + }, + "tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "typed-rest-client": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.6.tgz", + "integrity": "sha512-xcQpTEAJw2DP7GqVNECh4dD+riS+C1qndXLfBCJ3xk0kqprtGN491P5KlmrDbKdtuW8NEcP/5ChxiJI3S9WYTA==", + "dev": true, + "requires": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, + "typescript": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", + "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", + "dev": true + }, + "uc.micro": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", + "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "dev": true + }, + "underscore": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.2.tgz", + "integrity": "sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g==", + "dev": true + }, + "url-join": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz", + "integrity": "sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "vsce": { + "version": "1.103.1", + "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.103.1.tgz", + "integrity": "sha512-98oKQKKRp7J/vTIk1cuzom5cezZpYpRHs3WlySdsrTCrAEipB/HvaPTc4VZ3hGZHzHXS9P5p2L0IllntJeXwiQ==", + "dev": true, + "requires": { + "azure-devops-node-api": "^11.0.1", + "chalk": "^2.4.2", + "cheerio": "^1.0.0-rc.9", + "commander": "^6.1.0", + "denodeify": "^1.2.1", + "glob": "^7.0.6", + "hosted-git-info": "^4.0.2", + "keytar": "^7.7.0", + "leven": "^3.1.0", + "lodash": "^4.17.15", + "markdown-it": "^10.0.0", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "osenv": "^0.1.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "semver": "^5.1.0", + "tmp": "^0.2.1", + "typed-rest-client": "^1.8.4", + "url-join": "^1.1.0", + "xml2js": "^0.4.23", + "yauzl": "^2.3.1", + "yazl": "^2.2.2" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dev": true, + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3" + } + } + } +} diff --git a/vscode-java-kotlin/package.json b/vscode-java-kotlin/package.json new file mode 100644 index 00000000..eb729160 --- /dev/null +++ b/vscode-java-kotlin/package.json @@ -0,0 +1,46 @@ +{ + "name": "vscode-java-kotlin", + "displayName": "Java Kotlin", + "description": "Language support for Java + Kotlin projects", + "repository": { + "type": "git", + "url": "https://github.com/fwcd/kotlin-language-server.git" + }, + "version": "0.0.1", + "publisher": "fwcd", + "license": "MIT", + "categories": [ + "Programming Languages" + ], + "engines": { + "vscode": "^1.52.0" + }, + "keywords": [ + "java", + "kotlin" + ], + "activationEvents": [ + "onLanguage:java" + ], + "contributes": { + "javaExtensions": [ + "./jars/jdt-ls-extension.jar" + ] + }, + "main": "./out/src/extension", + "scripts": { + "vscode:prepublish": "npm run compile", + "compile": "tsc -p ./", + "watch": "tsc -watch -p ./" + }, + "devDependencies": { + "@types/node": "^12.8.1", + "@types/vscode": "^1.52.0", + "typescript": "^4.3.5", + "vsce": "^1.95.0" + }, + "extensionDependencies": [ + "redhat.java", + "fwcd.kotlin" + ] +} diff --git a/vscode-java-kotlin/src/extension.ts b/vscode-java-kotlin/src/extension.ts new file mode 100644 index 00000000..9cc14c32 --- /dev/null +++ b/vscode-java-kotlin/src/extension.ts @@ -0,0 +1,7 @@ +'use strict'; + +import * as vscode from 'vscode'; + +/** Called when extension is activated */ +export async function activate(context: vscode.ExtensionContext) { +} diff --git a/vscode-java-kotlin/tsconfig.json b/vscode-java-kotlin/tsconfig.json new file mode 100644 index 00000000..f1fd7c9d --- /dev/null +++ b/vscode-java-kotlin/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "module": "commonjs", + "moduleResolution": "node", + "target": "es6", + "lib": [ + "es6" + ], + "declaration": true, + "outDir": "out", + "sourceMap": true, + "rootDir": "." + }, + "include": [ + "typings/*.d.ts", + "src/**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} \ No newline at end of file From 2446de8a206e465b9d3df8d22d15a43989a095d7 Mon Sep 17 00:00:00 2001 From: daplf Date: Fri, 11 Mar 2022 23:53:38 +0000 Subject: [PATCH 02/34] Added gradle support --- .../main/kotlin/org/javacs/kt/SourcePath.kt | 17 ++- .../org.javacs.kt.jdt.ls.extension/plugin.xml | 8 +- .../ls/extension/KotlinGradleImporter.java | 65 +++++++++ .../jdt/ls/extension/KotlinImporterUtils.java | 135 +++++++++++++++++ .../jdt/ls/extension/KotlinMavenImporter.java | 137 ++---------------- 5 files changed, 228 insertions(+), 134 deletions(-) create mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinGradleImporter.java create mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinImporterUtils.java diff --git a/server/src/main/kotlin/org/javacs/kt/SourcePath.kt b/server/src/main/kotlin/org/javacs/kt/SourcePath.kt index 99b4cc57..06e4cd33 100644 --- a/server/src/main/kotlin/org/javacs/kt/SourcePath.kt +++ b/server/src/main/kotlin/org/javacs/kt/SourcePath.kt @@ -269,11 +269,18 @@ class SourcePath( */ fun save(uri: URI) { files[uri]?.let { - cp.compiler.removeGeneratedCode(listOfNotNull(it.lastSavedFile)) - it.compiledContainer?.let { container -> - it.compiledContext?.let { context -> - cp.compiler.generateCode(container, context, listOfNotNull(it.compiledFile)) - it.lastSavedFile = it.compiledFile + if (!it.isScript) { + // If the code generation fails for some reason, we generate code for the other files anyway + try { + cp.compiler.removeGeneratedCode(listOfNotNull(it.lastSavedFile)) + it.compiledContainer?.let { container -> + it.compiledContext?.let { context -> + cp.compiler.generateCode(container, context, listOfNotNull(it.compiledFile)) + it.lastSavedFile = it.compiledFile + } + } + } catch (ex: Exception) { + LOG.printStackTrace(ex) } } } diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/plugin.xml b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/plugin.xml index a14dc180..ffe5e988 100644 --- a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/plugin.xml +++ b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/plugin.xml @@ -5,9 +5,13 @@ id="importers" point="org.eclipse.jdt.ls.core.importers"> + + class = "org.javacs.kt.jdt.ls.extension.KotlinMavenImporter"/> \ No newline at end of file diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinGradleImporter.java b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinGradleImporter.java new file mode 100644 index 00000000..c2dc9964 --- /dev/null +++ b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinGradleImporter.java @@ -0,0 +1,65 @@ +package org.javacs.kt.jdt.ls.extension; + +import java.nio.file.Paths; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.Status; +import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; +import org.eclipse.jdt.ls.core.internal.ProjectUtils; +import org.eclipse.jdt.ls.core.internal.managers.GradleBuildSupport; +import org.eclipse.jdt.ls.core.internal.managers.GradleProjectImporter; + +/** + * Custom importer for kotlin gradle projects. + * This relies on the JDT LS GradleProjectImporter to actually import the base project. + * It then updates the classpath to include the kotlin compiled classes. + */ +@SuppressWarnings("restriction") +public class KotlinGradleImporter extends GradleProjectImporter { + + /** + * Checks if this is a gradle kotlin project. + * For now, we rely on GradleProjectImporter.applies to check if this is a gradle project. + * On top of that, we check if we have any kotlin files in the workspace. + * If we do, we assume this is a kotlin gradle project. + * TODO: We should make this more robust in the future. + */ + @Override + public boolean applies(IProgressMonitor monitor) throws CoreException { + return super.applies(monitor) && KotlinImporterUtils.anyKotlinFiles(rootFolder.toPath()); + } + + @Override + public void reset() { + super.reset(); + } + + /** + * This imports the project. It relies on the GradleProjectImporter.importToWorkspace to do most of the work. + * Once the base gradle project is imported, we add the kls folder to the classpath as a library. + * The kls folder is the folder used by the kotlin language server to output classfiles. + */ + @Override + public void importToWorkspace(IProgressMonitor monitor) throws CoreException { + super.importToWorkspace(monitor); + + for (IProject project : ProjectUtils.getGradleProjects()) { + java.nio.file.Path path = Paths.get(project.getLocation().toOSString(), "kls"); + KotlinImporterUtils.setKlsClasspathEntry(project, path, monitor, new GradleBuildSupport()); + KotlinImporterUtils.registerKlsWatcher(path, subMonitor -> { + try { + for (IProject gradleProject : ProjectUtils.getGradleProjects()) { + KotlinImporterUtils.setKlsClasspathEntry(gradleProject, path, subMonitor, new GradleBuildSupport()); + } + + return Status.OK_STATUS; + } catch (CoreException ex) { + JavaLanguageServerPlugin.logException(ex); + return Status.error("An error occurred while updating the kotlin classpath entry"); + } + }); + } + } +} diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinImporterUtils.java b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinImporterUtils.java new file mode 100644 index 00000000..a46ed21c --- /dev/null +++ b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinImporterUtils.java @@ -0,0 +1,135 @@ +package org.javacs.kt.jdt.ls.extension; + +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Stream; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jdt.core.IClasspathEntry; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; +import org.eclipse.jdt.ls.core.internal.managers.IBuildSupport; +import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager.CHANGE_TYPE; + +@SuppressWarnings("restriction") +public class KotlinImporterUtils { + + /** + * Checks if any kotlin files exist in the given directory and subdirectories. + */ + public static boolean anyKotlinFiles(java.nio.file.Path directory) { + try (Stream files = Files.walk(directory)) { + return files.anyMatch(f -> f.getFileName().toString().endsWith(".kt")); + } catch (IOException ex) { + return false; + } + } + + public static void setKlsClasspathEntry(IProject project, java.nio.file.Path path, IProgressMonitor monitor, IBuildSupport buildSupport) throws CoreException { + IJavaProject javaProject = JavaCore.create(project); + + List entries = new ArrayList<>(Arrays.asList(javaProject.getRawClasspath())); + IPath klsPath = Path.fromOSString(path.toString()); + + entries.removeIf(entry -> entry.getPath().equals(klsPath)); + IClasspathEntry classpathEntry = JavaCore.newLibraryEntry(klsPath, null, null); + entries.add(classpathEntry); + + javaProject.setRawClasspath(entries.toArray(new IClasspathEntry[0]), monitor); + buildSupport.refresh(project, CHANGE_TYPE.CHANGED, monitor); + } + + /** + * Registers a watcher for the kls directory. + * Any file change leads to an update in the classpath. + * The classpath update is done using a function send as parameter, since it's different for each importer. + */ + public static void registerKlsWatcher(java.nio.file.Path path, Function updateClasspathJob) { + new Thread(() -> { + try { + Files.createDirectories(path); + Map keys = new HashMap<>(); + // Create the watcher and watch all directories under the base kls directory. + WatchService watcher = FileSystems.getDefault().newWatchService(); + keys.putAll(watchDirectory(watcher, path)); + + // Wair for file related events. + // When a file is added or deleted, we update the classpath (we remove and re-add the kls classpath entry) + while (true) { + WatchKey key; + if ((key = watcher.take()) != null) { + java.nio.file.Path dir = keys.get(key); + if (dir != null) { + key.pollEvents().forEach(event -> { + @SuppressWarnings("unchecked") + WatchEvent ev = (WatchEvent) event; + + java.nio.file.Path name = ev.context(); + java.nio.file.Path child = dir.resolve(name); + + // If a new directory was created, we need to watch it as well. + if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { + if (Files.isDirectory(child, LinkOption.NOFOLLOW_LINKS)) { + keys.putAll(watchDirectory(watcher, dir)); + } + } + }); + Job job = new Job("Updating kotlin classpath entry") { + @Override + protected IStatus run(IProgressMonitor monitor) { + return updateClasspathJob.apply(monitor); + } + }; + job.schedule(); + job.join(); + key.reset(); + } + } + } + } catch (IOException | InterruptedException ex) { + JavaLanguageServerPlugin.logException(ex); + } + }).start(); + } + + private static Map watchDirectory(WatchService watcher, java.nio.file.Path path) { + Map keys = new HashMap<>(); + + try { + Files.walkFileTree(path, new SimpleFileVisitor() { + @Override + public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { + WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); + keys.put(key, dir); + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException ex) { + JavaLanguageServerPlugin.logException(ex); + } + + return keys; + } +} diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinMavenImporter.java b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinMavenImporter.java index 5094dcb3..91585f47 100644 --- a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinMavenImporter.java +++ b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinMavenImporter.java @@ -1,38 +1,13 @@ package org.javacs.kt.jdt.ls.extension; -import java.io.IOException; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.LinkOption; import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.StandardWatchEventKinds; -import java.nio.file.WatchEvent; -import java.nio.file.WatchKey; -import java.nio.file.WatchService; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; import org.eclipse.jdt.ls.core.internal.managers.MavenBuildSupport; import org.eclipse.jdt.ls.core.internal.managers.MavenProjectImporter; -import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager.CHANGE_TYPE; import org.eclipse.m2e.core.MavenPlugin; import org.eclipse.m2e.core.project.IMavenProjectFacade; @@ -53,15 +28,7 @@ public class KotlinMavenImporter extends MavenProjectImporter { */ @Override public boolean applies(IProgressMonitor monitor) throws CoreException { - if (super.applies(monitor)) { - try (Stream files = Files.walk(rootFolder.toPath())) { - return files.anyMatch(f -> f.getFileName().toString().endsWith(".kt")); - } catch (IOException ex) { - return false; - } - } else { - return false; - } + return super.applies(monitor) && KotlinImporterUtils.anyKotlinFiles(rootFolder.toPath()); } @Override @@ -81,103 +48,19 @@ public void importToWorkspace(IProgressMonitor monitor) throws CoreException { for (IMavenProjectFacade mavenProject : MavenPlugin.getMavenProjectRegistry().getProjects()) { IProject project = mavenProject.getProject(); java.nio.file.Path path = Paths.get(project.getLocation().toOSString(), "kls"); - setKlsClasspathEntry(project, path, monitor); - registerKlsWatcher(path); - } - } - - /** - * Registers a watcher for the kls directory. - * Any file change leads to an update in the classpath. - */ - private void registerKlsWatcher(java.nio.file.Path path) { - new Thread(() -> { - try { - Files.createDirectories(path); - Map keys = new HashMap<>(); - // Create the watcher and watch all directories under the base kls directory. - WatchService watcher = FileSystems.getDefault().newWatchService(); - keys.putAll(watchDirectory(watcher, path)); - - // Wair for file related events. - // When a file is added or deleted, we update the classpath (we remove and re-add the kls classpath entry) - while (true) { - WatchKey key; - if ((key = watcher.take()) != null) { - java.nio.file.Path dir = keys.get(key); - if (dir != null) { - key.pollEvents().forEach(event -> { - @SuppressWarnings("unchecked") - WatchEvent ev = (WatchEvent) event; - - java.nio.file.Path name = ev.context(); - java.nio.file.Path child = dir.resolve(name); - - // If a new directory was created, we need to watch it as well. - if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { - if (Files.isDirectory(child, LinkOption.NOFOLLOW_LINKS)) { - keys.putAll(watchDirectory(watcher, dir)); - } - } - }); - Job job = new Job("Updating kotlin classpath entry") { - @Override - protected IStatus run(IProgressMonitor monitor) { - try { - for (IMavenProjectFacade mavenProject : MavenPlugin.getMavenProjectRegistry().getProjects()) { - IProject project = mavenProject.getProject(); - setKlsClasspathEntry(project, path, monitor); - } - - return Status.OK_STATUS; - } catch (CoreException ex) { - JavaLanguageServerPlugin.logException(ex); - return Status.error("An error occurred while updating the kotlin classpath entry"); - } - } - }; - job.schedule(); - job.join(); - key.reset(); - } + KotlinImporterUtils.setKlsClasspathEntry(project, path, monitor, new MavenBuildSupport()); + KotlinImporterUtils.registerKlsWatcher(path, subMonitor -> { + try { + for (IMavenProjectFacade underliyingMavenProject : MavenPlugin.getMavenProjectRegistry().getProjects()) { + KotlinImporterUtils.setKlsClasspathEntry(underliyingMavenProject.getProject(), path, subMonitor, new MavenBuildSupport()); } - } - } catch (IOException | InterruptedException ex) { - JavaLanguageServerPlugin.logException(ex); - } - }).start(); - } - - private Map watchDirectory(WatchService watcher, java.nio.file.Path path) { - Map keys = new HashMap<>(); - try { - Files.walkFileTree(path, new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { - WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); - keys.put(key, dir); - return FileVisitResult.CONTINUE; + return Status.OK_STATUS; + } catch (CoreException ex) { + JavaLanguageServerPlugin.logException(ex); + return Status.error("An error occurred while updating the kotlin classpath entry"); } }); - } catch (IOException ex) { - JavaLanguageServerPlugin.logException(ex); } - - return keys; - } - - private void setKlsClasspathEntry(IProject project, java.nio.file.Path path, IProgressMonitor monitor) throws CoreException { - IJavaProject javaProject = JavaCore.create(project); - - List entries = new ArrayList<>(Arrays.asList(javaProject.getRawClasspath())); - IPath klsPath = Path.fromOSString(path.toString()); - - entries.removeIf(entry -> entry.getPath().equals(klsPath)); - IClasspathEntry classpathEntry = JavaCore.newLibraryEntry(klsPath, null, null); - entries.add(classpathEntry); - - javaProject.setRawClasspath(entries.toArray(new IClasspathEntry[0]), monitor); - new MavenBuildSupport().refresh(project, CHANGE_TYPE.CHANGED, monitor); } } From 84196d38f18bf38ef4df19406af0f6a9ca905fdc Mon Sep 17 00:00:00 2001 From: daplf Date: Sun, 13 Mar 2022 18:40:48 +0000 Subject: [PATCH 03/34] Update README.md --- vscode-java-kotlin/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vscode-java-kotlin/README.md b/vscode-java-kotlin/README.md index dc66223b..b8bcd996 100644 --- a/vscode-java-kotlin/README.md +++ b/vscode-java-kotlin/README.md @@ -2,10 +2,10 @@ A VSCode extension that enchances [vscode-java](https://github.com/redhat-developer/vscode-java) and [vscode-kotlin](https://github.com/fwcd/vscode-kotlin) with java + kotlin interoperability. This uses a JDT LS extension with a custom project importer to allow Java code to have access to Kotlin code. -**Disclaimer**: This is very experimental, but it seems to work for small maven projects at least. +**Disclaimer**: This is very experimental, but it seems to work for small maven and gradle projects at least. ## Setup (for now) For now, to set this up, you need to run the `build.sh` script in this directory to package the JDT LS extension. Afterwards, you should run `npm install` to install the extension dependencies. -To debug, you can use F5 on VSCode, as with any other extension. To package the extension you can use `vsce package`. \ No newline at end of file +To debug, you can use F5 on VSCode, as with any other extension. To package the extension you can use `vsce package`. From db5ba9f18460a7a6c4125520b97a08cc85d5ff33 Mon Sep 17 00:00:00 2001 From: fwcd Date: Thu, 17 Mar 2022 16:33:57 +0100 Subject: [PATCH 04/34] Move vscode-java-kotlin to its own repository See https://github.com/fwcd/vscode-java-kotlin --- vscode-java-kotlin/.gitignore | 9 - vscode-java-kotlin/.vscode/launch.json | 21 - vscode-java-kotlin/.vscodeignore | 8 - vscode-java-kotlin/README.md | 11 - vscode-java-kotlin/build.sh | 7 - vscode-java-kotlin/javaConfig.json | 6 - .../META-INF/MANIFEST.MF | 16 - .../build.properties | 5 - .../org.javacs.kt.jdt.ls.extension/plugin.xml | 17 - .../org.javacs.kt.jdt.ls.extension/pom.xml | 18 - .../ls/extension/KotlinGradleImporter.java | 65 - .../jdt/ls/extension/KotlinImporterUtils.java | 135 -- .../jdt/ls/extension/KotlinMavenImporter.java | 66 - vscode-java-kotlin/jdt-ls-extension/pom.xml | 79 -- .../jdt-ls-extension/target.target | 17 - vscode-java-kotlin/package-lock.json | 1158 ----------------- vscode-java-kotlin/package.json | 46 - vscode-java-kotlin/src/extension.ts | 7 - vscode-java-kotlin/tsconfig.json | 21 - 19 files changed, 1712 deletions(-) delete mode 100644 vscode-java-kotlin/.gitignore delete mode 100644 vscode-java-kotlin/.vscode/launch.json delete mode 100644 vscode-java-kotlin/.vscodeignore delete mode 100644 vscode-java-kotlin/README.md delete mode 100644 vscode-java-kotlin/build.sh delete mode 100644 vscode-java-kotlin/javaConfig.json delete mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/META-INF/MANIFEST.MF delete mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/build.properties delete mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/plugin.xml delete mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/pom.xml delete mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinGradleImporter.java delete mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinImporterUtils.java delete mode 100644 vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinMavenImporter.java delete mode 100644 vscode-java-kotlin/jdt-ls-extension/pom.xml delete mode 100644 vscode-java-kotlin/jdt-ls-extension/target.target delete mode 100644 vscode-java-kotlin/package-lock.json delete mode 100644 vscode-java-kotlin/package.json delete mode 100644 vscode-java-kotlin/src/extension.ts delete mode 100644 vscode-java-kotlin/tsconfig.json diff --git a/vscode-java-kotlin/.gitignore b/vscode-java-kotlin/.gitignore deleted file mode 100644 index c862d8ce..00000000 --- a/vscode-java-kotlin/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -node_modules -target -*.vsix -.idea -*.iml -.DS_Store -**/.DS_Store -jars -.vscode/settings.json \ No newline at end of file diff --git a/vscode-java-kotlin/.vscode/launch.json b/vscode-java-kotlin/.vscode/launch.json deleted file mode 100644 index 4faa2ec5..00000000 --- a/vscode-java-kotlin/.vscode/launch.json +++ /dev/null @@ -1,21 +0,0 @@ -// A launch configuration that compiles the extension and then opens it inside a new window -// Use IntelliSense to learn about possible attributes. -// Hover to view descriptions of existing attributes. -// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Extension", - "type": "extensionHost", - "request": "launch", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}" - ], - "outFiles": [ - "${workspaceFolder}/out/**/*.js" - ] - } - ] -} diff --git a/vscode-java-kotlin/.vscodeignore b/vscode-java-kotlin/.vscodeignore deleted file mode 100644 index e6ba7467..00000000 --- a/vscode-java-kotlin/.vscodeignore +++ /dev/null @@ -1,8 +0,0 @@ -.vscode/** -.idea/** -*.iml -javaConfig.json -tsconfig.json -org.javacs.kt.jdt.ls.extension -build.sh -.gitignore \ No newline at end of file diff --git a/vscode-java-kotlin/README.md b/vscode-java-kotlin/README.md deleted file mode 100644 index b8bcd996..00000000 --- a/vscode-java-kotlin/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# VSCode Extension for Java + Kotlin - -A VSCode extension that enchances [vscode-java](https://github.com/redhat-developer/vscode-java) and [vscode-kotlin](https://github.com/fwcd/vscode-kotlin) with java + kotlin interoperability. This uses a JDT LS extension with a custom project importer to allow Java code to have access to Kotlin code. - -**Disclaimer**: This is very experimental, but it seems to work for small maven and gradle projects at least. - -## Setup (for now) - -For now, to set this up, you need to run the `build.sh` script in this directory to package the JDT LS extension. Afterwards, you should run `npm install` to install the extension dependencies. - -To debug, you can use F5 on VSCode, as with any other extension. To package the extension you can use `vsce package`. diff --git a/vscode-java-kotlin/build.sh b/vscode-java-kotlin/build.sh deleted file mode 100644 index a186860a..00000000 --- a/vscode-java-kotlin/build.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash -rm -fr jars -mkdir -p jars - -cd jdt-ls-extension -mvn clean package -cp org.javacs.kt.jdt.ls.extension/target/org.javacs.kt.jdt.ls.extension-1.0.0-SNAPSHOT.jar ../jars/jdt-ls-extension.jar \ No newline at end of file diff --git a/vscode-java-kotlin/javaConfig.json b/vscode-java-kotlin/javaConfig.json deleted file mode 100644 index 5e886918..00000000 --- a/vscode-java-kotlin/javaConfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "projects": [ - "./jdt-ls-extension/org.javacs.kt.jdt.ls.extension" - ], - "targetPlatform": "./jdt-ls-extension/target.target" - } \ No newline at end of file diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/META-INF/MANIFEST.MF b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/META-INF/MANIFEST.MF deleted file mode 100644 index d2178539..00000000 --- a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/META-INF/MANIFEST.MF +++ /dev/null @@ -1,16 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: org.javacs.kt.jdt.ls.extension -Bundle-SymbolicName: org.javacs.kt.jdt.ls.extension;singleton:=true -Bundle-Version: 1.0.0.qualifier -Bundle-Vendor: VMware, Inc. -Bundle-RequiredExecutionEnvironment: JavaSE-1.8 -Require-Bundle: org.eclipse.jdt.ls.core, - org.eclipse.core.runtime, - org.eclipse.jdt.core, - org.eclipse.core.resources, - org.eclipse.m2e.core;resolution:=optional, - org.eclipse.m2e.jdt;resolution:=optional, - org.eclipse.m2e.maven.runtime;resolution:=optional, - org.eclipse.lsp4j, - org.eclipse.lsp4j.jsonrpc diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/build.properties b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/build.properties deleted file mode 100644 index e9863e28..00000000 --- a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/build.properties +++ /dev/null @@ -1,5 +0,0 @@ -source.. = src/ -output.. = bin/ -bin.includes = META-INF/,\ - .,\ - plugin.xml diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/plugin.xml b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/plugin.xml deleted file mode 100644 index ffe5e988..00000000 --- a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/plugin.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/pom.xml b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/pom.xml deleted file mode 100644 index 05c95656..00000000 --- a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/pom.xml +++ /dev/null @@ -1,18 +0,0 @@ - - 4.0.0 - eclipse-plugin - org.javacs.kt - org.javacs.kt.jdt.ls.extension - 1.0.0-SNAPSHOT - org.javacs.kt.jdt.ls.extension - - - org.javacs.kt - jdt-ls-extension-parent - 1.0.0-SNAPSHOT - ../pom.xml - - diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinGradleImporter.java b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinGradleImporter.java deleted file mode 100644 index c2dc9964..00000000 --- a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinGradleImporter.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.javacs.kt.jdt.ls.extension; - -import java.nio.file.Paths; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; -import org.eclipse.jdt.ls.core.internal.ProjectUtils; -import org.eclipse.jdt.ls.core.internal.managers.GradleBuildSupport; -import org.eclipse.jdt.ls.core.internal.managers.GradleProjectImporter; - -/** - * Custom importer for kotlin gradle projects. - * This relies on the JDT LS GradleProjectImporter to actually import the base project. - * It then updates the classpath to include the kotlin compiled classes. - */ -@SuppressWarnings("restriction") -public class KotlinGradleImporter extends GradleProjectImporter { - - /** - * Checks if this is a gradle kotlin project. - * For now, we rely on GradleProjectImporter.applies to check if this is a gradle project. - * On top of that, we check if we have any kotlin files in the workspace. - * If we do, we assume this is a kotlin gradle project. - * TODO: We should make this more robust in the future. - */ - @Override - public boolean applies(IProgressMonitor monitor) throws CoreException { - return super.applies(monitor) && KotlinImporterUtils.anyKotlinFiles(rootFolder.toPath()); - } - - @Override - public void reset() { - super.reset(); - } - - /** - * This imports the project. It relies on the GradleProjectImporter.importToWorkspace to do most of the work. - * Once the base gradle project is imported, we add the kls folder to the classpath as a library. - * The kls folder is the folder used by the kotlin language server to output classfiles. - */ - @Override - public void importToWorkspace(IProgressMonitor monitor) throws CoreException { - super.importToWorkspace(monitor); - - for (IProject project : ProjectUtils.getGradleProjects()) { - java.nio.file.Path path = Paths.get(project.getLocation().toOSString(), "kls"); - KotlinImporterUtils.setKlsClasspathEntry(project, path, monitor, new GradleBuildSupport()); - KotlinImporterUtils.registerKlsWatcher(path, subMonitor -> { - try { - for (IProject gradleProject : ProjectUtils.getGradleProjects()) { - KotlinImporterUtils.setKlsClasspathEntry(gradleProject, path, subMonitor, new GradleBuildSupport()); - } - - return Status.OK_STATUS; - } catch (CoreException ex) { - JavaLanguageServerPlugin.logException(ex); - return Status.error("An error occurred while updating the kotlin classpath entry"); - } - }); - } - } -} diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinImporterUtils.java b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinImporterUtils.java deleted file mode 100644 index a46ed21c..00000000 --- a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinImporterUtils.java +++ /dev/null @@ -1,135 +0,0 @@ -package org.javacs.kt.jdt.ls.extension; - -import java.io.IOException; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.LinkOption; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.StandardWatchEventKinds; -import java.nio.file.WatchEvent; -import java.nio.file.WatchKey; -import java.nio.file.WatchService; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Stream; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.Path; -import org.eclipse.core.runtime.jobs.Job; -import org.eclipse.jdt.core.IClasspathEntry; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.JavaCore; -import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; -import org.eclipse.jdt.ls.core.internal.managers.IBuildSupport; -import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager.CHANGE_TYPE; - -@SuppressWarnings("restriction") -public class KotlinImporterUtils { - - /** - * Checks if any kotlin files exist in the given directory and subdirectories. - */ - public static boolean anyKotlinFiles(java.nio.file.Path directory) { - try (Stream files = Files.walk(directory)) { - return files.anyMatch(f -> f.getFileName().toString().endsWith(".kt")); - } catch (IOException ex) { - return false; - } - } - - public static void setKlsClasspathEntry(IProject project, java.nio.file.Path path, IProgressMonitor monitor, IBuildSupport buildSupport) throws CoreException { - IJavaProject javaProject = JavaCore.create(project); - - List entries = new ArrayList<>(Arrays.asList(javaProject.getRawClasspath())); - IPath klsPath = Path.fromOSString(path.toString()); - - entries.removeIf(entry -> entry.getPath().equals(klsPath)); - IClasspathEntry classpathEntry = JavaCore.newLibraryEntry(klsPath, null, null); - entries.add(classpathEntry); - - javaProject.setRawClasspath(entries.toArray(new IClasspathEntry[0]), monitor); - buildSupport.refresh(project, CHANGE_TYPE.CHANGED, monitor); - } - - /** - * Registers a watcher for the kls directory. - * Any file change leads to an update in the classpath. - * The classpath update is done using a function send as parameter, since it's different for each importer. - */ - public static void registerKlsWatcher(java.nio.file.Path path, Function updateClasspathJob) { - new Thread(() -> { - try { - Files.createDirectories(path); - Map keys = new HashMap<>(); - // Create the watcher and watch all directories under the base kls directory. - WatchService watcher = FileSystems.getDefault().newWatchService(); - keys.putAll(watchDirectory(watcher, path)); - - // Wair for file related events. - // When a file is added or deleted, we update the classpath (we remove and re-add the kls classpath entry) - while (true) { - WatchKey key; - if ((key = watcher.take()) != null) { - java.nio.file.Path dir = keys.get(key); - if (dir != null) { - key.pollEvents().forEach(event -> { - @SuppressWarnings("unchecked") - WatchEvent ev = (WatchEvent) event; - - java.nio.file.Path name = ev.context(); - java.nio.file.Path child = dir.resolve(name); - - // If a new directory was created, we need to watch it as well. - if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { - if (Files.isDirectory(child, LinkOption.NOFOLLOW_LINKS)) { - keys.putAll(watchDirectory(watcher, dir)); - } - } - }); - Job job = new Job("Updating kotlin classpath entry") { - @Override - protected IStatus run(IProgressMonitor monitor) { - return updateClasspathJob.apply(monitor); - } - }; - job.schedule(); - job.join(); - key.reset(); - } - } - } - } catch (IOException | InterruptedException ex) { - JavaLanguageServerPlugin.logException(ex); - } - }).start(); - } - - private static Map watchDirectory(WatchService watcher, java.nio.file.Path path) { - Map keys = new HashMap<>(); - - try { - Files.walkFileTree(path, new SimpleFileVisitor() { - @Override - public FileVisitResult preVisitDirectory(java.nio.file.Path dir, BasicFileAttributes attrs) throws IOException { - WatchKey key = dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); - keys.put(key, dir); - return FileVisitResult.CONTINUE; - } - }); - } catch (IOException ex) { - JavaLanguageServerPlugin.logException(ex); - } - - return keys; - } -} diff --git a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinMavenImporter.java b/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinMavenImporter.java deleted file mode 100644 index 91585f47..00000000 --- a/vscode-java-kotlin/jdt-ls-extension/org.javacs.kt.jdt.ls.extension/src/org/javacs/kt/jdt/ls/extension/KotlinMavenImporter.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.javacs.kt.jdt.ls.extension; - -import java.nio.file.Paths; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.core.runtime.Status; -import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; -import org.eclipse.jdt.ls.core.internal.managers.MavenBuildSupport; -import org.eclipse.jdt.ls.core.internal.managers.MavenProjectImporter; -import org.eclipse.m2e.core.MavenPlugin; -import org.eclipse.m2e.core.project.IMavenProjectFacade; - -/** - * Custom importer for kotlin maven projects. - * This relies on the JDT LS MavenProjectImporter to actually import the base project. - * It then updates the classpath to include the kotlin compiled classes. - */ -@SuppressWarnings("restriction") -public class KotlinMavenImporter extends MavenProjectImporter { - - /** - * Checks if this is a maven kotlin project. - * For now, we rely on MavenProjectImporter.applies to check if this is a maven project. - * On top of that, we check if we have any kotlin files in the workspace. - * If we do, we assume this is a kotlin maven project. - * TODO: We should make this more robust in the future. - */ - @Override - public boolean applies(IProgressMonitor monitor) throws CoreException { - return super.applies(monitor) && KotlinImporterUtils.anyKotlinFiles(rootFolder.toPath()); - } - - @Override - public void reset() { - super.reset(); - } - - /** - * This imports the project. It relies on the MavenProjectImporter.importToWorkspace to do most of the work. - * Once the base maven project is imported, we add the kls folder to the classpath as a library. - * The kls folder is the folder used by the kotlin language server to output classfiles. - */ - @Override - public void importToWorkspace(IProgressMonitor monitor) throws CoreException { - super.importToWorkspace(monitor); - - for (IMavenProjectFacade mavenProject : MavenPlugin.getMavenProjectRegistry().getProjects()) { - IProject project = mavenProject.getProject(); - java.nio.file.Path path = Paths.get(project.getLocation().toOSString(), "kls"); - KotlinImporterUtils.setKlsClasspathEntry(project, path, monitor, new MavenBuildSupport()); - KotlinImporterUtils.registerKlsWatcher(path, subMonitor -> { - try { - for (IMavenProjectFacade underliyingMavenProject : MavenPlugin.getMavenProjectRegistry().getProjects()) { - KotlinImporterUtils.setKlsClasspathEntry(underliyingMavenProject.getProject(), path, subMonitor, new MavenBuildSupport()); - } - - return Status.OK_STATUS; - } catch (CoreException ex) { - JavaLanguageServerPlugin.logException(ex); - return Status.error("An error occurred while updating the kotlin classpath entry"); - } - }); - } - } -} diff --git a/vscode-java-kotlin/jdt-ls-extension/pom.xml b/vscode-java-kotlin/jdt-ls-extension/pom.xml deleted file mode 100644 index f3c84b7d..00000000 --- a/vscode-java-kotlin/jdt-ls-extension/pom.xml +++ /dev/null @@ -1,79 +0,0 @@ - - 4.0.0 - - org.javacs.kt - jdt-ls-extension-parent - pom - 1.0.0-SNAPSHOT - jdt-ls-extension-parent - - - org.javacs.kt.jdt.ls.extension - - - - 11 - 1.7.0 - - - - - - eclipse - p2 - https://download.eclipse.org/releases/2022-03 - - - - JDT.LS - p2 - https://download.eclipse.org/jdtls/snapshots/repository/latest/ - - - - jboss - p2 - https://download.jboss.org/jbosstools/updates/m2e-extensions/m2e-apt/1.5.3-2019-11-08_11-04-22-H22/ - - - - - - org.eclipse.tycho.extras - tycho-source-feature-plugin - ${tycho-version} - - - source-feature - package - - source-feature - - - - - - - org.eclipse.tycho - tycho-source-plugin - ${tycho-version} - - - plugin-source - - plugin-source - - - - - - - org.eclipse.tycho - tycho-maven-plugin - ${tycho-version} - true - - - - diff --git a/vscode-java-kotlin/jdt-ls-extension/target.target b/vscode-java-kotlin/jdt-ls-extension/target.target deleted file mode 100644 index e850b17b..00000000 --- a/vscode-java-kotlin/jdt-ls-extension/target.target +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vscode-java-kotlin/package-lock.json b/vscode-java-kotlin/package-lock.json deleted file mode 100644 index f0725d9b..00000000 --- a/vscode-java-kotlin/package-lock.json +++ /dev/null @@ -1,1158 +0,0 @@ -{ - "name": "vscode-java-kotlin", - "version": "0.0.1", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/node": { - "version": "12.20.46", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.46.tgz", - "integrity": "sha512-cPjLXj8d6anFPzFvOPxS3fvly3Shm5nTfl6g8X5smexixbuGUf7hfr21J5tX9JW+UPStp/5P5R8qrKL5IyVJ+A==", - "dev": true - }, - "@types/vscode": { - "version": "1.65.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.65.0.tgz", - "integrity": "sha512-wQhExnh2nEzpjDMSKhUvnNmz3ucpd3E+R7wJkOhBNK3No6fG3VUdmVmMOKD0A8NDZDDDiQcLNxe3oGmX5SjJ5w==", - "dev": true - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true - }, - "are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "dev": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "azure-devops-node-api": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.1.1.tgz", - "integrity": "sha512-XDG91XzLZ15reP12s3jFkKS8oiagSICjnLwxEYieme4+4h3ZveFOFRA4iYIG40RyHXsiI0mefFYYMFIJbMpWcg==", - "dev": true, - "requires": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "dev": true, - "requires": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - } - }, - "cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", - "dev": true, - "requires": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.7.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", - "domutils": "^2.8.0", - "nth-check": "^2.0.1" - } - }, - "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", - "dev": true - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "requires": { - "mimic-response": "^3.1.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true - }, - "denodeify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", - "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=", - "dev": true - }, - "detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", - "dev": true - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - }, - "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", - "dev": true, - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", - "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", - "dev": true, - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "dev": true - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "keytar": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", - "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", - "dev": true, - "requires": { - "node-addon-api": "^4.3.0", - "prebuild-install": "^7.0.1" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "linkify-it": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz", - "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "markdown-it": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz", - "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "entities": "~2.0.0", - "linkify-it": "^2.0.0", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "dependencies": { - "entities": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz", - "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ==", - "dev": true - } - } - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true - }, - "node-abi": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.8.0.tgz", - "integrity": "sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==", - "dev": true, - "requires": { - "semver": "^7.3.5" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "dev": true - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true - }, - "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "parse-semver": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", - "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", - "dev": true, - "requires": { - "semver": "^5.1.0" - } - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "requires": { - "parse5": "^6.0.1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "prebuild-install": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.0.1.tgz", - "integrity": "sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg==", - "dev": true, - "requires": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "qs": { - "version": "6.10.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", - "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "dev": true, - "requires": { - "mute-stream": "~0.0.4" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true - }, - "simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "dev": true, - "requires": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "dev": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "requires": { - "rimraf": "^3.0.0" - } - }, - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", - "dev": true - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "typed-rest-client": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.6.tgz", - "integrity": "sha512-xcQpTEAJw2DP7GqVNECh4dD+riS+C1qndXLfBCJ3xk0kqprtGN491P5KlmrDbKdtuW8NEcP/5ChxiJI3S9WYTA==", - "dev": true, - "requires": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "^1.12.1" - } - }, - "typescript": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", - "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", - "dev": true - }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "underscore": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.2.tgz", - "integrity": "sha512-ekY1NhRzq0B08g4bGuX4wd2jZx5GnKz6mKSqFL4nqBlfyMGiG10gDFhDTMEfYmDL6Jy0FUIZp7wiRB+0BP7J2g==", - "dev": true - }, - "url-join": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz", - "integrity": "sha1-dBxsL0WWxIMNZxhGCSDQySIC3Hg=", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "vsce": { - "version": "1.103.1", - "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.103.1.tgz", - "integrity": "sha512-98oKQKKRp7J/vTIk1cuzom5cezZpYpRHs3WlySdsrTCrAEipB/HvaPTc4VZ3hGZHzHXS9P5p2L0IllntJeXwiQ==", - "dev": true, - "requires": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "denodeify": "^1.2.1", - "glob": "^7.0.6", - "hosted-git-info": "^4.0.2", - "keytar": "^7.7.0", - "leven": "^3.1.0", - "lodash": "^4.17.15", - "markdown-it": "^10.0.0", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "osenv": "^0.1.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^1.1.0", - "xml2js": "^0.4.23", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - } - }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", - "dev": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3" - } - } - } -} diff --git a/vscode-java-kotlin/package.json b/vscode-java-kotlin/package.json deleted file mode 100644 index eb729160..00000000 --- a/vscode-java-kotlin/package.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "vscode-java-kotlin", - "displayName": "Java Kotlin", - "description": "Language support for Java + Kotlin projects", - "repository": { - "type": "git", - "url": "https://github.com/fwcd/kotlin-language-server.git" - }, - "version": "0.0.1", - "publisher": "fwcd", - "license": "MIT", - "categories": [ - "Programming Languages" - ], - "engines": { - "vscode": "^1.52.0" - }, - "keywords": [ - "java", - "kotlin" - ], - "activationEvents": [ - "onLanguage:java" - ], - "contributes": { - "javaExtensions": [ - "./jars/jdt-ls-extension.jar" - ] - }, - "main": "./out/src/extension", - "scripts": { - "vscode:prepublish": "npm run compile", - "compile": "tsc -p ./", - "watch": "tsc -watch -p ./" - }, - "devDependencies": { - "@types/node": "^12.8.1", - "@types/vscode": "^1.52.0", - "typescript": "^4.3.5", - "vsce": "^1.95.0" - }, - "extensionDependencies": [ - "redhat.java", - "fwcd.kotlin" - ] -} diff --git a/vscode-java-kotlin/src/extension.ts b/vscode-java-kotlin/src/extension.ts deleted file mode 100644 index 9cc14c32..00000000 --- a/vscode-java-kotlin/src/extension.ts +++ /dev/null @@ -1,7 +0,0 @@ -'use strict'; - -import * as vscode from 'vscode'; - -/** Called when extension is activated */ -export async function activate(context: vscode.ExtensionContext) { -} diff --git a/vscode-java-kotlin/tsconfig.json b/vscode-java-kotlin/tsconfig.json deleted file mode 100644 index f1fd7c9d..00000000 --- a/vscode-java-kotlin/tsconfig.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "moduleResolution": "node", - "target": "es6", - "lib": [ - "es6" - ], - "declaration": true, - "outDir": "out", - "sourceMap": true, - "rootDir": "." - }, - "include": [ - "typings/*.d.ts", - "src/**/*.ts" - ], - "exclude": [ - "node_modules" - ] -} \ No newline at end of file From ff2277c31d2e2e8b008b4df66977ce79bd5a952e Mon Sep 17 00:00:00 2001 From: daplf Date: Mon, 21 Mar 2022 00:05:37 +0000 Subject: [PATCH 05/34] Support definitions on JDK symbols --- .../main/kotlin/org/javacs/kt/CompiledFile.kt | 32 ++++++---- .../kotlin/org/javacs/kt/CompilerClassPath.kt | 1 + .../org/javacs/kt/KotlinLanguageServer.kt | 7 +-- .../kt/KotlinProtocolExtensionService.kt | 5 -- .../javacs/kt/KotlinTextDocumentService.kt | 5 +- .../main/kotlin/org/javacs/kt/SourcePath.kt | 32 +++++----- .../org/javacs/kt/URIContentProvider.kt | 13 ++-- .../kotlin/org/javacs/kt/compiler/Compiler.kt | 52 ++++++--------- .../org/javacs/kt/completion/Completions.kt | 6 +- .../javacs/kt/definition/GoToDefinition.kt | 13 ++-- ...entProvider.kt => ClassContentProvider.kt} | 16 ++--- .../ClassPathSourceArchiveProvider.kt | 29 +++++++++ .../ClassPathSourceJarProvider.kt | 11 ---- .../javacs/kt/externalsources/Decompiler.kt | 4 +- .../org/javacs/kt/externalsources/KlsURI.kt | 63 ++++++++++++++----- .../externalsources/SourceArchiveProvider.kt | 7 +++ .../kt/externalsources/SourceJarProvider.kt | 7 --- .../main/kotlin/org/javacs/kt/hover/Hovers.kt | 14 +---- 18 files changed, 168 insertions(+), 149 deletions(-) rename server/src/main/kotlin/org/javacs/kt/externalsources/{JarClassContentProvider.kt => ClassContentProvider.kt} (84%) create mode 100644 server/src/main/kotlin/org/javacs/kt/externalsources/ClassPathSourceArchiveProvider.kt delete mode 100644 server/src/main/kotlin/org/javacs/kt/externalsources/ClassPathSourceJarProvider.kt create mode 100644 server/src/main/kotlin/org/javacs/kt/externalsources/SourceArchiveProvider.kt delete mode 100644 server/src/main/kotlin/org/javacs/kt/externalsources/SourceJarProvider.kt diff --git a/server/src/main/kotlin/org/javacs/kt/CompiledFile.kt b/server/src/main/kotlin/org/javacs/kt/CompiledFile.kt index a821bf20..4c4ea3d3 100644 --- a/server/src/main/kotlin/org/javacs/kt/CompiledFile.kt +++ b/server/src/main/kotlin/org/javacs/kt/CompiledFile.kt @@ -2,15 +2,14 @@ package org.javacs.kt import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement -import com.intellij.psi.PsiIdentifier import org.javacs.kt.compiler.CompilationKind import org.javacs.kt.position.changedRegion import org.javacs.kt.position.position import org.javacs.kt.util.findParent import org.javacs.kt.util.nullResult import org.javacs.kt.util.toPath -import org.jetbrains.kotlin.container.ComponentProvider import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf @@ -23,7 +22,7 @@ class CompiledFile( val content: String, val parse: KtFile, val compile: BindingContext, - val container: ComponentProvider, + val module: ModuleDescriptor, val sourcePath: Collection, val classPath: CompilerClassPath, val isScript: Boolean = false, @@ -33,7 +32,7 @@ class CompiledFile( * Find the type of the expression at `cursor` */ fun typeAtPoint(cursor: Int): KotlinType? { - var cursorExpr = parseAtPoint(cursor, asReference = true)?.findParent() ?: return nullResult("Couldn't find expression at ${describePosition(cursor)}") + val cursorExpr = parseAtPoint(cursor, asReference = true)?.findParent() ?: return nullResult("Couldn't find expression at ${describePosition(cursor)}") val surroundingExpr = expandForType(cursor, cursorExpr) val scope = scopeAtPoint(cursor) ?: return nullResult("Couldn't find scope at ${describePosition(cursor)}") return typeOfExpression(surroundingExpr, scope) @@ -53,9 +52,17 @@ class CompiledFile( else return surroundingExpr } + /** + * Looks for a reference expression at the given cursor. + * This is currently used by many features in the language server. + * Unfortunately, it fails to find declarations for JDK symbols. + * [referenceExpressionAtPoint] provides an alternative implementation that can find JDK symbols. + * It cannot, however, replace this method at the moment. + * TODO: Investigate why this method doesn't find JDK symbols. + */ fun referenceAtPoint(cursor: Int): Pair? { val element = parseAtPoint(cursor, asReference = true) - var cursorExpr = element?.findParent() ?: return nullResult("Couldn't find expression at ${describePosition(cursor)} (only found $element)") + val cursorExpr = element?.findParent() ?: return nullResult("Couldn't find expression at ${describePosition(cursor)} (only found $element)") val surroundingExpr = expandForReference(cursor, cursorExpr) val scope = scopeAtPoint(cursor) ?: return nullResult("Couldn't find scope at ${describePosition(cursor)}") val context = bindingContextOf(surroundingExpr, scope) @@ -63,6 +70,15 @@ class CompiledFile( return referenceFromContext(cursor, context) } + /** + * Looks for a reference expression at the given cursor. + * This method is similar to [referenceAtPoint], but the latter fails to find declarations for JDK symbols. + * This method should not be used for anything other than finding definitions (at least for now). + */ + fun referenceExpressionAtPoint(cursor: Int): Pair? { + return referenceFromContext(cursor, compile) + } + private fun referenceFromContext(cursor: Int, context: BindingContext): Pair? { val targets = context.getSliceContents(BindingContext.REFERENCE_TARGET) return targets.asSequence() @@ -203,9 +219,3 @@ class CompiledFile( return "$file ${start.line}:${start.character + 1}-${end.line + 1}:${end.character + 1}" } } - -private fun fileName(file: KtFile): String { - val parts = file.name.split('/') - - return parts.last() -} diff --git a/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt b/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt index 9d3805e1..76fcdbdb 100644 --- a/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt +++ b/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt @@ -17,6 +17,7 @@ class CompilerClassPath(private val config: CompilerConfiguration) : Closeable { private val javaSourcePath = mutableSetOf() private val buildScriptClassPath = mutableSetOf() val classPath = mutableSetOf() + val javaHome: String? = System.getProperty("java.home", null) var compiler = Compiler(javaSourcePath, classPath.map { it.compiledJar }.toSet(), buildScriptClassPath) private set diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt index de4b093d..f1d90fcf 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt @@ -7,15 +7,14 @@ import org.eclipse.lsp4j.services.LanguageClient import org.eclipse.lsp4j.services.LanguageClientAware import org.eclipse.lsp4j.services.LanguageServer import org.javacs.kt.command.ALL_COMMANDS -import org.javacs.kt.externalsources.JarClassContentProvider -import org.javacs.kt.externalsources.ClassPathSourceJarProvider +import org.javacs.kt.externalsources.ClassContentProvider +import org.javacs.kt.externalsources.ClassPathSourceArchiveProvider import org.javacs.kt.util.AsyncExecutor import org.javacs.kt.util.TemporaryDirectory import org.javacs.kt.util.parseURI import org.javacs.kt.progress.Progress import org.javacs.kt.progress.LanguageClientProgress import org.javacs.kt.semantictokens.semanticTokensLegend -import java.net.URI import java.io.Closeable import java.nio.file.Paths import java.util.concurrent.CompletableFuture @@ -26,7 +25,7 @@ class KotlinLanguageServer : LanguageServer, LanguageClientAware, Closeable { val classPath = CompilerClassPath(config.compiler) private val tempDirectory = TemporaryDirectory() - private val uriContentProvider = URIContentProvider(JarClassContentProvider(config.externalSources, classPath, tempDirectory, ClassPathSourceJarProvider(classPath))) + private val uriContentProvider = URIContentProvider(ClassContentProvider(config.externalSources, classPath, tempDirectory, ClassPathSourceArchiveProvider(classPath))) val sourcePath = SourcePath(classPath, uriContentProvider, config.indexing) val sourceFiles = SourceFiles(sourcePath, uriContentProvider) diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensionService.kt b/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensionService.kt index 6fff3185..e8566262 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensionService.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensionService.kt @@ -1,13 +1,8 @@ package org.javacs.kt import org.eclipse.lsp4j.* -import org.javacs.kt.externalsources.JarClassContentProvider -import org.javacs.kt.externalsources.toKlsURI import org.javacs.kt.util.AsyncExecutor -import org.javacs.kt.util.noResult import org.javacs.kt.util.parseURI -import java.net.URI -import java.net.URISyntaxException import java.util.concurrent.CompletableFuture class KotlinProtocolExtensionService( diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt b/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt index 72174f50..86ea152f 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt @@ -8,7 +8,6 @@ import org.javacs.kt.codeaction.codeActions import org.javacs.kt.completion.* import org.javacs.kt.definition.goToDefinition import org.javacs.kt.diagnostic.convertDiagnostic -import org.javacs.kt.externalsources.JarClassContentProvider import org.javacs.kt.formatting.formatKotlinCode import org.javacs.kt.hover.hoverAt import org.javacs.kt.position.offset @@ -26,13 +25,11 @@ import org.javacs.kt.util.TemporaryDirectory import org.javacs.kt.util.parseURI import org.javacs.kt.util.describeURI import org.javacs.kt.util.describeURIs -import org.javacs.kt.command.JAVA_TO_KOTLIN_COMMAND import org.javacs.kt.rename.renameSymbol import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import java.net.URI import java.io.Closeable import java.nio.file.Path -import java.nio.file.Paths import java.time.Duration import java.util.concurrent.CompletableFuture @@ -118,7 +115,7 @@ class KotlinTextDocumentService( LOG.info("Go-to-definition at {}", describePosition(position)) val (file, cursor) = recover(position, Recompile.NEVER) - goToDefinition(file, cursor, uriContentProvider.jarClassContentProvider, tempDirectory, config.externalSources) + goToDefinition(file, cursor, uriContentProvider.classContentProvider, tempDirectory, config.externalSources) ?.let(::listOf) ?.let { Either.forLeft, List>(it) } ?: noResult("Couldn't find definition at ${describePosition(position)}", Either.forLeft(emptyList())) diff --git a/server/src/main/kotlin/org/javacs/kt/SourcePath.kt b/server/src/main/kotlin/org/javacs/kt/SourcePath.kt index 67c63b03..d8376059 100644 --- a/server/src/main/kotlin/org/javacs/kt/SourcePath.kt +++ b/server/src/main/kotlin/org/javacs/kt/SourcePath.kt @@ -8,8 +8,6 @@ import org.javacs.kt.util.describeURI import org.javacs.kt.index.SymbolIndex import org.javacs.kt.progress.Progress import com.intellij.lang.Language -import org.jetbrains.kotlin.container.ComponentProvider -import org.jetbrains.kotlin.container.getService import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.BindingContext @@ -48,7 +46,7 @@ class SourcePath( var parsed: KtFile? = null, var compiledFile: KtFile? = null, var compiledContext: BindingContext? = null, - var compiledContainer: ComponentProvider? = null, + var module: ModuleDescriptor? = null, val language: Language? = null, val isTemporary: Boolean = false // A temporary source file will not be returned by .all() ) { @@ -66,7 +64,7 @@ class SourcePath( parsed = null compiledFile = null compiledContext = null - compiledContainer = null + module = null } fun parse() { @@ -97,10 +95,10 @@ class SourcePath( val oldFile = clone() - val (context, container) = cp.compiler.compileKtFile(parsed!!, allIncludingThis(), kind) + val (context, module) = cp.compiler.compileKtFile(parsed!!, allIncludingThis(), kind) parseDataWriteLock.withLock { compiledContext = context - compiledContainer = container + this.module = module compiledFile = parsed } @@ -117,7 +115,7 @@ class SourcePath( parseIfChanged().apply { compileIfNull() }.let { doPrepareCompiledFile() } private fun doPrepareCompiledFile(): CompiledFile = - CompiledFile(content, compiledFile!!, compiledContext!!, compiledContainer!!, allIncludingThis(), cp, isScript, kind) + CompiledFile(content, compiledFile!!, compiledContext!!, module!!, allIncludingThis(), cp, isScript, kind) private fun allIncludingThis(): Collection = parseIfChanged().let { if (isTemporary) (all().asSequence() + sequenceOf(parsed!!)).toList() @@ -125,7 +123,7 @@ class SourcePath( } // Creates a shallow copy - fun clone(): SourceFile = SourceFile(uri, content, path, parsed, compiledFile, compiledContext, compiledContainer, language, isTemporary) + fun clone(): SourceFile = SourceFile(uri, content, path, parsed, compiledFile, compiledContext, module, language, isTemporary) } private fun sourceFile(uri: URI): SourceFile { @@ -214,7 +212,7 @@ class SourcePath( // Get all the files. This will parse them if they changed val allFiles = all() beforeCompileCallback.invoke() - val (context, container) = cp.compiler.compileKtFiles(parse.values, allFiles, kind) + val (context, module) = cp.compiler.compileKtFiles(parse.values, allFiles, kind) // Update cache for ((f, parsed) in parse) { @@ -223,7 +221,7 @@ class SourcePath( //only updated if the parsed file didn't change: f.compiledFile = parsed f.compiledContext = context - f.compiledContainer = container + f.module = module } } } @@ -257,9 +255,9 @@ class SourcePath( fun refreshDependencyIndexes() { compileAllFiles() - val container = files.values.first { it.compiledContainer != null }.compiledContainer - if (container != null) { - refreshDependencyIndexes(container) + val module = files.values.first { it.module != null }.module + if (module != null) { + refreshDependencyIndexes(module) } } @@ -279,9 +277,8 @@ class SourcePath( /** * Refreshes the indexes. If already done, refreshes only the declarations in the files that were changed. */ - private fun refreshDependencyIndexes(container: ComponentProvider) = indexAsync.execute { + private fun refreshDependencyIndexes(module: ModuleDescriptor) = indexAsync.execute { if (indexEnabled) { - val module = container.getService(ModuleDescriptor::class.java) val declarations = getDeclarationDescriptors(files.values) index.refresh(module, declarations) } @@ -291,9 +288,8 @@ class SourcePath( private fun getDeclarationDescriptors(files: Collection) = files.flatMap { file -> val compiledFile = file.compiledFile ?: file.parsed - val compiledContainer = file.compiledContainer - if (compiledFile != null && compiledContainer != null) { - val module = compiledContainer.getService(ModuleDescriptor::class.java) + val module = file.module + if (compiledFile != null && module != null) { module.getPackage(compiledFile.packageFqName).memberScope.getContributedDescriptors( DescriptorKindFilter.ALL ) { name -> compiledFile.declarations.map { it.name }.contains(name.toString()) } diff --git a/server/src/main/kotlin/org/javacs/kt/URIContentProvider.kt b/server/src/main/kotlin/org/javacs/kt/URIContentProvider.kt index a46233e9..fe54b418 100644 --- a/server/src/main/kotlin/org/javacs/kt/URIContentProvider.kt +++ b/server/src/main/kotlin/org/javacs/kt/URIContentProvider.kt @@ -1,24 +1,23 @@ package org.javacs.kt import java.net.URI -import java.net.URLDecoder -import java.nio.charset.StandardCharsets import java.nio.file.Paths -import org.javacs.kt.externalsources.JarClassContentProvider +import org.javacs.kt.externalsources.ClassContentProvider import org.javacs.kt.externalsources.toKlsURI import org.javacs.kt.util.KotlinLSException -import org.javacs.kt.util.partitionAroundLast /** * Fetches the content of Kotlin files identified by a URI. */ class URIContentProvider( - val jarClassContentProvider: JarClassContentProvider + val classContentProvider: ClassContentProvider ) { fun contentOf(uri: URI): String = when (uri.scheme) { "file" -> Paths.get(uri).toFile().readText() - "kls" -> uri.toKlsURI()?.let { jarClassContentProvider.contentOf(it).second } - ?: throw KotlinLSException("Could not find ${uri}") + "kls" -> { + uri.toKlsURI()?.let { classContentProvider.contentOf(it).second } + ?: throw KotlinLSException("Could not find $uri") + } else -> throw KotlinLSException("Unrecognized scheme ${uri.scheme}") } } diff --git a/server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt b/server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt index 4bff8995..77ce8f19 100644 --- a/server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt +++ b/server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt @@ -1,32 +1,17 @@ package org.javacs.kt.compiler -import com.intellij.codeInsight.NullableNotNullManager import com.intellij.lang.Language -import com.intellij.openapi.Disposable import com.intellij.openapi.util.Disposer import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.openapi.vfs.VirtualFileSystem import com.intellij.psi.PsiFile import com.intellij.psi.PsiFileFactory -import com.intellij.mock.MockProject import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback -import org.jetbrains.kotlin.cli.jvm.compiler.CliBindingTrace -import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles -import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment -import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoots import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots -import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser -import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration as KotlinCompilerConfiguration -import org.jetbrains.kotlin.config.JVMConfigurationKeys -import org.jetbrains.kotlin.config.JvmTarget -import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl -import org.jetbrains.kotlin.config.ApiVersion -import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.container.ComponentProvider import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar @@ -37,30 +22,17 @@ import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingTraceContext import org.jetbrains.kotlin.resolve.LazyTopDownAnalyzer import org.jetbrains.kotlin.resolve.TopDownAnalysisMode -import org.jetbrains.kotlin.resolve.calls.components.InferenceSession -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo -import org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension import org.jetbrains.kotlin.resolve.lazy.declarations.FileBasedDeclarationProviderFactory -import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar import org.jetbrains.kotlin.scripting.compiler.plugin.definitions.CliScriptDefinitionProvider import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys -import org.jetbrains.kotlin.scripting.definitions.ScriptCompilationConfigurationFromDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider -import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider -import org.jetbrains.kotlin.scripting.definitions.StandardScriptDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition // Legacy import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition import org.jetbrains.kotlin.scripting.definitions.getEnvironment -import org.jetbrains.kotlin.scripting.extensions.ScriptExtraImportsProviderExtension import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate -import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices -import org.jetbrains.kotlin.util.KotlinFrontEndException -import org.jetbrains.kotlin.utils.PathUtil import java.io.Closeable -import java.io.File import java.nio.file.Path import java.nio.file.Paths import java.net.URLClassLoader @@ -69,7 +41,6 @@ import kotlin.concurrent.withLock import kotlin.script.dependencies.Environment import kotlin.script.dependencies.ScriptContents import kotlin.script.experimental.dependencies.ScriptDependencies -import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult import kotlin.script.experimental.host.ScriptingHostConfiguration @@ -80,6 +51,19 @@ import org.javacs.kt.LOG import org.javacs.kt.CompilerConfiguration import org.javacs.kt.util.KotlinLSException import org.javacs.kt.util.LoggingMessageCollector +import org.jetbrains.kotlin.cli.jvm.compiler.CliBindingTrace +import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles +import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment +import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM +import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.container.getService +import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.resolve.calls.components.InferenceSession +import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo +import org.jetbrains.kotlin.resolve.scopes.LexicalScope +import org.jetbrains.kotlin.types.TypeUtils +import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices +import org.jetbrains.kotlin.util.KotlinFrontEndException private val GRADLE_DSL_DEPENDENCY_PATTERN = Regex("^gradle-(?:kotlin-dsl|core).*\\.jar$") @@ -515,10 +499,10 @@ class Compiler(javaSourcePath: Set, classPath: Set, buildScriptClass fun psiFileFactoryFor(kind: CompilationKind): PsiFileFactory = PsiFileFactory.getInstance(compileEnvironmentFor(kind).environment.project) - fun compileKtFile(file: KtFile, sourcePath: Collection, kind: CompilationKind = CompilationKind.DEFAULT): Pair = + fun compileKtFile(file: KtFile, sourcePath: Collection, kind: CompilationKind = CompilationKind.DEFAULT): Pair = compileKtFiles(listOf(file), sourcePath, kind) - fun compileKtFiles(files: Collection, sourcePath: Collection, kind: CompilationKind = CompilationKind.DEFAULT): Pair { + fun compileKtFiles(files: Collection, sourcePath: Collection, kind: CompilationKind = CompilationKind.DEFAULT): Pair { if (kind == CompilationKind.BUILD_SCRIPT) { // Print the (legacy) script template used by the compiled Kotlin DSL build file files.forEach { LOG.debug { "$it -> ScriptDefinition: ${it.findScriptDefinition()?.asLegacyOrNull()?.template?.simpleName}" } } @@ -527,8 +511,9 @@ class Compiler(javaSourcePath: Set, classPath: Set, buildScriptClass compileLock.withLock { val compileEnv = compileEnvironmentFor(kind) val (container, trace) = compileEnv.createContainer(sourcePath) + val module = container.getService(ModuleDescriptor::class.java) container.get().analyzeDeclarations(TopDownAnalysisMode.TopLevelDeclarations, files) - return Pair(trace.bindingContext, container) + return Pair(trace.bindingContext, module) } } @@ -536,7 +521,8 @@ class Compiler(javaSourcePath: Set, classPath: Set, buildScriptClass try { // Use same lock as 'compileFile' to avoid concurrency issues such as #42 compileLock.withLock { - val (container, trace) = compileEnvironmentFor(kind).createContainer(sourcePath) + val compileEnv = compileEnvironmentFor(kind) + val (container, trace) = compileEnv.createContainer(sourcePath) val incrementalCompiler = container.get() incrementalCompiler.getTypeInfo( scopeWithImports, diff --git a/server/src/main/kotlin/org/javacs/kt/completion/Completions.kt b/server/src/main/kotlin/org/javacs/kt/completion/Completions.kt index 75949d2f..8b07ac9b 100644 --- a/server/src/main/kotlin/org/javacs/kt/completion/Completions.kt +++ b/server/src/main/kotlin/org/javacs/kt/completion/Completions.kt @@ -21,7 +21,6 @@ import org.javacs.kt.util.toPath import org.javacs.kt.util.onEachIndexed import org.javacs.kt.position.location import org.jetbrains.kotlin.builtins.KotlinBuiltIns -import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor @@ -45,7 +44,6 @@ import org.jetbrains.kotlin.resolve.scopes.getDescriptorsFiltered import org.jetbrains.kotlin.resolve.scopes.utils.parentsWithSelf import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.TypeUtils -import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.types.typeUtil.replaceArgumentsWithStarProjections import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import java.util.concurrent.TimeUnit @@ -278,7 +276,7 @@ private fun elementCompletions(file: CompiledFile, cursor: Int, surroundingEleme // import x.y.? is KtImportDirective -> { LOG.info("Completing import '{}'", surroundingElement.text) - val module = file.container.get() + val module = file.module val match = Regex("import ((\\w+\\.)*)[\\w*]*").matchEntire(surroundingElement.text) ?: return doesntLookLikeImport(surroundingElement) val parentDot = if (match.groupValues[1].isNotBlank()) match.groupValues[1] else "." val parent = parentDot.substring(0, parentDot.length - 1) @@ -289,7 +287,7 @@ private fun elementCompletions(file: CompiledFile, cursor: Int, surroundingEleme // package x.y.? is KtPackageDirective -> { LOG.info("Completing package '{}'", surroundingElement.text) - val module = file.container.get() + val module = file.module val match = Regex("package ((\\w+\\.)*)[\\w*]*").matchEntire(surroundingElement.text) ?: return doesntLookLikePackage(surroundingElement) val parentDot = if (match.groupValues[1].isNotBlank()) match.groupValues[1] else "." diff --git a/server/src/main/kotlin/org/javacs/kt/definition/GoToDefinition.kt b/server/src/main/kotlin/org/javacs/kt/definition/GoToDefinition.kt index 434d75cd..96082708 100644 --- a/server/src/main/kotlin/org/javacs/kt/definition/GoToDefinition.kt +++ b/server/src/main/kotlin/org/javacs/kt/definition/GoToDefinition.kt @@ -6,8 +6,7 @@ import java.nio.file.Path import org.javacs.kt.CompiledFile import org.javacs.kt.LOG import org.javacs.kt.ExternalSourcesConfiguration -import org.javacs.kt.classpath.ClassPathEntry -import org.javacs.kt.externalsources.JarClassContentProvider +import org.javacs.kt.externalsources.ClassContentProvider import org.javacs.kt.externalsources.toKlsURI import org.javacs.kt.externalsources.KlsURI import org.javacs.kt.position.location @@ -26,11 +25,11 @@ private val definitionPattern = Regex("(?:class|interface|object|fun)\\s+(\\w+)" fun goToDefinition( file: CompiledFile, cursor: Int, - jarClassContentProvider: JarClassContentProvider, + classContentProvider: ClassContentProvider, tempDir: TemporaryDirectory, config: ExternalSourcesConfiguration ): Location? { - val (_, target) = file.referenceAtPoint(cursor) ?: return null + val (_, target) = file.referenceExpressionAtPoint(cursor) ?: return null LOG.info("Found declaration descriptor {}", target) var destination = location(target) @@ -43,9 +42,9 @@ fun goToDefinition( if (destination != null) { val rawClassURI = destination.uri - if (isInsideJar(rawClassURI)) { + if (isInsideArchive(rawClassURI)) { parseURI(rawClassURI).toKlsURI()?.let { klsURI -> - val (klsSourceURI, content) = jarClassContentProvider.contentOf(klsURI) + val (klsSourceURI, content) = classContentProvider.contentOf(klsURI) if (config.useKlsScheme) { // Defer decompilation until a jarClassContents request is sent @@ -87,4 +86,4 @@ fun goToDefinition( return destination } -private fun isInsideJar(uri: String) = uri.contains(".jar!") +private fun isInsideArchive(uri: String) = uri.contains("!") diff --git a/server/src/main/kotlin/org/javacs/kt/externalsources/JarClassContentProvider.kt b/server/src/main/kotlin/org/javacs/kt/externalsources/ClassContentProvider.kt similarity index 84% rename from server/src/main/kotlin/org/javacs/kt/externalsources/JarClassContentProvider.kt rename to server/src/main/kotlin/org/javacs/kt/externalsources/ClassContentProvider.kt index 356e5fdf..715308ea 100644 --- a/server/src/main/kotlin/org/javacs/kt/externalsources/JarClassContentProvider.kt +++ b/server/src/main/kotlin/org/javacs/kt/externalsources/ClassContentProvider.kt @@ -14,13 +14,13 @@ import java.util.LinkedHashMap /** * Provides the source code for classes located inside - * compiled or source JARs. + * compiled or source archives, such as JARs or ZIPs. */ -class JarClassContentProvider( +class ClassContentProvider( private val config: ExternalSourcesConfiguration, private val cp: CompilerClassPath, private val tempDir: TemporaryDirectory, - private val sourceJarProvider: SourceJarProvider, + private val sourceArchiveProvider: SourceArchiveProvider, private val decompiler: Decompiler = FernflowerDecompiler() ) { /** Maps recently used (source-)KLS-URIs to their source contents (e.g. decompiled code) and the file extension. */ @@ -29,16 +29,16 @@ class JarClassContentProvider( } /** - * Fetches the contents of a compiled class/source file in a JAR + * Fetches the contents of a compiled class/source file in an archive * and another URI which can be used to refer to these extracted * contents. - * If the file is inside a source JAR, the source code is returned as is. + * If the file is inside a source archive, the source code is returned as is. */ - public fun contentOf(uri: KlsURI): Pair { - val resolvedUri = sourceJarProvider.fetchSourceJar(uri.jarPath)?.let(uri.withSource(true)::withJarPath) ?: uri + fun contentOf(uri: KlsURI): Pair { + val resolvedUri = sourceArchiveProvider.fetchSourceArchive(uri.archivePath)?.let(uri.withSource(true)::withArchivePath) ?: uri val key = resolvedUri.toString() val (contents, extension) = cachedContents[key] ?: run { - LOG.info("Finding contents of {}", describeURI(uri.fileUri)) + LOG.info("Finding contents of {}", describeURI(resolvedUri.fileUri)) tryReadContentOf(resolvedUri) ?: tryReadContentOf(resolvedUri.withFileExtension("class")) ?: tryReadContentOf(resolvedUri.withFileExtension("java")) diff --git a/server/src/main/kotlin/org/javacs/kt/externalsources/ClassPathSourceArchiveProvider.kt b/server/src/main/kotlin/org/javacs/kt/externalsources/ClassPathSourceArchiveProvider.kt new file mode 100644 index 00000000..d777f395 --- /dev/null +++ b/server/src/main/kotlin/org/javacs/kt/externalsources/ClassPathSourceArchiveProvider.kt @@ -0,0 +1,29 @@ +package org.javacs.kt.externalsources + +import org.javacs.kt.CompilerClassPath +import java.io.File +import java.nio.file.Path +import java.nio.file.Paths + +class ClassPathSourceArchiveProvider( + private val cp: CompilerClassPath +) : SourceArchiveProvider { + override fun fetchSourceArchive(compiledArchive: Path): Path? = + getJdkSource(compiledArchive) ?: cp.classPath.firstOrNull { it.compiledJar == compiledArchive }?.sourceJar + + /** + * Checks if the given path is inside the JDK. If it is, we return the corresponding source zip. + * Note that this method currently doesn't take into the account the JDK version, which means JDK source code + * is only available for JDK 9+ builds. + * TODO: improve this resolution logic to work for older JDK versions as well. + */ + private fun getJdkSource(path: Path): Path? { + cp.javaHome?.let { + val javaHomePath = File(it).toPath() + if (path == javaHomePath) { + return Paths.get(path.toString(), "lib", "src.zip") + } + } + return null + } +} diff --git a/server/src/main/kotlin/org/javacs/kt/externalsources/ClassPathSourceJarProvider.kt b/server/src/main/kotlin/org/javacs/kt/externalsources/ClassPathSourceJarProvider.kt deleted file mode 100644 index fab86e83..00000000 --- a/server/src/main/kotlin/org/javacs/kt/externalsources/ClassPathSourceJarProvider.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.javacs.kt.externalsources - -import org.javacs.kt.CompilerClassPath -import java.nio.file.Path - -class ClassPathSourceJarProvider( - private val cp: CompilerClassPath -) : SourceJarProvider { - override fun fetchSourceJar(compiledJar: Path): Path? = - cp.classPath.firstOrNull { it.compiledJar == compiledJar }?.sourceJar -} diff --git a/server/src/main/kotlin/org/javacs/kt/externalsources/Decompiler.kt b/server/src/main/kotlin/org/javacs/kt/externalsources/Decompiler.kt index 5d34a18f..00e0aa48 100644 --- a/server/src/main/kotlin/org/javacs/kt/externalsources/Decompiler.kt +++ b/server/src/main/kotlin/org/javacs/kt/externalsources/Decompiler.kt @@ -2,10 +2,10 @@ package org.javacs.kt.externalsources import java.nio.file.Path -interface Decompiler : SourceJarProvider { +interface Decompiler : SourceArchiveProvider { fun decompileClass(compiledClass: Path): Path fun decompileJar(compiledJar: Path): Path - override fun fetchSourceJar(compiledJar: Path) = decompileJar(compiledJar) + override fun fetchSourceArchive(compiledArchive: Path) = decompileJar(compiledArchive) } diff --git a/server/src/main/kotlin/org/javacs/kt/externalsources/KlsURI.kt b/server/src/main/kotlin/org/javacs/kt/externalsources/KlsURI.kt index b901c502..4a3dc4b5 100644 --- a/server/src/main/kotlin/org/javacs/kt/externalsources/KlsURI.kt +++ b/server/src/main/kotlin/org/javacs/kt/externalsources/KlsURI.kt @@ -7,18 +7,20 @@ import java.net.URI import java.net.URL import java.net.JarURLConnection import java.io.BufferedReader +import java.io.File import java.nio.file.Path import java.nio.file.Files import java.nio.file.Paths +import java.util.zip.ZipFile fun URI.toKlsURI(): KlsURI? = when (scheme) { - "kls" -> KlsURI(URI("kls:$schemeSpecificPart")) + "kls" -> KlsURI(URI("kls:${schemeSpecificPart.replace(" ", "%20")}")) "file" -> KlsURI(URI("kls:$this")) else -> null } /** - * Identifies a class or source file inside a JAR archive using a Uniform + * Identifies a class or source file inside an archive using a Uniform * Resource Identifier (URI) with a "kls" (Kotlin language server) scheme. * The URI should be structured as follows: * @@ -37,6 +39,12 @@ data class KlsURI(val fileUri: URI, val query: Map) { override fun toString(): String = parameterName } + enum class ArchiveType(val delimiter: String) { + JAR("!"), + ZIP("!"), + JDK("!/modules") + } + private val queryString: String get() = if (query.isEmpty()) "" else query.entries.fold("?") { accum, next -> "$accum${next.key}=${next.value}" } @@ -48,21 +56,33 @@ data class KlsURI(val fileUri: URI, val query: Map) { .takeIf { it.size > 1 } ?.lastOrNull() - val jarPath: Path - get() = Paths.get(parseURI(fileUri.schemeSpecificPart.split("!")[0])) - val innerPath: String? - get() = fileUri.schemeSpecificPart.split("!", limit = 2).get(1) + private val archiveType: ArchiveType + get() = when { + fileUri.schemeSpecificPart.contains("!/modules") -> { + ArchiveType.JDK + } + fileUri.schemeSpecificPart.contains(".zip!") -> { + ArchiveType.ZIP + } + else -> { + ArchiveType.JAR + } + } + + val archivePath: Path + get() = Paths.get(parseURI(fileUri.schemeSpecificPart.split(archiveType.delimiter)[0])) + + private val innerPath: String + get() = fileUri.schemeSpecificPart.split(archiveType.delimiter, limit = 2)[1] val source: Boolean get() = query[QueryParam.SOURCE]?.toBoolean() ?: false - val isCompiled: Boolean - get() = fileExtension == "class" constructor(uri: URI) : this(parseKlsURIFileURI(uri), parseKlsURIQuery(uri)) - // If the newJarPath doesn't have the kls scheme, it is added in the returned KlsURI. - fun withJarPath(newJarPath: Path): KlsURI? = - URI(newJarPath.toUri().toString() + (innerPath?.let { "!$it" } ?: "")).toKlsURI()?.let { KlsURI(it.fileUri, query) } + // If the newArchivePath doesn't have the kls scheme, it is added in the returned KlsURI. + fun withArchivePath(newArchivePath: Path): KlsURI? = + URI(newArchivePath.toUri().toString() + (innerPath.let { "!$it" } )).toKlsURI()?.let { KlsURI(it.fileUri, query) } fun withFileExtension(newExtension: String): KlsURI { val (parentUri, fileName) = fileUri.toString().partitionAroundLast("/") @@ -77,7 +97,7 @@ data class KlsURI(val fileUri: URI, val query: Map) { return KlsURI(fileUri, newQuery) } - fun toURI(): URI = URI(fileUri.toString() + queryString) + private fun toURI(): URI = URI(fileUri.toString() + queryString) private fun toJarURL(): URL = URL("jar:${fileUri.schemeSpecificPart}") @@ -93,11 +113,20 @@ data class KlsURI(val fileUri: URI, val query: Map) { return result } - fun readContents(): String = withJarURLConnection { - it.jarFile - .getInputStream(it.jarEntry) - .bufferedReader() - .use(BufferedReader::readText) + fun readContents(): String { + return if (archiveType == ArchiveType.ZIP) { + val zipFile = ZipFile(File("$archivePath")) + zipFile.getInputStream(zipFile.getEntry(innerPath.trimStart('/'))) + .bufferedReader() + .use(BufferedReader::readText) + } else { + withJarURLConnection { + it.jarFile + .getInputStream(it.jarEntry) + .bufferedReader() + .use(BufferedReader::readText) + } + } } fun extractToTemporaryFile(dir: TemporaryDirectory): Path = withJarURLConnection { diff --git a/server/src/main/kotlin/org/javacs/kt/externalsources/SourceArchiveProvider.kt b/server/src/main/kotlin/org/javacs/kt/externalsources/SourceArchiveProvider.kt new file mode 100644 index 00000000..12a3a740 --- /dev/null +++ b/server/src/main/kotlin/org/javacs/kt/externalsources/SourceArchiveProvider.kt @@ -0,0 +1,7 @@ +package org.javacs.kt.externalsources + +import java.nio.file.Path + +interface SourceArchiveProvider { + fun fetchSourceArchive(compiledArchive: Path): Path? +} diff --git a/server/src/main/kotlin/org/javacs/kt/externalsources/SourceJarProvider.kt b/server/src/main/kotlin/org/javacs/kt/externalsources/SourceJarProvider.kt deleted file mode 100644 index 0eafe90e..00000000 --- a/server/src/main/kotlin/org/javacs/kt/externalsources/SourceJarProvider.kt +++ /dev/null @@ -1,7 +0,0 @@ -package org.javacs.kt.externalsources - -import java.nio.file.Path - -interface SourceJarProvider { - fun fetchSourceJar(compiledJar: Path): Path? -} diff --git a/server/src/main/kotlin/org/javacs/kt/hover/Hovers.kt b/server/src/main/kotlin/org/javacs/kt/hover/Hovers.kt index 718e193e..f16d13a3 100644 --- a/server/src/main/kotlin/org/javacs/kt/hover/Hovers.kt +++ b/server/src/main/kotlin/org/javacs/kt/hover/Hovers.kt @@ -3,26 +3,18 @@ package org.javacs.kt.hover import org.eclipse.lsp4j.Hover import org.eclipse.lsp4j.MarkupContent import org.eclipse.lsp4j.Range -import org.eclipse.lsp4j.jsonrpc.messages.Either -import com.intellij.openapi.util.TextRange -import com.intellij.psi.PsiElement import com.intellij.psi.PsiDocCommentBase import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtCallableDeclaration -import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.CallableDescriptor import org.jetbrains.kotlin.descriptors.ClassifierDescriptor import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector -import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.renderer.ClassifierNamePolicy import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.renderer.RenderingFormat import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.calls.callUtil.getType -import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory -import org.jetbrains.kotlin.kdoc.psi.api.KDoc import org.javacs.kt.CompiledFile import org.javacs.kt.completion.DECL_RENDERER import org.javacs.kt.position.position @@ -43,9 +35,9 @@ fun hoverAt(file: CompiledFile, cursor: Int): Hover? { private fun typeHoverAt(file: CompiledFile, cursor: Int): Hover? { val expression = file.parseAtPoint(cursor)?.findParent() ?: return null - var javaDoc: String = expression.children.mapNotNull { (it as? PsiDocCommentBase)?.text }.map(::renderJavaDoc).firstOrNull() ?: "" + val javaDoc: String = expression.children.mapNotNull { (it as? PsiDocCommentBase)?.text }.map(::renderJavaDoc).firstOrNull() ?: "" val scope = file.scopeAtPoint(cursor) ?: return null - val hoverText = renderTypeOf(expression, file.bindingContextOf(expression, scope)) ?: return null + val hoverText = renderTypeOf(expression, file.bindingContextOf(expression, scope)) val hover = MarkupContent("markdown", listOf("```kotlin\n$hoverText\n```", javaDoc).filter { it.isNotEmpty() }.joinToString("\n---\n")) return Hover(hover) } @@ -67,7 +59,7 @@ private val TYPE_RENDERER: DescriptorRenderer by lazy { DescriptorRenderer.COMPA private fun renderJavaDoc(text: String): String { val split = text.split('\n') return split.mapIndexed { i, it -> - var ret: String + val ret: String if (i == 0) ret = it.substring(it.indexOf("/**") + 3) // get rid of the start comment characters else if (i == split.size - 1) ret = it.substring(it.indexOf("*/") + 2) // get rid of the end comment characters else ret = it.substring(it.indexOf('*') + 1) // get rid of any leading * From 747d3f3c12045e2028ec2d909765282a645f79c5 Mon Sep 17 00:00:00 2001 From: daplf Date: Mon, 21 Mar 2022 00:09:38 +0000 Subject: [PATCH 06/34] Format --- server/src/main/kotlin/org/javacs/kt/URIContentProvider.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/server/src/main/kotlin/org/javacs/kt/URIContentProvider.kt b/server/src/main/kotlin/org/javacs/kt/URIContentProvider.kt index fe54b418..300608fb 100644 --- a/server/src/main/kotlin/org/javacs/kt/URIContentProvider.kt +++ b/server/src/main/kotlin/org/javacs/kt/URIContentProvider.kt @@ -14,10 +14,8 @@ class URIContentProvider( ) { fun contentOf(uri: URI): String = when (uri.scheme) { "file" -> Paths.get(uri).toFile().readText() - "kls" -> { - uri.toKlsURI()?.let { classContentProvider.contentOf(it).second } - ?: throw KotlinLSException("Could not find $uri") - } + "kls" -> uri.toKlsURI()?.let { classContentProvider.contentOf(it).second } + ?: throw KotlinLSException("Could not find $uri") else -> throw KotlinLSException("Unrecognized scheme ${uri.scheme}") } } From 1cd8d677b58b2d81647fca77b89350baeaeff99e Mon Sep 17 00:00:00 2001 From: daplf Date: Wed, 23 Mar 2022 15:27:58 +0000 Subject: [PATCH 07/34] Setup custom KotlinLanguageClient --- .../main/kotlin/org/javacs/kt/CompilerClassPath.kt | 12 +++--------- .../kotlin/org/javacs/kt/KotlinLanguageClient.kt | 14 ++++++++++++++ .../kotlin/org/javacs/kt/KotlinLanguageServer.kt | 10 +++++++--- server/src/main/kotlin/org/javacs/kt/Main.kt | 3 ++- .../main/kotlin/org/javacs/kt/compiler/Compiler.kt | 8 ++++---- .../test/kotlin/org/javacs/kt/CompiledFileTest.kt | 2 +- .../src/test/kotlin/org/javacs/kt/CompilerTest.kt | 2 +- .../org/javacs/kt/LanguageServerTestFixture.kt | 3 +-- 8 files changed, 33 insertions(+), 21 deletions(-) create mode 100644 server/src/main/kotlin/org/javacs/kt/KotlinLanguageClient.kt diff --git a/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt b/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt index 450edabe..44c5683b 100644 --- a/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt +++ b/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt @@ -7,8 +7,8 @@ import org.javacs.kt.util.AsyncExecutor import java.io.Closeable import java.io.File import java.nio.file.FileSystems +import java.nio.file.Files import java.nio.file.Path -import java.nio.file.Paths /** * Manages the class path (compiled JARs, etc), the Java source path @@ -19,9 +19,9 @@ class CompilerClassPath(private val config: CompilerConfiguration) : Closeable { private val javaSourcePath = mutableSetOf() private val buildScriptClassPath = mutableSetOf() val classPath = mutableSetOf() - private var outputDirectory: File? = null + val outputDirectory: File = Files.createTempDirectory("klsBuildOutput").toFile() - var compiler = Compiler(javaSourcePath, classPath.map { it.compiledJar }.toSet(), buildScriptClassPath) + var compiler = Compiler(javaSourcePath, classPath.map { it.compiledJar }.toSet(), buildScriptClassPath, outputDirectory) private set private val async = AsyncExecutor() @@ -98,10 +98,6 @@ class CompilerClassPath(private val config: CompilerConfiguration) : Closeable { workspaceRoots.add(root) javaSourcePath.addAll(findJavaSourceFiles(root)) - val outputDir = Paths.get(root.toString(), "kls").toFile() - outputDirectory = outputDir - compiler.outputDirectory = outputDir - return refresh() } @@ -110,8 +106,6 @@ class CompilerClassPath(private val config: CompilerConfiguration) : Closeable { workspaceRoots.remove(root) javaSourcePath.removeAll(findJavaSourceFiles(root)) - outputDirectory = null - compiler.outputDirectory = null return refresh() } diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageClient.kt b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageClient.kt new file mode 100644 index 00000000..346de6f1 --- /dev/null +++ b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageClient.kt @@ -0,0 +1,14 @@ +package org.javacs.kt + +import org.eclipse.lsp4j.jsonrpc.services.JsonNotification +import org.eclipse.lsp4j.jsonrpc.services.JsonSegment +import org.eclipse.lsp4j.services.LanguageClient + +@JsonSegment("kotlin") +interface KotlinLanguageClient : LanguageClient { + + @JsonNotification + fun buildOutputLocationSet(buildOutputLocation: String) { + throw UnsupportedOperationException() + } +} diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt index de4b093d..d534ecec 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt @@ -21,7 +21,7 @@ import java.nio.file.Paths import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture.completedFuture -class KotlinLanguageServer : LanguageServer, LanguageClientAware, Closeable { +class KotlinLanguageServer : LanguageServer, Closeable { val config = Configuration() val classPath = CompilerClassPath(config.compiler) @@ -34,7 +34,7 @@ class KotlinLanguageServer : LanguageServer, LanguageClientAware, Closeable { private val workspaces = KotlinWorkspaceService(sourceFiles, sourcePath, classPath, textDocuments, config) private val protocolExtensions = KotlinProtocolExtensionService(uriContentProvider) - private lateinit var client: LanguageClient + private lateinit var client: KotlinLanguageClient private val async = AsyncExecutor() private var progressFactory: Progress.Factory = Progress.Factory.None @@ -51,7 +51,7 @@ class KotlinLanguageServer : LanguageServer, LanguageClientAware, Closeable { LOG.info("Kotlin Language Server: Version ${VERSION ?: "?"}") } - override fun connect(client: LanguageClient) { + fun connect(client: KotlinLanguageClient) { this.client = client connectLoggingBackend() @@ -132,6 +132,10 @@ class KotlinLanguageServer : LanguageServer, LanguageClientAware, Closeable { InitializeResult(serverCapabilities, serverInfo) } + override fun initialized(params: InitializedParams?) { + client.buildOutputLocationSet(classPath.outputDirectory.absolutePath) + } + private fun connectLoggingBackend() { val backend: (LogMessage) -> Unit = { client.logMessage(MessageParams().apply { diff --git a/server/src/main/kotlin/org/javacs/kt/Main.kt b/server/src/main/kotlin/org/javacs/kt/Main.kt index 137e74c7..de7165f3 100644 --- a/server/src/main/kotlin/org/javacs/kt/Main.kt +++ b/server/src/main/kotlin/org/javacs/kt/Main.kt @@ -6,6 +6,7 @@ import java.util.concurrent.Executors import org.eclipse.lsp4j.launch.LSPLauncher import org.eclipse.lsp4j.ConfigurationParams import org.eclipse.lsp4j.ConfigurationItem +import org.eclipse.lsp4j.jsonrpc.Launcher import org.javacs.kt.util.ExitingInputStream import org.javacs.kt.util.tcpStartServer import org.javacs.kt.util.tcpConnectToClient @@ -43,7 +44,7 @@ fun main(argv: Array) { val server = KotlinLanguageServer() val threads = Executors.newSingleThreadExecutor { Thread(it, "client") } - val launcher = LSPLauncher.createServerLauncher(server, ExitingInputStream(inStream), outStream, threads, { it }) + val launcher = Launcher.createLauncher(server, KotlinLanguageClient::class.java, ExitingInputStream(inStream), outStream, threads) { it } server.connect(launcher.remoteProxy) launcher.startListening() diff --git a/server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt b/server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt index 56cb0ccf..dcb3defe 100644 --- a/server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt +++ b/server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt @@ -440,7 +440,7 @@ enum class CompilationKind { * Incrementally compiles files and expressions. * The basic strategy for compiling one file at-a-time is outlined in OneFilePerformance. */ -class Compiler(javaSourcePath: Set, classPath: Set, buildScriptClassPath: Set = emptySet(), var outputDirectory: File? = null) : Closeable { +class Compiler(javaSourcePath: Set, classPath: Set, buildScriptClassPath: Set = emptySet(), private val outputDirectory: File) : Closeable { private var closed = false private val localFileSystem: VirtualFileSystem @@ -551,15 +551,15 @@ class Compiler(javaSourcePath: Set, classPath: Set, buildScriptClass fun removeGeneratedCode(files: Collection) { files.forEach { file -> file.declarations.forEach { declaration -> - outputDirectory?.resolve( + outputDirectory.resolve( file.packageFqName.asString().replace(".", File.separator) + File.separator + declaration.name + ".class" - )?.delete() + ).delete() } } } fun generateCode(container: ComponentProvider, bindingContext: BindingContext, files: Collection) { - outputDirectory?.let { + outputDirectory.let { compileLock.withLock { val compileEnv = compileEnvironmentFor(CompilationKind.DEFAULT) val state = GenerationState.Builder( diff --git a/server/src/test/kotlin/org/javacs/kt/CompiledFileTest.kt b/server/src/test/kotlin/org/javacs/kt/CompiledFileTest.kt index 61a1560f..a2eaab79 100644 --- a/server/src/test/kotlin/org/javacs/kt/CompiledFileTest.kt +++ b/server/src/test/kotlin/org/javacs/kt/CompiledFileTest.kt @@ -16,7 +16,7 @@ class CompiledFileTest { } } - fun compileFile(): CompiledFile = Compiler(setOf(), setOf()).use { compiler -> + fun compileFile(): CompiledFile = Compiler(setOf(), setOf(), outputDirectory = Files.createTempDirectory("klsBuildOutput").toFile()).use { compiler -> val file = testResourcesRoot().resolve("compiledFile/CompiledFileExample.kt") val content = Files.readAllLines(file).joinToString("\n") val parse = compiler.createKtFile(content, file) diff --git a/server/src/test/kotlin/org/javacs/kt/CompilerTest.kt b/server/src/test/kotlin/org/javacs/kt/CompilerTest.kt index 576a59e7..661ebb9a 100644 --- a/server/src/test/kotlin/org/javacs/kt/CompilerTest.kt +++ b/server/src/test/kotlin/org/javacs/kt/CompilerTest.kt @@ -14,7 +14,7 @@ import org.junit.BeforeClass import java.nio.file.Files class CompilerTest { - val compiler = Compiler(setOf(), setOf()) + val compiler = Compiler(setOf(), setOf(), outputDirectory = Files.createTempDirectory("klsBuildOutput").toFile()) val myTestResources = testResourcesRoot().resolve("compiler") val file = myTestResources.resolve("FileToEdit.kt") val editedText = """ diff --git a/server/src/test/kotlin/org/javacs/kt/LanguageServerTestFixture.kt b/server/src/test/kotlin/org/javacs/kt/LanguageServerTestFixture.kt index 2f88a64f..e12af0bd 100644 --- a/server/src/test/kotlin/org/javacs/kt/LanguageServerTestFixture.kt +++ b/server/src/test/kotlin/org/javacs/kt/LanguageServerTestFixture.kt @@ -1,14 +1,13 @@ package org.javacs.kt import org.eclipse.lsp4j.* -import org.eclipse.lsp4j.services.LanguageClient import org.junit.Before import org.junit.After import java.nio.file.Path import java.nio.file.Paths import java.util.concurrent.CompletableFuture -abstract class LanguageServerTestFixture(relativeWorkspaceRoot: String) : LanguageClient { +abstract class LanguageServerTestFixture(relativeWorkspaceRoot: String) : KotlinLanguageClient { val workspaceRoot = absoluteWorkspaceRoot(relativeWorkspaceRoot) val languageServer = createLanguageServer() val diagnostics = mutableListOf() From d5d7ab3320bc00a6757fcd199efde448134851a2 Mon Sep 17 00:00:00 2001 From: daplf Date: Wed, 23 Mar 2022 17:08:49 +0000 Subject: [PATCH 08/34] Catch UnsupportedOperationException on client extensions --- .../src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt index d534ecec..0599680b 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt @@ -133,7 +133,11 @@ class KotlinLanguageServer : LanguageServer, Closeable { } override fun initialized(params: InitializedParams?) { - client.buildOutputLocationSet(classPath.outputDirectory.absolutePath) + try { + client.buildOutputLocationSet(classPath.outputDirectory.absolutePath) + } catch (ex: UnsupportedOperationException) { + LOG.info("Client does not support notification kotlin/buildOutputLocationSet") + } } private fun connectLoggingBackend() { From 5a38c51f74636952545f537b472ada848f50da35 Mon Sep 17 00:00:00 2001 From: daplf Date: Wed, 23 Mar 2022 19:50:55 +0000 Subject: [PATCH 09/34] Use a request instead of a notification --- .../org/javacs/kt/KotlinLanguageClient.kt | 14 -------------- .../org/javacs/kt/KotlinLanguageServer.kt | 17 ++++------------- .../javacs/kt/KotlinProtocolExtensionService.kt | 12 ++++++------ .../org/javacs/kt/KotlinProtocolExtensions.kt | 3 +++ server/src/main/kotlin/org/javacs/kt/Main.kt | 5 +---- .../org/javacs/kt/LanguageServerTestFixture.kt | 3 ++- 6 files changed, 16 insertions(+), 38 deletions(-) delete mode 100644 server/src/main/kotlin/org/javacs/kt/KotlinLanguageClient.kt diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageClient.kt b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageClient.kt deleted file mode 100644 index 346de6f1..00000000 --- a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageClient.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.javacs.kt - -import org.eclipse.lsp4j.jsonrpc.services.JsonNotification -import org.eclipse.lsp4j.jsonrpc.services.JsonSegment -import org.eclipse.lsp4j.services.LanguageClient - -@JsonSegment("kotlin") -interface KotlinLanguageClient : LanguageClient { - - @JsonNotification - fun buildOutputLocationSet(buildOutputLocation: String) { - throw UnsupportedOperationException() - } -} diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt index 0599680b..02b04f8c 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt @@ -15,13 +15,12 @@ import org.javacs.kt.util.parseURI import org.javacs.kt.progress.Progress import org.javacs.kt.progress.LanguageClientProgress import org.javacs.kt.semantictokens.semanticTokensLegend -import java.net.URI import java.io.Closeable import java.nio.file.Paths import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture.completedFuture -class KotlinLanguageServer : LanguageServer, Closeable { +class KotlinLanguageServer : LanguageServer, LanguageClientAware, Closeable { val config = Configuration() val classPath = CompilerClassPath(config.compiler) @@ -32,9 +31,9 @@ class KotlinLanguageServer : LanguageServer, Closeable { private val textDocuments = KotlinTextDocumentService(sourceFiles, sourcePath, config, tempDirectory, uriContentProvider) private val workspaces = KotlinWorkspaceService(sourceFiles, sourcePath, classPath, textDocuments, config) - private val protocolExtensions = KotlinProtocolExtensionService(uriContentProvider) + private val protocolExtensions = KotlinProtocolExtensionService(uriContentProvider, classPath) - private lateinit var client: KotlinLanguageClient + private lateinit var client: LanguageClient private val async = AsyncExecutor() private var progressFactory: Progress.Factory = Progress.Factory.None @@ -51,7 +50,7 @@ class KotlinLanguageServer : LanguageServer, Closeable { LOG.info("Kotlin Language Server: Version ${VERSION ?: "?"}") } - fun connect(client: KotlinLanguageClient) { + override fun connect(client: LanguageClient) { this.client = client connectLoggingBackend() @@ -132,14 +131,6 @@ class KotlinLanguageServer : LanguageServer, Closeable { InitializeResult(serverCapabilities, serverInfo) } - override fun initialized(params: InitializedParams?) { - try { - client.buildOutputLocationSet(classPath.outputDirectory.absolutePath) - } catch (ex: UnsupportedOperationException) { - LOG.info("Client does not support notification kotlin/buildOutputLocationSet") - } - } - private fun connectLoggingBackend() { val backend: (LogMessage) -> Unit = { client.logMessage(MessageParams().apply { diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensionService.kt b/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensionService.kt index 6fff3185..15ab37f0 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensionService.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensionService.kt @@ -1,21 +1,21 @@ package org.javacs.kt import org.eclipse.lsp4j.* -import org.javacs.kt.externalsources.JarClassContentProvider -import org.javacs.kt.externalsources.toKlsURI import org.javacs.kt.util.AsyncExecutor -import org.javacs.kt.util.noResult import org.javacs.kt.util.parseURI -import java.net.URI -import java.net.URISyntaxException import java.util.concurrent.CompletableFuture class KotlinProtocolExtensionService( - private val uriContentProvider: URIContentProvider + private val uriContentProvider: URIContentProvider, + private val cp: CompilerClassPath ) : KotlinProtocolExtensions { private val async = AsyncExecutor() override fun jarClassContents(textDocument: TextDocumentIdentifier): CompletableFuture = async.compute { uriContentProvider.contentOf(parseURI(textDocument.uri)) } + + override fun getBuildOutputLocation(): CompletableFuture = async.compute { + cp.outputDirectory.absolutePath + } } diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensions.kt b/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensions.kt index 7e14672b..692805b6 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensions.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensions.kt @@ -9,4 +9,7 @@ import java.util.concurrent.CompletableFuture interface KotlinProtocolExtensions { @JsonRequest fun jarClassContents(textDocument: TextDocumentIdentifier): CompletableFuture + + @JsonRequest + fun getBuildOutputLocation(): CompletableFuture } diff --git a/server/src/main/kotlin/org/javacs/kt/Main.kt b/server/src/main/kotlin/org/javacs/kt/Main.kt index de7165f3..87245a4f 100644 --- a/server/src/main/kotlin/org/javacs/kt/Main.kt +++ b/server/src/main/kotlin/org/javacs/kt/Main.kt @@ -4,9 +4,6 @@ import com.beust.jcommander.JCommander import com.beust.jcommander.Parameter import java.util.concurrent.Executors import org.eclipse.lsp4j.launch.LSPLauncher -import org.eclipse.lsp4j.ConfigurationParams -import org.eclipse.lsp4j.ConfigurationItem -import org.eclipse.lsp4j.jsonrpc.Launcher import org.javacs.kt.util.ExitingInputStream import org.javacs.kt.util.tcpStartServer import org.javacs.kt.util.tcpConnectToClient @@ -44,7 +41,7 @@ fun main(argv: Array) { val server = KotlinLanguageServer() val threads = Executors.newSingleThreadExecutor { Thread(it, "client") } - val launcher = Launcher.createLauncher(server, KotlinLanguageClient::class.java, ExitingInputStream(inStream), outStream, threads) { it } + val launcher = LSPLauncher.createServerLauncher(server, ExitingInputStream(inStream), outStream, threads) { it } server.connect(launcher.remoteProxy) launcher.startListening() diff --git a/server/src/test/kotlin/org/javacs/kt/LanguageServerTestFixture.kt b/server/src/test/kotlin/org/javacs/kt/LanguageServerTestFixture.kt index e12af0bd..2f88a64f 100644 --- a/server/src/test/kotlin/org/javacs/kt/LanguageServerTestFixture.kt +++ b/server/src/test/kotlin/org/javacs/kt/LanguageServerTestFixture.kt @@ -1,13 +1,14 @@ package org.javacs.kt import org.eclipse.lsp4j.* +import org.eclipse.lsp4j.services.LanguageClient import org.junit.Before import org.junit.After import java.nio.file.Path import java.nio.file.Paths import java.util.concurrent.CompletableFuture -abstract class LanguageServerTestFixture(relativeWorkspaceRoot: String) : KotlinLanguageClient { +abstract class LanguageServerTestFixture(relativeWorkspaceRoot: String) : LanguageClient { val workspaceRoot = absoluteWorkspaceRoot(relativeWorkspaceRoot) val languageServer = createLanguageServer() val diagnostics = mutableListOf() From 8b24f5a70c368764ca20a7bbe9ffa96933c7821e Mon Sep 17 00:00:00 2001 From: fwcd Date: Tue, 29 Mar 2022 19:32:42 +0200 Subject: [PATCH 10/34] Add pull_request trigger to build workflow --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cf4ad997..bc9f5df3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,5 @@ name: Build -on: [push] +on: [push, pull_request] jobs: build: From e975cf2248b90fe74369e4c075156212be514de1 Mon Sep 17 00:00:00 2001 From: Marie Katrine Ekeberg Date: Sat, 2 Apr 2022 15:21:40 +0200 Subject: [PATCH 11/34] Initial version of a add missing import quick fix. --- .../javacs/kt/KotlinTextDocumentService.kt | 2 +- .../org/javacs/kt/codeaction/CodeAction.kt | 18 +++++---- .../ImplementAbstractFunctionsQuickFix.kt | 7 ++-- .../javacs/kt/codeaction/quickfix/QuickFix.kt | 5 ++- .../org/javacs/kt/completion/Completions.kt | 24 +----------- .../kotlin/org/javacs/kt/imports/Imports.kt | 38 +++++++++++++++++++ .../kotlin/org/javacs/kt/index/SymbolIndex.kt | 4 +- 7 files changed, 61 insertions(+), 37 deletions(-) create mode 100644 server/src/main/kotlin/org/javacs/kt/imports/Imports.kt diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt b/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt index 72174f50..6023d5c0 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt @@ -93,7 +93,7 @@ class KotlinTextDocumentService( override fun codeAction(params: CodeActionParams): CompletableFuture>> = async.compute { val (file, _) = recover(params.textDocument.uri, params.range.start, Recompile.NEVER) - codeActions(file, params.range, params.context) + codeActions(file, sp.index, params.range, params.context) } override fun hover(position: HoverParams): CompletableFuture = async.compute { diff --git a/server/src/main/kotlin/org/javacs/kt/codeaction/CodeAction.kt b/server/src/main/kotlin/org/javacs/kt/codeaction/CodeAction.kt index bbaa355a..1adc4f99 100644 --- a/server/src/main/kotlin/org/javacs/kt/codeaction/CodeAction.kt +++ b/server/src/main/kotlin/org/javacs/kt/codeaction/CodeAction.kt @@ -4,19 +4,23 @@ import org.eclipse.lsp4j.* import org.eclipse.lsp4j.jsonrpc.messages.Either import org.javacs.kt.CompiledFile import org.javacs.kt.codeaction.quickfix.ImplementAbstractFunctionsQuickFix +import org.javacs.kt.codeaction.quickfix.AddMissingImportsQuickFix import org.javacs.kt.command.JAVA_TO_KOTLIN_COMMAND import org.javacs.kt.util.toPath +import org.javacs.kt.index.SymbolIndex val QUICK_FIXES = listOf( - ImplementAbstractFunctionsQuickFix() + ImplementAbstractFunctionsQuickFix(), + AddMissingImportsQuickFix() ) -fun codeActions(file: CompiledFile, range: Range, context: CodeActionContext): List> { - val requestedKinds = context.only ?: listOf(CodeActionKind.Refactor) +fun codeActions(file: CompiledFile, index: SymbolIndex, range: Range, context: CodeActionContext): List> { + // context.only does not work when client is emacs... + val requestedKinds = context.only ?: listOf(CodeActionKind.Refactor, CodeActionKind.QuickFix) return requestedKinds.map { when (it) { CodeActionKind.Refactor -> getRefactors(file, range) - CodeActionKind.QuickFix -> getQuickFixes(file, range, context.diagnostics) + CodeActionKind.QuickFix -> getQuickFixes(file, index, range, context.diagnostics) else -> listOf() } }.flatten() @@ -38,8 +42,8 @@ fun getRefactors(file: CompiledFile, range: Range): List): List> { - return QUICK_FIXES.mapNotNull { - it.compute(file, range, diagnostics) +fun getQuickFixes(file: CompiledFile, index: SymbolIndex, range: Range, diagnostics: List): List> { + return QUICK_FIXES.flatMap { + it.compute(file, index, range, diagnostics) } } diff --git a/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/ImplementAbstractFunctionsQuickFix.kt b/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/ImplementAbstractFunctionsQuickFix.kt index fb6f8bed..cb063951 100644 --- a/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/ImplementAbstractFunctionsQuickFix.kt +++ b/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/ImplementAbstractFunctionsQuickFix.kt @@ -3,6 +3,7 @@ package org.javacs.kt.codeaction.quickfix import org.eclipse.lsp4j.* import org.eclipse.lsp4j.jsonrpc.messages.Either import org.javacs.kt.CompiledFile +import org.javacs.kt.index.SymbolIndex import org.javacs.kt.position.offset import org.javacs.kt.position.position import org.javacs.kt.util.toPath @@ -20,7 +21,7 @@ import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics private const val DEFAULT_TAB_SIZE = 4 class ImplementAbstractFunctionsQuickFix : QuickFix { - override fun compute(file: CompiledFile, range: Range, diagnostics: List): Either? { + override fun compute(file: CompiledFile, index: SymbolIndex, range: Range, diagnostics: List): List> { val diagnostic = findDiagnosticMatch(diagnostics, range) val startCursor = offset(file.content, range.start) @@ -52,10 +53,10 @@ class ImplementAbstractFunctionsQuickFix : QuickFix { codeAction.kind = CodeActionKind.QuickFix codeAction.title = "Implement abstract functions" codeAction.diagnostics = listOf(diagnostic) - return Either.forRight(codeAction) + return listOf(Either.forRight(codeAction)) } } - return null + return listOf() } } diff --git a/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/QuickFix.kt b/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/QuickFix.kt index fd43352a..43000f91 100644 --- a/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/QuickFix.kt +++ b/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/QuickFix.kt @@ -6,12 +6,13 @@ import org.eclipse.lsp4j.Diagnostic import org.eclipse.lsp4j.Range import org.eclipse.lsp4j.jsonrpc.messages.Either import org.javacs.kt.CompiledFile +import org.javacs.kt.index.SymbolIndex import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics import org.jetbrains.kotlin.diagnostics.Diagnostic as KotlinDiagnostic interface QuickFix { - // Computes the quickfix. Return null if the quickfix is not valid. - fun compute(file: CompiledFile, range: Range, diagnostics: List): Either? + // Computes the quickfix. Return empty list if the quickfix is not valid or no alternatives exist. + fun compute(file: CompiledFile, index: SymbolIndex, range: Range, diagnostics: List): List> } fun diagnosticMatch(diagnostic: Diagnostic, range: Range, diagnosticTypes: HashSet): Boolean = diff --git a/server/src/main/kotlin/org/javacs/kt/completion/Completions.kt b/server/src/main/kotlin/org/javacs/kt/completion/Completions.kt index 75949d2f..e9a957ce 100644 --- a/server/src/main/kotlin/org/javacs/kt/completion/Completions.kt +++ b/server/src/main/kotlin/org/javacs/kt/completion/Completions.kt @@ -20,6 +20,7 @@ import org.javacs.kt.util.stringDistance import org.javacs.kt.util.toPath import org.javacs.kt.util.onEachIndexed import org.javacs.kt.position.location +import org.javacs.kt.imports.getImportTextEditEntry import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.container.get import org.jetbrains.kotlin.descriptors.* @@ -142,31 +143,10 @@ private fun indexCompletionItems(file: CompiledFile, cursor: Int, element: KtEle Symbol.Kind.UNKNOWN -> CompletionItemKind.Text } detail = "(import from ${it.fqName.parent()})" - val pos = findImportInsertionPosition(parsedFile, it.fqName) - val prefix = if (importedNames.isEmpty()) "\n\n" else "\n" - additionalTextEdits = listOf(TextEdit(Range(pos, pos), "${prefix}import ${it.fqName}")) // TODO: CRLF? + additionalTextEdits = listOf(getImportTextEditEntry(parsedFile, it.fqName)) // TODO: CRLF? } } } -/** Finds a good insertion position for a new import of the given fully-qualified name. */ -private fun findImportInsertionPosition(parsedFile: KtFile, fqName: FqName): Position = - (closestImport(parsedFile.importDirectives, fqName) as? KtElement ?: parsedFile.packageDirective as? KtElement) - ?.let(::location) - ?.range - ?.end - ?: Position(0, 0) - -// TODO: Lexicographic insertion -private fun closestImport(imports: List, fqName: FqName): KtImportDirective? = - imports - .asReversed() - .maxByOrNull { it.importedFqName?.let { matchingPrefixLength(it, fqName) } ?: 0 } - -private fun matchingPrefixLength(left: FqName, right: FqName): Int = - left.pathSegments().asSequence().zip(right.pathSegments().asSequence()) - .takeWhile { it.first == it.second } - .count() - /** Finds keyword completions starting with the given partial identifier. */ private fun keywordCompletionItems(partial: String): Sequence = (KtTokens.SOFT_KEYWORDS.getTypes() + KtTokens.KEYWORDS.getTypes()).asSequence() diff --git a/server/src/main/kotlin/org/javacs/kt/imports/Imports.kt b/server/src/main/kotlin/org/javacs/kt/imports/Imports.kt new file mode 100644 index 00000000..018fccca --- /dev/null +++ b/server/src/main/kotlin/org/javacs/kt/imports/Imports.kt @@ -0,0 +1,38 @@ +package org.javacs.kt.imports + +import org.eclipse.lsp4j.Position +import org.eclipse.lsp4j.Range +import org.eclipse.lsp4j.TextEdit +import org.jetbrains.kotlin.name.FqName +import org.jetbrains.kotlin.psi.* +import org.javacs.kt.position.location + +fun getImportTextEditEntry(parsedFile: KtFile, fqName: FqName): TextEdit { + val imports = parsedFile.importDirectives + val importedNames = imports + .mapNotNull { it.importedFqName?.shortName() } + .toSet() + + val pos = findImportInsertionPosition(parsedFile, fqName) + val prefix = if (importedNames.isEmpty()) "\n\n" else "\n" + return TextEdit(Range(pos, pos), "${prefix}import ${fqName}") +} + +/** Finds a good insertion position for a new import of the given fully-qualified name. */ +private fun findImportInsertionPosition(parsedFile: KtFile, fqName: FqName): Position = + (closestImport(parsedFile.importDirectives, fqName) as? KtElement ?: parsedFile.packageDirective as? KtElement) + ?.let(::location) + ?.range + ?.end + ?: Position(0, 0) + +// TODO: Lexicographic insertion +private fun closestImport(imports: List, fqName: FqName): KtImportDirective? = + imports + .asReversed() + .maxByOrNull { it.importedFqName?.let { matchingPrefixLength(it, fqName) } ?: 0 } + +private fun matchingPrefixLength(left: FqName, right: FqName): Int = + left.pathSegments().asSequence().zip(right.pathSegments().asSequence()) + .takeWhile { it.first == it.second } + .count() diff --git a/server/src/main/kotlin/org/javacs/kt/index/SymbolIndex.kt b/server/src/main/kotlin/org/javacs/kt/index/SymbolIndex.kt index 6e405c6a..9cf1bddc 100644 --- a/server/src/main/kotlin/org/javacs/kt/index/SymbolIndex.kt +++ b/server/src/main/kotlin/org/javacs/kt/index/SymbolIndex.kt @@ -177,11 +177,11 @@ class SymbolIndex { fqName.toString().length <= MAX_FQNAME_LENGTH && fqName.shortName().toString().length <= MAX_SHORT_NAME_LENGTH - fun query(prefix: String, receiverType: FqName? = null, limit: Int = 20): List = transaction(db) { + fun query(prefix: String, receiverType: FqName? = null, limit: Int = 20, wildcardMatcher: String = "%"): List = transaction(db) { // TODO: Extension completion currently only works if the receiver matches exactly, // ideally this should work with subtypes as well SymbolEntity.find { - (Symbols.shortName like "$prefix%") and (Symbols.extensionReceiverType eq receiverType?.toString()) + (Symbols.shortName like "$prefix$wildcardMatcher") and (Symbols.extensionReceiverType eq receiverType?.toString()) }.limit(limit) .map { Symbol( fqName = FqName(it.fqName), From 2303201b052f014f1dc8e4c2d863a6970cc69837 Mon Sep 17 00:00:00 2001 From: Marie Katrine Ekeberg Date: Sat, 2 Apr 2022 15:51:11 +0200 Subject: [PATCH 12/34] Added the actual quickfix missing imports class. --- .../quickfix/AddMissingImportsQuickFix.kt | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/AddMissingImportsQuickFix.kt diff --git a/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/AddMissingImportsQuickFix.kt b/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/AddMissingImportsQuickFix.kt new file mode 100644 index 00000000..bed5f09e --- /dev/null +++ b/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/AddMissingImportsQuickFix.kt @@ -0,0 +1,59 @@ +package org.javacs.kt.codeaction.quickfix + +import org.eclipse.lsp4j.* +import org.eclipse.lsp4j.jsonrpc.messages.Either +import org.jetbrains.kotlin.psi.KtFile +import org.javacs.kt.CompiledFile +import org.javacs.kt.LOG +import org.javacs.kt.index.SymbolIndex +import org.javacs.kt.index.Symbol +import org.javacs.kt.position.offset +import org.javacs.kt.util.toPath +import org.javacs.kt.codeaction.quickfix.diagnosticMatch +import org.javacs.kt.imports.getImportTextEditEntry + +class AddMissingImportsQuickFix: QuickFix { + override fun compute(file: CompiledFile, index: SymbolIndex, range: Range, diagnostics: List): List> { + val uri = file.parse.toPath().toUri().toString() + val unresolvedReferences = getUnresolvedReferencesFromDiagnostics(diagnostics) + + return unresolvedReferences.flatMap { diagnostic -> + val diagnosticRange = diagnostic.range + val startCursor = offset(file.content, diagnosticRange.start) + val endCursor = offset(file.content, diagnosticRange.end) + val symbolName = file.content.substring(startCursor, endCursor) + + getImportAlternatives(symbolName, file.parse, index).map { (importStr, edit) -> + val codeAction = CodeAction() + codeAction.title = "import ${importStr}" + codeAction.kind = CodeActionKind.QuickFix + codeAction.diagnostics = listOf(diagnostic) + codeAction.edit = WorkspaceEdit(mapOf(uri to listOf(edit))) + + Either.forRight(codeAction) + } + } + } + + private fun getUnresolvedReferencesFromDiagnostics(diagnostics: List): List = + diagnostics.filter { + "UNRESOLVED_REFERENCE" == it.code.left.trim() + } + + private fun getImportAlternatives(symbolName: String, file: KtFile, index: SymbolIndex): List> { + // wildcard matcher to empty string, because we only want to match exactly the symbol itself, not anything extra + val queryResult = index.query(symbolName, wildcardMatcher = "") + + return queryResult + .filter { it.kind != Symbol.Kind.MODULE } + .filter { + // TODO: Visibility checker should be less liberal + it.visibility == Symbol.Visibility.PUBLIC + || it.visibility == Symbol.Visibility.PROTECTED + || it.visibility == Symbol.Visibility.INTERNAL + } + .map { + Pair(it.fqName.toString(), getImportTextEditEntry(file, it.fqName)) + } + } +} From e393dec56e978a91391eee9d72757d78ada7fc1a Mon Sep 17 00:00:00 2001 From: fwcd Date: Sun, 3 Apr 2022 03:40:26 +0200 Subject: [PATCH 13/34] Use Set instead of HashSet in diagnostic match helpers --- .../kotlin/org/javacs/kt/codeaction/quickfix/QuickFix.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/QuickFix.kt b/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/QuickFix.kt index fd43352a..d25ffc00 100644 --- a/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/QuickFix.kt +++ b/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/QuickFix.kt @@ -14,14 +14,14 @@ interface QuickFix { fun compute(file: CompiledFile, range: Range, diagnostics: List): Either? } -fun diagnosticMatch(diagnostic: Diagnostic, range: Range, diagnosticTypes: HashSet): Boolean = +fun diagnosticMatch(diagnostic: Diagnostic, range: Range, diagnosticTypes: Set): Boolean = diagnostic.range.equals(range) && diagnosticTypes.contains(diagnostic.code.left) -fun diagnosticMatch(diagnostic: KotlinDiagnostic, startCursor: Int, endCursor: Int, diagnosticTypes: HashSet): Boolean = +fun diagnosticMatch(diagnostic: KotlinDiagnostic, startCursor: Int, endCursor: Int, diagnosticTypes: Set): Boolean = diagnostic.textRanges.any { it.startOffset == startCursor && it.endOffset == endCursor } && diagnosticTypes.contains(diagnostic.factory.name) -fun findDiagnosticMatch(diagnostics: List, range: Range, diagnosticTypes: HashSet) = +fun findDiagnosticMatch(diagnostics: List, range: Range, diagnosticTypes: Set) = diagnostics.find { diagnosticMatch(it, range, diagnosticTypes) } -fun anyDiagnosticMatch(diagnostics: Diagnostics, startCursor: Int, endCursor: Int, diagnosticTypes: HashSet) = +fun anyDiagnosticMatch(diagnostics: Diagnostics, startCursor: Int, endCursor: Int, diagnosticTypes: Set) = diagnostics.any { diagnosticMatch(it, startCursor, endCursor, diagnosticTypes) } From c3b9d2c44ed692da8874ce15f701f9b9be96ea89 Mon Sep 17 00:00:00 2001 From: Marie Katrine Ekeberg Date: Sun, 3 Apr 2022 12:08:55 +0200 Subject: [PATCH 14/34] PR comments, mostly related to style and consistency. --- .../codeaction/quickfix/AddMissingImportsQuickFix.kt | 12 ++++++------ .../main/kotlin/org/javacs/kt/index/SymbolIndex.kt | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/AddMissingImportsQuickFix.kt b/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/AddMissingImportsQuickFix.kt index bed5f09e..1eb9462e 100644 --- a/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/AddMissingImportsQuickFix.kt +++ b/server/src/main/kotlin/org/javacs/kt/codeaction/quickfix/AddMissingImportsQuickFix.kt @@ -25,7 +25,7 @@ class AddMissingImportsQuickFix: QuickFix { getImportAlternatives(symbolName, file.parse, index).map { (importStr, edit) -> val codeAction = CodeAction() - codeAction.title = "import ${importStr}" + codeAction.title = "Import ${importStr}" codeAction.kind = CodeActionKind.QuickFix codeAction.diagnostics = listOf(diagnostic) codeAction.edit = WorkspaceEdit(mapOf(uri to listOf(edit))) @@ -42,15 +42,15 @@ class AddMissingImportsQuickFix: QuickFix { private fun getImportAlternatives(symbolName: String, file: KtFile, index: SymbolIndex): List> { // wildcard matcher to empty string, because we only want to match exactly the symbol itself, not anything extra - val queryResult = index.query(symbolName, wildcardMatcher = "") + val queryResult = index.query(symbolName, suffix = "") return queryResult - .filter { it.kind != Symbol.Kind.MODULE } .filter { + it.kind != Symbol.Kind.MODULE && // TODO: Visibility checker should be less liberal - it.visibility == Symbol.Visibility.PUBLIC - || it.visibility == Symbol.Visibility.PROTECTED - || it.visibility == Symbol.Visibility.INTERNAL + (it.visibility == Symbol.Visibility.PUBLIC + || it.visibility == Symbol.Visibility.PROTECTED + || it.visibility == Symbol.Visibility.INTERNAL) } .map { Pair(it.fqName.toString(), getImportTextEditEntry(file, it.fqName)) diff --git a/server/src/main/kotlin/org/javacs/kt/index/SymbolIndex.kt b/server/src/main/kotlin/org/javacs/kt/index/SymbolIndex.kt index 9cf1bddc..f989eeff 100644 --- a/server/src/main/kotlin/org/javacs/kt/index/SymbolIndex.kt +++ b/server/src/main/kotlin/org/javacs/kt/index/SymbolIndex.kt @@ -177,11 +177,11 @@ class SymbolIndex { fqName.toString().length <= MAX_FQNAME_LENGTH && fqName.shortName().toString().length <= MAX_SHORT_NAME_LENGTH - fun query(prefix: String, receiverType: FqName? = null, limit: Int = 20, wildcardMatcher: String = "%"): List = transaction(db) { + fun query(prefix: String, receiverType: FqName? = null, limit: Int = 20, suffix: String = "%"): List = transaction(db) { // TODO: Extension completion currently only works if the receiver matches exactly, // ideally this should work with subtypes as well SymbolEntity.find { - (Symbols.shortName like "$prefix$wildcardMatcher") and (Symbols.extensionReceiverType eq receiverType?.toString()) + (Symbols.shortName like "$prefix$suffix") and (Symbols.extensionReceiverType eq receiverType?.toString()) }.limit(limit) .map { Symbol( fqName = FqName(it.fqName), From 757154b60aab24061fb8a71d3d80dadec67fe8c2 Mon Sep 17 00:00:00 2001 From: daplf Date: Sun, 3 Apr 2022 18:12:36 +0100 Subject: [PATCH 15/34] Update server/src/main/kotlin/org/javacs/kt/externalsources/KlsURI.kt Co-authored-by: FW <30873659+fwcd@users.noreply.github.com> --- .../main/kotlin/org/javacs/kt/externalsources/KlsURI.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/src/main/kotlin/org/javacs/kt/externalsources/KlsURI.kt b/server/src/main/kotlin/org/javacs/kt/externalsources/KlsURI.kt index 4a3dc4b5..9368fc6e 100644 --- a/server/src/main/kotlin/org/javacs/kt/externalsources/KlsURI.kt +++ b/server/src/main/kotlin/org/javacs/kt/externalsources/KlsURI.kt @@ -113,13 +113,14 @@ data class KlsURI(val fileUri: URI, val query: Map) { return result } - fun readContents(): String { - return if (archiveType == ArchiveType.ZIP) { + fun readContents(): String = when (archiveType) { + ArchiveType.ZIP -> { val zipFile = ZipFile(File("$archivePath")) zipFile.getInputStream(zipFile.getEntry(innerPath.trimStart('/'))) .bufferedReader() .use(BufferedReader::readText) - } else { + } + ArchiveType.JAR, ArchiveType.JDK -> { withJarURLConnection { it.jarFile .getInputStream(it.jarEntry) From 20228842180afdb9dd8bfbf9743b59c38ea3dadc Mon Sep 17 00:00:00 2001 From: daplf Date: Sun, 3 Apr 2022 18:58:59 +0100 Subject: [PATCH 16/34] Refactor source archive providers --- .../org/javacs/kt/KotlinLanguageServer.kt | 5 ++-- .../ClassPathSourceArchiveProvider.kt | 20 +------------- .../JdkSourceArchiveProvider.kt | 27 +++++++++++++++++++ .../externalsources/SourceArchiveProvider.kt | 5 ++++ 4 files changed, 35 insertions(+), 22 deletions(-) create mode 100644 server/src/main/kotlin/org/javacs/kt/externalsources/JdkSourceArchiveProvider.kt diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt index f1d90fcf..50f62286 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt @@ -7,8 +7,7 @@ import org.eclipse.lsp4j.services.LanguageClient import org.eclipse.lsp4j.services.LanguageClientAware import org.eclipse.lsp4j.services.LanguageServer import org.javacs.kt.command.ALL_COMMANDS -import org.javacs.kt.externalsources.ClassContentProvider -import org.javacs.kt.externalsources.ClassPathSourceArchiveProvider +import org.javacs.kt.externalsources.* import org.javacs.kt.util.AsyncExecutor import org.javacs.kt.util.TemporaryDirectory import org.javacs.kt.util.parseURI @@ -25,7 +24,7 @@ class KotlinLanguageServer : LanguageServer, LanguageClientAware, Closeable { val classPath = CompilerClassPath(config.compiler) private val tempDirectory = TemporaryDirectory() - private val uriContentProvider = URIContentProvider(ClassContentProvider(config.externalSources, classPath, tempDirectory, ClassPathSourceArchiveProvider(classPath))) + private val uriContentProvider = URIContentProvider(ClassContentProvider(config.externalSources, classPath, tempDirectory, CompositeSourceArchiveProvider(JdkSourceArchiveProvider(classPath), ClassPathSourceArchiveProvider(classPath)))) val sourcePath = SourcePath(classPath, uriContentProvider, config.indexing) val sourceFiles = SourceFiles(sourcePath, uriContentProvider) diff --git a/server/src/main/kotlin/org/javacs/kt/externalsources/ClassPathSourceArchiveProvider.kt b/server/src/main/kotlin/org/javacs/kt/externalsources/ClassPathSourceArchiveProvider.kt index d777f395..03c84fcb 100644 --- a/server/src/main/kotlin/org/javacs/kt/externalsources/ClassPathSourceArchiveProvider.kt +++ b/server/src/main/kotlin/org/javacs/kt/externalsources/ClassPathSourceArchiveProvider.kt @@ -1,29 +1,11 @@ package org.javacs.kt.externalsources import org.javacs.kt.CompilerClassPath -import java.io.File import java.nio.file.Path -import java.nio.file.Paths class ClassPathSourceArchiveProvider( private val cp: CompilerClassPath ) : SourceArchiveProvider { override fun fetchSourceArchive(compiledArchive: Path): Path? = - getJdkSource(compiledArchive) ?: cp.classPath.firstOrNull { it.compiledJar == compiledArchive }?.sourceJar - - /** - * Checks if the given path is inside the JDK. If it is, we return the corresponding source zip. - * Note that this method currently doesn't take into the account the JDK version, which means JDK source code - * is only available for JDK 9+ builds. - * TODO: improve this resolution logic to work for older JDK versions as well. - */ - private fun getJdkSource(path: Path): Path? { - cp.javaHome?.let { - val javaHomePath = File(it).toPath() - if (path == javaHomePath) { - return Paths.get(path.toString(), "lib", "src.zip") - } - } - return null - } + cp.classPath.firstOrNull { it.compiledJar == compiledArchive }?.sourceJar } diff --git a/server/src/main/kotlin/org/javacs/kt/externalsources/JdkSourceArchiveProvider.kt b/server/src/main/kotlin/org/javacs/kt/externalsources/JdkSourceArchiveProvider.kt new file mode 100644 index 00000000..eddb2959 --- /dev/null +++ b/server/src/main/kotlin/org/javacs/kt/externalsources/JdkSourceArchiveProvider.kt @@ -0,0 +1,27 @@ +package org.javacs.kt.externalsources + +import org.javacs.kt.CompilerClassPath +import java.io.File +import java.nio.file.Path +import java.nio.file.Paths + +class JdkSourceArchiveProvider( + private val cp: CompilerClassPath +) : SourceArchiveProvider { + + /** + * Checks if the given path is inside the JDK. If it is, we return the corresponding source zip. + * Note that this method currently doesn't take into the account the JDK version, which means JDK source code + * is only available for JDK 9+ builds. + * TODO: improve this resolution logic to work for older JDK versions as well. + */ + override fun fetchSourceArchive(compiledArchive: Path): Path? { + cp.javaHome?.let { + val javaHomePath = File(it).toPath() + if (compiledArchive == javaHomePath) { + return Paths.get(compiledArchive.toString(), "lib", "src.zip") + } + } + return null + } +} diff --git a/server/src/main/kotlin/org/javacs/kt/externalsources/SourceArchiveProvider.kt b/server/src/main/kotlin/org/javacs/kt/externalsources/SourceArchiveProvider.kt index 12a3a740..4357bf7f 100644 --- a/server/src/main/kotlin/org/javacs/kt/externalsources/SourceArchiveProvider.kt +++ b/server/src/main/kotlin/org/javacs/kt/externalsources/SourceArchiveProvider.kt @@ -5,3 +5,8 @@ import java.nio.file.Path interface SourceArchiveProvider { fun fetchSourceArchive(compiledArchive: Path): Path? } + +class CompositeSourceArchiveProvider(val lhs: SourceArchiveProvider, val rhs: SourceArchiveProvider) : SourceArchiveProvider { + override fun fetchSourceArchive(compiledArchive: Path): Path? = + lhs.fetchSourceArchive(compiledArchive) ?: rhs.fetchSourceArchive(compiledArchive) +} From 931ed26e7933b18cf11622915df209ff8d7242e2 Mon Sep 17 00:00:00 2001 From: daplf Date: Sun, 3 Apr 2022 19:59:09 +0100 Subject: [PATCH 17/34] Allow exclamation marks on paths --- .../kotlin/org/javacs/kt/KotlinLanguageServer.kt | 2 +- .../org/javacs/kt/KotlinTextDocumentService.kt | 5 +++-- .../org/javacs/kt/definition/GoToDefinition.kt | 13 ++++++++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt index 50f62286..56e97515 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt @@ -28,7 +28,7 @@ class KotlinLanguageServer : LanguageServer, LanguageClientAware, Closeable { val sourcePath = SourcePath(classPath, uriContentProvider, config.indexing) val sourceFiles = SourceFiles(sourcePath, uriContentProvider) - private val textDocuments = KotlinTextDocumentService(sourceFiles, sourcePath, config, tempDirectory, uriContentProvider) + private val textDocuments = KotlinTextDocumentService(sourceFiles, sourcePath, config, tempDirectory, uriContentProvider, classPath) private val workspaces = KotlinWorkspaceService(sourceFiles, sourcePath, classPath, textDocuments, config) private val protocolExtensions = KotlinProtocolExtensionService(uriContentProvider) diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt b/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt index 86ea152f..625bc312 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinTextDocumentService.kt @@ -38,7 +38,8 @@ class KotlinTextDocumentService( private val sp: SourcePath, private val config: Configuration, private val tempDirectory: TemporaryDirectory, - private val uriContentProvider: URIContentProvider + private val uriContentProvider: URIContentProvider, + private val cp: CompilerClassPath ) : TextDocumentService, Closeable { private lateinit var client: LanguageClient private val async = AsyncExecutor() @@ -115,7 +116,7 @@ class KotlinTextDocumentService( LOG.info("Go-to-definition at {}", describePosition(position)) val (file, cursor) = recover(position, Recompile.NEVER) - goToDefinition(file, cursor, uriContentProvider.classContentProvider, tempDirectory, config.externalSources) + goToDefinition(file, cursor, uriContentProvider.classContentProvider, tempDirectory, config.externalSources, cp) ?.let(::listOf) ?.let { Either.forLeft, List>(it) } ?: noResult("Couldn't find definition at ${describePosition(position)}", Either.forLeft(emptyList())) diff --git a/server/src/main/kotlin/org/javacs/kt/definition/GoToDefinition.kt b/server/src/main/kotlin/org/javacs/kt/definition/GoToDefinition.kt index 96082708..77c8a05d 100644 --- a/server/src/main/kotlin/org/javacs/kt/definition/GoToDefinition.kt +++ b/server/src/main/kotlin/org/javacs/kt/definition/GoToDefinition.kt @@ -4,6 +4,7 @@ import org.eclipse.lsp4j.Location import org.eclipse.lsp4j.Range import java.nio.file.Path import org.javacs.kt.CompiledFile +import org.javacs.kt.CompilerClassPath import org.javacs.kt.LOG import org.javacs.kt.ExternalSourcesConfiguration import org.javacs.kt.externalsources.ClassContentProvider @@ -18,6 +19,8 @@ import org.javacs.kt.util.parseURI import org.jetbrains.kotlin.js.resolve.diagnostics.findPsi import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.descriptors.ConstructorDescriptor +import java.io.File +import java.nio.file.Paths private val cachedTempFiles = mutableMapOf() private val definitionPattern = Regex("(?:class|interface|object|fun)\\s+(\\w+)") @@ -27,7 +30,8 @@ fun goToDefinition( cursor: Int, classContentProvider: ClassContentProvider, tempDir: TemporaryDirectory, - config: ExternalSourcesConfiguration + config: ExternalSourcesConfiguration, + cp: CompilerClassPath ): Location? { val (_, target) = file.referenceExpressionAtPoint(cursor) ?: return null @@ -42,7 +46,7 @@ fun goToDefinition( if (destination != null) { val rawClassURI = destination.uri - if (isInsideArchive(rawClassURI)) { + if (isInsideArchive(rawClassURI, cp)) { parseURI(rawClassURI).toKlsURI()?.let { klsURI -> val (klsSourceURI, content) = classContentProvider.contentOf(klsURI) @@ -86,4 +90,7 @@ fun goToDefinition( return destination } -private fun isInsideArchive(uri: String) = uri.contains("!") +private fun isInsideArchive(uri: String, cp: CompilerClassPath) = + uri.contains(".jar!") || uri.contains(".zip!") || cp.javaHome?.let { + Paths.get(parseURI(uri)).toString().startsWith(File(it).path) + } ?: false From 00a14b6de3403e1591b5aa9e9a7bbd906d7546a5 Mon Sep 17 00:00:00 2001 From: fwcd Date: Tue, 5 Apr 2022 13:55:59 +0200 Subject: [PATCH 18/34] Disable conversion of external sources to Kotlin by default --- server/src/main/kotlin/org/javacs/kt/Configuration.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/kotlin/org/javacs/kt/Configuration.kt b/server/src/main/kotlin/org/javacs/kt/Configuration.kt index f05a68cd..ecf687f7 100644 --- a/server/src/main/kotlin/org/javacs/kt/Configuration.kt +++ b/server/src/main/kotlin/org/javacs/kt/Configuration.kt @@ -31,8 +31,8 @@ public data class IndexingConfiguration( public data class ExternalSourcesConfiguration( /** Whether kls-URIs should be sent to the client to describe classes in JARs. */ var useKlsScheme: Boolean = false, - /** Whether external classes classes should be automatically converted to Kotlin. */ - var autoConvertToKotlin: Boolean = true + /** Whether external classes should be automatically converted to Kotlin. */ + var autoConvertToKotlin: Boolean = false ) public data class Configuration( From c7e08424e9f5237c594c38ab51af475e40d256f2 Mon Sep 17 00:00:00 2001 From: fwcd Date: Tue, 5 Apr 2022 16:40:46 +0200 Subject: [PATCH 19/34] Make ClassPathEntry.sourceJar null by default --- .../main/kotlin/org/javacs/kt/classpath/ClassPathEntry.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared/src/main/kotlin/org/javacs/kt/classpath/ClassPathEntry.kt b/shared/src/main/kotlin/org/javacs/kt/classpath/ClassPathEntry.kt index 405a3f08..b379dfea 100644 --- a/shared/src/main/kotlin/org/javacs/kt/classpath/ClassPathEntry.kt +++ b/shared/src/main/kotlin/org/javacs/kt/classpath/ClassPathEntry.kt @@ -2,4 +2,7 @@ package org.javacs.kt.classpath import java.nio.file.Path -data class ClassPathEntry(val compiledJar: Path, val sourceJar: Path?) +data class ClassPathEntry( + val compiledJar: Path, + val sourceJar: Path? = null +) From 17a34b47c8d273d6f7d80d7e15d26b8c18d2d708 Mon Sep 17 00:00:00 2001 From: fwcd Date: Tue, 5 Apr 2022 17:40:17 +0200 Subject: [PATCH 20/34] Use getResourceAsStream instead of getSystemResourceAsStream --- .../kotlin/org/javacs/kt/classpath/GradleClassPathResolver.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/main/kotlin/org/javacs/kt/classpath/GradleClassPathResolver.kt b/shared/src/main/kotlin/org/javacs/kt/classpath/GradleClassPathResolver.kt index 9232744b..dc1b5fd7 100644 --- a/shared/src/main/kotlin/org/javacs/kt/classpath/GradleClassPathResolver.kt +++ b/shared/src/main/kotlin/org/javacs/kt/classpath/GradleClassPathResolver.kt @@ -50,7 +50,7 @@ private fun gradleScriptToTempFile(scriptName: String, deleteOnExit: Boolean = f LOG.debug("Creating temporary gradle file {}", config.absolutePath) config.bufferedWriter().use { configWriter -> - ClassLoader.getSystemResourceAsStream(scriptName).bufferedReader().use { configReader -> + GradleClassPathResolver::class.java.getResourceAsStream("/$scriptName").bufferedReader().use { configReader -> configReader.copyTo(configWriter) } } From b4c9349b7bc5eacca54cc72f4782983ab97825f4 Mon Sep 17 00:00:00 2001 From: fwcd Date: Tue, 5 Apr 2022 18:02:38 +0200 Subject: [PATCH 21/34] Move Gradle class path scripts to shared module This fixes an issue where an application depending on the shared module outside of KLS would be unable to read these scripts since they would never be included in the library jar. --- .../src/main/resources/kotlinDSLClassPathFinder.gradle | 0 .../src/main/resources/projectClassPathFinder.gradle | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {server => shared}/src/main/resources/kotlinDSLClassPathFinder.gradle (100%) rename {server => shared}/src/main/resources/projectClassPathFinder.gradle (100%) diff --git a/server/src/main/resources/kotlinDSLClassPathFinder.gradle b/shared/src/main/resources/kotlinDSLClassPathFinder.gradle similarity index 100% rename from server/src/main/resources/kotlinDSLClassPathFinder.gradle rename to shared/src/main/resources/kotlinDSLClassPathFinder.gradle diff --git a/server/src/main/resources/projectClassPathFinder.gradle b/shared/src/main/resources/projectClassPathFinder.gradle similarity index 100% rename from server/src/main/resources/projectClassPathFinder.gradle rename to shared/src/main/resources/projectClassPathFinder.gradle From cb15b9d19cb338f39f56228f829e19ee49019efd Mon Sep 17 00:00:00 2001 From: Boris Brodski Date: Wed, 18 Nov 2020 10:49:36 +0100 Subject: [PATCH 22/34] Fix ShellClassPathResolver on Windows +README.md Teach ShellClassPathResolver how to get classpath from classpath.bat or classpath.cmd on Windows. Improve README.md describing how to use ShellClassPathResolver on Linux and Windows. Fix broken URL for classpath resolution. --- README.md | 19 ++++++++++++++++++- .../kt/classpath/ShellClassPathResolver.kt | 10 +++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1144e634..1ff373f5 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,24 @@ There are two hard parts of implementing a language server: The project uses the internal APIs of the [Kotlin compiler](https://github.com/JetBrains/kotlin/tree/master/compiler). -Dependencies are determined by the [findClassPath](server/src/main/kotlin/org/javacs/kt/classpath/findClassPath.kt) function, which invokes Maven or Gradle and tells it to output a list of dependencies. Currently, both Maven and Gradle projects are supported. + +### Figuring out the dependencies + +Dependencies are determined by the [DefaultClassPathResolver.kt](shared/src/main/kotlin/org/javacs/kt/classpath/DefaultClassPathResolver.kt), which invokes Maven, Gradle or `$HOME/.config/KotlinLanguageServer/classpath.{sh,bat,cmd}` and tells it to output a list of dependencies. + +* Example of the `~/.config/KotlinLanguageServer/classpath.sh` on Linux: +```bash +#!/bin/bash +echo /my/path/kotlin-compiler-1.4.10/lib/kotlin-stdlib.jar:/my/path/my-lib.jar +``` + +* Example of the `%HOMEPATH%\.config\KotlinLanguageServer\classpath.bat` on Windows: +```cmd +@echo off +echo C:\my\path\kotlin-compiler-1.4.10\lib\kotlin-stdlib.jar;C:\my\path\my-lib.jar +``` + +### Incrementally re-compiling as the user types I get incremental compilation at the file-level by keeping the same `KotlinCoreEnvironment` alive between compilations in [Compiler.kt](server/src/main/kotlin/org/javacs/kt/compiler/Compiler.kt). There is a performance benchmark in [OneFilePerformance.kt](server/src/test/kotlin/org/javacs/kt/OneFilePerformance.kt) that verifies this works. diff --git a/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt b/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt index fee759d5..077ca218 100644 --- a/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt +++ b/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt @@ -1,5 +1,6 @@ package org.javacs.kt.classpath +import java.io.File import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths @@ -19,7 +20,7 @@ internal class ShellClassPathResolver( val process = Runtime.getRuntime().exec(cmd, null, workingDirectory) return process.inputStream.bufferedReader().readText() - .split(':') + .split(File.pathSeparator) .asSequence() .map { it.trim() } .filter { it.isNotEmpty() } @@ -38,8 +39,11 @@ internal class ShellClassPathResolver( /** Returns the ShellClassPathResolver for the global home directory shell script. */ fun global(workingDir: Path?): ClassPathResolver = - globalConfigRoot.resolve("KotlinLanguageServer").resolve("classpath.sh") - .takeIf { Files.exists(it) } + globalConfigRoot.resolve("KotlinLanguageServer")?.let { + it.resolve("classpath.sh").takeIf { Files.exists(it) } ?: + it.resolve("classpath.bat").takeIf { Files.exists(it) } ?: + it.resolve("classpath.cmd").takeIf { Files.exists(it) } + } ?.let { ShellClassPathResolver(it, workingDir) } ?: ClassPathResolver.empty } From ae2dcd54146d57bb6f5ec4c13a295d1f1a8ffebb Mon Sep 17 00:00:00 2001 From: fwcd Date: Tue, 12 Apr 2022 15:49:18 +0200 Subject: [PATCH 23/34] Update ShellClassPathResolver and description --- README.md | 8 +++++--- .../javacs/kt/classpath/ShellClassPathResolver.kt | 14 +++++++++----- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 1ff373f5..4d784035 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # Kotlin Language Server + [![Release](https://img.shields.io/github/release/fwcd/kotlin-language-server)](https://github.com/fwcd/kotlin-language-server/releases) [![Build](https://github.com/fwcd/kotlin-language-server/actions/workflows/build.yml/badge.svg)](https://github.com/fwcd/kotlin-language-server/actions/workflows/build.yml) [![Downloads](https://img.shields.io/github/downloads/fwcd/kotlin-language-server/total)](https://github.com/fwcd/kotlin-language-server/releases) @@ -11,6 +12,7 @@ A [language server](https://microsoft.github.io/language-server-protocol/) that Any editor conforming to LSP is supported, including [VSCode](https://github.com/fwcd/vscode-kotlin) and [Atom](https://github.com/fwcd/atom-ide-kotlin). ## Getting Started + * See [BUILDING.md](BUILDING.md) for build instructions * See [Editor Integration](EDITORS.md) for editor-specific instructions * See [Roadmap](https://github.com/fwcd/kotlin-language-server/projects/1) for features, planned additions, bugfixes and changes @@ -19,6 +21,7 @@ Any editor conforming to LSP is supported, including [VSCode](https://github.com * See [tree-sitter-kotlin](https://github.com/fwcd/tree-sitter-kotlin) for an experimental [Tree-Sitter](https://tree-sitter.github.io/tree-sitter/) grammar ## This repository needs your help! + [The original author](https://github.com/georgewfraser) created this project while he was considering using Kotlin in his work. He ended up deciding not to and is not really using Kotlin these days though this is a pretty fully-functional language server that just needs someone to use it every day for a while and iron out the last few pesky bugs. There are two hard parts of implementing a language server: @@ -27,10 +30,9 @@ There are two hard parts of implementing a language server: The project uses the internal APIs of the [Kotlin compiler](https://github.com/JetBrains/kotlin/tree/master/compiler). +### Figuring out the dependencies -### Figuring out the dependencies - -Dependencies are determined by the [DefaultClassPathResolver.kt](shared/src/main/kotlin/org/javacs/kt/classpath/DefaultClassPathResolver.kt), which invokes Maven, Gradle or `$HOME/.config/KotlinLanguageServer/classpath.{sh,bat,cmd}` and tells it to output a list of dependencies. +Dependencies are determined by the [DefaultClassPathResolver.kt](shared/src/main/kotlin/org/javacs/kt/classpath/DefaultClassPathResolver.kt), which invokes Maven or Gradle to get a list of classpath JARs. Alternatively, projects can also 'manually' provide a list of dependencies through a shell script, located either at `[project root]/kotlinLspClasspath.{sh,bat,cmd}` or `[config root]/KotlinLanguageServer/classpath.{sh,bat,cmd}`, which outputs a list of JARs. * Example of the `~/.config/KotlinLanguageServer/classpath.sh` on Linux: ```bash diff --git a/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt b/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt index 077ca218..bc5f20eb 100644 --- a/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt +++ b/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt @@ -29,9 +29,12 @@ internal class ShellClassPathResolver( } companion object { + private val scriptExtensions = listOf("sh", "bat", "cmd") + /** Create a shell resolver if a file is a pom. */ fun maybeCreate(file: Path): ShellClassPathResolver? = - file.takeIf { it.endsWith("kotlinLspClasspath.sh") }?.let { ShellClassPathResolver(it) } + file.takeIf { scriptExtensions.any { file.endsWith("kotlinLspClasspath.$it") } } + ?.let { ShellClassPathResolver(it) } /** The root directory for config files. */ private val globalConfigRoot: Path = @@ -39,10 +42,11 @@ internal class ShellClassPathResolver( /** Returns the ShellClassPathResolver for the global home directory shell script. */ fun global(workingDir: Path?): ClassPathResolver = - globalConfigRoot.resolve("KotlinLanguageServer")?.let { - it.resolve("classpath.sh").takeIf { Files.exists(it) } ?: - it.resolve("classpath.bat").takeIf { Files.exists(it) } ?: - it.resolve("classpath.cmd").takeIf { Files.exists(it) } + globalConfigRoot.resolve("KotlinLanguageServer") + ?.let { root -> + scriptExtensions + .map { root.resolve("classpath.$it") } + .first { Files.exists(it) } } ?.let { ShellClassPathResolver(it, workingDir) } ?: ClassPathResolver.empty From 0dc7623cb80da53666931ad016146ba629db2142 Mon Sep 17 00:00:00 2001 From: fwcd Date: Tue, 12 Apr 2022 15:51:02 +0200 Subject: [PATCH 24/34] Use ProcessBuilder instead of Runtime.exec --- .../kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt b/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt index bc5f20eb..4ba736dd 100644 --- a/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt +++ b/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt @@ -17,7 +17,7 @@ internal class ShellClassPathResolver( val workingDirectory = workingDir?.toFile() ?: script.toAbsolutePath().parent.toFile() val cmd = script.toString() LOG.info("Run {} in {}", cmd, workingDirectory) - val process = Runtime.getRuntime().exec(cmd, null, workingDirectory) + val process = ProcessBuilder(cmd).directory(workingDirectory).start() return process.inputStream.bufferedReader().readText() .split(File.pathSeparator) From 17bbc6eb6b83d1ab7942ac7d8b2a113adeb7a382 Mon Sep 17 00:00:00 2001 From: fwcd Date: Tue, 12 Apr 2022 16:00:24 +0200 Subject: [PATCH 25/34] Spawn subprocesses without shell --- .../org/javacs/kt/classpath/GradleClassPathResolver.kt | 4 ++-- .../org/javacs/kt/classpath/MavenClassPathResolver.kt | 6 +++--- shared/src/main/kotlin/org/javacs/kt/util/Utils.kt | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/shared/src/main/kotlin/org/javacs/kt/classpath/GradleClassPathResolver.kt b/shared/src/main/kotlin/org/javacs/kt/classpath/GradleClassPathResolver.kt index dc1b5fd7..60c1b8ee 100644 --- a/shared/src/main/kotlin/org/javacs/kt/classpath/GradleClassPathResolver.kt +++ b/shared/src/main/kotlin/org/javacs/kt/classpath/GradleClassPathResolver.kt @@ -76,7 +76,7 @@ private fun readDependenciesViaGradleCLI(projectDirectory: Path, gradleScripts: val tmpScripts = gradleScripts.map { gradleScriptToTempFile(it, deleteOnExit = false).toPath().toAbsolutePath() } val gradle = getGradleCommand(projectDirectory) - val command = "$gradle ${tmpScripts.map { "-I $it" }.joinToString(" ")} ${gradleTasks.joinToString(" ")} --console=plain" + val command = listOf(gradle.toString()) + tmpScripts.flatMap { listOf("-I", it.toString()) } + gradleTasks + listOf("--console=plain") val dependencies = findGradleCLIDependencies(command, projectDirectory) ?.also { LOG.debug("Classpath for task {}", it) } .orEmpty() @@ -87,7 +87,7 @@ private fun readDependenciesViaGradleCLI(projectDirectory: Path, gradleScripts: return dependencies } -private fun findGradleCLIDependencies(command: String, projectDirectory: Path): Set? { +private fun findGradleCLIDependencies(command: List, projectDirectory: Path): Set? { val (result, errors) = execAndReadStdoutAndStderr(command, projectDirectory) if ("FAILURE: Build failed" in errors) { LOG.warn("Gradle task failed: {}", errors) diff --git a/shared/src/main/kotlin/org/javacs/kt/classpath/MavenClassPathResolver.kt b/shared/src/main/kotlin/org/javacs/kt/classpath/MavenClassPathResolver.kt index d397bb8d..3ff7f567 100644 --- a/shared/src/main/kotlin/org/javacs/kt/classpath/MavenClassPathResolver.kt +++ b/shared/src/main/kotlin/org/javacs/kt/classpath/MavenClassPathResolver.kt @@ -104,19 +104,19 @@ private fun mavenJarName(a: Artifact, source: Boolean) = private fun generateMavenDependencyList(pom: Path): Path { val mavenOutput = Files.createTempFile("deps", ".txt") - val command = "${mvnCommand(pom)} dependency:list -DincludeScope=test -DoutputFile=$mavenOutput -Dstyle.color=never" + val command = listOf(mvnCommand(pom).toString(), "dependency:list", "-DincludeScope=test", "-DoutputFile=$mavenOutput", "-Dstyle.color=never") runCommand(pom, command) return mavenOutput } private fun generateMavenDependencySourcesList(pom: Path): Path { val mavenOutput = Files.createTempFile("sources", ".txt") - val command = "${mvnCommand(pom)} dependency:sources -DincludeScope=test -DoutputFile=$mavenOutput -Dstyle.color=never" + val command = listOf(mvnCommand(pom).toString(), "dependency:sources", "-DincludeScope=test", "-DoutputFile=$mavenOutput", "-Dstyle.color=never") runCommand(pom, command) return mavenOutput } -private fun runCommand(pom: Path, command: String) { +private fun runCommand(pom: Path, command: List) { val workingDirectory = pom.toAbsolutePath().parent LOG.info("Run {} in {}", command, workingDirectory) val (result, errors) = execAndReadStdoutAndStderr(command, workingDirectory) diff --git a/shared/src/main/kotlin/org/javacs/kt/util/Utils.kt b/shared/src/main/kotlin/org/javacs/kt/util/Utils.kt index 51909c49..3dfc8507 100644 --- a/shared/src/main/kotlin/org/javacs/kt/util/Utils.kt +++ b/shared/src/main/kotlin/org/javacs/kt/util/Utils.kt @@ -6,14 +6,14 @@ import java.nio.file.Path import java.nio.file.Paths import java.util.concurrent.CompletableFuture -fun execAndReadStdout(shellCommand: String, directory: Path): String { - val process = Runtime.getRuntime().exec(shellCommand, null, directory.toFile()) +fun execAndReadStdout(shellCommand: List, directory: Path): String { + val process = ProcessBuilder(shellCommand).directory(directory.toFile()).start() val stdout = process.inputStream return stdout.bufferedReader().use { it.readText() } } -fun execAndReadStdoutAndStderr(shellCommand: String, directory: Path): Pair { - val process = Runtime.getRuntime().exec(shellCommand, null, directory.toFile()) +fun execAndReadStdoutAndStderr(shellCommand: List, directory: Path): Pair { + val process = ProcessBuilder(shellCommand).directory(directory.toFile()).start() val stdout = process.inputStream val stderr = process.errorStream var output = "" From f5f338830b3ea6af0d02180758fcaabca92632e2 Mon Sep 17 00:00:00 2001 From: fwcd Date: Tue, 12 Apr 2022 16:01:11 +0200 Subject: [PATCH 26/34] Fix ShellClassPathResolver --- .../kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt b/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt index 4ba736dd..3f3dfefe 100644 --- a/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt +++ b/shared/src/main/kotlin/org/javacs/kt/classpath/ShellClassPathResolver.kt @@ -46,7 +46,7 @@ internal class ShellClassPathResolver( ?.let { root -> scriptExtensions .map { root.resolve("classpath.$it") } - .first { Files.exists(it) } + .firstOrNull { Files.exists(it) } } ?.let { ShellClassPathResolver(it, workingDir) } ?: ClassPathResolver.empty From d338e4d215a9a61627106671a64f8dbc376debda Mon Sep 17 00:00:00 2001 From: Marie Katrine Ekeberg Date: Wed, 13 Apr 2022 14:02:48 +0200 Subject: [PATCH 27/34] Notify client that folder sync is done, so the message is not there for the entire session. Also added a elvis in cases where folder.name is null to avoid confusing notification messages. --- server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt index 56e97515..76410e82 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt @@ -108,7 +108,7 @@ class KotlinLanguageServer : LanguageServer, LanguageClientAware, Closeable { folders.forEachIndexed { i, folder -> LOG.info("Adding workspace folder {}", folder.name) - val progressPrefix = "[${i + 1}/${folders.size}] ${folder.name}" + val progressPrefix = "[${i + 1}/${folders.size}] ${folder.name ?: ""}" val progressPercent = (100 * i) / folders.size progress?.update("$progressPrefix: Updating source path", progressPercent) @@ -122,6 +122,7 @@ class KotlinLanguageServer : LanguageServer, LanguageClientAware, Closeable { sourcePath.refresh() } } + progress?.close() textDocuments.lintAll() From 58b531689d1d3828119f159ddf0ff7b42a0952c8 Mon Sep 17 00:00:00 2001 From: Marie Katrine Ekeberg Date: Thu, 14 Apr 2022 18:05:15 +0200 Subject: [PATCH 28/34] Fixed indentation --- server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt index 76410e82..a8871b69 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinLanguageServer.kt @@ -122,7 +122,7 @@ class KotlinLanguageServer : LanguageServer, LanguageClientAware, Closeable { sourcePath.refresh() } } - progress?.close() + progress?.close() textDocuments.lintAll() From dd3bd4b684991c27f5bf02e716c15e3b6411b4fe Mon Sep 17 00:00:00 2001 From: daplf Date: Sat, 16 Apr 2022 23:53:52 +0100 Subject: [PATCH 29/34] PR improvements --- .../kotlin/org/javacs/kt/CompilerClassPath.kt | 1 + .../javacs/kt/KotlinProtocolExtensionService.kt | 2 +- .../org/javacs/kt/KotlinProtocolExtensions.kt | 2 +- .../src/main/kotlin/org/javacs/kt/SourcePath.kt | 1 - .../test/kotlin/org/javacs/kt/CompiledFileTest.kt | 13 +++++++++++-- .../src/test/kotlin/org/javacs/kt/CompilerTest.kt | 15 +++++++++++++-- 6 files changed, 27 insertions(+), 7 deletions(-) diff --git a/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt b/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt index 9b322305..23fe1356 100644 --- a/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt +++ b/server/src/main/kotlin/org/javacs/kt/CompilerClassPath.kt @@ -141,6 +141,7 @@ class CompilerClassPath(private val config: CompilerConfiguration) : Closeable { override fun close() { compiler.close() + outputDirectory.delete() } } diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensionService.kt b/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensionService.kt index 15ab37f0..cba9d5d6 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensionService.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensionService.kt @@ -15,7 +15,7 @@ class KotlinProtocolExtensionService( uriContentProvider.contentOf(parseURI(textDocument.uri)) } - override fun getBuildOutputLocation(): CompletableFuture = async.compute { + override fun buildOutputLocation(): CompletableFuture = async.compute { cp.outputDirectory.absolutePath } } diff --git a/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensions.kt b/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensions.kt index 692805b6..b6338eaf 100644 --- a/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensions.kt +++ b/server/src/main/kotlin/org/javacs/kt/KotlinProtocolExtensions.kt @@ -11,5 +11,5 @@ interface KotlinProtocolExtensions { fun jarClassContents(textDocument: TextDocumentIdentifier): CompletableFuture @JsonRequest - fun getBuildOutputLocation(): CompletableFuture + fun buildOutputLocation(): CompletableFuture } diff --git a/server/src/main/kotlin/org/javacs/kt/SourcePath.kt b/server/src/main/kotlin/org/javacs/kt/SourcePath.kt index e430d4af..15069619 100644 --- a/server/src/main/kotlin/org/javacs/kt/SourcePath.kt +++ b/server/src/main/kotlin/org/javacs/kt/SourcePath.kt @@ -13,7 +13,6 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.CompositeBindingContext import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter -import java.lang.Exception import kotlin.concurrent.withLock import java.nio.file.Path import java.nio.file.Paths diff --git a/server/src/test/kotlin/org/javacs/kt/CompiledFileTest.kt b/server/src/test/kotlin/org/javacs/kt/CompiledFileTest.kt index a2eaab79..026ddbb1 100644 --- a/server/src/test/kotlin/org/javacs/kt/CompiledFileTest.kt +++ b/server/src/test/kotlin/org/javacs/kt/CompiledFileTest.kt @@ -2,21 +2,30 @@ package org.javacs.kt import org.hamcrest.Matchers.equalTo import org.javacs.kt.compiler.Compiler +import org.junit.AfterClass import org.junit.Assert.assertThat import org.junit.Test import org.junit.BeforeClass +import java.io.File import java.nio.file.Files class CompiledFileTest { val compiledFile = compileFile() companion object { - @JvmStatic @BeforeClass fun setupLogger() { + lateinit var outputDirectory: File + + @JvmStatic @BeforeClass fun setup() { LOG.connectStdioBackend() + outputDirectory = Files.createTempDirectory("klsBuildOutput").toFile() + } + + @JvmStatic @AfterClass fun tearDown() { + outputDirectory.delete() } } - fun compileFile(): CompiledFile = Compiler(setOf(), setOf(), outputDirectory = Files.createTempDirectory("klsBuildOutput").toFile()).use { compiler -> + fun compileFile(): CompiledFile = Compiler(setOf(), setOf(), outputDirectory = outputDirectory).use { compiler -> val file = testResourcesRoot().resolve("compiledFile/CompiledFileExample.kt") val content = Files.readAllLines(file).joinToString("\n") val parse = compiler.createKtFile(content, file) diff --git a/server/src/test/kotlin/org/javacs/kt/CompilerTest.kt b/server/src/test/kotlin/org/javacs/kt/CompilerTest.kt index 661ebb9a..0c96c094 100644 --- a/server/src/test/kotlin/org/javacs/kt/CompilerTest.kt +++ b/server/src/test/kotlin/org/javacs/kt/CompilerTest.kt @@ -10,11 +10,12 @@ import org.javacs.kt.compiler.Compiler import org.junit.Assert.assertThat import org.junit.Test import org.junit.After +import org.junit.AfterClass import org.junit.BeforeClass +import java.io.File import java.nio.file.Files class CompilerTest { - val compiler = Compiler(setOf(), setOf(), outputDirectory = Files.createTempDirectory("klsBuildOutput").toFile()) val myTestResources = testResourcesRoot().resolve("compiler") val file = myTestResources.resolve("FileToEdit.kt") val editedText = """ @@ -23,8 +24,18 @@ private class FileToEdit { }""" companion object { - @JvmStatic @BeforeClass fun setupLogger() { + lateinit var outputDirectory: File + lateinit var compiler: Compiler + + @JvmStatic @BeforeClass fun setup() { LOG.connectStdioBackend() + outputDirectory = Files.createTempDirectory("klsBuildOutput").toFile() + compiler = Compiler(setOf(), setOf(), outputDirectory = outputDirectory) + } + + @JvmStatic @AfterClass + fun tearDown() { + outputDirectory.delete() } } From ef9c5b9d8d03a227f04229081298aa601f31365b Mon Sep 17 00:00:00 2001 From: Goooler Date: Fri, 22 Apr 2022 11:06:13 +0800 Subject: [PATCH 30/34] Bump actions/setup-java to v3 --- .github/workflows/build.yml | 2 +- .github/workflows/deploy.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bc9f5df3..78ced0bb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Setup JDK - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: ${{ matrix.java }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 644a4a8f..7cf655ed 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -10,7 +10,7 @@ jobs: steps: - uses: actions/checkout@v3 - name: Setup JDK - uses: actions/setup-java@v2 + uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '11' From 27e3449c3eb6ce8f1512690339d3b59b5ae9529c Mon Sep 17 00:00:00 2001 From: Goooler Date: Fri, 22 Apr 2022 11:07:18 +0800 Subject: [PATCH 31/34] Use gradle-build-action --- .github/workflows/build.yml | 5 +++-- .github/workflows/deploy.yml | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 78ced0bb..43e51914 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,12 +1,12 @@ name: Build -on: [push, pull_request] +on: [ push, pull_request ] jobs: build: runs-on: ubuntu-latest strategy: matrix: - java: ['11', '17'] + java: [ '11', '17' ] steps: - uses: actions/checkout@v3 - name: Setup JDK @@ -14,5 +14,6 @@ jobs: with: distribution: 'temurin' java-version: ${{ matrix.java }} + - uses: gradle/gradle-build-action@v2 - name: Build run: ./gradlew :server:build :shared:build diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 7cf655ed..cb758290 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -14,6 +14,7 @@ jobs: with: distribution: 'temurin' java-version: '11' + - uses: gradle/gradle-build-action@v2 - name: Build distribution run: ./gradlew :server:distZip :grammars:distZip - name: Create release From 42c9f0a434fef61b0540667800f50b5ef5bb7e0d Mon Sep 17 00:00:00 2001 From: Goooler Date: Fri, 22 Apr 2022 11:09:50 +0800 Subject: [PATCH 32/34] Disable deploy job in forked repository --- .github/workflows/deploy.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index cb758290..8e1a1c05 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -7,6 +7,7 @@ on: jobs: deploy: runs-on: ubuntu-latest + if: github.repository == 'fwcd/kotlin-language-server' steps: - uses: actions/checkout@v3 - name: Setup JDK From f693eb2355c77fe59fca8db45d41537fee4b3d99 Mon Sep 17 00:00:00 2001 From: fwcd Date: Sat, 23 Apr 2022 22:12:20 +0200 Subject: [PATCH 33/34] Remove progress indicators on incremental indexing --- .../kotlin/org/javacs/kt/index/SymbolIndex.kt | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/server/src/main/kotlin/org/javacs/kt/index/SymbolIndex.kt b/server/src/main/kotlin/org/javacs/kt/index/SymbolIndex.kt index f989eeff..b6a6cf00 100644 --- a/server/src/main/kotlin/org/javacs/kt/index/SymbolIndex.kt +++ b/server/src/main/kotlin/org/javacs/kt/index/SymbolIndex.kt @@ -117,22 +117,18 @@ class SymbolIndex { val started = System.currentTimeMillis() LOG.info("Updating symbol index...") - progressFactory.create("Indexing").thenApplyAsync { progress -> - try { - transaction(db) { - removeDeclarations(remove) - addDeclarations(add) - - val finished = System.currentTimeMillis() - val count = Symbols.slice(Symbols.fqName.count()).selectAll().first()[Symbols.fqName.count()] - LOG.info("Updated symbol index in ${finished - started} ms! (${count} symbol(s))") - } - } catch (e: Exception) { - LOG.error("Error while updating symbol index") - LOG.printStackTrace(e) + try { + transaction(db) { + removeDeclarations(remove) + addDeclarations(add) + + val finished = System.currentTimeMillis() + val count = Symbols.slice(Symbols.fqName.count()).selectAll().first()[Symbols.fqName.count()] + LOG.info("Updated symbol index in ${finished - started} ms! (${count} symbol(s))") } - - progress.close() + } catch (e: Exception) { + LOG.error("Error while updating symbol index") + LOG.printStackTrace(e) } } From 322fb60be038c20dfa11cec8db90a47d48be0e2f Mon Sep 17 00:00:00 2001 From: fwcd Date: Fri, 29 Apr 2022 01:25:36 +0200 Subject: [PATCH 34/34] Trigger push CI only on main branch --- .github/workflows/build.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 43e51914..7afdab91 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,5 +1,10 @@ name: Build -on: [ push, pull_request ] + +on: + push: + branches: + - main + pull_request: jobs: build: