Skip to content
This repository was archived by the owner on Dec 29, 2022. It is now read-only.

Commit 16e0213

Browse files
author
Nick Cameron
committed
Add contributing.md
1 parent 9e248ff commit 16e0213

File tree

2 files changed

+224
-2
lines changed

2 files changed

+224
-2
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
# Rust Language Server (RLS)
66

7-
**This project is in the early stages of development, it is not yet ready for real
8-
use. It will probably eat your laundry.**
7+
**This project is in the alpha stage of development. It is likely to be buggy in
8+
some situations; proceed with caution.**
99

1010
The RLS provides a server that runs in the background, providing IDEs,
1111
editors, and other tools with information about Rust programs. It supports

contributing.md

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
# Contributing
2+
3+
This document provides information for developers who want to contribute to the
4+
RLS or run it in a heavily customised configuration.
5+
6+
The RLS is open source and we'd love you to contribute to the project. Testing,
7+
reporting issues, writing documentation, writing tests, writing code, and
8+
implementing clients are all extremely valuable.
9+
10+
Here is the list of known [issues](https://github.com/rust-lang-nursery/rls/issues).
11+
These are [good issues to start on](https://github.com/rust-lang-nursery/rls/issues?q=is%3Aopen+is%3Aissue+label%3Aeasy).
12+
13+
We're happy to help however we can. The best way to get help is either to
14+
leave a comment on an issue in this repo, or to ping us (nrc or jntrnr) in #rust-tools
15+
on IRC.
16+
17+
We'd love for existing and new tools to use the RLS. If that sounds interesting
18+
please get in touch by filing an issue or on IRC.
19+
20+
21+
## Building
22+
23+
Since the RLS is closely linked to the compiler and is in active development,
24+
you'll need a recent nightly compiler to build it.
25+
26+
Use `cargo build` to build.
27+
28+
See [README.md](README.md) for more setup steps.
29+
30+
## Running and testing
31+
32+
You can run the rls by hand with:
33+
34+
```
35+
cargo run
36+
```
37+
38+
Though more commonly, you'll use an IDE plugin to invoke it for you.
39+
40+
Test using `RUST_TEST_THREADS=1 cargo test`.
41+
42+
Testing is unfortunately minimal. There is support for regression tests, but not
43+
many actual tests exists yet. There is signifcant [work to do](https://github.com/rust-lang-nursery/rls/issues/12)
44+
before we have a comprehensive testing story.
45+
46+
47+
## Standard library support
48+
49+
The way it works is that when the libraries are built, the compiler can emit all
50+
the data that the RLS needs. This can be read by the RLS on startup and used to
51+
provide things like type on hover without having access to the source code for
52+
the libraries.
53+
54+
The compiler gives every definition an id, and the RLS matches up these ids. In
55+
order for the RLS to work, the id of a identifier used in the IDE and the id of
56+
its declaration in a library must match exactly. Since ids are very unstable,
57+
the data used by the RLS for libraries must match exactly with the crate that
58+
your source code links with.
59+
60+
You need a version of the above data which exactly matches the standard
61+
libraries you will use with your project. Rustup takes care of this for you and
62+
is the preferred (and easiest) method for installing this data. If you want to
63+
use the RLS with a Rust compiler/libraries you have built yourself, then you'll
64+
need to take some extra steps.
65+
66+
67+
### Install with rustup
68+
69+
You'll need to be using [rustup](https://www.rustup.rs/) to manage your Rust
70+
compiler toolchains. The RLS does not yet support cross-compilation - your
71+
compiler host and target must be exactly the same.
72+
73+
You must be using nightly (you need to be using nightly for the RLS to work at
74+
the moment in any case). To install a nightly toolchain use `rustup install
75+
nightly`. To switch to using that nightly toolchain by default use `rustup
76+
default nightly`.
77+
78+
Add the RLS data component using `rustup component add rust-analysis`.
79+
80+
Everything should now work! You may need to restart the RLS.
81+
82+
83+
### Build it yourself
84+
85+
When you build Rust, add `-Zsave-analysis-api` to your stage 2 flags, e.g., by
86+
setting the environment variable:
87+
88+
```
89+
export RUSTFLAGS_STAGE2='-Zsave-analysis-api'
90+
```
91+
92+
When the build has finished, you should have a bunch of JSON data in a directory like
93+
`~/rust1/build/x86_64-unknown-linux-gnu/stage1-std/x86_64-unknown-linux-gnu/release/deps/save-analysis`.
94+
95+
You need to copy all those files (should be around 16) into a new directory:
96+
`~/rust1/build/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnu/analysis`
97+
(assuming you are running the stage 2 compiler you just built. You'll need to
98+
modify the root directory (`~/rust1` here) and the host triple
99+
(`x86_64-unknown-linux-gnu` in both places)).
100+
101+
102+
Finally, to run the RLS you'll need to set things up to use the newly built
103+
compiler, something like:
104+
105+
```
106+
export RUSTC="~/rust1/build/x86_64-unknown-linux-gnu/stage2/bin/rustc"
107+
```
108+
109+
Either before you run the RLS, or before you run the IDE which will start the
110+
RLS.
111+
112+
113+
### Details
114+
115+
Rustup (or you, manually) will install the rls data (which is a bunch of json
116+
files) into `$SYSROOT/lib/rustlib/$TARGET_TRIPLE/analysis`, where `$SYSROOT` is
117+
your Rust sysroot, this can be found using `rustc --print=sysroot`.
118+
`$TARGET_TRIPLE` is the triple which defines the compilation target. Since the
119+
RLS currently does not support cross-compilation, this must match your host
120+
triple. It will look something like `x86_64-unknown-linux-gnu`.
121+
122+
For example, on my system RLS data is installed at:
123+
124+
```
125+
/home/ncameron/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/analysis
126+
```
127+
128+
This data is only for the standard libraries, project-specific data is stored
129+
inside your project's target directory.
130+
131+
132+
## Implementation overview
133+
134+
The goal of the RLS project is to provide an awesome IDE experience *now*. That
135+
means not waiting for incremental compilation support in the compiler. However,
136+
Rust is a somewhat complex language to analyse and providing precise and
137+
complete information about programs requires using the compiler.
138+
139+
The RLS has two data sources - the compiler and Racer. The compiler is always
140+
right, and always precise. But can sometimes be too slow for IDEs. Racer is
141+
nearly always fast, but can't handle some constructs (e.g., macros) or can only
142+
handle them with limited precision (e.g., complex generic types).
143+
144+
The RLS tries to provide data using the compiler. It sets a time budget and
145+
queries both the compiler and Racer. If the compiler completes within the time
146+
budget, we use that data. If not, we use Racer's data.
147+
148+
We link both Racer and the compiler into the RLS, so we don't need to shell out
149+
to either (though see notes on the build process below). We also customise our
150+
use of the compiler (via standard APIs) so that we can read modified files
151+
directly from memory without saving them to disk.
152+
153+
### Building
154+
155+
The RLS tracks changes to files, and keeps the changed file in memory (i.e., the
156+
RLS does not need the IDE to save a file before providing data). These changed
157+
files are tracked by the 'Virtual File System' (which is a bit of a grandiose
158+
name for a pretty simple file cache at the moment, but I expect this area to
159+
grow significantly in the future). The VFS is in a [separate
160+
crate](https://github.com/nrc/rls-vfs).
161+
162+
We want to start building before the user needs information (it would be too
163+
slow to start a build when data is requested). However, we don't want to start a
164+
build on every keystroke (this would be too heavy on user resources). Nor is
165+
there any point starting multiple builds when we would throw away the data from
166+
some of them. We therefore try to queue up and coalesce builds. This is further
167+
documented in [src/build.rs](src/build.rs).
168+
169+
When we do start a build, we may also need to build dependent crates. We
170+
therefore do a full `cargo build`. However, we do not compile the last crate
171+
(the one the user is editing in the IDE). We only run Cargo to get a command
172+
line to build that crate. Furthermore, we cache that command line, so for most
173+
builds (where we don't need to build dependent crates, and where we can be
174+
reasonably sure they haven't changed since a previous build) we don't run Cargo
175+
at all.
176+
177+
The command line we got from Cargo, we chop up and feed to the in-process
178+
compiler. We then collect error messages and analysis data in JSON format
179+
(although this is inefficient and [should
180+
change](https://github.com/rust-lang-nursery/rls/issues/25)).
181+
182+
### Analysis data
183+
184+
From the compiler, we get a serialised dump of its analysis data (from name
185+
resolution and type checking). We combine data from all crates and the standard
186+
libraries and combine this into an index for the whole project. We cross-
187+
reference and store this data in HashMaps and use it to look up data for the
188+
IDE.
189+
190+
Reading, processing, and storing the analysis data is handled by the
191+
[rls-analysis crate](https://github.com/nrc/rls-analysis).
192+
193+
### Communicating with IDEs
194+
195+
The RLS communicates with IDEs via
196+
the [Language Server protocol](https://github.com/Microsoft/language-server-protocol/blob/master/protocol.md).
197+
198+
The LS protocol uses JSON sent over stdin/stdout. The JSON is rather dynamic -
199+
we can't make structs to easily map to many of the protocol objects. The client
200+
sends commands and notifications to the RLS. Commands must get a reply,
201+
notifications do not. Usually the structure of the reply is dictated by the
202+
protocol spec. The RLS can also send notifications to the client. So for a long
203+
running task (such as a build), the RLS will reply quickly to acknowledge the
204+
request, then send a message later with the result of the task.
205+
206+
Associating requests with replies is done using an id which must be handled by
207+
the RLS.
208+
209+
210+
### Extensions to the Language Server Protocol
211+
212+
The RLS uses some custom extensions to the Language Server Protocol. Currently
213+
these are all sent from the RLS to an LSP client and are only used to improve
214+
the user experience by showing progress indicators.
215+
216+
* `rustDocument/diagnosticsBegin`: notification, no arguments. Sent before a
217+
build starts and before any diagnostics from a build are sent.
218+
* `rustDocument/diagnosticsEnd`: notification, no arguments. Sent when a build
219+
is complete (successfully or not, or even skipped) and all post-build analysis
220+
by the RLS is complete.
221+
222+

0 commit comments

Comments
 (0)