diff options
Diffstat (limited to 'docs/dev')
-rw-r--r-- | docs/dev/README.md | 278 | ||||
-rw-r--r-- | docs/dev/lsp-extensions.md | 150 | ||||
-rw-r--r-- | docs/dev/lsp-features.md | 72 |
3 files changed, 386 insertions, 114 deletions
diff --git a/docs/dev/README.md b/docs/dev/README.md index 65cc9fc12..3af01cd6b 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -1,6 +1,6 @@ | |||
1 | # Contributing Quick Start | 1 | # Contributing Quick Start |
2 | 2 | ||
3 | Rust Analyzer is just a usual rust project, which is organized as a Cargo | 3 | Rust Analyzer is an ordinary Rust project, which is organized as a Cargo |
4 | workspace, builds on stable and doesn't depend on C libraries. So, just | 4 | workspace, builds on stable and doesn't depend on C libraries. So, just |
5 | 5 | ||
6 | ``` | 6 | ``` |
@@ -30,7 +30,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0 | |||
30 | 30 | ||
31 | * [good-first-issue](https://github.com/rust-analyzer/rust-analyzer/labels/good%20first%20issue) | 31 | * [good-first-issue](https://github.com/rust-analyzer/rust-analyzer/labels/good%20first%20issue) |
32 | are good issues to get into the project. | 32 | are good issues to get into the project. |
33 | * [E-mentor](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-mentor) | 33 | * [E-has-instructions](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-has-instructions) |
34 | issues have links to the code in question and tests. | 34 | issues have links to the code in question and tests. |
35 | * [E-easy](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy), | 35 | * [E-easy](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-easy), |
36 | [E-medium](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-medium), | 36 | [E-medium](https://github.com/rust-analyzer/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3AE-medium), |
@@ -55,7 +55,7 @@ You can run `cargo xtask install-pre-commit-hook` to install git-hook to run rus | |||
55 | All Rust code lives in the `crates` top-level directory, and is organized as a | 55 | All Rust code lives in the `crates` top-level directory, and is organized as a |
56 | single Cargo workspace. The `editors` top-level directory contains code for | 56 | single Cargo workspace. The `editors` top-level directory contains code for |
57 | integrating with editors. Currently, it contains the plugin for VS Code (in | 57 | integrating with editors. Currently, it contains the plugin for VS Code (in |
58 | typescript). The `docs` top-level directory contains both developer and user | 58 | TypeScript). The `docs` top-level directory contains both developer and user |
59 | documentation. | 59 | documentation. |
60 | 60 | ||
61 | We have some automation infra in Rust in the `xtask` package. It contains | 61 | We have some automation infra in Rust in the `xtask` package. It contains |
@@ -65,7 +65,7 @@ directory). | |||
65 | 65 | ||
66 | # Launching rust-analyzer | 66 | # Launching rust-analyzer |
67 | 67 | ||
68 | Debugging language server can be tricky: LSP is rather chatty, so driving it | 68 | Debugging the language server can be tricky: LSP is rather chatty, so driving it |
69 | from the command line is not really feasible, driving it via VS Code requires | 69 | from the command line is not really feasible, driving it via VS Code requires |
70 | interacting with two processes. | 70 | interacting with two processes. |
71 | 71 | ||
@@ -73,14 +73,14 @@ For this reason, the best way to see how rust-analyzer works is to find a | |||
73 | relevant test and execute it (VS Code includes an action for running a single | 73 | relevant test and execute it (VS Code includes an action for running a single |
74 | test). | 74 | test). |
75 | 75 | ||
76 | However, launching a VS Code instance with locally build language server is | 76 | However, launching a VS Code instance with a locally built language server is |
77 | possible. There's **"Run Extension (Debug Build)"** launch configuration for this. | 77 | possible. There's **"Run Extension (Debug Build)"** launch configuration for this. |
78 | 78 | ||
79 | In general, I use one of the following workflows for fixing bugs and | 79 | In general, I use one of the following workflows for fixing bugs and |
80 | implementing features. | 80 | implementing features. |
81 | 81 | ||
82 | If the problem concerns only internal parts of rust-analyzer (ie, I don't need | 82 | If the problem concerns only internal parts of rust-analyzer (i.e. I don't need |
83 | to touch `rust-analyzer` crate or typescript code), there is a unit-test for it. | 83 | to touch the `rust-analyzer` crate or TypeScript code), there is a unit-test for it. |
84 | So, I use **Rust Analyzer: Run** action in VS Code to run this single test, and | 84 | So, I use **Rust Analyzer: Run** action in VS Code to run this single test, and |
85 | then just do printf-driven development/debugging. As a sanity check after I'm | 85 | then just do printf-driven development/debugging. As a sanity check after I'm |
86 | done, I use `cargo xtask install --server` and **Reload Window** action in VS | 86 | done, I use `cargo xtask install --server` and **Reload Window** action in VS |
@@ -88,8 +88,8 @@ Code to sanity check that the thing works as I expect. | |||
88 | 88 | ||
89 | If the problem concerns only the VS Code extension, I use **Run Installed Extension** | 89 | If the problem concerns only the VS Code extension, I use **Run Installed Extension** |
90 | launch configuration from `launch.json`. Notably, this uses the usual | 90 | launch configuration from `launch.json`. Notably, this uses the usual |
91 | `rust-analyzer` binary from `PATH`. For this it is important to have the following | 91 | `rust-analyzer` binary from `PATH`. For this, it is important to have the following |
92 | in `setting.json` file: | 92 | in your `settings.json` file: |
93 | ```json | 93 | ```json |
94 | { | 94 | { |
95 | "rust-analyzer.serverPath": "rust-analyzer" | 95 | "rust-analyzer.serverPath": "rust-analyzer" |
@@ -107,7 +107,7 @@ things up, sometimes I open a temporary hello-world project which has | |||
107 | `"rust-analyzer.withSysroot": false` in `.code/settings.json`. This flag causes | 107 | `"rust-analyzer.withSysroot": false` in `.code/settings.json`. This flag causes |
108 | rust-analyzer to skip loading the sysroot, which greatly reduces the amount of | 108 | rust-analyzer to skip loading the sysroot, which greatly reduces the amount of |
109 | things rust-analyzer needs to do, and makes printf's more useful. Note that you | 109 | things rust-analyzer needs to do, and makes printf's more useful. Note that you |
110 | should only use `eprint!` family of macros for debugging: stdout is used for LSP | 110 | should only use the `eprint!` family of macros for debugging: stdout is used for LSP |
111 | communication, and `print!` would break it. | 111 | communication, and `print!` would break it. |
112 | 112 | ||
113 | If I need to fix something simultaneously in the server and in the client, I | 113 | If I need to fix something simultaneously in the server and in the client, I |
@@ -117,6 +117,258 @@ Additionally, I use `cargo run --release -p rust-analyzer -- analysis-stats | |||
117 | path/to/some/rust/crate` to run a batch analysis. This is primarily useful for | 117 | path/to/some/rust/crate` to run a batch analysis. This is primarily useful for |
118 | performance optimizations, or for bug minimization. | 118 | performance optimizations, or for bug minimization. |
119 | 119 | ||
120 | # Code Style & Review Process | ||
121 | |||
122 | Our approach to "clean code" is two-fold: | ||
123 | |||
124 | * We generally don't block PRs on style changes. | ||
125 | * At the same time, all code in rust-analyzer is constantly refactored. | ||
126 | |||
127 | It is explicitly OK for a reviewer to flag only some nits in the PR, and then send a follow-up cleanup PR for things which are easier to explain by example, cc-ing the original author. | ||
128 | Sending small cleanup PRs (like renaming a single local variable) is encouraged. | ||
129 | |||
130 | ## Scale of Changes | ||
131 | |||
132 | Everyone knows that it's better to send small & focused pull requests. | ||
133 | The problem is, sometimes you *have* to, eg, rewrite the whole compiler, and that just doesn't fit into a set of isolated PRs. | ||
134 | |||
135 | The main things to keep an eye on are the boundaries between various components. | ||
136 | There are three kinds of changes: | ||
137 | |||
138 | 1. Internals of a single component are changed. | ||
139 | Specifically, you don't change any `pub` items. | ||
140 | A good example here would be an addition of a new assist. | ||
141 | |||
142 | 2. API of a component is expanded. | ||
143 | Specifically, you add a new `pub` function which wasn't there before. | ||
144 | A good example here would be expansion of assist API, for example, to implement lazy assists or assists groups. | ||
145 | |||
146 | 3. A new dependency between components is introduced. | ||
147 | Specifically, you add a `pub use` reexport from another crate or you add a new line to the `[dependencies]` section of `Cargo.toml`. | ||
148 | A good example here would be adding reference search capability to the assists crates. | ||
149 | |||
150 | For the first group, the change is generally merged as long as: | ||
151 | |||
152 | * it works for the happy case, | ||
153 | * it has tests, | ||
154 | * it doesn't panic for the unhappy case. | ||
155 | |||
156 | For the second group, the change would be subjected to quite a bit of scrutiny and iteration. | ||
157 | The new API needs to be right (or at least easy to change later). | ||
158 | The actual implementation doesn't matter that much. | ||
159 | It's very important to minimize the amount of changed lines of code for changes of the second kind. | ||
160 | Often, you start doing a change of the first kind, only to realise that you need to elevate to a change of the second kind. | ||
161 | In this case, we'll probably ask you to split API changes into a separate PR. | ||
162 | |||
163 | Changes of the third group should be pretty rare, so we don't specify any specific process for them. | ||
164 | That said, adding an innocent-looking `pub use` is a very simple way to break encapsulation, keep an eye on it! | ||
165 | |||
166 | Note: if you enjoyed this abstract hand-waving about boundaries, you might appreciate | ||
167 | https://www.tedinski.com/2018/02/06/system-boundaries.html | ||
168 | |||
169 | ## Minimal Tests | ||
170 | |||
171 | Most tests in rust-analyzer start with a snippet of Rust code. | ||
172 | This snippets should be minimal -- if you copy-paste a snippet of real code into the tests, make sure to remove everything which could be removed. | ||
173 | There are many benefits to this: | ||
174 | |||
175 | * less to read or to scroll past | ||
176 | * easier to understand what exactly is tested | ||
177 | * less stuff printed during printf-debugging | ||
178 | * less time to run test | ||
179 | |||
180 | It also makes sense to format snippets more compactly (for example, by placing enum defitions like `enum E { Foo, Bar }` on a single line), | ||
181 | as long as they are still readable. | ||
182 | |||
183 | ## Order of Imports | ||
184 | |||
185 | We separate import groups with blank lines | ||
186 | |||
187 | ```rust | ||
188 | mod x; | ||
189 | mod y; | ||
190 | |||
191 | use std::{ ... } | ||
192 | |||
193 | use crate_foo::{ ... } | ||
194 | use crate_bar::{ ... } | ||
195 | |||
196 | use crate::{} | ||
197 | |||
198 | use super::{} // but prefer `use crate::` | ||
199 | ``` | ||
200 | |||
201 | ## Import Style | ||
202 | |||
203 | Items from `hir` and `ast` should be used qualified: | ||
204 | |||
205 | ```rust | ||
206 | // Good | ||
207 | use ra_syntax::ast; | ||
208 | |||
209 | fn frobnicate(func: hir::Function, strukt: ast::StructDef) {} | ||
210 | |||
211 | // Not as good | ||
212 | use hir::Function; | ||
213 | use ra_syntax::ast::StructDef; | ||
214 | |||
215 | fn frobnicate(func: Function, strukt: StructDef) {} | ||
216 | ``` | ||
217 | |||
218 | Avoid local `use MyEnum::*` imports. | ||
219 | |||
220 | Prefer `use crate::foo::bar` to `use super::bar`. | ||
221 | |||
222 | ## Order of Items | ||
223 | |||
224 | Optimize for the reader who sees the file for the first time, and wants to get the general idea about what's going on. | ||
225 | People read things from top to bottom, so place most important things first. | ||
226 | |||
227 | Specifically, if all items except one are private, always put the non-private item on top. | ||
228 | |||
229 | Put `struct`s and `enum`s first, functions and impls last. | ||
230 | |||
231 | Do | ||
232 | |||
233 | ```rust | ||
234 | // Good | ||
235 | struct Foo { | ||
236 | bars: Vec<Bar> | ||
237 | } | ||
238 | |||
239 | struct Bar; | ||
240 | ``` | ||
241 | |||
242 | rather than | ||
243 | |||
244 | ```rust | ||
245 | // Not as good | ||
246 | struct Bar; | ||
247 | |||
248 | struct Foo { | ||
249 | bars: Vec<Bar> | ||
250 | } | ||
251 | ``` | ||
252 | |||
253 | ## Variable Naming | ||
254 | |||
255 | We generally use boring and long names for local variables ([yay code completion](https://github.com/rust-analyzer/rust-analyzer/pull/4162#discussion_r417130973)). | ||
256 | The default name is a lowercased name of the type: `global_state: GlobalState`. | ||
257 | Avoid ad-hoc acronyms and contractions, but use the ones that exist consistently (`db`, `ctx`, `acc`). | ||
258 | The default name for "result of the function" local variable is `res`. | ||
259 | |||
260 | ## Collection types | ||
261 | |||
262 | We prefer `rustc_hash::FxHashMap` and `rustc_hash::FxHashSet` instead of the ones in `std::collections`. | ||
263 | They use a hasher that's slightly faster and using them consistently will reduce code size by some small amount. | ||
264 | |||
265 | ## Preconditions | ||
266 | |||
267 | Function preconditions should generally be expressed in types and provided by the caller (rather than checked by callee): | ||
268 | |||
269 | ```rust | ||
270 | // Good | ||
271 | fn frbonicate(walrus: Walrus) { | ||
272 | ... | ||
273 | } | ||
274 | |||
275 | // Not as good | ||
276 | fn frobnicate(walrus: Option<Walrus>) { | ||
277 | let walrus = match walrus { | ||
278 | Some(it) => it, | ||
279 | None => return, | ||
280 | }; | ||
281 | ... | ||
282 | } | ||
283 | ``` | ||
284 | |||
285 | ## Premature Pessimization | ||
286 | |||
287 | While we don't specifically optimize code yet, avoid writing code which is slower than it needs to be. | ||
288 | Don't allocate a `Vec` where an iterator would do, don't allocate strings needlessly. | ||
289 | |||
290 | ```rust | ||
291 | // Good | ||
292 | use itertools::Itertools; | ||
293 | |||
294 | let (first_word, second_word) = match text.split_ascii_whitespace().collect_tuple() { | ||
295 | Some(it) => it, | ||
296 | None => return, | ||
297 | } | ||
298 | |||
299 | // Not as good | ||
300 | let words = text.split_ascii_whitespace().collect::<Vec<_>>(); | ||
301 | if words.len() != 2 { | ||
302 | return | ||
303 | } | ||
304 | ``` | ||
305 | |||
306 | ## Documentation | ||
307 | |||
308 | For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines. | ||
309 | If the line is too long, you want to split the sentence in two :-) | ||
310 | |||
311 | ## Commit Style | ||
312 | |||
313 | We don't have specific rules around git history hygiene. | ||
314 | Maintaining clean git history is encouraged, but not enforced. | ||
315 | We use rebase workflow, it's OK to rewrite history during PR review process. | ||
316 | |||
317 | Avoid @mentioning people in commit messages and pull request descriptions (they are added to commit message by bors), as such messages create a lot of duplicate notification traffic during rebases. | ||
318 | |||
319 | # Architecture Invariants | ||
320 | |||
321 | This section tries to document high-level design constraints, which are not | ||
322 | always obvious from the low-level code. | ||
323 | |||
324 | ## Incomplete syntax trees | ||
325 | |||
326 | Syntax trees are by design incomplete and do not enforce well-formedness. | ||
327 | If an AST method returns an `Option`, it *can* be `None` at runtime, even if this is forbidden by the grammar. | ||
328 | |||
329 | ## LSP independence | ||
330 | |||
331 | rust-analyzer is independent from LSP. | ||
332 | It provides features for a hypothetical perfect Rust-specific IDE client. | ||
333 | Internal representations are lowered to LSP in the `rust-analyzer` crate (the only crate which is allowed to use LSP types). | ||
334 | |||
335 | ## IDE/Compiler split | ||
336 | |||
337 | There's a semi-hard split between "compiler" and "IDE", at the `ra_hir` crate. | ||
338 | Compiler derives new facts about source code. | ||
339 | It explicitly acknowledges that not all info is available (i.e. you can't look at types during name resolution). | ||
340 | |||
341 | IDE assumes that all information is available at all times. | ||
342 | |||
343 | IDE should use only types from `ra_hir`, and should not depend on the underling compiler types. | ||
344 | `ra_hir` is a facade. | ||
345 | |||
346 | ## IDE API | ||
347 | |||
348 | The main IDE crate (`ra_ide`) uses "Plain Old Data" for the API. | ||
349 | Rather than talking in definitions and references, it talks in Strings and textual offsets. | ||
350 | In general, API is centered around UI concerns -- the result of the call is what the user sees in the editor, and not what the compiler sees underneath. | ||
351 | The results are 100% Rust specific though. | ||
352 | |||
353 | ## Parser Tests | ||
354 | |||
355 | Tests for the parser (`ra_parser`) live in the `ra_syntax` crate (see `test_data` directory). | ||
356 | There are two kinds of tests: | ||
357 | |||
358 | * Manually written test cases in `parser/ok` and `parser/err` | ||
359 | * "Inline" tests in `parser/inline` (these are generated) from comments in `ra_parser` crate. | ||
360 | |||
361 | The purpose of inline tests is not to achieve full coverage by test cases, but to explain to the reader of the code what each particular `if` and `match` is responsible for. | ||
362 | If you are tempted to add a large inline test, it might be a good idea to leave only the simplest example in place, and move the test to a manual `parser/ok` test. | ||
363 | |||
364 | To update test data, run with `UPDATE_EXPECT` variable: | ||
365 | |||
366 | ```bash | ||
367 | env UPDATE_EXPECT=1 cargo qt | ||
368 | ``` | ||
369 | |||
370 | After adding a new inline test you need to run `cargo xtest codegen` and also update the test data as described above. | ||
371 | |||
120 | # Logging | 372 | # Logging |
121 | 373 | ||
122 | Logging is done by both rust-analyzer and VS Code, so it might be tricky to | 374 | Logging is done by both rust-analyzer and VS Code, so it might be tricky to |
@@ -143,7 +395,7 @@ To log all communication between the server and the client, there are two choice | |||
143 | [@DJMcNab](https://github.com/DJMcNab) for setting this awesome infra up! | 395 | [@DJMcNab](https://github.com/DJMcNab) for setting this awesome infra up! |
144 | 396 | ||
145 | 397 | ||
146 | There's also two VS Code commands which might be of interest: | 398 | There are also two VS Code commands which might be of interest: |
147 | 399 | ||
148 | * `Rust Analyzer: Status` shows some memory-usage statistics. To take full | 400 | * `Rust Analyzer: Status` shows some memory-usage statistics. To take full |
149 | advantage of it, you need to compile rust-analyzer with jemalloc support: | 401 | advantage of it, you need to compile rust-analyzer with jemalloc support: |
@@ -159,8 +411,8 @@ There's also two VS Code commands which might be of interest: | |||
159 | rust code that it refers to and the rust editor will also highlight the proper | 411 | rust code that it refers to and the rust editor will also highlight the proper |
160 | text range. | 412 | text range. |
161 | 413 | ||
162 | If you press <kbd>Ctrl</kbd> (i.e. trigger goto definition) in the inspected | 414 | If you trigger Go to Definition in the inspected Rust source file, |
163 | Rust source file the syntax tree read-only editor should scroll to and select the | 415 | the syntax tree read-only editor should scroll to and select the |
164 | appropriate syntax node token. | 416 | appropriate syntax node token. |
165 | 417 | ||
166 |  | 418 |  |
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index dbc95be38..6d6bbac7c 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -7,6 +7,16 @@ All capabilities are enabled via `experimental` field of `ClientCapabilities` or | |||
7 | Requests which we hope to upstream live under `experimental/` namespace. | 7 | Requests which we hope to upstream live under `experimental/` namespace. |
8 | Requests, which are likely to always remain specific to `rust-analyzer` are under `rust-analyzer/` namespace. | 8 | Requests, which are likely to always remain specific to `rust-analyzer` are under `rust-analyzer/` namespace. |
9 | 9 | ||
10 | If you want to be notified about the changes to this document, subscribe to [#4604](https://github.com/rust-analyzer/rust-analyzer/issues/4604). | ||
11 | |||
12 | ## `initializationOptions` | ||
13 | |||
14 | As `initializationOptions`, `rust-analyzer` expects `"rust-analyzer"` section of the configuration. | ||
15 | That is, `rust-analyzer` usually sends `"workspace/configuration"` request with `{ "items": ["rust-analyzer"] }` payload. | ||
16 | `initializationOptions` should contain the same data that would be in the first item of the result. | ||
17 | It's OK to not send anything, then all the settings would take their default values. | ||
18 | However, some settings can not be changed after startup at the moment. | ||
19 | |||
10 | ## Snippet `TextEdit` | 20 | ## Snippet `TextEdit` |
11 | 21 | ||
12 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/724 | 22 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/724 |
@@ -87,6 +97,30 @@ Invoking code action at this position will yield two code actions for importing | |||
87 | * Is a fixed two-level structure enough? | 97 | * Is a fixed two-level structure enough? |
88 | * Should we devise a general way to encode custom interaction protocols for GUI refactorings? | 98 | * Should we devise a general way to encode custom interaction protocols for GUI refactorings? |
89 | 99 | ||
100 | ## Lazy assists with `ResolveCodeAction` | ||
101 | |||
102 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/787 | ||
103 | |||
104 | **Client Capability** `{ "resolveCodeAction": boolean }` | ||
105 | |||
106 | If this capability is set, the assists will be computed lazily. Thus `CodeAction` returned from the server will only contain `id` but not `edit` or `command` fields. The only exclusion from the rule is the diagnostic edits. | ||
107 | |||
108 | After the client got the id, it should then call `experimental/resolveCodeAction` command on the server and provide the following payload: | ||
109 | |||
110 | ```typescript | ||
111 | interface ResolveCodeActionParams { | ||
112 | id: string; | ||
113 | codeActionParams: lc.CodeActionParams; | ||
114 | } | ||
115 | ``` | ||
116 | |||
117 | As a result of the command call the client will get the respective workspace edit (`lc.WorkspaceEdit`). | ||
118 | |||
119 | ### Unresolved Questions | ||
120 | |||
121 | * Apply smarter filtering for ids? | ||
122 | * Upon `resolveCodeAction` command only call the assits which should be resolved and not all of them? | ||
123 | |||
90 | ## Parent Module | 124 | ## Parent Module |
91 | 125 | ||
92 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/1002 | 126 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/1002 |
@@ -301,6 +335,50 @@ Moreover, it would be cool if editors didn't need to implement even basic langua | |||
301 | This is how `SelectionRange` request works. | 335 | This is how `SelectionRange` request works. |
302 | * Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs? | 336 | * Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs? |
303 | 337 | ||
338 | ## Runnables | ||
339 | |||
340 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/944 | ||
341 | |||
342 | **Server Capability:** `{ "runnables": { "kinds": string[] } }` | ||
343 | |||
344 | This request is send from client to server to get the list of things that can be run (tests, binaries, `cargo check -p`). | ||
345 | |||
346 | **Method:** `experimental/runnables` | ||
347 | |||
348 | **Request:** | ||
349 | |||
350 | ```typescript | ||
351 | interface RunnablesParams { | ||
352 | textDocument: TextDocumentIdentifier; | ||
353 | /// If null, compute runnables for the whole file. | ||
354 | position?: Position; | ||
355 | } | ||
356 | ``` | ||
357 | |||
358 | **Response:** `Runnable[]` | ||
359 | |||
360 | ```typescript | ||
361 | interface Runnable { | ||
362 | label: string; | ||
363 | /// If this Runnable is associated with a specific function/module, etc, the location of this item | ||
364 | location?: LocationLink; | ||
365 | /// Running things is necessary technology specific, `kind` needs to be advertised via server capabilities, | ||
366 | // the type of `args` is specific to `kind`. The actual running is handled by the client. | ||
367 | kind: string; | ||
368 | args: any; | ||
369 | } | ||
370 | ``` | ||
371 | |||
372 | rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look like this: | ||
373 | |||
374 | ```typescript | ||
375 | { | ||
376 | workspaceRoot?: string; | ||
377 | cargoArgs: string[]; | ||
378 | executableArgs: string[]; | ||
379 | } | ||
380 | ``` | ||
381 | |||
304 | ## Analyzer Status | 382 | ## Analyzer Status |
305 | 383 | ||
306 | **Method:** `rust-analyzer/analyzerStatus` | 384 | **Method:** `rust-analyzer/analyzerStatus` |
@@ -311,15 +389,27 @@ Moreover, it would be cool if editors didn't need to implement even basic langua | |||
311 | 389 | ||
312 | Returns internal status message, mostly for debugging purposes. | 390 | Returns internal status message, mostly for debugging purposes. |
313 | 391 | ||
314 | ## Collect Garbage | 392 | ## Reload Workspace |
315 | 393 | ||
316 | **Method:** `rust-analyzer/collectGarbage` | 394 | **Method:** `rust-analyzer/reloadWorkspace` |
317 | 395 | ||
318 | **Request:** `null` | 396 | **Request:** `null` |
319 | 397 | ||
320 | **Response:** `null` | 398 | **Response:** `null` |
321 | 399 | ||
322 | Frees some caches. For internal use, and is mostly broken at the moment. | 400 | Reloads project information (that is, re-executes `cargo metadata`). |
401 | |||
402 | ## Status Notification | ||
403 | |||
404 | **Client Capability:** `{ "statusNotification": boolean }` | ||
405 | |||
406 | **Method:** `rust-analyzer/status` | ||
407 | |||
408 | **Notification:** `"loading" | "ready" | "invalid" | "needsReload"` | ||
409 | |||
410 | This notification is sent from server to client. | ||
411 | The client can use it to display persistent status to the user (in modline). | ||
412 | For `needsReload` state, the client can provide a context-menu action to run `rust-analyzer/reloadWorkspace` request. | ||
323 | 413 | ||
324 | ## Syntax Tree | 414 | ## Syntax Tree |
325 | 415 | ||
@@ -390,38 +480,40 @@ interface InlayHint { | |||
390 | } | 480 | } |
391 | ``` | 481 | ``` |
392 | 482 | ||
393 | ## Runnables | 483 | ## Hover Actions |
394 | |||
395 | **Method:** `rust-analyzer/runnables` | ||
396 | 484 | ||
397 | This request is send from client to server to get the list of things that can be run (tests, binaries, `cargo check -p`). | 485 | **Client Capability:** `{ "hoverActions": boolean }` |
398 | Note that we plan to move this request to `experimental/runnables`, as it is not really Rust-specific, but the current API is not necessary the right one. | ||
399 | Upstream issue: https://github.com/microsoft/language-server-protocol/issues/944 | ||
400 | 486 | ||
401 | **Request:** | 487 | If this capability is set, `Hover` request returned from the server might contain an additional field, `actions`: |
402 | 488 | ||
403 | ```typescript | 489 | ```typescript |
404 | interface RunnablesParams { | 490 | interface Hover { |
405 | textDocument: TextDocumentIdentifier; | 491 | ... |
406 | /// If null, compute runnables for the whole file. | 492 | actions?: CommandLinkGroup[]; |
407 | position?: Position; | ||
408 | } | 493 | } |
409 | ``` | ||
410 | 494 | ||
411 | **Response:** `Runnable[]` | 495 | interface CommandLink extends Command { |
496 | /** | ||
497 | * A tooltip for the command, when represented in the UI. | ||
498 | */ | ||
499 | tooltip?: string; | ||
500 | } | ||
412 | 501 | ||
413 | ```typescript | 502 | interface CommandLinkGroup { |
414 | interface Runnable { | 503 | title?: string; |
415 | /// The range this runnable is applicable for. | 504 | commands: CommandLink[]; |
416 | range: lc.Range; | ||
417 | /// The label to show in the UI. | ||
418 | label: string; | ||
419 | /// The following fields describe a process to spawn. | ||
420 | bin: string; | ||
421 | args: string[]; | ||
422 | /// Args for cargo after `--`. | ||
423 | extraArgs: string[]; | ||
424 | env: { [key: string]: string }; | ||
425 | cwd: string | null; | ||
426 | } | 505 | } |
427 | ``` | 506 | ``` |
507 | |||
508 | Such actions on the client side are appended to a hover bottom as command links: | ||
509 | ``` | ||
510 | +-----------------------------+ | ||
511 | | Hover content | | ||
512 | | | | ||
513 | +-----------------------------+ | ||
514 | | _Action1_ | _Action2_ | <- first group, no TITLE | ||
515 | +-----------------------------+ | ||
516 | | TITLE _Action1_ | _Action2_ | <- second group | ||
517 | +-----------------------------+ | ||
518 | ... | ||
519 | ``` | ||
diff --git a/docs/dev/lsp-features.md b/docs/dev/lsp-features.md deleted file mode 100644 index 00b0867d7..000000000 --- a/docs/dev/lsp-features.md +++ /dev/null | |||
@@ -1,72 +0,0 @@ | |||
1 | # Supported LSP features | ||
2 | |||
3 | This list documents LSP features, supported by rust-analyzer. | ||
4 | |||
5 | ## General | ||
6 | - [x] [initialize](https://microsoft.github.io/language-server-protocol/specification#initialize) | ||
7 | - [x] [initialized](https://microsoft.github.io/language-server-protocol/specification#initialized) | ||
8 | - [x] [shutdown](https://microsoft.github.io/language-server-protocol/specification#shutdown) | ||
9 | - [ ] [exit](https://microsoft.github.io/language-server-protocol/specification#exit) | ||
10 | - [x] [$/cancelRequest](https://microsoft.github.io/language-server-protocol/specification#cancelRequest) | ||
11 | |||
12 | ## Workspace | ||
13 | - [ ] [workspace/workspaceFolders](https://microsoft.github.io/language-server-protocol/specification#workspace_workspaceFolders) | ||
14 | - [ ] [workspace/didChangeWorkspaceFolders](https://microsoft.github.io/language-server-protocol/specification#workspace_didChangeWorkspaceFolders) | ||
15 | - [x] [workspace/didChangeConfiguration](https://microsoft.github.io/language-server-protocol/specification#workspace_didChangeConfiguration) | ||
16 | - [ ] [workspace/configuration](https://microsoft.github.io/language-server-protocol/specification#workspace_configuration) | ||
17 | - [x] [workspace/didChangeWatchedFiles](https://microsoft.github.io/language-server-protocol/specification#workspace_didChangeWatchedFiles) | ||
18 | - [x] [workspace/symbol](https://microsoft.github.io/language-server-protocol/specification#workspace_symbol) | ||
19 | - [ ] [workspace/applyEdit](https://microsoft.github.io/language-server-protocol/specification#workspace_applyEdit) | ||
20 | |||
21 | ## Text Synchronization | ||
22 | - [x] [textDocument/didOpen](https://microsoft.github.io/language-server-protocol/specification#textDocument_didOpen) | ||
23 | - [x] [textDocument/didChange](https://microsoft.github.io/language-server-protocol/specification#textDocument_didChange) | ||
24 | - [ ] [textDocument/willSave](https://microsoft.github.io/language-server-protocol/specification#textDocument_willSave) | ||
25 | - [ ] [textDocument/willSaveWaitUntil](https://microsoft.github.io/language-server-protocol/specification#textDocument_willSaveWaitUntil) | ||
26 | - [x] [textDocument/didSave](https://microsoft.github.io/language-server-protocol/specification#textDocument_didSave) | ||
27 | - [x] [textDocument/didClose](https://microsoft.github.io/language-server-protocol/specification#textDocument_didClose) | ||
28 | |||
29 | ## Diagnostics | ||
30 | - [x] [textDocument/publishDiagnostics](https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics) | ||
31 | |||
32 | ## Lanuguage Features | ||
33 | - [x] [textDocument/completion](https://microsoft.github.io/language-server-protocol/specification#textDocument_completion) | ||
34 | - open close: false | ||
35 | - change: Full | ||
36 | - will save: false | ||
37 | - will save wait until: false | ||
38 | - save: false | ||
39 | - [x] [completionItem/resolve](https://microsoft.github.io/language-server-protocol/specification#completionItem_resolve) | ||
40 | - resolve provider: none | ||
41 | - trigger characters: `:`, `.` | ||
42 | - [x] [textDocument/hover](https://microsoft.github.io/language-server-protocol/specification#textDocument_hover) | ||
43 | - [x] [textDocument/signatureHelp](https://microsoft.github.io/language-server-protocol/specification#textDocument_signatureHelp) | ||
44 | - trigger characters: `(`, `,` | ||
45 | - [ ] [textDocument/declaration](https://microsoft.github.io/language-server-protocol/specification#textDocument_declaration) | ||
46 | - [x] [textDocument/definition](https://microsoft.github.io/language-server-protocol/specification#textDocument_definition) | ||
47 | - [x] [textDocument/typeDefinition](https://microsoft.github.io/language-server-protocol/specification#textDocument_typeDefinition) | ||
48 | - [x] [textDocument/implementation](https://microsoft.github.io/language-server-protocol/specification#textDocument_implementation) | ||
49 | - [x] [textDocument/references](https://microsoft.github.io/language-server-protocol/specification#textDocument_references) | ||
50 | - [x] [textDocument/documentHighlight](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight) | ||
51 | - [x] [textDocument/documentSymbol](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) | ||
52 | - [x] [textDocument/codeAction](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeAction) | ||
53 | - [x] [textDocument/selectionRange](https://github.com/Microsoft/language-server-protocol/issues/613) | ||
54 | - rust-analyzer.syntaxTree | ||
55 | - rust-analyzer.matchingBrace | ||
56 | - rust-analyzer.parentModule | ||
57 | - rust-analyzer.joinLines | ||
58 | - rust-analyzer.run | ||
59 | - rust-analyzer.analyzerStatus | ||
60 | - [x] [textDocument/codeLens](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeLens) | ||
61 | - [x] [codeLens/resolve](https://microsoft.github.io/language-server-protocol/specification#codeLens_resolve) | ||
62 | - [ ] [documentLink/resolve](https://microsoft.github.io/language-server-protocol/specification#documentLink_resolve) | ||
63 | - [ ] [textDocument/documentColor](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentColor) | ||
64 | - [ ] [textDocument/colorPresentation](https://microsoft.github.io/language-server-protocol/specification#textDocument_colorPresentation) | ||
65 | - [x] [textDocument/formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_formatting) | ||
66 | - [ ] [textDocument/rangeFormatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_rangeFormatting) | ||
67 | - [x] [textDocument/onTypeFormatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_onTypeFormatting) | ||
68 | - first trigger character: `=` | ||
69 | - more trigger character `.` | ||
70 | - [x] [textDocument/rename](https://microsoft.github.io/language-server-protocol/specification#textDocument_rename) | ||
71 | - [x] [textDocument/prepareRename](https://microsoft.github.io/language-server-protocol/specification#textDocument_prepareRename) | ||
72 | - [x] [textDocument/foldingRange](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange) | ||