Skip to content

Commit 538bb12

Browse files
darthorimarintellij-monorepo-bot
authored andcommitted
[lsp] extract arguments parser to a separate file
also, add tests LSP-166 GitOrigin-RevId: 566ba53cf85a4ce75d2b515ed484994276afe81c
1 parent a45a813 commit 538bb12

File tree

5 files changed

+184
-36
lines changed

5 files changed

+184
-36
lines changed

kotlin-lsp/BUILD.bazel

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
### auto-generated section `build language-server.kotlin-lsp` start
22
load("@community//build:compiler-options.bzl", "create_kotlinc_options")
3-
load("@rules_jvm//:jvm.bzl", "jvm_library")
3+
load("@rules_jvm//:jvm.bzl", "jvm_library", "jvm_test")
44

55
create_kotlinc_options(
66
name = "custom",
@@ -55,4 +55,65 @@ jvm_library(
5555
"@lib//:kotlinx-io-core",
5656
]
5757
)
58+
59+
jvm_library(
60+
name = "kotlin-lsp_test_lib",
61+
visibility = ["//visibility:public"],
62+
srcs = glob(["test/**/*.kt", "test/**/*.java"], allow_empty = True),
63+
kotlinc_opts = ":custom",
64+
associates = [":kotlin-lsp"],
65+
deps = [
66+
"@lib//:kotlin-stdlib",
67+
"@community//fleet/lsp.protocol",
68+
"@community//fleet/util/core",
69+
"@community//platform/core-api:core",
70+
"@community//platform/core-impl",
71+
"@community//java/java-psi-api:psi",
72+
"@community//platform/util",
73+
"@lib//:kotlinx-coroutines-core",
74+
"@lib//:kotlinx-serialization-json",
75+
"@lib//:kotlinx-serialization-core",
76+
"@lib//:kotlinc-kotlin-compiler-common",
77+
"@community//platform/workspace/storage",
78+
"//language-server/community/api.core",
79+
"//language-server/community/api.core:api.core_test_lib",
80+
"//language-server/api.impl.analyzer",
81+
"@lib//:kotlinc-analysis-api",
82+
"@lib//:kotlinc-analysis-api-k2",
83+
"@community//java/java-impl:impl",
84+
"@community//java/openapi:java",
85+
"@community//plugins/kotlin/base/plugin",
86+
"@community//plugins/kotlin/base/plugin:plugin_test_lib",
87+
"//language-server/community/api.features",
88+
"@community//platform/editor-ui-ex:editor-ex",
89+
"@community//plugins/kotlin/fir",
90+
"@community//plugins/kotlin/base/project-structure",
91+
"@community//plugins/kotlin/base/project-structure:project-structure_test_lib",
92+
"//language-server/community/features-impl/common",
93+
"//language-server/community/features-impl/kotlin",
94+
"//language-server/analyzer",
95+
"//language-server/analyzer:analyzer_test_lib",
96+
"@community//plugins/kotlin/base/code-insight",
97+
"@community//plugins/kotlin/base/code-insight:code-insight_test_lib",
98+
"@community//plugins/kotlin/kotlin.searching/base",
99+
"//language-server/community/workspace-import:language-server-project-import",
100+
"@community//platform/workspace/jps",
101+
"@lib//:clikt",
102+
"@community//fleet/rhizomedb",
103+
"@community//fleet/kernel",
104+
"@community//platform/service-container",
105+
"@community//platform/service-container:service-container_test_lib",
106+
"@lib//:ktor-network-tls",
107+
"@lib//:kotlinx-io-core",
108+
"@lib//:junit5",
109+
"@lib//:junit5Jupiter",
110+
"@lib//:junit5Launcher",
111+
"@lib//:junit5Params",
112+
]
113+
)
114+
115+
jvm_test(
116+
name = "kotlin-lsp_test",
117+
runtime_deps = [":kotlin-lsp_test_lib"]
118+
)
58119
### auto-generated section `build language-server.kotlin-lsp` end

kotlin-lsp/language-server.kotlin-lsp.iml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<exclude-output />
2121
<content url="file://$MODULE_DIR$">
2222
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
23+
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
2324
</content>
2425
<orderEntry type="inheritedJdk" />
2526
<orderEntry type="sourceFolder" forTests="false" />
@@ -60,5 +61,9 @@
6061
<orderEntry type="module" module-name="intellij.platform.serviceContainer" />
6162
<orderEntry type="library" name="ktor-network-tls" level="project" />
6263
<orderEntry type="library" name="kotlinx-io-core" level="project" />
64+
<orderEntry type="library" scope="TEST" name="JUnit5" level="project" />
65+
<orderEntry type="library" scope="TEST" name="JUnit5Jupiter" level="project" />
66+
<orderEntry type="library" scope="TEST" name="JUnit5Launcher" level="project" />
67+
<orderEntry type="library" scope="TEST" name="JUnit5Params" level="project" />
6368
</component>
6469
</module>

kotlin-lsp/src/com/jetbrains/ls/kotlinLsp/KotlinLspServer.kt

Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
22
package com.jetbrains.ls.kotlinLsp
33

4-
import com.github.ajalt.clikt.core.CliktCommand
5-
import com.github.ajalt.clikt.parameters.options.*
6-
import com.github.ajalt.clikt.parameters.types.int
74
import com.intellij.openapi.application.PathManager
85
import com.jetbrains.ls.api.core.LSServer
96
import com.jetbrains.ls.api.core.LSServerContext
@@ -35,38 +32,16 @@ import kotlin.io.path.createTempDirectory
3532
import kotlin.system.exitProcess
3633

3734
fun main(args: Array<String>) {
38-
RunKotlinLspCommand().main(args)
39-
exitProcess(0)
40-
}
41-
42-
private class RunKotlinLspCommand : CliktCommand(name = "kotlin-lsp") {
43-
val socket: Int by option().int().default(9999).help("A port which will be used for a Kotlin LSP connection. Default is 9999")
44-
val stdio: Boolean by option().flag()
45-
.help("Whether the Kotlin LSP server is used in stdio mode. If not set, server mode will be used with a port specified by `${::socket.name}`")
46-
val client: Boolean by option().flag()
47-
.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}`")
48-
.validate { if (it && stdio) fail("Can't use stdio mode with client mode") }
49-
50-
val multiclient: Boolean by option().flag()
51-
.help("Whether the Kotlin LSP server is used in multiclient mode. If not set, server will be shut down after the first client disconnects.`")
52-
.validate {
53-
if (it && stdio) fail("Stdio mode doesn't support multiclient mode")
54-
if (it && client) fail("Client mode doesn't support multiclient mode")
35+
when (val command = parseArguments(args)) {
36+
is KotlinLspCommand.Help -> {
37+
println(command.message)
38+
exitProcess(0)
5539
}
56-
57-
58-
private fun createRunConfig(): KotlinLspServerRunConfig {
59-
val mode = when {
60-
stdio -> KotlinLspServerMode.Stdio
61-
client -> KotlinLspServerMode.Socket(TcpConnectionConfig.Client(port = socket))
62-
else -> KotlinLspServerMode.Socket(TcpConnectionConfig.Server(port = socket, isMulticlient = multiclient))
40+
is KotlinLspCommand.RunLsp -> {
41+
val runConfig = command.config
42+
run(runConfig)
43+
exitProcess(0)
6344
}
64-
return KotlinLspServerRunConfig(mode)
65-
}
66-
67-
override fun run() {
68-
val runConfig = createRunConfig()
69-
run(runConfig)
7045
}
7146
}
7247

kotlin-lsp/src/com/jetbrains/ls/kotlinLsp/KotlinLspServerRunConfig.kt

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
package com.jetbrains.ls.kotlinLsp
22

3+
import com.github.ajalt.clikt.core.CliktCommand
4+
import com.github.ajalt.clikt.core.PrintHelpMessage
5+
import com.github.ajalt.clikt.parameters.options.default
6+
import com.github.ajalt.clikt.parameters.options.flag
7+
import com.github.ajalt.clikt.parameters.options.help
8+
import com.github.ajalt.clikt.parameters.options.option
9+
import com.github.ajalt.clikt.parameters.options.validate
10+
import com.github.ajalt.clikt.parameters.types.int
311
import com.jetbrains.lsp.implementation.TcpConnectionConfig
412

5-
class KotlinLspServerRunConfig(
13+
data class KotlinLspServerRunConfig(
614
val mode: KotlinLspServerMode
715
)
816

@@ -13,11 +21,57 @@ sealed interface KotlinLspServerMode {
1321
}
1422

1523

24+
fun parseArguments(args: Array<String>): KotlinLspCommand {
25+
val parser = Parser()
26+
try {
27+
parser.parse(args)
28+
return KotlinLspCommand.RunLsp(parser.createRunConfig())
29+
} catch (e: PrintHelpMessage) {
30+
return KotlinLspCommand.Help(e.command.getFormattedHelp())
31+
}
32+
}
33+
34+
sealed class KotlinLspCommand {
35+
data class RunLsp(val config: KotlinLspServerRunConfig) : KotlinLspCommand()
36+
data class Help(val message: String) : KotlinLspCommand()
37+
}
38+
39+
private class Parser : CliktCommand(name = "kotlin-lsp") {
40+
val socket: Int by option().int().default(9999).help("A port which will be used for a Kotlin LSP connection. Default is 9999")
41+
val stdio: Boolean by option().flag()
42+
.help("Whether the Kotlin LSP server is used in stdio mode. If not set, server mode will be used with a port specified by `${::socket.name}`")
43+
val client: Boolean by option().flag()
44+
.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}`")
45+
.validate { if (it && stdio) fail("Can't use stdio mode with client mode") }
46+
47+
val multiclient: Boolean by option().flag()
48+
.help("Whether the Kotlin LSP server is used in multiclient mode. If not set, server will be shut down after the first client disconnects.`")
49+
.validate {
50+
if (it && stdio) fail("Stdio mode doesn't support multiclient mode")
51+
if (it && client) fail("Client mode doesn't support multiclient mode")
52+
}
53+
54+
55+
fun createRunConfig(): KotlinLspServerRunConfig {
56+
val mode = when {
57+
stdio -> KotlinLspServerMode.Stdio
58+
client -> KotlinLspServerMode.Socket(TcpConnectionConfig.Client(port = socket))
59+
else -> KotlinLspServerMode.Socket(TcpConnectionConfig.Server(port = socket, isMulticlient = multiclient))
60+
}
61+
return KotlinLspServerRunConfig(mode)
62+
}
63+
64+
override fun run() {}
65+
}
66+
1667
fun KotlinLspServerRunConfig.toArguments(): List<String> =
1768
when (mode) {
1869
is KotlinLspServerMode.Stdio -> listOf("--stdio")
1970
is KotlinLspServerMode.Socket -> when (val tcpConfig = mode.config) {
2071
is TcpConnectionConfig.Client -> listOf("--client", "--socket=${tcpConfig.port}")
21-
is TcpConnectionConfig.Server -> listOf("--socket=${tcpConfig.port}")
72+
is TcpConnectionConfig.Server -> buildList {
73+
add("--socket=${tcpConfig.port}")
74+
if (tcpConfig.isMulticlient) add("--multiclient")
75+
}
2276
}
2377
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
2+
package com.jetbrains.ls.kotlinLsp
3+
4+
import com.jetbrains.lsp.implementation.TcpConnectionConfig
5+
import org.junit.jupiter.api.Assertions
6+
import org.junit.jupiter.api.Test
7+
8+
9+
class KotlinLspServerRunConfigKtTest {
10+
@Test
11+
fun `stdio`() {
12+
doConsistencyTest(KotlinLspServerRunConfig(KotlinLspServerMode.Stdio))
13+
}
14+
15+
@Test
16+
fun `tcp client`() {
17+
doConsistencyTest(KotlinLspServerRunConfig(KotlinLspServerMode.Socket(TcpConnectionConfig.Client(port = 9999))))
18+
}
19+
20+
@Test
21+
fun `tcp server`() {
22+
doConsistencyTest(
23+
KotlinLspServerRunConfig(
24+
KotlinLspServerMode.Socket(
25+
TcpConnectionConfig.Server(
26+
port = 9999,
27+
isMulticlient = false
28+
)
29+
)
30+
)
31+
)
32+
}
33+
34+
@Test
35+
fun `tcp server multiclient`() {
36+
doConsistencyTest(
37+
KotlinLspServerRunConfig(
38+
KotlinLspServerMode.Socket(
39+
TcpConnectionConfig.Server(
40+
port = 9999,
41+
isMulticlient = true
42+
)
43+
)
44+
)
45+
)
46+
}
47+
48+
private fun doConsistencyTest(config: KotlinLspServerRunConfig, ) {
49+
val arguments = config.toArguments()
50+
val parsed = parseArguments(arguments.toTypedArray()) as KotlinLspCommand.RunLsp
51+
Assertions.assertEquals(config, parsed.config)
52+
}
53+
}

0 commit comments

Comments
 (0)