In the past, many code editors were built just for the specific language, and to provide rich and smart code editing, tight integration between the editor and the language tooling was a must. On the other hand, there were (and still are) more general-purpose editors, but they lacked in functionality when it came to more advanced language-specific features like code completion, “go to definition”, etc. (for example, code highlighting was done using the regular expressions).
With growing amount of code editors and programming languages this became the classic M*N complexity problem.
But then Microsoft introduced the Language Server Protocol (LSP) as a solution to the problem above, which elegantly transforms this M*N complexity into a more manageable M+N situation.
The LSP was initially driven by the needs of VS Code
LSP separates language servers from code editors (language clients). By making language servers independent processes dedicated to language understanding, the LSP enables any editor to utilize a standard language server. Which means that a single standard language server can be used by all editors.
This interoperability is achieved through a defined set of standard messages and procedures that govern communication between language servers and editors. The LSP defines the format of the messages sent using JSON-RPC between the development tool and the language server.
Language Server Features
The list of features may vary for each individual language server, but usually they provide the following functionalities:
Auto-completion
Go to definition/declaration
Find references
Code formatting
Diagnostics
Documentation
etc.
For example, here you can see the list of editor features that gopls (Go Language Server) provides.
And here you can see the full LSP specification for available features.
How does LSP work?
The Language Server Protocol is built upon JSON-RPC. It specifically uses JSON RPC 2.0. You can think of JSON-RPC as a remote procedure call protocol that uses JSON for data encoding.
In a nutshell it works like this. First, the editor establishes a connection with the language server, then as the developer types code, the editor sends incremental changes to the language server. It then sends back insights like: code completion suggestions, diagnostics.
Let’s see one real example for auto-completion. The request from Language Client (editor) for this case will be:
{
"jsonrpc": "2.0",
"id": 1,
"method": "textDocument/completion",
"params": {
"textDocument": {
"uri": "file:///home/alex/code/test/main.go"
},
"position": {
"line": 35,
"character": 21
}
}
}
As you can see it send the information about current cursor position and the buffer file. Let's break it down:
ID: The client sets this field to identify the request uniquely. Once the request is processed, it will return a response with the same request ID so that the client can match which response is for what request.
Method: A string containing the name of the method to be invoked.
Params: The parameters to be passed to the method. This can be structured as an array or an object.
Language server can access this file, analyze it and respond with suggestions:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"isIncomplete": false,
"items": [
{
"label": "Println",
"kind": 3,
"insertText": "Println(${1:format}, ${2:a ...interface{}})$0",
"insertTextFormat": 2,
"detail": "func Println(a ...interface{}) (n int, err error)",
"documentation": "Println formats ..."
},
// ... other items
]
}
}
Language Server for Go
The most popular and commonly used language server for Go is gopls. It is used by many editors, for example by Visual Studio Code Go extension. Previously, there was another popular Language Server for Go by the Sourcegraph team called go-langserver, but this is no longer under active maintenance.
Many editors install gopls Language Server automatically if it’s not present on the host machine, but you can install it manually as well:
go install golang.org/x/tools/gopls@latest
gopls also provides an experimental CLI interface:
gopls references ./main.go:35:8
Conclusion
Thanks to the Language Server Protocol, advanced coding capabilities are becoming universally accessible across various programming languages and coding environments.
It’s good to know how your code editors work, therefore it’s beneficial to have an understanding of this widely used technology called LSP.
LSP is a win for both language providers and tooling vendors!