@@ -22,14 +22,14 @@ import com.jetbrains.ls.kotlinLsp.util.addKotlinStdlib
2222import com.jetbrains.ls.kotlinLsp.util.logSystemInfo
2323import com.jetbrains.ls.snapshot.api.impl.core.createServerStarterAnalyzerImpl
2424import com.jetbrains.lsp.implementation.*
25- import kotlinx.coroutines.*
25+ import kotlinx.coroutines.CompletableDeferred
26+ import kotlinx.coroutines.Dispatchers
27+ import kotlinx.coroutines.awaitCancellation
28+ import kotlinx.coroutines.runBlocking
2629import org.jetbrains.kotlin.idea.base.plugin.artifacts.KotlinArtifacts
2730import org.jetbrains.kotlin.idea.compiler.configuration.KotlinPluginLayoutMode
2831import org.jetbrains.kotlin.idea.compiler.configuration.KotlinPluginLayoutModeProvider
2932import org.jetbrains.kotlin.idea.compiler.configuration.isRunningFromSources
30- import java.io.InputStream
31- import java.io.OutputStream
32- import java.net.Socket
3333import kotlin.io.path.absolutePathString
3434import kotlin.io.path.createTempDirectory
3535
@@ -45,11 +45,19 @@ private class RunKotlinLspCommand : CliktCommand(name = "kotlin-lsp") {
4545 .help(" Whether the Kotlin LSP server is used in client mode. If not set, server mode will be used with a port specified by `${::socket.name} `" )
4646 .validate { if (it && stdio) fail(" Can't use stdio mode with client mode" ) }
4747
48+ val multiclient: Boolean by option().flag()
49+ .help(" Whether the Kotlin LSP server is used in multiclient mode. If not set, server will be shut down after the first client disconnects.`" )
50+ .validate {
51+ if (it && stdio) fail(" Stdio mode doesn't support multiclient mode" )
52+ if (it && client) fail(" Client mode doesn't support multiclient mode" )
53+ }
54+
55+
4856 private fun createRunConfig (): KotlinLspServerRunConfig {
4957 val mode = when {
5058 stdio -> KotlinLspServerMode .Stdio
51- client -> KotlinLspServerMode .Socket .Client (socket)
52- else -> KotlinLspServerMode .Socket .Server (socket)
59+ client -> KotlinLspServerMode .Socket ( TcpConnectionConfig .Client (port = socket) )
60+ else -> KotlinLspServerMode .Socket ( TcpConnectionConfig .Server (port = socket, isMulticlient = multiclient) )
5361 }
5462 return KotlinLspServerRunConfig (mode)
5563 }
@@ -76,16 +84,17 @@ private fun run(runConfig: KotlinLspServerRunConfig) {
7684 KotlinLspServerMode .Stdio -> {
7785 val stdout = System .out
7886 System .setOut(System .err)
79- handleRequests(System .`in `, stdout, config, mode)
87+ stdioConnection(System .`in `, stdout) { connection ->
88+ handleRequests(connection, config, mode)
89+ }
8090 }
8191
8292 is KotlinLspServerMode .Socket -> {
8393 logSystemInfo()
8494 tcpConnection(
85- clientMode = mode is KotlinLspServerMode .Socket .Client ,
86- port = mode.port,
95+ mode.config,
8796 ) { connection ->
88- handleRequests(connection.inputStream, connection.outputStream , config, mode)
97+ handleRequests(connection, config, mode)
8998 }
9099 }
91100 }
@@ -94,11 +103,19 @@ private fun run(runConfig: KotlinLspServerRunConfig) {
94103}
95104
96105context(LSServerContext )
97- private suspend fun handleRequests (input : InputStream , output : OutputStream , config : LSConfiguration , mode : KotlinLspServerMode ) {
98- withBaseProtocolFraming(input, output) { incoming, outgoing ->
106+ private suspend fun handleRequests (connection : LspConnection , config : LSConfiguration , mode : KotlinLspServerMode ) {
107+ val shutdownOnExitSignal = when (mode) {
108+ is KotlinLspServerMode .Socket -> when (val tcpConfig = mode.config) {
109+ is TcpConnectionConfig .Client -> true
110+ is TcpConnectionConfig .Server -> ! tcpConfig.isMulticlient
111+ }
112+ KotlinLspServerMode .Stdio -> true
113+ }
114+ val exitSignal = if (shutdownOnExitSignal) CompletableDeferred <Unit >() else null
115+
116+ withBaseProtocolFraming(connection, exitSignal) { incoming, outgoing ->
99117 withServer {
100- val exitSignal = CompletableDeferred <Unit >()
101- val handler = createLspHandlers(config, exitSignal, clientMode = mode is KotlinLspServerMode .Socket .Client )
118+ val handler = createLspHandlers(config, exitSignal)
102119
103120 withLsp(
104121 incoming,
@@ -108,7 +125,11 @@ private suspend fun handleRequests(input: InputStream, output: OutputStream, con
108125 Client .contextElement(lspClient)
109126 },
110127 ) { lsp ->
111- exitSignal.await()
128+ if (exitSignal != null ) {
129+ exitSignal.await()
130+ } else {
131+ awaitCancellation()
132+ }
112133 }
113134 }
114135 }
@@ -164,12 +185,12 @@ fun createConfiguration(
164185}
165186
166187context(LSServer )
167- fun createLspHandlers (config : LSConfiguration , exitSignal : CompletableDeferred <Unit >, clientMode : Boolean = false ): LspHandlers {
188+ fun createLspHandlers (config : LSConfiguration , exitSignal : CompletableDeferred <Unit >? ): LspHandlers {
168189 with (config) {
169190 return lspHandlers {
170191 initializeRequest()
171192 setTraceNotification()
172- shutdownRequest(clientMode, exitSignal)
193+ shutdownRequest(exitSignal)
173194 fileUpdateRequests()
174195 features()
175196 }
0 commit comments