diff --git a/.gitignore b/.gitignore index 47af25bb5d8a0cd83786205a92348555ae5cf657..9460fd2ef2cc1e85ff4a8cf73d7c89f1e001e10d 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,4 @@ hs_err_pid* # Ignore Gradle build output directory build +/.idea/ diff --git a/build.gradle.kts b/build.gradle.kts index ae11418a7094a50351a10c9a10c678cdbb8047d4..03f0b4e5081caf2256b5e73955438c52ae5f89ff 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -10,6 +10,7 @@ plugins { idea // Apply the application plugin to add support for building a CLI application. application + id("com.github.johnrengelman.shadow") version "5.2.0" } repositories { @@ -25,6 +26,8 @@ dependencies { // Use the Kotlin JDK 8 standard library. implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + implementation("org.eclipse.lsp4j", "org.eclipse.lsp4j", "0.9.0") + // Use the Kotlin test library. testImplementation("org.jetbrains.kotlin:kotlin-test") diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000000000000000000000000000000000..622ab64a3cb60378cd29384961554c0b032c9368 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/src/main/kotlin/b/language/server/App.kt b/src/main/kotlin/b/language/server/App.kt new file mode 100644 index 0000000000000000000000000000000000000000..b88299a03240f5c7b9b69da9c3663aeaadc94ea0 --- /dev/null +++ b/src/main/kotlin/b/language/server/App.kt @@ -0,0 +1,33 @@ +/* + * This Kotlin source file was generated by the Gradle 'init' task. + */ +package b.language.server + +import org.eclipse.lsp4j.jsonrpc.Launcher +import org.eclipse.lsp4j.launch.LSPLauncher +import org.eclipse.lsp4j.services.LanguageClient +import java.io.InputStream +import java.io.OutputStream +import java.util.concurrent.Future + + +class App { + val greeting: String + get() { + return "Hello world." + } +} + +fun main(args: Array<String>) { + startServer(System.`in`, System.out); + +} + +fun startServer(inputStream: InputStream, outputStream: OutputStream){ + val server : Server = Server() + val launcher : Launcher<LanguageClient> = LSPLauncher.createServerLauncher(server, inputStream, outputStream) + val startListing : Future<*> = launcher.startListening() + server.setRemoteProxy(launcher.remoteProxy) + startListing.get() + +} diff --git a/src/main/kotlin/b/language/server/BDocumentService.kt b/src/main/kotlin/b/language/server/BDocumentService.kt new file mode 100644 index 0000000000000000000000000000000000000000..a0dbf76133a81005ac6d3040053d5e03c3008aec --- /dev/null +++ b/src/main/kotlin/b/language/server/BDocumentService.kt @@ -0,0 +1,67 @@ +package b.language.server + +import org.eclipse.lsp4j.* +import org.eclipse.lsp4j.jsonrpc.messages.Either +import org.eclipse.lsp4j.services.TextDocumentService +import java.util.concurrent.CompletableFuture +import java.util.concurrent.ConcurrentHashMap + +class BDocumentService(private val server: Server) : TextDocumentService { + + private val documents = ConcurrentHashMap<String, String>() + + /** + * The document open notification is sent from the client to the server to + * signal newly opened text documents. The document's truth is now managed + * by the client and the server must not try to read the document's truth + * using the document's uri. + * + * Registration Options: TextDocumentRegistrationOptions + */ + override fun didOpen(params: DidOpenTextDocumentParams?) { + documents[params?.textDocument!!.uri] = params.textDocument!!.text + } + + /** + * The document save notification is sent from the client to the server when + * the document for saved in the client. + * + * Registration Options: TextDocumentSaveRegistrationOptions + */ + override fun didSave(params: DidSaveTextDocumentParams?) { + println("Save") + TODO("Not yet implemented") + } + + /** + * The document close notification is sent from the client to the server + * when the document got closed in the client. The document's truth now + * exists where the document's uri points to (e.g. if the document's uri is + * a file uri the truth now exists on disk). + * + * Registration Options: TextDocumentRegistrationOptions + */ + override fun didClose(params: DidCloseTextDocumentParams?) { + TODO("Not yet implemented") + } + + /** + * The document change notification is sent from the client to the server to + * signal changes to a text document. + * + * Registration Options: TextDocumentChangeRegistrationOptions + */ + override fun didChange(params: DidChangeTextDocumentParams?) { + + CompletableFuture.runAsync { + val diagnostics : ArrayList<Diagnostic> = + arrayListOf(Diagnostic(Range(Position(1,1), Position(1,1)), "Test", DiagnosticSeverity.Error, "Test")) + server.languageClient.publishDiagnostics(PublishDiagnosticsParams(params?.textDocument?.uri, diagnostics)) + } + } + + + + + +} \ No newline at end of file diff --git a/src/main/kotlin/b/language/server/BWorkspaceService.kt b/src/main/kotlin/b/language/server/BWorkspaceService.kt new file mode 100644 index 0000000000000000000000000000000000000000..2ae854082e00ded8133538d7179fee1ec0c5b564 --- /dev/null +++ b/src/main/kotlin/b/language/server/BWorkspaceService.kt @@ -0,0 +1,23 @@ +package b.language.server + +import org.eclipse.lsp4j.DidChangeConfigurationParams +import org.eclipse.lsp4j.DidChangeWatchedFilesParams +import org.eclipse.lsp4j.services.WorkspaceService + +class BWorkspaceService : WorkspaceService { + /** + * The watched files notification is sent from the client to the server when + * the client detects changes to file watched by the language client. + */ + override fun didChangeWatchedFiles(params: DidChangeWatchedFilesParams?) { + TODO("Not yet implemented") + } + + /** + * A notification sent from the client to the server to signal the change of + * configuration settings. + */ + override fun didChangeConfiguration(params: DidChangeConfigurationParams?) { + TODO("Not yet implemented") + } +} \ No newline at end of file diff --git a/src/main/kotlin/b/language/server/Server.kt b/src/main/kotlin/b/language/server/Server.kt new file mode 100644 index 0000000000000000000000000000000000000000..3e5e5b17e904fb553cd6b0f101d7ef3f58579544 --- /dev/null +++ b/src/main/kotlin/b/language/server/Server.kt @@ -0,0 +1,90 @@ +package b.language.server + +import org.eclipse.lsp4j.* +import org.eclipse.lsp4j.services.LanguageClient +import org.eclipse.lsp4j.services.LanguageServer +import org.eclipse.lsp4j.services.TextDocumentService +import org.eclipse.lsp4j.services.WorkspaceService +import java.util.concurrent.CompletableFuture +import kotlin.system.exitProcess + + +class Server : LanguageServer { + + private val textDocumentService : TextDocumentService + private val bWorkspaceService : WorkspaceService + lateinit var languageClient : LanguageClient + + + + init { + textDocumentService = BDocumentService(this) + bWorkspaceService = BWorkspaceService() + } + + + /** + * The initialize request is sent as the first request from the client to + * the server. + * + * If the server receives request or notification before the initialize request it should act as follows: + * - for a request the respond should be errored with code: -32001. The message can be picked by the server. + * - notifications should be dropped, except for the exit notification. This will allow the exit a server without an initialize request. + * + * Until the server has responded to the initialize request with an InitializeResult + * the client must not sent any additional requests or notifications to the server. + * + * During the initialize request the server is allowed to sent the notifications window/showMessage, + * window/logMessage and telemetry/event as well as the window/showMessageRequest request to the client. + */ + override fun initialize(params: InitializeParams?): CompletableFuture<InitializeResult> { + val res = InitializeResult(ServerCapabilities()) + res.capabilities.setCodeActionProvider(true) + res.capabilities.completionProvider = CompletionOptions() + res.capabilities.definitionProvider = false + res.capabilities.hoverProvider = false + res.capabilities.referencesProvider = false + res.capabilities.setTextDocumentSync(TextDocumentSyncKind.Full) + res.capabilities.documentSymbolProvider = false + + return CompletableFuture.supplyAsync { res } + } + + + /** + * The shutdown request is sent from the client to the server. It asks the + * server to shutdown, but to not exit (otherwise the response might not be + * delivered correctly to the client). There is a separate exit notification + * that asks the server to exit. + */ + override fun shutdown(): CompletableFuture<Any> { + return CompletableFuture.supplyAsync{true} + } + + /** + * Provides access to the textDocument services. + */ + override fun getTextDocumentService(): TextDocumentService { + return textDocumentService + } + + /** + * A notification to ask the server to exit its process. + */ + override fun exit() { + exitProcess(0); + } + + + + /** + * Provides access to the workspace services. + */ + override fun getWorkspaceService(): WorkspaceService { + return bWorkspaceService + } + + fun setRemoteProxy(remoteProxy: LanguageClient) { + this.languageClient = remoteProxy + } +} \ No newline at end of file diff --git a/src/test/kotlin/b/language/server/AppTest.kt b/src/test/kotlin/b/language/server/AppTest.kt new file mode 100644 index 0000000000000000000000000000000000000000..898b91cb22e908c9325dcb997e8f150623f48a9c --- /dev/null +++ b/src/test/kotlin/b/language/server/AppTest.kt @@ -0,0 +1,14 @@ +/* + * This Kotlin source file was generated by the Gradle 'init' task. + */ +package b.language.server + +import kotlin.test.Test +import kotlin.test.assertNotNull + +class AppTest { + @Test fun testAppHasAGreeting() { + val classUnderTest = App() + assertNotNull(classUnderTest.greeting, "app should have a greeting") + } +}