Remote Language Servers
Metals has experimental support to offload certain requests to a remote language server. This feature can be used to navigate large codebases when it's not possible to index all the code on a local computer.
Difference from local language servers
There are some important differences between local and remote language servers:
- Instead of JSON-RPC, a remote language server responds to HTTP POST requests
with an
application/json
header and a JSON-formatted body. The reason HTTP is chosen over JSON-RPC is because it makes the remote language server accessible from more clients, for example viacurl
. A caveat with using HTTP instead of JSON-RPC is that it's not possible for the remote language server to push notification down to the client. In the future, we could consider using JSON-RPC via websockets instead. - Instead of using absolute
file://
URIs, a remote language server uses relativesource://
URIs. For example, the absolute URIfile://path/to/workspace/src/main/scala/Address.scala
becomes the relative URIsource://src/main/scala/Address.scala
when communicating with a remote language server.
Methods
Each remote language server method expects a JSON-formatted body of type
JsonRpcRequest<T>
.
interface JsonRpcRequest<T> {
/** The JSON-RPC method name, for example textDocument/definition */
method: string;
/** The parameter for the JSON-RPC method, for example `TextDocumentPositionParams` */
params: T;
/** The ID of this request, can be any integer number. */
id: number;
}
textDocument/definition
The textDocument/definition
request is sent from the client to the server to
get the list of definitions for a given position.
Request:
- method:
textDocument/definition
- params:
JsonRpcRequest<TextDocumentPositionParams>
, whereTextDocumentPositionParams
is defined in LSP.
Response:
- result:
Location[]
, as defined in LSP.
Example request:
curl --location --request POST 'http://remote-language-server.com' \
--header 'Content-Type: application/json' \
--data-raw '{
"method": "textDocument/definition",
"params": {
"textDocument": {
"uri": "source://src/main/scala/Address.scala"
},
"position": {
"line": 5,
"character": 10
}
},
"id": 10
}'
Example response:
[
{
"uri": "source://src/main/scala/User.scala",
"range": {
"start": { "line": 61, "character": 15 },
"end": { "line": 61, "character": 31 }
}
}
]
textDocument/references
The textDocument/references
request is sent from the client to the server to
get the list of all references to a symbol at a given position.
Request:
- method:
textDocument/references
- params:
JsonRpcRequest<ReferenceParams>
, whereReferenceParams
is defined in LSP.
Response:
- result:
Location[]
, as defined in LSP.
Example request:
curl --location --request POST 'http://remote-language-server.com' \
--header 'Content-Type: application/json' \
--data-raw '{
"method": "textDocument/references",
"params": {
"textDocument": {
"uri": "source://src/main/scala/Address.scala"
},
"position": {
"line": 5,
"character": 10
},
"context": {
"includeDeclaration": true
}
},
"id": 10
}'
Example response:
[
{
"uri": "source://src/main/scala/User.scala",
"range": {
"start": { "line": 61, "character": 15 },
"end": { "line": 61, "character": 31 }
}
},
{
"uri": "source://src/main/scala/Country.scala",
"range": {
"start": { "line": 62, "character": 16 },
"end": { "line": 62, "character": 32 }
}
}
]
Open questions
The protocol for remote language servers is new and likely to have breaking changes in upcoming releases. The protocol in this document should be considered as a proof-of-concept that demonstrates the feasibility of this approach. There remain a few open questions in order to extend remote language servers to support richer functionality:
- how do we ensure that results from the remote server are synchronized with the file changes to the local disk?
- how do we combine local and remote
workspace/symbol
results? - how should
textDocument/definition
return results to library dependency sources that are not present on local disk?
Given these open questions and the experimental status of remote language servers, this functionality may be removed from Metals in future releases without notice.