Skip to content

Commit 2f75884

Browse files
committed
Add TCP Client mode
Add an option to launch the language server as a TCP client, which is the default form of socket communication supported by VSCode.
1 parent 2db6693 commit 2f75884

File tree

5 files changed

+55
-17
lines changed

5 files changed

+55
-17
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ COPY --from=builder /kotlin-language-server/server/build/install/server /server
1414

1515
EXPOSE 49100
1616

17-
CMD ["/server/bin/kotlin-language-server", "--tcpPort=49100"]
17+
CMD ["/server/bin/kotlin-language-server", "--tcpServerPort=49100"]

EDITORS.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,13 @@ Note that you may need to substitute `kotlin-language-server` with `kotlin-langu
4444
## Other Editors
4545
Install a [Language Server Protocol client](https://microsoft.github.io/language-server-protocol/implementors/tools/) for your tool. Then invoke the language server executable in a client-specific way.
4646

47-
The server uses `stdio` by default to send and receive `JSON-RPC` messages, but can be launched with the argument `--tcpPort=port` for TCP support.
47+
The server can be launched in three modes:
48+
49+
* `Stdio` (the default mode)
50+
* The language server uses the standard streams for JSON-RPC communication
51+
* `TCP Server`
52+
* The language server starts a server socket and listens on `--tcpServerPort`
53+
* `TCP Client`
54+
* The language server tries to connect to `--tcpClientHost` and `--tcpClientPort`
55+
56+
The mode is automatically determined by the arguments provided to the language server.

server/src/main/kotlin/org/javacs/kt/Main.kt

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,35 @@ import org.eclipse.lsp4j.ConfigurationItem
99
import org.javacs.kt.util.ExitingInputStream
1010

1111
class Args {
12-
@Parameter(names = ["--tcpPort", "-p"])
13-
var tcpPort: Int? = null
12+
/*
13+
* The language server can currently be launched in three modes:
14+
* - Stdio, in which case no argument should be specified (used by default)
15+
* - TCP Server, in which case the client has to connect to the specified tcpServerPort (used by the Docker image)
16+
* - TCP Client, in whcih case the server will connect to the specified tcpClientPort/tcpClientHost (optionally used by VSCode)
17+
*/
18+
19+
@Parameter(names = ["--tcpServerPort", "-sp"])
20+
var tcpServerPort: Int? = null
21+
@Parameter(names = ["--tcpClientPort", "-p"])
22+
var tcpClientPort: Int? = null
23+
@Parameter(names = ["--tcpCllientHost", "-h"])
24+
var tcpClientHost: String = "localhost"
1425
}
1526

1627
fun main(argv: Array<String>) {
1728
// Redirect java.util.logging calls (e.g. from LSP4J)
1829
LOG.connectJULFrontend()
1930

2031
val args = Args().also { JCommander.newBuilder().addObject(it).build().parse(*argv) }
21-
val (inStream, outStream) = args.tcpPort?.let { tcpConnectToClient(it) } ?: Pair(System.`in`, System.out)
32+
val (inStream, outStream) = args.tcpClientPort?.let {
33+
// Launch as TCP Client
34+
LOG.connectStdioBackend()
35+
tcpConnectToClient(args.tcpClientHost, it)
36+
} ?: args.tcpServerPort?.let {
37+
// Launch as TCP Server
38+
LOG.connectStdioBackend()
39+
tcpStartServer(it)
40+
} ?: Pair(System.`in`, System.out)
2241

2342
val server = KotlinLanguageServer()
2443
val threads = Executors.newSingleThreadExecutor { Thread(it, "client") }
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.javacs.kt
2+
3+
import java.io.InputStream
4+
import java.io.OutputStream
5+
import java.net.Socket
6+
import java.net.ServerSocket
7+
8+
/**
9+
* Starts a TCP server socket. Blocks until the first
10+
* client has connected, then returns a pair of IO streams.
11+
*/
12+
fun tcpStartServer(port: Int): Pair<InputStream, OutputStream> = ServerSocket(port)
13+
.also { LOG.info("Waiting for client on port {}...", port) }
14+
.accept()
15+
.let { Pair(it.inputStream, it.outputStream) }
16+
17+
/**
18+
* Starts a TCP client socket and connects to the client at
19+
* the specified address, then returns a pair of IO streams.
20+
*/
21+
fun tcpConnectToClient(host: String, port: Int): Pair<InputStream, OutputStream> = Socket(host, port)
22+
.let { Pair(it.inputStream, it.outputStream) }

server/src/main/kotlin/org/javacs/kt/TcpStream.kt

Lines changed: 0 additions & 12 deletions
This file was deleted.

0 commit comments

Comments
 (0)