diff options
Diffstat (limited to 'docs')
-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 | ||||
-rw-r--r-- | docs/user/generated_assists.adoc | 1015 | ||||
-rw-r--r-- | docs/user/generated_features.adoc | 298 | ||||
-rw-r--r-- | docs/user/manual.adoc | 123 |
6 files changed, 494 insertions, 1442 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 | ![demo](https://user-images.githubusercontent.com/36276403/78225773-6636a480-74d3-11ea-9d9f-1c9d42da03b0.png) | 418 | ![demo](https://user-images.githubusercontent.com/36276403/78225773-6636a480-74d3-11ea-9d9f-1c9d42da03b0.png) |
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) | ||
diff --git a/docs/user/generated_assists.adoc b/docs/user/generated_assists.adoc deleted file mode 100644 index 580ab4358..000000000 --- a/docs/user/generated_assists.adoc +++ /dev/null | |||
@@ -1,1015 +0,0 @@ | |||
1 | [discrete] | ||
2 | === `add_custom_impl` | ||
3 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/add_custom_impl.rs#L14[add_custom_impl.rs] | ||
4 | |||
5 | Adds impl block for derived trait. | ||
6 | |||
7 | .Before | ||
8 | ```rust | ||
9 | #[derive(Deb┃ug, Display)] | ||
10 | struct S; | ||
11 | ``` | ||
12 | |||
13 | .After | ||
14 | ```rust | ||
15 | #[derive(Display)] | ||
16 | struct S; | ||
17 | |||
18 | impl Debug for S { | ||
19 | $0 | ||
20 | } | ||
21 | ``` | ||
22 | |||
23 | |||
24 | [discrete] | ||
25 | === `add_derive` | ||
26 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/add_derive.rs#L9[add_derive.rs] | ||
27 | |||
28 | Adds a new `#[derive()]` clause to a struct or enum. | ||
29 | |||
30 | .Before | ||
31 | ```rust | ||
32 | struct Point { | ||
33 | x: u32, | ||
34 | y: u32,┃ | ||
35 | } | ||
36 | ``` | ||
37 | |||
38 | .After | ||
39 | ```rust | ||
40 | #[derive($0)] | ||
41 | struct Point { | ||
42 | x: u32, | ||
43 | y: u32, | ||
44 | } | ||
45 | ``` | ||
46 | |||
47 | |||
48 | [discrete] | ||
49 | === `add_explicit_type` | ||
50 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/add_explicit_type.rs#L9[add_explicit_type.rs] | ||
51 | |||
52 | Specify type for a let binding. | ||
53 | |||
54 | .Before | ||
55 | ```rust | ||
56 | fn main() { | ||
57 | let x┃ = 92; | ||
58 | } | ||
59 | ``` | ||
60 | |||
61 | .After | ||
62 | ```rust | ||
63 | fn main() { | ||
64 | let x: i32 = 92; | ||
65 | } | ||
66 | ``` | ||
67 | |||
68 | |||
69 | [discrete] | ||
70 | === `add_from_impl_for_enum` | ||
71 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs#L7[add_from_impl_for_enum.rs] | ||
72 | |||
73 | Adds a From impl for an enum variant with one tuple field. | ||
74 | |||
75 | .Before | ||
76 | ```rust | ||
77 | enum A { ┃One(u32) } | ||
78 | ``` | ||
79 | |||
80 | .After | ||
81 | ```rust | ||
82 | enum A { One(u32) } | ||
83 | |||
84 | impl From<u32> for A { | ||
85 | fn from(v: u32) -> Self { | ||
86 | A::One(v) | ||
87 | } | ||
88 | } | ||
89 | ``` | ||
90 | |||
91 | |||
92 | [discrete] | ||
93 | === `add_function` | ||
94 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/add_function.rs#L19[add_function.rs] | ||
95 | |||
96 | Adds a stub function with a signature matching the function under the cursor. | ||
97 | |||
98 | .Before | ||
99 | ```rust | ||
100 | struct Baz; | ||
101 | fn baz() -> Baz { Baz } | ||
102 | fn foo() { | ||
103 | bar┃("", baz()); | ||
104 | } | ||
105 | |||
106 | ``` | ||
107 | |||
108 | .After | ||
109 | ```rust | ||
110 | struct Baz; | ||
111 | fn baz() -> Baz { Baz } | ||
112 | fn foo() { | ||
113 | bar("", baz()); | ||
114 | } | ||
115 | |||
116 | fn bar(arg: &str, baz: Baz) { | ||
117 | ${0:todo!()} | ||
118 | } | ||
119 | |||
120 | ``` | ||
121 | |||
122 | |||
123 | [discrete] | ||
124 | === `add_hash` | ||
125 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/raw_string.rs#L65[raw_string.rs] | ||
126 | |||
127 | Adds a hash to a raw string literal. | ||
128 | |||
129 | .Before | ||
130 | ```rust | ||
131 | fn main() { | ||
132 | r#"Hello,┃ World!"#; | ||
133 | } | ||
134 | ``` | ||
135 | |||
136 | .After | ||
137 | ```rust | ||
138 | fn main() { | ||
139 | r##"Hello, World!"##; | ||
140 | } | ||
141 | ``` | ||
142 | |||
143 | |||
144 | [discrete] | ||
145 | === `add_impl` | ||
146 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/add_impl.rs#L6[add_impl.rs] | ||
147 | |||
148 | Adds a new inherent impl for a type. | ||
149 | |||
150 | .Before | ||
151 | ```rust | ||
152 | struct Ctx<T: Clone> { | ||
153 | data: T,┃ | ||
154 | } | ||
155 | ``` | ||
156 | |||
157 | .After | ||
158 | ```rust | ||
159 | struct Ctx<T: Clone> { | ||
160 | data: T, | ||
161 | } | ||
162 | |||
163 | impl<T: Clone> Ctx<T> { | ||
164 | $0 | ||
165 | } | ||
166 | ``` | ||
167 | |||
168 | |||
169 | [discrete] | ||
170 | === `add_impl_default_members` | ||
171 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/add_missing_impl_members.rs#L64[add_missing_impl_members.rs] | ||
172 | |||
173 | Adds scaffold for overriding default impl members. | ||
174 | |||
175 | .Before | ||
176 | ```rust | ||
177 | trait Trait { | ||
178 | Type X; | ||
179 | fn foo(&self); | ||
180 | fn bar(&self) {} | ||
181 | } | ||
182 | |||
183 | impl Trait for () { | ||
184 | Type X = (); | ||
185 | fn foo(&self) {}┃ | ||
186 | |||
187 | } | ||
188 | ``` | ||
189 | |||
190 | .After | ||
191 | ```rust | ||
192 | trait Trait { | ||
193 | Type X; | ||
194 | fn foo(&self); | ||
195 | fn bar(&self) {} | ||
196 | } | ||
197 | |||
198 | impl Trait for () { | ||
199 | Type X = (); | ||
200 | fn foo(&self) {} | ||
201 | $0fn bar(&self) {} | ||
202 | |||
203 | } | ||
204 | ``` | ||
205 | |||
206 | |||
207 | [discrete] | ||
208 | === `add_impl_missing_members` | ||
209 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/add_missing_impl_members.rs#L24[add_missing_impl_members.rs] | ||
210 | |||
211 | Adds scaffold for required impl members. | ||
212 | |||
213 | .Before | ||
214 | ```rust | ||
215 | trait Trait<T> { | ||
216 | Type X; | ||
217 | fn foo(&self) -> T; | ||
218 | fn bar(&self) {} | ||
219 | } | ||
220 | |||
221 | impl Trait<u32> for () {┃ | ||
222 | |||
223 | } | ||
224 | ``` | ||
225 | |||
226 | .After | ||
227 | ```rust | ||
228 | trait Trait<T> { | ||
229 | Type X; | ||
230 | fn foo(&self) -> T; | ||
231 | fn bar(&self) {} | ||
232 | } | ||
233 | |||
234 | impl Trait<u32> for () { | ||
235 | fn foo(&self) -> u32 { | ||
236 | ${0:todo!()} | ||
237 | } | ||
238 | |||
239 | } | ||
240 | ``` | ||
241 | |||
242 | |||
243 | [discrete] | ||
244 | === `add_new` | ||
245 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/add_new.rs#L12[add_new.rs] | ||
246 | |||
247 | Adds a new inherent impl for a type. | ||
248 | |||
249 | .Before | ||
250 | ```rust | ||
251 | struct Ctx<T: Clone> { | ||
252 | data: T,┃ | ||
253 | } | ||
254 | ``` | ||
255 | |||
256 | .After | ||
257 | ```rust | ||
258 | struct Ctx<T: Clone> { | ||
259 | data: T, | ||
260 | } | ||
261 | |||
262 | impl<T: Clone> Ctx<T> { | ||
263 | fn $0new(data: T) -> Self { Self { data } } | ||
264 | } | ||
265 | |||
266 | ``` | ||
267 | |||
268 | |||
269 | [discrete] | ||
270 | === `add_turbo_fish` | ||
271 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/add_turbo_fish.rs#L10[add_turbo_fish.rs] | ||
272 | |||
273 | Adds `::<_>` to a call of a generic method or function. | ||
274 | |||
275 | .Before | ||
276 | ```rust | ||
277 | fn make<T>() -> T { todo!() } | ||
278 | fn main() { | ||
279 | let x = make┃(); | ||
280 | } | ||
281 | ``` | ||
282 | |||
283 | .After | ||
284 | ```rust | ||
285 | fn make<T>() -> T { todo!() } | ||
286 | fn main() { | ||
287 | let x = make::<${0:_}>(); | ||
288 | } | ||
289 | ``` | ||
290 | |||
291 | |||
292 | [discrete] | ||
293 | === `apply_demorgan` | ||
294 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/apply_demorgan.rs#L5[apply_demorgan.rs] | ||
295 | |||
296 | Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). | ||
297 | This transforms expressions of the form `!l || !r` into `!(l && r)`. | ||
298 | This also works with `&&`. This assist can only be applied with the cursor | ||
299 | on either `||` or `&&`, with both operands being a negation of some kind. | ||
300 | This means something of the form `!x` or `x != y`. | ||
301 | |||
302 | .Before | ||
303 | ```rust | ||
304 | fn main() { | ||
305 | if x != 4 ||┃ !y {} | ||
306 | } | ||
307 | ``` | ||
308 | |||
309 | .After | ||
310 | ```rust | ||
311 | fn main() { | ||
312 | if !(x == 4 && y) {} | ||
313 | } | ||
314 | ``` | ||
315 | |||
316 | |||
317 | [discrete] | ||
318 | === `auto_import` | ||
319 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/auto_import.rs#L18[auto_import.rs] | ||
320 | |||
321 | If the name is unresolved, provides all possible imports for it. | ||
322 | |||
323 | .Before | ||
324 | ```rust | ||
325 | fn main() { | ||
326 | let map = HashMap┃::new(); | ||
327 | } | ||
328 | ``` | ||
329 | |||
330 | .After | ||
331 | ```rust | ||
332 | use std::collections::HashMap; | ||
333 | |||
334 | fn main() { | ||
335 | let map = HashMap::new(); | ||
336 | } | ||
337 | ``` | ||
338 | |||
339 | |||
340 | [discrete] | ||
341 | === `change_lifetime_anon_to_named` | ||
342 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/change_lifetime_anon_to_named.rs#L9[change_lifetime_anon_to_named.rs] | ||
343 | |||
344 | Change an anonymous lifetime to a named lifetime. | ||
345 | |||
346 | .Before | ||
347 | ```rust | ||
348 | impl Cursor<'_┃> { | ||
349 | fn node(self) -> &SyntaxNode { | ||
350 | match self { | ||
351 | Cursor::Replace(node) | Cursor::Before(node) => node, | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | ``` | ||
356 | |||
357 | .After | ||
358 | ```rust | ||
359 | impl<'a> Cursor<'a> { | ||
360 | fn node(self) -> &SyntaxNode { | ||
361 | match self { | ||
362 | Cursor::Replace(node) | Cursor::Before(node) => node, | ||
363 | } | ||
364 | } | ||
365 | } | ||
366 | ``` | ||
367 | |||
368 | |||
369 | [discrete] | ||
370 | === `change_return_type_to_result` | ||
371 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/change_return_type_to_result.rs#L8[change_return_type_to_result.rs] | ||
372 | |||
373 | Change the function's return type to Result. | ||
374 | |||
375 | .Before | ||
376 | ```rust | ||
377 | fn foo() -> i32┃ { 42i32 } | ||
378 | ``` | ||
379 | |||
380 | .After | ||
381 | ```rust | ||
382 | fn foo() -> Result<i32, ${0:_}> { Ok(42i32) } | ||
383 | ``` | ||
384 | |||
385 | |||
386 | [discrete] | ||
387 | === `change_visibility` | ||
388 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/change_visibility.rs#L14[change_visibility.rs] | ||
389 | |||
390 | Adds or changes existing visibility specifier. | ||
391 | |||
392 | .Before | ||
393 | ```rust | ||
394 | ┃fn frobnicate() {} | ||
395 | ``` | ||
396 | |||
397 | .After | ||
398 | ```rust | ||
399 | pub(crate) fn frobnicate() {} | ||
400 | ``` | ||
401 | |||
402 | |||
403 | [discrete] | ||
404 | === `convert_to_guarded_return` | ||
405 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/early_return.rs#L21[early_return.rs] | ||
406 | |||
407 | Replace a large conditional with a guarded return. | ||
408 | |||
409 | .Before | ||
410 | ```rust | ||
411 | fn main() { | ||
412 | ┃if cond { | ||
413 | foo(); | ||
414 | bar(); | ||
415 | } | ||
416 | } | ||
417 | ``` | ||
418 | |||
419 | .After | ||
420 | ```rust | ||
421 | fn main() { | ||
422 | if !cond { | ||
423 | return; | ||
424 | } | ||
425 | foo(); | ||
426 | bar(); | ||
427 | } | ||
428 | ``` | ||
429 | |||
430 | |||
431 | [discrete] | ||
432 | === `fill_match_arms` | ||
433 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/fill_match_arms.rs#L14[fill_match_arms.rs] | ||
434 | |||
435 | Adds missing clauses to a `match` expression. | ||
436 | |||
437 | .Before | ||
438 | ```rust | ||
439 | enum Action { Move { distance: u32 }, Stop } | ||
440 | |||
441 | fn handle(action: Action) { | ||
442 | match action { | ||
443 | ┃ | ||
444 | } | ||
445 | } | ||
446 | ``` | ||
447 | |||
448 | .After | ||
449 | ```rust | ||
450 | enum Action { Move { distance: u32 }, Stop } | ||
451 | |||
452 | fn handle(action: Action) { | ||
453 | match action { | ||
454 | $0Action::Move { distance } => {} | ||
455 | Action::Stop => {} | ||
456 | } | ||
457 | } | ||
458 | ``` | ||
459 | |||
460 | |||
461 | [discrete] | ||
462 | === `fix_visibility` | ||
463 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/fix_visibility.rs#L13[fix_visibility.rs] | ||
464 | |||
465 | Makes inaccessible item public. | ||
466 | |||
467 | .Before | ||
468 | ```rust | ||
469 | mod m { | ||
470 | fn frobnicate() {} | ||
471 | } | ||
472 | fn main() { | ||
473 | m::frobnicate┃() {} | ||
474 | } | ||
475 | ``` | ||
476 | |||
477 | .After | ||
478 | ```rust | ||
479 | mod m { | ||
480 | $0pub(crate) fn frobnicate() {} | ||
481 | } | ||
482 | fn main() { | ||
483 | m::frobnicate() {} | ||
484 | } | ||
485 | ``` | ||
486 | |||
487 | |||
488 | [discrete] | ||
489 | === `flip_binexpr` | ||
490 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/flip_binexpr.rs#L5[flip_binexpr.rs] | ||
491 | |||
492 | Flips operands of a binary expression. | ||
493 | |||
494 | .Before | ||
495 | ```rust | ||
496 | fn main() { | ||
497 | let _ = 90 +┃ 2; | ||
498 | } | ||
499 | ``` | ||
500 | |||
501 | .After | ||
502 | ```rust | ||
503 | fn main() { | ||
504 | let _ = 2 + 90; | ||
505 | } | ||
506 | ``` | ||
507 | |||
508 | |||
509 | [discrete] | ||
510 | === `flip_comma` | ||
511 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/flip_comma.rs#L5[flip_comma.rs] | ||
512 | |||
513 | Flips two comma-separated items. | ||
514 | |||
515 | .Before | ||
516 | ```rust | ||
517 | fn main() { | ||
518 | ((1, 2),┃ (3, 4)); | ||
519 | } | ||
520 | ``` | ||
521 | |||
522 | .After | ||
523 | ```rust | ||
524 | fn main() { | ||
525 | ((3, 4), (1, 2)); | ||
526 | } | ||
527 | ``` | ||
528 | |||
529 | |||
530 | [discrete] | ||
531 | === `flip_trait_bound` | ||
532 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/flip_trait_bound.rs#L9[flip_trait_bound.rs] | ||
533 | |||
534 | Flips two trait bounds. | ||
535 | |||
536 | .Before | ||
537 | ```rust | ||
538 | fn foo<T: Clone +┃ Copy>() { } | ||
539 | ``` | ||
540 | |||
541 | .After | ||
542 | ```rust | ||
543 | fn foo<T: Copy + Clone>() { } | ||
544 | ``` | ||
545 | |||
546 | |||
547 | [discrete] | ||
548 | === `inline_local_variable` | ||
549 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/inline_local_variable.rs#L13[inline_local_variable.rs] | ||
550 | |||
551 | Inlines local variable. | ||
552 | |||
553 | .Before | ||
554 | ```rust | ||
555 | fn main() { | ||
556 | let x┃ = 1 + 2; | ||
557 | x * 4; | ||
558 | } | ||
559 | ``` | ||
560 | |||
561 | .After | ||
562 | ```rust | ||
563 | fn main() { | ||
564 | (1 + 2) * 4; | ||
565 | } | ||
566 | ``` | ||
567 | |||
568 | |||
569 | [discrete] | ||
570 | === `introduce_variable` | ||
571 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/introduce_variable.rs#L14[introduce_variable.rs] | ||
572 | |||
573 | Extracts subexpression into a variable. | ||
574 | |||
575 | .Before | ||
576 | ```rust | ||
577 | fn main() { | ||
578 | ┃(1 + 2)┃ * 4; | ||
579 | } | ||
580 | ``` | ||
581 | |||
582 | .After | ||
583 | ```rust | ||
584 | fn main() { | ||
585 | let $0var_name = (1 + 2); | ||
586 | var_name * 4; | ||
587 | } | ||
588 | ``` | ||
589 | |||
590 | |||
591 | [discrete] | ||
592 | === `invert_if` | ||
593 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/invert_if.rs#L12[invert_if.rs] | ||
594 | |||
595 | Apply invert_if | ||
596 | This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}` | ||
597 | This also works with `!=`. This assist can only be applied with the cursor | ||
598 | on `if`. | ||
599 | |||
600 | .Before | ||
601 | ```rust | ||
602 | fn main() { | ||
603 | if┃ !y { A } else { B } | ||
604 | } | ||
605 | ``` | ||
606 | |||
607 | .After | ||
608 | ```rust | ||
609 | fn main() { | ||
610 | if y { B } else { A } | ||
611 | } | ||
612 | ``` | ||
613 | |||
614 | |||
615 | [discrete] | ||
616 | === `make_raw_string` | ||
617 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/raw_string.rs#L10[raw_string.rs] | ||
618 | |||
619 | Adds `r#` to a plain string literal. | ||
620 | |||
621 | .Before | ||
622 | ```rust | ||
623 | fn main() { | ||
624 | "Hello,┃ World!"; | ||
625 | } | ||
626 | ``` | ||
627 | |||
628 | .After | ||
629 | ```rust | ||
630 | fn main() { | ||
631 | r#"Hello, World!"#; | ||
632 | } | ||
633 | ``` | ||
634 | |||
635 | |||
636 | [discrete] | ||
637 | === `make_usual_string` | ||
638 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/raw_string.rs#L39[raw_string.rs] | ||
639 | |||
640 | Turns a raw string into a plain string. | ||
641 | |||
642 | .Before | ||
643 | ```rust | ||
644 | fn main() { | ||
645 | r#"Hello,┃ "World!""#; | ||
646 | } | ||
647 | ``` | ||
648 | |||
649 | .After | ||
650 | ```rust | ||
651 | fn main() { | ||
652 | "Hello, \"World!\""; | ||
653 | } | ||
654 | ``` | ||
655 | |||
656 | |||
657 | [discrete] | ||
658 | === `merge_imports` | ||
659 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/merge_imports.rs#L14[merge_imports.rs] | ||
660 | |||
661 | Merges two imports with a common prefix. | ||
662 | |||
663 | .Before | ||
664 | ```rust | ||
665 | use std::┃fmt::Formatter; | ||
666 | use std::io; | ||
667 | ``` | ||
668 | |||
669 | .After | ||
670 | ```rust | ||
671 | use std::{fmt::Formatter, io}; | ||
672 | ``` | ||
673 | |||
674 | |||
675 | [discrete] | ||
676 | === `merge_match_arms` | ||
677 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/merge_match_arms.rs#L11[merge_match_arms.rs] | ||
678 | |||
679 | Merges identical match arms. | ||
680 | |||
681 | .Before | ||
682 | ```rust | ||
683 | enum Action { Move { distance: u32 }, Stop } | ||
684 | |||
685 | fn handle(action: Action) { | ||
686 | match action { | ||
687 | ┃Action::Move(..) => foo(), | ||
688 | Action::Stop => foo(), | ||
689 | } | ||
690 | } | ||
691 | ``` | ||
692 | |||
693 | .After | ||
694 | ```rust | ||
695 | enum Action { Move { distance: u32 }, Stop } | ||
696 | |||
697 | fn handle(action: Action) { | ||
698 | match action { | ||
699 | Action::Move(..) | Action::Stop => foo(), | ||
700 | } | ||
701 | } | ||
702 | ``` | ||
703 | |||
704 | |||
705 | [discrete] | ||
706 | === `move_arm_cond_to_match_guard` | ||
707 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/move_guard.rs#L56[move_guard.rs] | ||
708 | |||
709 | Moves if expression from match arm body into a guard. | ||
710 | |||
711 | .Before | ||
712 | ```rust | ||
713 | enum Action { Move { distance: u32 }, Stop } | ||
714 | |||
715 | fn handle(action: Action) { | ||
716 | match action { | ||
717 | Action::Move { distance } => ┃if distance > 10 { foo() }, | ||
718 | _ => (), | ||
719 | } | ||
720 | } | ||
721 | ``` | ||
722 | |||
723 | .After | ||
724 | ```rust | ||
725 | enum Action { Move { distance: u32 }, Stop } | ||
726 | |||
727 | fn handle(action: Action) { | ||
728 | match action { | ||
729 | Action::Move { distance } if distance > 10 => foo(), | ||
730 | _ => (), | ||
731 | } | ||
732 | } | ||
733 | ``` | ||
734 | |||
735 | |||
736 | [discrete] | ||
737 | === `move_bounds_to_where_clause` | ||
738 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/move_bounds.rs#L10[move_bounds.rs] | ||
739 | |||
740 | Moves inline type bounds to a where clause. | ||
741 | |||
742 | .Before | ||
743 | ```rust | ||
744 | fn apply<T, U, ┃F: FnOnce(T) -> U>(f: F, x: T) -> U { | ||
745 | f(x) | ||
746 | } | ||
747 | ``` | ||
748 | |||
749 | .After | ||
750 | ```rust | ||
751 | fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U { | ||
752 | f(x) | ||
753 | } | ||
754 | ``` | ||
755 | |||
756 | |||
757 | [discrete] | ||
758 | === `move_guard_to_arm_body` | ||
759 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/move_guard.rs#L8[move_guard.rs] | ||
760 | |||
761 | Moves match guard into match arm body. | ||
762 | |||
763 | .Before | ||
764 | ```rust | ||
765 | enum Action { Move { distance: u32 }, Stop } | ||
766 | |||
767 | fn handle(action: Action) { | ||
768 | match action { | ||
769 | Action::Move { distance } ┃if distance > 10 => foo(), | ||
770 | _ => (), | ||
771 | } | ||
772 | } | ||
773 | ``` | ||
774 | |||
775 | .After | ||
776 | ```rust | ||
777 | enum Action { Move { distance: u32 }, Stop } | ||
778 | |||
779 | fn handle(action: Action) { | ||
780 | match action { | ||
781 | Action::Move { distance } => if distance > 10 { foo() }, | ||
782 | _ => (), | ||
783 | } | ||
784 | } | ||
785 | ``` | ||
786 | |||
787 | |||
788 | [discrete] | ||
789 | === `remove_dbg` | ||
790 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/remove_dbg.rs#L8[remove_dbg.rs] | ||
791 | |||
792 | Removes `dbg!()` macro call. | ||
793 | |||
794 | .Before | ||
795 | ```rust | ||
796 | fn main() { | ||
797 | ┃dbg!(92); | ||
798 | } | ||
799 | ``` | ||
800 | |||
801 | .After | ||
802 | ```rust | ||
803 | fn main() { | ||
804 | 92; | ||
805 | } | ||
806 | ``` | ||
807 | |||
808 | |||
809 | [discrete] | ||
810 | === `remove_hash` | ||
811 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/raw_string.rs#L89[raw_string.rs] | ||
812 | |||
813 | Removes a hash from a raw string literal. | ||
814 | |||
815 | .Before | ||
816 | ```rust | ||
817 | fn main() { | ||
818 | r#"Hello,┃ World!"#; | ||
819 | } | ||
820 | ``` | ||
821 | |||
822 | .After | ||
823 | ```rust | ||
824 | fn main() { | ||
825 | r"Hello, World!"; | ||
826 | } | ||
827 | ``` | ||
828 | |||
829 | |||
830 | [discrete] | ||
831 | === `remove_mut` | ||
832 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/remove_mut.rs#L5[remove_mut.rs] | ||
833 | |||
834 | Removes the `mut` keyword. | ||
835 | |||
836 | .Before | ||
837 | ```rust | ||
838 | impl Walrus { | ||
839 | fn feed(&mut┃ self, amount: u32) {} | ||
840 | } | ||
841 | ``` | ||
842 | |||
843 | .After | ||
844 | ```rust | ||
845 | impl Walrus { | ||
846 | fn feed(&self, amount: u32) {} | ||
847 | } | ||
848 | ``` | ||
849 | |||
850 | |||
851 | [discrete] | ||
852 | === `reorder_fields` | ||
853 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/reorder_fields.rs#L10[reorder_fields.rs] | ||
854 | |||
855 | Reorder the fields of record literals and record patterns in the same order as in | ||
856 | the definition. | ||
857 | |||
858 | .Before | ||
859 | ```rust | ||
860 | struct Foo {foo: i32, bar: i32}; | ||
861 | const test: Foo = ┃Foo {bar: 0, foo: 1} | ||
862 | ``` | ||
863 | |||
864 | .After | ||
865 | ```rust | ||
866 | struct Foo {foo: i32, bar: i32}; | ||
867 | const test: Foo = Foo {foo: 1, bar: 0} | ||
868 | ``` | ||
869 | |||
870 | |||
871 | [discrete] | ||
872 | === `replace_if_let_with_match` | ||
873 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/replace_if_let_with_match.rs#L13[replace_if_let_with_match.rs] | ||
874 | |||
875 | Replaces `if let` with an else branch with a `match` expression. | ||
876 | |||
877 | .Before | ||
878 | ```rust | ||
879 | enum Action { Move { distance: u32 }, Stop } | ||
880 | |||
881 | fn handle(action: Action) { | ||
882 | ┃if let Action::Move { distance } = action { | ||
883 | foo(distance) | ||
884 | } else { | ||
885 | bar() | ||
886 | } | ||
887 | } | ||
888 | ``` | ||
889 | |||
890 | .After | ||
891 | ```rust | ||
892 | enum Action { Move { distance: u32 }, Stop } | ||
893 | |||
894 | fn handle(action: Action) { | ||
895 | match action { | ||
896 | Action::Move { distance } => foo(distance), | ||
897 | _ => bar(), | ||
898 | } | ||
899 | } | ||
900 | ``` | ||
901 | |||
902 | |||
903 | [discrete] | ||
904 | === `replace_let_with_if_let` | ||
905 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/replace_let_with_if_let.rs#L14[replace_let_with_if_let.rs] | ||
906 | |||
907 | Replaces `let` with an `if-let`. | ||
908 | |||
909 | .Before | ||
910 | ```rust | ||
911 | |||
912 | fn main(action: Action) { | ||
913 | ┃let x = compute(); | ||
914 | } | ||
915 | |||
916 | fn compute() -> Option<i32> { None } | ||
917 | ``` | ||
918 | |||
919 | .After | ||
920 | ```rust | ||
921 | |||
922 | fn main(action: Action) { | ||
923 | if let Some(x) = compute() { | ||
924 | } | ||
925 | } | ||
926 | |||
927 | fn compute() -> Option<i32> { None } | ||
928 | ``` | ||
929 | |||
930 | |||
931 | [discrete] | ||
932 | === `replace_qualified_name_with_use` | ||
933 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs#L6[replace_qualified_name_with_use.rs] | ||
934 | |||
935 | Adds a use statement for a given fully-qualified name. | ||
936 | |||
937 | .Before | ||
938 | ```rust | ||
939 | fn process(map: std::collections::┃HashMap<String, String>) {} | ||
940 | ``` | ||
941 | |||
942 | .After | ||
943 | ```rust | ||
944 | use std::collections::HashMap; | ||
945 | |||
946 | fn process(map: HashMap<String, String>) {} | ||
947 | ``` | ||
948 | |||
949 | |||
950 | [discrete] | ||
951 | === `replace_unwrap_with_match` | ||
952 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs#L17[replace_unwrap_with_match.rs] | ||
953 | |||
954 | Replaces `unwrap` a `match` expression. Works for Result and Option. | ||
955 | |||
956 | .Before | ||
957 | ```rust | ||
958 | enum Result<T, E> { Ok(T), Err(E) } | ||
959 | fn main() { | ||
960 | let x: Result<i32, i32> = Result::Ok(92); | ||
961 | let y = x.┃unwrap(); | ||
962 | } | ||
963 | ``` | ||
964 | |||
965 | .After | ||
966 | ```rust | ||
967 | enum Result<T, E> { Ok(T), Err(E) } | ||
968 | fn main() { | ||
969 | let x: Result<i32, i32> = Result::Ok(92); | ||
970 | let y = match x { | ||
971 | Ok(a) => a, | ||
972 | $0_ => unreachable!(), | ||
973 | }; | ||
974 | } | ||
975 | ``` | ||
976 | |||
977 | |||
978 | [discrete] | ||
979 | === `split_import` | ||
980 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/split_import.rs#L7[split_import.rs] | ||
981 | |||
982 | Wraps the tail of import into braces. | ||
983 | |||
984 | .Before | ||
985 | ```rust | ||
986 | use std::┃collections::HashMap; | ||
987 | ``` | ||
988 | |||
989 | .After | ||
990 | ```rust | ||
991 | use std::{collections::HashMap}; | ||
992 | ``` | ||
993 | |||
994 | |||
995 | [discrete] | ||
996 | === `unwrap_block` | ||
997 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_assists/src/handlers/unwrap_block.rs#L9[unwrap_block.rs] | ||
998 | |||
999 | This assist removes if...else, for, while and loop control statements to just keep the body. | ||
1000 | |||
1001 | .Before | ||
1002 | ```rust | ||
1003 | fn foo() { | ||
1004 | if true {┃ | ||
1005 | println!("foo"); | ||
1006 | } | ||
1007 | } | ||
1008 | ``` | ||
1009 | |||
1010 | .After | ||
1011 | ```rust | ||
1012 | fn foo() { | ||
1013 | println!("foo"); | ||
1014 | } | ||
1015 | ``` | ||
diff --git a/docs/user/generated_features.adoc b/docs/user/generated_features.adoc deleted file mode 100644 index 12812fa0b..000000000 --- a/docs/user/generated_features.adoc +++ /dev/null | |||
@@ -1,298 +0,0 @@ | |||
1 | === Expand Macro Recursively | ||
2 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/expand_macro.rs#L15[expand_macro.rs] | ||
3 | |||
4 | Shows the full macro expansion of the macro at current cursor. | ||
5 | |||
6 | |=== | ||
7 | | Editor | Action Name | ||
8 | |||
9 | | VS Code | **Rust Analyzer: Expand macro recursively** | ||
10 | |=== | ||
11 | |||
12 | |||
13 | === Extend Selection | ||
14 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/extend_selection.rs#L15[extend_selection.rs] | ||
15 | |||
16 | Extends the current selection to the encompassing syntactic construct | ||
17 | (expression, statement, item, module, etc). It works with multiple cursors. | ||
18 | |||
19 | |=== | ||
20 | | Editor | Shortcut | ||
21 | |||
22 | | VS Code | kbd:[Ctrl+Shift+→] | ||
23 | |=== | ||
24 | |||
25 | |||
26 | === File Structure | ||
27 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/display/structure.rs#L17[structure.rs] | ||
28 | |||
29 | Provides a tree of the symbols defined in the file. Can be used to | ||
30 | |||
31 | * fuzzy search symbol in a file (super useful) | ||
32 | * draw breadcrumbs to describe the context around the cursor | ||
33 | * draw outline of the file | ||
34 | |||
35 | |=== | ||
36 | | Editor | Shortcut | ||
37 | |||
38 | | VS Code | kbd:[Ctrl+Shift+O] | ||
39 | |=== | ||
40 | |||
41 | |||
42 | === Go to Definition | ||
43 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/goto_definition.rs#L18[goto_definition.rs] | ||
44 | |||
45 | Navigates to the definition of an identifier. | ||
46 | |||
47 | |=== | ||
48 | | Editor | Shortcut | ||
49 | |||
50 | | VS Code | kbd:[F12] | ||
51 | |=== | ||
52 | |||
53 | |||
54 | === Go to Implementation | ||
55 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/goto_implementation.rs#L7[goto_implementation.rs] | ||
56 | |||
57 | Navigates to the impl block of structs, enums or traits. Also implemented as a code lens. | ||
58 | |||
59 | |=== | ||
60 | | Editor | Shortcut | ||
61 | |||
62 | | VS Code | kbd:[Ctrl+F12] | ||
63 | |=== | ||
64 | |||
65 | |||
66 | === Go to Type Definition | ||
67 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/goto_type_definition.rs#L6[goto_type_definition.rs] | ||
68 | |||
69 | Navigates to the type of an identifier. | ||
70 | |||
71 | |=== | ||
72 | | Editor | Action Name | ||
73 | |||
74 | | VS Code | **Go to Type Definition* | ||
75 | |=== | ||
76 | |||
77 | |||
78 | === Hover | ||
79 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/hover.rs#L63[hover.rs] | ||
80 | |||
81 | Shows additional information, like type of an expression or documentation for definition when "focusing" code. | ||
82 | Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. | ||
83 | |||
84 | |||
85 | === Inlay Hints | ||
86 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/inlay_hints.rs#L40[inlay_hints.rs] | ||
87 | |||
88 | rust-analyzer shows additional information inline with the source code. | ||
89 | Editors usually render this using read-only virtual text snippets interspersed with code. | ||
90 | |||
91 | rust-analyzer shows hits for | ||
92 | |||
93 | * types of local variables | ||
94 | * names of function arguments | ||
95 | * types of chained expressions | ||
96 | |||
97 | **Note:** VS Code does not have native support for inlay hints https://github.com/microsoft/vscode/issues/16221[yet] and the hints are implemented using decorations. | ||
98 | This approach has limitations, the caret movement and bracket highlighting near the edges of the hint may be weird: | ||
99 | https://github.com/rust-analyzer/rust-analyzer/issues/1623[1], https://github.com/rust-analyzer/rust-analyzer/issues/3453[2]. | ||
100 | |||
101 | |=== | ||
102 | | Editor | Action Name | ||
103 | |||
104 | | VS Code | **Rust Analyzer: Toggle inlay hints* | ||
105 | |=== | ||
106 | |||
107 | |||
108 | === Join Lines | ||
109 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/join_lines.rs#L12[join_lines.rs] | ||
110 | |||
111 | Join selected lines into one, smartly fixing up whitespace, trailing commas, and braces. | ||
112 | |||
113 | |=== | ||
114 | | Editor | Action Name | ||
115 | |||
116 | | VS Code | **Rust Analyzer: Join lines** | ||
117 | |=== | ||
118 | |||
119 | |||
120 | === Magic Completions | ||
121 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/completion.rs#L38[completion.rs] | ||
122 | |||
123 | In addition to usual reference completion, rust-analyzer provides some ✨magic✨ | ||
124 | completions as well: | ||
125 | |||
126 | Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor | ||
127 | is placed at the appropriate position. Even though `if` is easy to type, you | ||
128 | still want to complete it, to get ` { }` for free! `return` is inserted with a | ||
129 | space or `;` depending on the return type of the function. | ||
130 | |||
131 | When completing a function call, `()` are automatically inserted. If a function | ||
132 | takes arguments, the cursor is positioned inside the parenthesis. | ||
133 | |||
134 | There are postfix completions, which can be triggered by typing something like | ||
135 | `foo().if`. The word after `.` determines postfix completion. Possible variants are: | ||
136 | |||
137 | - `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result` | ||
138 | - `expr.match` -> `match expr {}` | ||
139 | - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result` | ||
140 | - `expr.ref` -> `&expr` | ||
141 | - `expr.refm` -> `&mut expr` | ||
142 | - `expr.not` -> `!expr` | ||
143 | - `expr.dbg` -> `dbg!(expr)` | ||
144 | |||
145 | There also snippet completions: | ||
146 | |||
147 | .Expressions | ||
148 | - `pd` -> `println!("{:?}")` | ||
149 | - `ppd` -> `println!("{:#?}")` | ||
150 | |||
151 | .Items | ||
152 | - `tfn` -> `#[test] fn f(){}` | ||
153 | - `tmod` -> | ||
154 | ```rust | ||
155 | #[cfg(test)] | ||
156 | mod tests { | ||
157 | use super::*; | ||
158 | |||
159 | #[test] | ||
160 | fn test_fn() {} | ||
161 | } | ||
162 | ``` | ||
163 | |||
164 | |||
165 | === Matching Brace | ||
166 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/matching_brace.rs#L3[matching_brace.rs] | ||
167 | |||
168 | If the cursor is on any brace (`<>(){}[]`) which is a part of a brace-pair, | ||
169 | moves cursor to the matching brace. It uses the actual parser to determine | ||
170 | braces, so it won't confuse generics with comparisons. | ||
171 | |||
172 | |=== | ||
173 | | Editor | Action Name | ||
174 | |||
175 | | VS Code | **Rust Analyzer: Find matching brace** | ||
176 | |=== | ||
177 | |||
178 | |||
179 | === On Typing Assists | ||
180 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/typing.rs#L35[typing.rs] | ||
181 | |||
182 | Some features trigger on typing certain characters: | ||
183 | |||
184 | - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression | ||
185 | - Enter inside comments automatically inserts `///` | ||
186 | - typing `.` in a chain method call auto-indents | ||
187 | |||
188 | |||
189 | === Parent Module | ||
190 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/parent_module.rs#L12[parent_module.rs] | ||
191 | |||
192 | Navigates to the parent module of the current module. | ||
193 | |||
194 | |=== | ||
195 | | Editor | Action Name | ||
196 | |||
197 | | VS Code | **Rust Analyzer: Locate parent module** | ||
198 | |=== | ||
199 | |||
200 | |||
201 | === Run | ||
202 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/runnables.rs#L45[runnables.rs] | ||
203 | |||
204 | Shows a popup suggesting to run a test/benchmark/binary **at the current cursor | ||
205 | location**. Super useful for repeatedly running just a single test. Do bind this | ||
206 | to a shortcut! | ||
207 | |||
208 | |=== | ||
209 | | Editor | Action Name | ||
210 | |||
211 | | VS Code | **Rust Analyzer: Run** | ||
212 | |=== | ||
213 | |||
214 | |||
215 | === Semantic Syntax Highlighting | ||
216 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/syntax_highlighting.rs#L33[syntax_highlighting.rs] | ||
217 | |||
218 | rust-analyzer highlights the code semantically. | ||
219 | For example, `bar` in `foo::Bar` might be colored differently depending on whether `Bar` is an enum or a trait. | ||
220 | rust-analyzer does not specify colors directly, instead it assigns tag (like `struct`) and a set of modifiers (like `declaration`) to each token. | ||
221 | It's up to the client to map those to specific colors. | ||
222 | |||
223 | The general rule is that a reference to an entity gets colored the same way as the entity itself. | ||
224 | We also give special modifier for `mut` and `&mut` local variables. | ||
225 | |||
226 | |||
227 | === Show Syntax Tree | ||
228 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/syntax_tree.rs#L9[syntax_tree.rs] | ||
229 | |||
230 | Shows the parse tree of the current file. It exists mostly for debugging | ||
231 | rust-analyzer itself. | ||
232 | |||
233 | |=== | ||
234 | | Editor | Action Name | ||
235 | |||
236 | | VS Code | **Rust Analyzer: Show Syntax Tree** | ||
237 | |=== | ||
238 | |||
239 | |||
240 | === Status | ||
241 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/status.rs#L27[status.rs] | ||
242 | |||
243 | Shows internal statistic about memory usage of rust-analyzer. | ||
244 | |||
245 | |=== | ||
246 | | Editor | Action Name | ||
247 | |||
248 | | VS Code | **Rust Analyzer: Status** | ||
249 | |=== | ||
250 | |||
251 | |||
252 | === Structural Seach and Replace | ||
253 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide/src/ssr.rs#L26[ssr.rs] | ||
254 | |||
255 | Search and replace with named wildcards that will match any expression. | ||
256 | The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`. | ||
257 | A `$<name>:expr` placeholder in the search pattern will match any expression and `$<name>` will reference it in the replacement. | ||
258 | Available via the command `rust-analyzer.ssr`. | ||
259 | |||
260 | ```rust | ||
261 | // Using structural search replace command [foo($a:expr, $b:expr) ==>> ($a).foo($b)] | ||
262 | |||
263 | // BEFORE | ||
264 | String::from(foo(y + 5, z)) | ||
265 | |||
266 | // AFTER | ||
267 | String::from((y + 5).foo(z)) | ||
268 | ``` | ||
269 | |||
270 | |=== | ||
271 | | Editor | Action Name | ||
272 | |||
273 | | VS Code | **Rust Analyzer: Structural Search Replace** | ||
274 | |=== | ||
275 | |||
276 | |||
277 | === Workspace Symbol | ||
278 | **Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/crates/ra_ide_db/src/symbol_index.rs#L113[symbol_index.rs] | ||
279 | |||
280 | Uses fuzzy-search to find types, modules and functions by name across your | ||
281 | project and dependencies. This is **the** most useful feature, which improves code | ||
282 | navigation tremendously. It mostly works on top of the built-in LSP | ||
283 | functionality, however `#` and `*` symbols can be used to narrow down the | ||
284 | search. Specifically, | ||
285 | |||
286 | - `Foo` searches for `Foo` type in the current workspace | ||
287 | - `foo#` searches for `foo` function in the current workspace | ||
288 | - `Foo*` searches for `Foo` type among dependencies, including `stdlib` | ||
289 | - `foo#*` searches for `foo` function among dependencies | ||
290 | |||
291 | That is, `#` switches from "types" to all symbols, `*` switches from the current | ||
292 | workspace to dependencies. | ||
293 | |||
294 | |=== | ||
295 | | Editor | Shortcut | ||
296 | |||
297 | | VS Code | kbd:[Ctrl+T] | ||
298 | |=== | ||
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc index 202783fd9..7fab7237b 100644 --- a/docs/user/manual.adoc +++ b/docs/user/manual.adoc | |||
@@ -13,8 +13,12 @@ This manual focuses on a specific usage of the library -- running it as part of | |||
13 | https://microsoft.github.io/language-server-protocol/[Language Server Protocol] (LSP). | 13 | https://microsoft.github.io/language-server-protocol/[Language Server Protocol] (LSP). |
14 | The LSP allows various code editors, like VS Code, Emacs or Vim, to implement semantic features like completion or goto definition by talking to an external language server process. | 14 | The LSP allows various code editors, like VS Code, Emacs or Vim, to implement semantic features like completion or goto definition by talking to an external language server process. |
15 | 15 | ||
16 | To improve this document, send a pull request against | 16 | [TIP] |
17 | https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/manual.adoc[this file]. | 17 | ==== |
18 | [.lead] | ||
19 | To improve this document, send a pull request: + | ||
20 | https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/manual.adoc[https://github.com/rust-analyzer/.../manual.adoc] | ||
21 | ==== | ||
18 | 22 | ||
19 | If you have questions about using rust-analyzer, please ask them in the https://users.rust-lang.org/c/ide/14["`IDEs and Editors`"] topic of Rust users forum. | 23 | If you have questions about using rust-analyzer, please ask them in the https://users.rust-lang.org/c/ide/14["`IDEs and Editors`"] topic of Rust users forum. |
20 | 24 | ||
@@ -57,7 +61,7 @@ To disable this notification put the following to `settings.json` | |||
57 | The server binary is stored in: | 61 | The server binary is stored in: |
58 | 62 | ||
59 | * Linux: `~/.config/Code/User/globalStorage/matklad.rust-analyzer` | 63 | * Linux: `~/.config/Code/User/globalStorage/matklad.rust-analyzer` |
60 | * macOS: `~/Library/Application Support/Code/User/globalStorage/matklad.rust-analyzer` | 64 | * macOS: `~/Library/Application\ Support/Code/User/globalStorage/matklad.rust-analyzer` |
61 | * Windows: `%APPDATA%\Code\User\globalStorage\matklad.rust-analyzer` | 65 | * Windows: `%APPDATA%\Code\User\globalStorage\matklad.rust-analyzer` |
62 | 66 | ||
63 | Note that we only support two most recent versions of VS Code. | 67 | Note that we only support two most recent versions of VS Code. |
@@ -109,18 +113,6 @@ Here are some useful self-diagnostic commands: | |||
109 | * To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Server Trace` in the panel. | 113 | * To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Server Trace` in the panel. |
110 | * To enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open the `Console` tab of VS Code developer tools. | 114 | * To enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open the `Console` tab of VS Code developer tools. |
111 | 115 | ||
112 | ==== Special `when` clause context for keybindings. | ||
113 | You may use `inRustProject` context to configure keybindings for rust projects only. For example: | ||
114 | [source,json] | ||
115 | ---- | ||
116 | { | ||
117 | "key": "ctrl+i", | ||
118 | "command": "rust-analyzer.toggleInlayHints", | ||
119 | "when": "inRustProject" | ||
120 | } | ||
121 | ---- | ||
122 | More about `when` clause contexts https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts[here]. | ||
123 | |||
124 | === rust-analyzer Language Server Binary | 116 | === rust-analyzer Language Server Binary |
125 | 117 | ||
126 | Other editors generally require the `rust-analyzer` binary to be in `$PATH`. | 118 | Other editors generally require the `rust-analyzer` binary to be in `$PATH`. |
@@ -269,6 +261,63 @@ Gnome Builder currently has support for RLS, and there's no way to configure the | |||
269 | 1. Rename, symlink or copy the `rust-analyzer` binary to `rls` and place it somewhere Builder can find (in `PATH`, or under `~/.cargo/bin`). | 261 | 1. Rename, symlink or copy the `rust-analyzer` binary to `rls` and place it somewhere Builder can find (in `PATH`, or under `~/.cargo/bin`). |
270 | 2. Enable the Rust Builder plugin. | 262 | 2. Enable the Rust Builder plugin. |
271 | 263 | ||
264 | ==== GNOME Builder (Nightly) | ||
265 | |||
266 | https://nightly.gnome.org/repo/appstream/org.gnome.Builder.flatpakref[GNOME Builder (Nightly)] has now native support for `rust-analyzer` out of the box. If the `rust-analyzer` binary is not available, GNOME Builder can install it when opening a Rust source file. | ||
267 | |||
268 | == Non-Cargo Based Projects | ||
269 | |||
270 | rust-analyzer does not require Cargo. | ||
271 | However, if you use some other build system, you'll have to describe the structure of your project for rust-analyzer in the `rust-project.json` format: | ||
272 | |||
273 | [source,TypeScript] | ||
274 | ---- | ||
275 | interface JsonProject { | ||
276 | /// The set of paths containing the crates for this project. | ||
277 | /// Any `Crate` must be nested inside some `root`. | ||
278 | roots: string[]; | ||
279 | /// The set of crates comprising the current project. | ||
280 | /// Must include all transitive dependencies as well as sysroot crate (libstd, libcore and such). | ||
281 | crates: Crate[]; | ||
282 | } | ||
283 | |||
284 | interface Crate { | ||
285 | /// Path to the root module of the crate. | ||
286 | root_module: string; | ||
287 | /// Edition of the crate. | ||
288 | edition: "2015" | "2018"; | ||
289 | /// Dependencies | ||
290 | deps: Dep[]; | ||
291 | /// The set of cfgs activated for a given crate, like `["unix", "feature=foo", "feature=bar"]`. | ||
292 | cfg: string[]; | ||
293 | |||
294 | /// value of the OUT_DIR env variable. | ||
295 | out_dir?: string; | ||
296 | /// For proc-macro crates, path to compiles proc-macro (.so file). | ||
297 | proc_macro_dylib_path?: string; | ||
298 | } | ||
299 | |||
300 | interface Dep { | ||
301 | /// Index of a crate in the `crates` array. | ||
302 | crate: number, | ||
303 | /// Name as should appear in the (implicit) `extern crate name` declaration. | ||
304 | name: string, | ||
305 | } | ||
306 | ---- | ||
307 | |||
308 | This format is provisional and subject to change. | ||
309 | Specifically, the `roots` setup will be different eventually. | ||
310 | |||
311 | There are tree ways to feed `rust-project.json` to rust-analyzer: | ||
312 | |||
313 | * Place `rust-project.json` file at the root of the project, and rust-anlayzer will discover it. | ||
314 | * Specify `"rust-analyzer.linkedProjects": [ "path/to/rust-project.json" ]` in the settings (and make sure that your LSP client sends settings as a part of initialize request). | ||
315 | * Specify `"rust-analyzer.linkedProjects": [ { "roots": [...], "crates": [...] }]` inline. | ||
316 | |||
317 | Relative paths are interpreted relative to `rust-project.json` file location or (for inline JSON) relative to `rootUri`. | ||
318 | |||
319 | See https://github.com/rust-analyzer/rust-project.json-example for a small example. | ||
320 | |||
272 | == Features | 321 | == Features |
273 | 322 | ||
274 | include::./generated_features.adoc[] | 323 | include::./generated_features.adoc[] |
@@ -280,3 +329,47 @@ They are usually triggered by a shortcut or by clicking a light bulb icon in the | |||
280 | Cursor position or selection is signified by `┃` character. | 329 | Cursor position or selection is signified by `┃` character. |
281 | 330 | ||
282 | include::./generated_assists.adoc[] | 331 | include::./generated_assists.adoc[] |
332 | |||
333 | == Editor Features | ||
334 | === VS Code | ||
335 | ==== Special `when` clause context for keybindings. | ||
336 | You may use `inRustProject` context to configure keybindings for rust projects only. For example: | ||
337 | [source,json] | ||
338 | ---- | ||
339 | { | ||
340 | "key": "ctrl+i", | ||
341 | "command": "rust-analyzer.toggleInlayHints", | ||
342 | "when": "inRustProject" | ||
343 | } | ||
344 | ---- | ||
345 | More about `when` clause contexts https://code.visualstudio.com/docs/getstarted/keybindings#_when-clause-contexts[here]. | ||
346 | |||
347 | ==== Setting runnable environment variables | ||
348 | You can use "rust-analyzer.runnableEnv" setting to define runnable environment-specific substitution variables. | ||
349 | The simplest way for all runnables in a bunch: | ||
350 | ```jsonc | ||
351 | "rust-analyzer.runnableEnv": { | ||
352 | "RUN_SLOW_TESTS": "1" | ||
353 | } | ||
354 | ``` | ||
355 | |||
356 | Or it is possible to specify vars more granularly: | ||
357 | ```jsonc | ||
358 | "rust-analyzer.runnableEnv": [ | ||
359 | { | ||
360 | // "mask": null, // null mask means that this rule will be applied for all runnables | ||
361 | env: { | ||
362 | "APP_ID": "1", | ||
363 | "APP_DATA": "asdf" | ||
364 | } | ||
365 | }, | ||
366 | { | ||
367 | "mask": "test_name", | ||
368 | "env": { | ||
369 | "APP_ID": "2", // overwrites only APP_ID | ||
370 | } | ||
371 | } | ||
372 | ] | ||
373 | ``` | ||
374 | |||
375 | You can use any valid RegExp as a mask. Also note that a full runnable name is something like *run bin_or_example_name*, *test some::mod::test_name* or *test-mod some::mod*, so it is possible to distinguish binaries, single tests, and test modules with this masks: `"^run"`, `"^test "` (the trailing space matters!), and `"^test-mod"` respectively. | ||