diff --git a/fleet/lsp.protocol/BUILD.bazel b/fleet/lsp.protocol/BUILD.bazel index af24a1d5b047..861b05d932c3 100644 --- a/fleet/lsp.protocol/BUILD.bazel +++ b/fleet/lsp.protocol/BUILD.bazel @@ -7,6 +7,7 @@ create_kotlinc_options( opt_in = [ "kotlinx.coroutines.ExperimentalCoroutinesApi", "kotlinx.serialization.ExperimentalSerializationApi", + "kotlin.concurrent.atomics.ExperimentalAtomicApi", ], x_consistent_data_class_copy_visibility = True, x_context_parameters = True, @@ -17,7 +18,7 @@ jvm_library( name = "lsp.protocol", module_name = "fleet.lsp.protocol", visibility = ["//visibility:public"], - srcs = glob(["src/main/**/*.kt", "src/main/**/*.java", "src/main/**/*.form"], allow_empty = True, exclude = ["**/module-info.java"]), + srcs = glob(["srcCommonMain/**/*.kt", "srcCommonMain/**/*.java", "srcCommonMain/**/*.form", "srcJvmMain/**/*.kt", "srcJvmMain/**/*.java", "srcJvmMain/**/*.form"], allow_empty = True, exclude = ["**/module-info.java"]), kotlinc_opts = ":custom_lsp.protocol", deps = [ "@lib//:kotlin-stdlib", diff --git a/fleet/lsp.protocol/fleet.lsp.protocol.iml b/fleet/lsp.protocol/fleet.lsp.protocol.iml index afaaa43a0f80..41fad3e4396a 100644 --- a/fleet/lsp.protocol/fleet.lsp.protocol.iml +++ b/fleet/lsp.protocol/fleet.lsp.protocol.iml @@ -4,7 +4,7 @@ - @@ -24,7 +24,8 @@ - + + diff --git a/fleet/lsp.protocol/gradlebuild/build.gradle.kts b/fleet/lsp.protocol/gradlebuild/build.gradle.kts index b9aed9843d2f..9f844f2eb226 100644 --- a/fleet/lsp.protocol/gradlebuild/build.gradle.kts +++ b/fleet/lsp.protocol/gradlebuild/build.gradle.kts @@ -33,11 +33,13 @@ kotlin { "-Xcontext-parameters", "-Xjvm-default=all", "-XXLanguage:+AllowEagerSupertypeAccessibilityChecks", + "-opt-in=kotlin.concurrent.atomics.ExperimentalAtomicApi", ) jvm {} + wasmJs { + browser {} + } pluginManager.withPlugin("fleet-build-jps-module-plugin") { - sourceSets.jvmMain.configure { kotlin.srcDir(layout.projectDirectory.dir("../src/main")) } - configureAtMostOneJvmTargetOrThrow { compilations.named("main") { withJavaSourceSet { javaSourceSet -> javaSourceSet.java.srcDir(layout.projectDirectory.dir("../src/main")) } } } sourceSets.commonMain.configure { kotlin.srcDir(layout.projectDirectory.dir("../srcCommonMain")) } sourceSets.commonMain.configure { resources.srcDir(layout.projectDirectory.dir("../resourcesCommonMain")) } sourceSets.commonTest.configure { kotlin.srcDir(layout.projectDirectory.dir("../testCommonTest")) } @@ -48,6 +50,10 @@ kotlin { sourceSets.jvmTest.configure { kotlin.srcDir(layout.projectDirectory.dir("../testJvmTest")) } configureAtMostOneJvmTargetOrThrow { compilations.named("test") { withJavaSourceSet { javaSourceSet -> javaSourceSet.java.srcDir(layout.projectDirectory.dir("../testJvmTest")) } } } sourceSets.jvmTest.configure { resources.srcDir(layout.projectDirectory.dir("../testResourcesJvmTest")) } + sourceSets.wasmJsMain.configure { kotlin.srcDir(layout.projectDirectory.dir("../srcWasmJsMain")) } + sourceSets.wasmJsMain.configure { resources.srcDir(layout.projectDirectory.dir("../resourcesWasmJsMain")) } + sourceSets.wasmJsTest.configure { kotlin.srcDir(layout.projectDirectory.dir("../testWasmJsTest")) } + sourceSets.wasmJsTest.configure { resources.srcDir(layout.projectDirectory.dir("../testResourcesWasmJsTest")) } } sourceSets.commonMain.dependencies { implementation(jps.org.jetbrains.kotlin.kotlin.stdlib1993400674.get().let { "${it.group}:${it.name}:${it.version}" }) { diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/protocolFraming.kt b/fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/protocolFraming.kt deleted file mode 100644 index f946f783ff0a..000000000000 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/protocolFraming.kt +++ /dev/null @@ -1,157 +0,0 @@ -package com.jetbrains.lsp.implementation - -import com.jetbrains.lsp.protocol.* -import io.ktor.utils.io.* -import kotlinx.coroutines.* -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.ReceiveChannel -import kotlinx.coroutines.channels.SendChannel -import kotlinx.coroutines.channels.consumeEach -import kotlinx.io.IOException -import kotlinx.serialization.json.JsonElement -import java.io.ByteArrayOutputStream - -private suspend fun ByteReadChannel.readLine(): String { - val buffer = ByteArrayOutputStream() - var prevChar: Int? = null - while (true) { - val currentChar = this.readByte().toInt() - if (currentChar == -1 || (prevChar == '\r'.code && currentChar == '\n'.code)) { - break - } - if (prevChar != null) { - buffer.write(prevChar) - } - prevChar = currentChar - } - return buffer.toString(Charsets.UTF_8).trim() -} - -private suspend fun ByteReadChannel.readFrame(): JsonElement? { - var contentLength = -1 - var readSomething = false - val buf = try { - while (!isClosedForRead) { - val line = this.readLine() - if (line.isEmpty()) break - readSomething = true - val (key, value) = line.split(':').map { it.trim() } - if (key == "Content-Length") { - contentLength = value.toInt() - } - } - if (!readSomething) return null - if (contentLength == -1) throw IllegalStateException("Content-Length header not found") - readByteArray(contentLength) - } catch (e: Exception) { - when (e) { - is IOException -> return null - else -> throw e - } - } - return LSP.json.decodeFromString(JsonElement.serializer(), String(buf, Charsets.UTF_8)) -} - -/** - * @return Boolean indicating whether the frame was successfully written (`true`) or the channel was closed (`false`). - */ -private suspend fun ByteWriteChannel.writeFrame(jsonElement: JsonElement): Boolean { - val str = LSP.json.encodeToString(JsonElement.serializer(), jsonElement) - val frameStr = buildString { - // protocol requires string length in bytes - val contentLengthInBytes = str.toByteArray(Charsets.UTF_8).size - append("Content-Length: $contentLengthInBytes\r\n") - append("Content-Type: application/json-rpc; charset=utf-8\r\n") - append("\r\n") - append(str) - } - try { - if (isClosedForWrite) return false - writeByteArray(frameStr.toByteArray(Charsets.UTF_8)) - flush() - return true - } - catch (e: Exception) { - when (e) { - is IOException -> return false - else -> throw e - } - } -} - -suspend fun withBaseProtocolFraming( - connection: LspConnection, - exitSignal: CompletableDeferred?, - body: suspend CoroutineScope.( - incoming: ReceiveChannel, - outgoing: SendChannel, - ) -> Unit, -) { - val reader = connection.input - val writer = connection.output - - coroutineScope { - val (incomingSender, incomingReceiver) = channels() - val (outgoingSender, outgoingReceiver) = channels(Channel.UNLIMITED) - val readJob = launch { - incomingSender.use { - while (true) { - val frame = reader.readFrame() - if (frame == null) { - exitSignal?.complete(Unit) - break - } - incomingSender.send(frame) - } - } - } - val writeJob = launch { - outgoingReceiver.consumeEach { frame -> - val success = writer.writeFrame(frame) - if (!success) { - exitSignal?.complete(Unit) - } - } - } - - try { - body(incomingReceiver, outgoingSender) - } - finally { - readJob.cancel() - writeJob.cancel() - connection.close() - } - } -} - -fun main() { - val handler = lspHandlers { - request(Initialize) { initParams -> - InitializeResult( - capabilities = ServerCapabilities( - textDocumentSync = TextDocumentSyncKind.Incremental, - ), - serverInfo = InitializeResult.ServerInfo( - name = "IntelliJ Analyzer", - version = "1.0" - ), - ) - } - notification(DocumentSync.DidOpen) { didOpen -> - println("didOpen: $didOpen") - } - notification(DocumentSync.DidChange) { didChange -> - println("didChange: $didChange") - } - } - runBlocking(Dispatchers.Default) { - tcpServer(TcpConnectionConfig.Server("127.0.0.1", 9999, isMultiClient = true)) { connection -> - withBaseProtocolFraming(connection, exitSignal = null) { incoming, outgoing -> - withLsp(incoming, outgoing, handler) { lsp -> - awaitCancellation() - } - } - } - } -} \ No newline at end of file diff --git a/fleet/lsp.protocol/srcCommonMain/.pseudoCommonKotlinSourceSet b/fleet/lsp.protocol/srcCommonMain/.pseudoCommonKotlinSourceSet new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/AsyncUtil.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/AsyncUtil.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/AsyncUtil.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/AsyncUtil.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/LspClient.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/LspClient.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/LspClient.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/LspClient.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/LspConnection.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/LspConnection.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/LspConnection.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/LspConnection.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/LspException.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/LspException.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/LspException.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/LspException.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/LspHandlers.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/LspHandlers.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/LspHandlers.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/LspHandlers.kt diff --git a/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/protocolFraming.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/protocolFraming.kt new file mode 100644 index 000000000000..98be77f26317 --- /dev/null +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/protocolFraming.kt @@ -0,0 +1,114 @@ +package com.jetbrains.lsp.implementation + +import com.jetbrains.lsp.protocol.LSP +import fleet.util.decodeToStringUtf8 +import fleet.util.encodeToByteArrayUtf8 +import io.ktor.utils.io.* +import kotlinx.coroutines.CompletableDeferred +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.channels.ReceiveChannel +import kotlinx.coroutines.channels.SendChannel +import kotlinx.coroutines.channels.consumeEach +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import kotlinx.io.IOException +import kotlinx.serialization.json.JsonElement + +suspend fun withBaseProtocolFraming( + connection: LspConnection, + exitSignal: CompletableDeferred?, + body: suspend CoroutineScope.( + incoming: ReceiveChannel, + outgoing: SendChannel, + ) -> Unit, +) { + val reader = connection.input + val writer = connection.output + + coroutineScope { + val (incomingSender, incomingReceiver) = channels() + val (outgoingSender, outgoingReceiver) = channels(Channel.UNLIMITED) + val readJob = launch { + incomingSender.use { + while (true) { + val frame = reader.readFrame() + if (frame == null) { + exitSignal?.complete(Unit) + break + } + incomingSender.send(frame) + } + } + } + val writeJob = launch { + outgoingReceiver.consumeEach { frame -> + val success = writer.writeFrame(frame) + if (!success) { + exitSignal?.complete(Unit) + } + } + } + + try { + body(incomingReceiver, outgoingSender) + } + finally { + readJob.cancel() + writeJob.cancel() + connection.close() + } + } +} + +private suspend fun ByteReadChannel.readFrame(): JsonElement? { + var contentLength = -1 + var readSomething = false + val buf = try { + while (!isClosedForRead) { + val line = readUTF8Line() + if (line.isNullOrEmpty()) break + readSomething = true + val (key, value) = line.split(':').map { it.trim() } + if (key == "Content-Length") { + contentLength = value.toInt() + } + } + if (!readSomething) return null + if (contentLength == -1) throw IllegalStateException("Content-Length header not found") + readByteArray(contentLength) + } catch (e: Exception) { + when (e) { + is IOException -> return null + else -> throw e + } + } + return LSP.json.decodeFromString(JsonElement.serializer(), buf.decodeToStringUtf8()) +} + +/** + * @return Boolean indicating whether the frame was successfully written (`true`) or the channel was closed (`false`). + */ +private suspend fun ByteWriteChannel.writeFrame(jsonElement: JsonElement): Boolean { + val str = LSP.json.encodeToString(JsonElement.serializer(), jsonElement) + val frameStr = buildString { + // protocol requires string length in bytes + val contentLengthInBytes = str.encodeToByteArrayUtf8().size + append("Content-Length: $contentLengthInBytes\r\n") + append("Content-Type: application/json-rpc; charset=utf-8\r\n") + append("\r\n") + append(str) + } + try { + if (isClosedForWrite) return false + writeByteArray(frameStr.encodeToByteArrayUtf8()) + flush() + return true + } + catch (e: Exception) { + when (e) { + is IOException -> return false + else -> throw e + } + } +} \ No newline at end of file diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/streaming.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/streaming.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/streaming.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/streaming.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/withLsp.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/withLsp.kt similarity index 86% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/withLsp.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/withLsp.kt index 99775eb3a8b1..4029dd0fb6a6 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/withLsp.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/implementation/withLsp.kt @@ -1,19 +1,18 @@ package com.jetbrains.lsp.implementation import com.jetbrains.lsp.protocol.* +import fleet.multiplatform.shims.ConcurrentHashMap import fleet.util.logging.logger import kotlinx.coroutines.* -import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.SendChannel import kotlinx.coroutines.channels.consumeEach import kotlinx.serialization.KSerializer -import kotlinx.serialization.builtins.serializer import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive -import java.util.concurrent.ConcurrentHashMap -import java.util.concurrent.atomic.AtomicInteger +import kotlin.concurrent.atomics.AtomicInt +import kotlin.concurrent.atomics.incrementAndFetch import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext @@ -43,13 +42,13 @@ suspend fun withLsp( ) { coroutineScope { val outgoingRequests = ConcurrentHashMap() - val idGen = AtomicInteger(0) + val idGen = AtomicInt(0) val lspClient = object : LspClient { override suspend fun request( requestType: RequestType, params: Params, ): Result { - val id = StringOrInt(JsonPrimitive(idGen.incrementAndGet())) + val id = StringOrInt(JsonPrimitive(idGen.incrementAndFetch())) val deferred = CompletableDeferred() outgoingRequests[id] = OutgoingRequest(deferred, requestType) val request = RequestMessage( @@ -273,57 +272,4 @@ suspend fun withLsp( } } -fun main() { - runBlocking(Dispatchers.Default) { - val clientToServer = Channel(Channel.UNLIMITED) - val serverToClient = Channel(Channel.UNLIMITED) - val HelloRequestType = RequestType("hello", String.serializer(), String.serializer(), Unit.serializer()) - val HangRequestType = RequestType("hand", Unit.serializer(), Unit.serializer(), Unit.serializer()) - val PrintHelloNotification = NotificationType("printHello", String.serializer()) - - withLsp( - incoming = clientToServer, - outgoing = serverToClient, - handlers = lspHandlers { - request(HelloRequestType) { str -> - "Hello, $str" - } - notification(PrintHelloNotification) { str -> - println("server: $str") - } - request(HangRequestType) { - try { - awaitCancellation() - } catch (c: CancellationException) { - println("cancelled by client") - throw c - } - } - }, - ) { server -> - withLsp( - incoming = serverToClient, - outgoing = clientToServer, - handlers = lspHandlers { - notification(PrintHelloNotification) { str -> - println("client: $str") - } - }, - ) { client -> - println(client.request(HelloRequestType, "World")) - client.notify(PrintHelloNotification, "Hello World") - client.notify(PrintHelloNotification, "Hello World") - val hangingRequestJob = launch { - client.request(HangRequestType, Unit) - } - delay(100) - hangingRequestJob.cancel() - println("request cancelled") - delay(100) - println("quitting") - } - } - } -} - private val LOG = logger() \ No newline at end of file diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ApplyEdit.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ApplyEdit.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ApplyEdit.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ApplyEdit.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ClientCapabilities.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ClientCapabilities.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ClientCapabilities.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ClientCapabilities.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ClientFileOperationsCapabilities.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ClientFileOperationsCapabilities.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ClientFileOperationsCapabilities.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ClientFileOperationsCapabilities.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ClientGeneralCapabilities.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ClientGeneralCapabilities.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ClientGeneralCapabilities.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ClientGeneralCapabilities.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ClientWindowCapabilities.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ClientWindowCapabilities.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ClientWindowCapabilities.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ClientWindowCapabilities.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ClientWorkspaceCapabilities.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ClientWorkspaceCapabilities.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ClientWorkspaceCapabilities.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ClientWorkspaceCapabilities.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/CodeAction.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/CodeAction.kt similarity index 99% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/CodeAction.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/CodeAction.kt index 7d7eae3df814..7a693dba0494 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/CodeAction.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/CodeAction.kt @@ -10,6 +10,7 @@ import kotlinx.serialization.json.JsonContentPolymorphicSerializer import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive +import kotlin.jvm.JvmInline @Serializable data class CodeActionOptions( diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/CodeLens.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/CodeLens.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/CodeLens.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/CodeLens.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Completion.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Completion.kt similarity index 99% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Completion.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Completion.kt index 3fe630b34b0f..c9481ea05659 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Completion.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Completion.kt @@ -8,6 +8,7 @@ import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonContentPolymorphicSerializer import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive +import kotlin.jvm.JvmInline @Serializable data class CompletionClientCapabilities( diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Declaration.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Declaration.kt similarity index 99% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Declaration.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Declaration.kt index 57160223aaa8..2e6f18c377c0 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Declaration.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Declaration.kt @@ -8,6 +8,7 @@ import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.jsonArray +import kotlin.jvm.JvmInline @Serializable data class DeclarationClientCapabilities( diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Definition.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Definition.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Definition.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Definition.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Diagnostics.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Diagnostics.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Diagnostics.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Diagnostics.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/DocumentColor.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/DocumentColor.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/DocumentColor.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/DocumentColor.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/DocumentSync.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/DocumentSync.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/DocumentSync.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/DocumentSync.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/EnumAsIntSerializer.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/EnumAsIntSerializer.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/EnumAsIntSerializer.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/EnumAsIntSerializer.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ExecuteCommand.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ExecuteCommand.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ExecuteCommand.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ExecuteCommand.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Formatting.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Formatting.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Formatting.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Formatting.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Hover.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Hover.kt similarity index 99% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Hover.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Hover.kt index 4c8fe2388f65..f50084476c75 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Hover.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Hover.kt @@ -9,6 +9,7 @@ import kotlinx.serialization.json.JsonContentPolymorphicSerializer import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive +import kotlin.jvm.JvmInline @Serializable data class HoverParams( diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Implementation.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Implementation.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Implementation.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Implementation.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Initialize.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Initialize.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Initialize.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Initialize.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/InlayHint.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/InlayHint.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/InlayHint.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/InlayHint.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/JsonRpc.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/JsonRpc.kt similarity index 96% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/JsonRpc.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/JsonRpc.kt index 47036bd015cc..a2d119c18448 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/JsonRpc.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/JsonRpc.kt @@ -1,12 +1,10 @@ package com.jetbrains.lsp.protocol -import kotlinx.serialization.DeserializationStrategy import kotlinx.serialization.KSerializer -import kotlinx.serialization.json.JsonElement import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonContentPolymorphicSerializer +import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.jsonObject +import kotlin.jvm.JvmInline data class Header( val contentLenght: Int, diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/LSP.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/LSP.kt similarity index 98% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/LSP.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/LSP.kt index 2b4b223fcf84..498f5d96d108 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/LSP.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/LSP.kt @@ -1,5 +1,7 @@ package com.jetbrains.lsp.protocol +import fleet.util.isValidUriString +import io.ktor.http.Url import kotlinx.serialization.* import kotlinx.serialization.builtins.serializer import kotlinx.serialization.descriptors.PolymorphicKind @@ -8,6 +10,7 @@ import kotlinx.serialization.descriptors.buildSerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.json.* +import kotlin.jvm.JvmInline /** * URI following the URI specification, so special spaces (like spaces) are encoded. @@ -18,18 +21,21 @@ import kotlinx.serialization.json.* @JvmInline value class URI(val uri: String) { init { - require(isValidUriString(uri)) { "Invalid URI: $uri" } + /** + * We need to have consistent URIs as they are used as keys in the analyzer + */ + require(uri.isValidUriString()) { "Invalid URI: $uri" } } /** * Returns the URI's schema without schema delimiter (`://`) */ - val scheme: String get() = asJavaUri().scheme + val scheme: String get() = Url(uri).protocol.name /** * Returns the file name */ - val fileName: String get() = asJavaUri().path.substringAfterLast('/') + val fileName: String get() = Url(uri).segments.last() /** * Returns the file extension (without dot) if present @@ -41,25 +47,12 @@ value class URI(val uri: String) { return if (dotIndex > 0) name.substring(dotIndex + 1) else null } - - fun asJavaUri(): java.net.URI = java.net.URI(uri) - object Schemas { const val FILE: String = "file" const val JRT: String = "jrt" const val JAR: String = "jar" const val ZIP: String = "zip" } - - companion object { - /** - * We need to have consistent URIs as they are used as keys in the analyzer - */ - fun isValidUriString(uriString: String): Boolean { - val javaUri = runCatching { java.net.URI(uriString) }.getOrNull() ?: return false - return javaUri.scheme != null - } - } } diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/LogMessage.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/LogMessage.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/LogMessage.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/LogMessage.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/LogTrace.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/LogTrace.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/LogTrace.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/LogTrace.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Notebooks.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Notebooks.kt similarity index 99% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Notebooks.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Notebooks.kt index 9f4f77d0910a..704a8a2f1455 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Notebooks.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Notebooks.kt @@ -3,6 +3,7 @@ package com.jetbrains.lsp.protocol import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonElement import kotlinx.serialization.Serializable +import kotlin.jvm.JvmInline @Serializable data class NotebookDocumentClientCapabilities( diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/SelectionRange.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/SelectionRange.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/SelectionRange.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/SelectionRange.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/SemanticTokens.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/SemanticTokens.kt similarity index 99% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/SemanticTokens.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/SemanticTokens.kt index 5fa192078923..05c5cff7b1ba 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/SemanticTokens.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/SemanticTokens.kt @@ -8,6 +8,7 @@ import kotlinx.serialization.builtins.serializer import kotlinx.serialization.json.JsonContentPolymorphicSerializer import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject +import kotlin.jvm.JvmInline @Serializable data class SemanticTokensLegend( diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ServerCapabilities.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ServerCapabilities.kt similarity index 99% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ServerCapabilities.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ServerCapabilities.kt index 1783aafdc3da..ce680eeb77c8 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/ServerCapabilities.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/ServerCapabilities.kt @@ -7,6 +7,7 @@ import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.boolean import kotlinx.serialization.json.booleanOrNull import kotlinx.serialization.json.decodeFromJsonElement +import kotlin.jvm.JvmInline @Serializable @JvmInline diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Shutdown.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Shutdown.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Shutdown.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Shutdown.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/SignatureHelp.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/SignatureHelp.kt similarity index 99% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/SignatureHelp.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/SignatureHelp.kt index f7163a0504df..931dce974e29 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/SignatureHelp.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/SignatureHelp.kt @@ -15,6 +15,7 @@ import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonContentPolymorphicSerializer import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonPrimitive +import kotlin.jvm.JvmInline @Serializable data class SignatureHelpOptions( diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Telemetry.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Telemetry.kt similarity index 97% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Telemetry.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Telemetry.kt index 6a194a2d92d5..6a22cdf4603e 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Telemetry.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Telemetry.kt @@ -7,6 +7,7 @@ import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonContentPolymorphicSerializer import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject +import kotlin.jvm.JvmInline @Serializable(with = JsonObjectOrArraySerializer::class) sealed interface JsonObjectOrArray { diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/TextDocument.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/TextDocument.kt similarity index 99% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/TextDocument.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/TextDocument.kt index 9035e0df560d..e16773c06ce8 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/TextDocument.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/TextDocument.kt @@ -10,6 +10,7 @@ import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonContentPolymorphicSerializer import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject +import kotlin.jvm.JvmInline @Serializable data class DocumentHighlightParams( diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/TextDocumentClientCapabilities.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/TextDocumentClientCapabilities.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/TextDocumentClientCapabilities.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/TextDocumentClientCapabilities.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Window.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Window.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Window.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Window.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Workspace.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Workspace.kt similarity index 99% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Workspace.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Workspace.kt index 4200ca7e178d..7366a965d9dd 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/Workspace.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/Workspace.kt @@ -10,6 +10,7 @@ import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonContentPolymorphicSerializer import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject +import kotlin.jvm.JvmInline @Serializable data class DidChangeWorkspaceFoldersParams( diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/references.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/references.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/references.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/references.kt diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/rename.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/rename.kt similarity index 99% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/rename.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/rename.kt index ea8911402099..acfb0e594548 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/rename.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/rename.kt @@ -8,6 +8,7 @@ import kotlinx.serialization.builtins.serializer import kotlinx.serialization.json.JsonContentPolymorphicSerializer import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject +import kotlin.jvm.JvmInline @Serializable data class PrepareRenameParams( diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/symbols.kt b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/symbols.kt similarity index 99% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/symbols.kt rename to fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/symbols.kt index 288bd11e62e0..2625cb23a5d7 100644 --- a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/protocol/symbols.kt +++ b/fleet/lsp.protocol/srcCommonMain/com/jetbrains/lsp/protocol/symbols.kt @@ -7,6 +7,7 @@ import kotlinx.serialization.builtins.serializer import kotlinx.serialization.json.JsonContentPolymorphicSerializer import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject +import kotlin.jvm.JvmInline @Serializable data class WorkspaceSymbolOptions( diff --git a/fleet/lsp.protocol/srcJvmMain/com/jetbrains/lsp/implementation/lspMain.kt b/fleet/lsp.protocol/srcJvmMain/com/jetbrains/lsp/implementation/lspMain.kt new file mode 100644 index 000000000000..97047138acd3 --- /dev/null +++ b/fleet/lsp.protocol/srcJvmMain/com/jetbrains/lsp/implementation/lspMain.kt @@ -0,0 +1,66 @@ +package com.jetbrains.lsp.implementation + +import com.jetbrains.lsp.protocol.NotificationType +import com.jetbrains.lsp.protocol.RequestType +import kotlinx.coroutines.CancellationException +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.json.JsonElement + +fun main() { + runBlocking(Dispatchers.Default) { + val clientToServer = Channel(Channel.UNLIMITED) + val serverToClient = Channel(Channel.UNLIMITED) + val HelloRequestType = RequestType("hello", String.serializer(), String.serializer(), Unit.serializer()) + val HangRequestType = RequestType("hand", Unit.serializer(), Unit.serializer(), Unit.serializer()) + val PrintHelloNotification = NotificationType("printHello", String.serializer()) + + withLsp( + incoming = clientToServer, + outgoing = serverToClient, + handlers = lspHandlers { + request(HelloRequestType) { str -> + "Hello, $str" + } + notification(PrintHelloNotification) { str -> + println("server: $str") + } + request(HangRequestType) { + try { + awaitCancellation() + } catch (c: CancellationException) { + println("cancelled by client") + throw c + } + } + }, + ) { server -> + withLsp( + incoming = serverToClient, + outgoing = clientToServer, + handlers = lspHandlers { + notification(PrintHelloNotification) { str -> + println("client: $str") + } + }, + ) { client -> + println(client.request(HelloRequestType, "World")) + client.notify(PrintHelloNotification, "Hello World") + client.notify(PrintHelloNotification, "Hello World") + val hangingRequestJob = launch { + client.request(HangRequestType, Unit) + } + delay(100) + hangingRequestJob.cancel() + println("request cancelled") + delay(100) + println("quitting") + } + } + } +} diff --git a/fleet/lsp.protocol/srcJvmMain/com/jetbrains/lsp/implementation/protocolFramingMain.kt b/fleet/lsp.protocol/srcJvmMain/com/jetbrains/lsp/implementation/protocolFramingMain.kt new file mode 100644 index 000000000000..22fcde80cbe5 --- /dev/null +++ b/fleet/lsp.protocol/srcJvmMain/com/jetbrains/lsp/implementation/protocolFramingMain.kt @@ -0,0 +1,37 @@ +package com.jetbrains.lsp.implementation + +import com.jetbrains.lsp.protocol.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.awaitCancellation +import kotlinx.coroutines.runBlocking + +fun main() { + val handler = lspHandlers { + request(Initialize) { initParams -> + InitializeResult( + capabilities = ServerCapabilities( + textDocumentSync = TextDocumentSyncKind.Incremental, + ), + serverInfo = InitializeResult.ServerInfo( + name = "IntelliJ Analyzer", + version = "1.0" + ), + ) + } + notification(DocumentSync.DidOpen) { didOpen -> + println("didOpen: $didOpen") + } + notification(DocumentSync.DidChange) { didChange -> + println("didChange: $didChange") + } + } + runBlocking(Dispatchers.Default) { + tcpServer(TcpConnectionConfig.Server("127.0.0.1", 9999, isMultiClient = true)) { connection -> + withBaseProtocolFraming(connection, exitSignal = null) { incoming, outgoing -> + withLsp(incoming, outgoing, handler) { lsp -> + awaitCancellation() + } + } + } + } +} \ No newline at end of file diff --git a/fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/tcp.kt b/fleet/lsp.protocol/srcJvmMain/com/jetbrains/lsp/implementation/tcp.kt similarity index 100% rename from fleet/lsp.protocol/src/main/com/jetbrains/lsp/implementation/tcp.kt rename to fleet/lsp.protocol/srcJvmMain/com/jetbrains/lsp/implementation/tcp.kt diff --git a/fleet/lsp.protocol/srcJvmMain/com/jetbrains/lsp/protocol/LspExt.kt b/fleet/lsp.protocol/srcJvmMain/com/jetbrains/lsp/protocol/LspExt.kt new file mode 100644 index 000000000000..d84492a6b87b --- /dev/null +++ b/fleet/lsp.protocol/srcJvmMain/com/jetbrains/lsp/protocol/LspExt.kt @@ -0,0 +1,4 @@ +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.jetbrains.lsp.protocol + +fun URI.asJavaUri(): java.net.URI = java.net.URI(uri) \ No newline at end of file