https://github.com/sourcegraph/lsp-adapter
lsp-adapter provides a proxy which adapts Sourcegraph LSP requests to vanilla LSP requests
https://github.com/sourcegraph/lsp-adapter
language-server language-server-protocol lsp lsp-server repo-type-codeintel
Last synced: 6 months ago
JSON representation
lsp-adapter provides a proxy which adapts Sourcegraph LSP requests to vanilla LSP requests
- Host: GitHub
- URL: https://github.com/sourcegraph/lsp-adapter
- Owner: sourcegraph
- License: mit
- Archived: true
- Created: 2018-04-18T22:07:44.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2022-06-23T22:21:49.000Z (over 3 years ago)
- Last Synced: 2024-08-07T18:32:37.010Z (over 1 year ago)
- Topics: language-server, language-server-protocol, lsp, lsp-server, repo-type-codeintel
- Language: Go
- Homepage:
- Size: 315 KB
- Stars: 29
- Watchers: 65
- Forks: 8
- Open Issues: 16
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# lsp-adapter [](https://travis-ci.org/sourcegraph/lsp-adapter) [](https://ci.appveyor.com/project/sourcegraph/lsp-adapter/branch/master) [](http://godoc.org/github.com/sourcegraph/lsp-adapter) [](https://goreportcard.com/report/github.com/sourcegraph/lsp-adapter)
Command `lsp-adapter` provides a proxy which adapts Sourcegraph LSP requests to
vanilla LSP requests.
## Background
[Code Intelligence on Sourcegraph](https://about.sourcegraph.com/docs/code-intelligence/) is powered by the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/).
Previously, language servers that were used on sourcegraph.com were additionally required to support our
custom LSP [files extensions](https://github.com/sourcegraph/language-server-protocol/blob/master/extension-files.md). These extensions allowed language servers to operate without sharing a physical file system with the client. While it's preferable for language servers to implement these extensions for performance reasons, implementing this functionality is a large undertaking.
`lsp-adapter` eliminates the need for this requirement, which allows off-the-shelf language servers to be able to provide basic functionality (hovers, local definitions) to Sourcegraph.
## How to Install
You can download the latest binary on the [releases page](https://github.com/sourcegraph/lsp-adapter/releases).
Alternatively, install it with `go get`:
```shell
go get -u -v github.com/sourcegraph/lsp-adapter
```
Running `lsp-adapter --help` shows you some of its options:
```shell
> lsp-adapter --help
Usage: lsp-adapter [OPTIONS] LSP_COMMAND_ARGS...
Options:
-beforeInitializeHook string
A program to run after cloning the repository, but before the 'initialize' call is forwarded to the language server. (For example, you can use this to run a script to install dependencies for the project). The program's cwd will be the workspace's cache directory, and it will also be passed the cache directory as an argument.
-cacheDirectory string
cache directory location (default "/var/folders/qq/1q_cmsmx6qv7bs_m6g_2pt1r0000gn/T/proxy-cache")
-didOpenLanguage string
(HACK) If non-empty, send 'textDocument/didOpen' notifications with the specified language field (e.x. 'python') to the language server for every file.
-glob string
A colon (:) separated list of file globs to sync locally. By default we place all files into the workspace, but some language servers may only look at a subset of files. Specifying this allows us to avoid syncing all files. Note: This is done by basename only.
-jsonrpc2IDRewrite string
(HACK) Rewrite jsonrpc2 ID. none (default) is no rewriting. string will use a string ID. number will use number ID. Useful for language servers with non-spec complaint JSONRPC2 implementations. (default "none")
-pprofAddr string
server listen address for pprof
-proxyAddress string
proxy server listen address (tcp) (default "127.0.0.1:8080")
-trace
trace logs to stderr (default true)
```
## How to Use `lsp-adapter`
`lsp-adapter` proxies requests between your Sourcegraph instance and the language server, and modifies them in such a way that allows for the two to communicate correctly. In order to do this, we need to know
- How to connect `lsp-adapter` to the language server
- How to connect to your Sourcegraph instance to `lsp-adapter`
### Connect `lsp-adapter` to the Language Server
`lsp-adapter` can talk to language servers over standard I/O.
`lsp-adapter` interprets any positional arguments after the flags as the necessary command (+ arguments) to start the language server binary. It uses this command to communicate to the language server inside of a subprocess.
For example, if I am trying to use Rust’s language server, the command to start it up is just `rls`. `lsp-adapter` can be told to start the start the same server via:
```shell
lsp-adapter rls
```
Any stderr output from the binary will also appear in `lsp-adapter`'s logs.
### Connect Sourcegraph to `lsp-adapter`
1. Use the `-proxyAddress` flag to tell `lsp-adapter` what address to listen for connections from Sourcegraph on. For example, I can tell `lsp-adapter` to listen on my local `8080` port with `-proxyAddress=127.0.0.1:8080`.
2. We then need to add a new entry to the `"langservers"` field in the site configuration in order to point Sourcegraph at `lsp-adapter` (similar to the steps in [this document](https://about.sourcegraph.com/docs/code-intelligence/install-manual)). For example, if `lsp-adapter` is connected to the Rust language server, and the `lsp-adapter` itself is listening on `127.0.0.1:8080`:
```json
{
"language": "rust",
"address": "tcp://127.0.0.1:8080"
}
```
would be the new entry that needs to be added to the `"langservers"` field.
## Example Commands
Connect via standard I/O to a language server whose command can be run with `rls`, and listen for connections from Sourcegraph from any address on port `1234`.
```shell
> lsp-adapter -proxyAddresss=0.0.0.0:1234 rls
2018/04/04 15:27:04 proxy.go:71: CloneProxy: accepting connections at [::]:8080
```
Connect via standard I/O to a language server whose command can be run with `rls`, change the location of the cache directory (used for cloning the repo locally) to `/tmpDir`, and enable tracing for every request to/from the language server.
```shell
> lsp-adapter -cacheDir='/tmpDir' -trace rls
```
## Docker
There is a [skeleton Dockerfile](./Dockerfile) that shows how to package `lsp-adapter` along with your desired language server inside of a docker container. There are fully working examples in [dockerfiles](./dockerfiles). For example [dockerfiles/rust/Dockerfile](./dockerfiles/rust/Dockerfile), which can be built with:
```shell
> docker build -f dockerfiles/rust/Dockerfile .
```
## Glob
Most language servers will only ever look at files that match a set of known patterns. On initialize lsp-adapter copies a full work-tree to disk for a repository, but by specifying `-glob` we can avoid copying over files that will not be looked at. For example, if a python language server only looks at `py` and `pyc` files you can specify `-glob=*.py:*.pyc`. The matching is done on the basename of the path using [path.Match](https://godoc.org/path#Match).
## Did Open Hack
Some language servers do not follow the LSP spec correctly and refuse to work unless the `textDocument/didOpen` notification has been sent. See [this commit](https://github.com/sourcegraph/lsp-adapter/commit/1228a1fbaf102aa44575cec6802a5a211d117ee1) for more context. If the language server that you’re trying to use has this issue, try setting the `didOpenLanguage` flag (example: if a python language server had this issue - use `./lsp-adapter -didOpenLanguage=python ...`) to work around it.
## JSONRPC2 ID Rewrite Hack
Some language servers do not follow the JSONRPC2 spec correctly and fail if the Request ID is not a number of string. If the language server that you’re trying to use has this issue, try setting the `jsonrpc2IDRewrite` flag (example: if a rust language server had this issue - use `./lsp-adapter -jsonrpc2IDRewrite=number ...`) to work around it.
## Before Initialization Hook
Some language servers need to run setup scripts (to install dependencies, for example) in order to provide code intelligence. By using the `-beforeInitializeHook` flag, you can specify a program/script that will run after the repository is cloned to workspace's cache directory, but before the language server receives the `initalize` request. The program's `cwd` will be the cache directory (which will also be passed as an argument for convenience).
For example, if you have the following script named `hook.sh`:
```shell
#!/bin/sh
set -x
echo $(pwd)
```
After specifying the hook via `lsp-adapter -beforeInitializeHook='/test.sh'` You will see output like
```shell
2018/06/20 21:11:45 uris.go:25: Cloned workspace to /tmp/proxy-cache/3bb76102-a73b-4442-a03e-930c59e1fdcb
2018/06/20 21:11:45 hook.go:26: Running pre-init hook: '/test.sh /tmp/proxy-cache/3bb76102-a73b-4442-a03e-930c59e1fdcb'
++ pwd
+ echo /Users/ggilmore/dev/go/src/github.com/sourcegraph/lsp-adapter
/Users/ggilmore/dev/go/src/github.com/sourcegraph/lsp-adapter
```
every time the language sever receives an `initialize` request. Obviously, you should replace this script with something meaningful.