diff options
author | Mikhail Rakhmanov <[email protected]> | 2020-06-03 19:10:54 +0100 |
---|---|---|
committer | Mikhail Rakhmanov <[email protected]> | 2020-06-03 19:10:54 +0100 |
commit | eefa10bc6bff3624ddd0bbb6bc89d8beb4bed186 (patch) | |
tree | 15c38c2993c52f4065d338090ca9185cc1fcd3da /docs | |
parent | a9d567584857b1be4ca8eaa5ef2c7d85f7b2845e (diff) | |
parent | 794f6da821c5d6e2490b996baffe162e4753262d (diff) |
Merge branch 'master' into assists_extract_enum
Diffstat (limited to 'docs')
-rw-r--r-- | docs/dev/README.md | 105 | ||||
-rw-r--r-- | docs/dev/lsp-extensions.md | 341 | ||||
-rw-r--r-- | docs/dev/lsp-features.md | 72 | ||||
-rw-r--r-- | docs/user/assists.md | 769 | ||||
-rw-r--r-- | docs/user/features.md | 212 | ||||
-rw-r--r-- | docs/user/manual.adoc (renamed from docs/user/readme.adoc) | 96 |
6 files changed, 494 insertions, 1101 deletions
diff --git a/docs/dev/README.md b/docs/dev/README.md index 65cc9fc12..1de5a2aab 100644 --- a/docs/dev/README.md +++ b/docs/dev/README.md | |||
@@ -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), |
@@ -117,6 +117,109 @@ 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 reviewer to flag only some nits in the PR, and than 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 rename 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 thing too keep an eye on is 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 `[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 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 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 | ## Order of Imports | ||
170 | |||
171 | We separate import groups with blank lines | ||
172 | |||
173 | ``` | ||
174 | mod x; | ||
175 | mod y; | ||
176 | |||
177 | use std::{ ... } | ||
178 | |||
179 | use crate_foo::{ ... } | ||
180 | use crate_bar::{ ... } | ||
181 | |||
182 | use crate::{} | ||
183 | |||
184 | use super::{} // but prefer `use crate::` | ||
185 | ``` | ||
186 | |||
187 | ## Order of Items | ||
188 | |||
189 | Optimize for the reader who sees the file for the first time, and wants to get the general idea about what's going on. | ||
190 | People read things from top to bottom, so place most important things first. | ||
191 | |||
192 | Specifically, if all items except one are private, always put the non-private item on top. | ||
193 | |||
194 | Put `struct`s and `enum`s first, functions and impls last. | ||
195 | |||
196 | Do | ||
197 | |||
198 | ``` | ||
199 | // Good | ||
200 | struct Foo { | ||
201 | bars: Vec<Bar> | ||
202 | } | ||
203 | |||
204 | struct Bar; | ||
205 | ``` | ||
206 | |||
207 | rather than | ||
208 | |||
209 | ``` | ||
210 | // Not as good | ||
211 | struct Bar; | ||
212 | |||
213 | struct Foo { | ||
214 | bars: Vec<Bar> | ||
215 | } | ||
216 | ``` | ||
217 | |||
218 | ## Documentation | ||
219 | |||
220 | For `.md` and `.adoc` files, prefer a sentence-per-line format, don't wrap lines. | ||
221 | If the line is too long, you want to split the sentence in two :-) | ||
222 | |||
120 | # Logging | 223 | # Logging |
121 | 224 | ||
122 | Logging is done by both rust-analyzer and VS Code, so it might be tricky to | 225 | Logging is done by both rust-analyzer and VS Code, so it might be tricky to |
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md index 158d3c599..647cf6107 100644 --- a/docs/dev/lsp-extensions.md +++ b/docs/dev/lsp-extensions.md | |||
@@ -3,7 +3,19 @@ | |||
3 | This document describes LSP extensions used by rust-analyzer. | 3 | This document describes LSP extensions used by rust-analyzer. |
4 | It's a best effort document, when in doubt, consult the source (and send a PR with clarification ;-) ). | 4 | It's a best effort document, when in doubt, consult the source (and send a PR with clarification ;-) ). |
5 | We aim to upstream all non Rust-specific extensions to the protocol, but this is not a top priority. | 5 | We aim to upstream all non Rust-specific extensions to the protocol, but this is not a top priority. |
6 | All capabilities are enabled via `experimental` field of `ClientCapabilities`. | 6 | All capabilities are enabled via `experimental` field of `ClientCapabilities` or `ServerCapabilities`. |
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. | ||
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. | ||
7 | 19 | ||
8 | ## Snippet `TextEdit` | 20 | ## Snippet `TextEdit` |
9 | 21 | ||
@@ -38,6 +50,87 @@ At the moment, rust-analyzer guarantees that only a single edit will have `Inser | |||
38 | * Where exactly are `SnippetTextEdit`s allowed (only in code actions at the moment)? | 50 | * Where exactly are `SnippetTextEdit`s allowed (only in code actions at the moment)? |
39 | * Can snippets span multiple files (so far, no)? | 51 | * Can snippets span multiple files (so far, no)? |
40 | 52 | ||
53 | ## `CodeAction` Groups | ||
54 | |||
55 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/994 | ||
56 | |||
57 | **Client Capability:** `{ "codeActionGroup": boolean }` | ||
58 | |||
59 | If this capability is set, `CodeAction` returned from the server contain an additional field, `group`: | ||
60 | |||
61 | ```typescript | ||
62 | interface CodeAction { | ||
63 | title: string; | ||
64 | group?: string; | ||
65 | ... | ||
66 | } | ||
67 | ``` | ||
68 | |||
69 | All code-actions with the same `group` should be grouped under single (extendable) entry in lightbulb menu. | ||
70 | The set of actions `[ { title: "foo" }, { group: "frobnicate", title: "bar" }, { group: "frobnicate", title: "baz" }]` should be rendered as | ||
71 | |||
72 | ``` | ||
73 | 💡 | ||
74 | +-------------+ | ||
75 | | foo | | ||
76 | +-------------+-----+ | ||
77 | | frobnicate >| bar | | ||
78 | +-------------+-----+ | ||
79 | | baz | | ||
80 | +-----+ | ||
81 | ``` | ||
82 | |||
83 | Alternatively, selecting `frobnicate` could present a user with an additional menu to choose between `bar` and `baz`. | ||
84 | |||
85 | ### Example | ||
86 | |||
87 | ```rust | ||
88 | fn main() { | ||
89 | let x: Entry/*cursor here*/ = todo!(); | ||
90 | } | ||
91 | ``` | ||
92 | |||
93 | Invoking code action at this position will yield two code actions for importing `Entry` from either `collections::HashMap` or `collection::BTreeMap`, grouped under a single "import" group. | ||
94 | |||
95 | ### Unresolved Questions | ||
96 | |||
97 | * Is a fixed two-level structure enough? | ||
98 | * Should we devise a general way to encode custom interaction protocols for GUI refactorings? | ||
99 | |||
100 | ## Parent Module | ||
101 | |||
102 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/1002 | ||
103 | |||
104 | **Server Capability:** `{ "parentModule": boolean }` | ||
105 | |||
106 | This request is send from client to server to handle "Goto Parent Module" editor action. | ||
107 | |||
108 | **Method:** `experimental/parentModule` | ||
109 | |||
110 | **Request:** `TextDocumentPositionParams` | ||
111 | |||
112 | **Response:** `Location | Location[] | LocationLink[] | null` | ||
113 | |||
114 | |||
115 | ### Example | ||
116 | |||
117 | ```rust | ||
118 | // src/main.rs | ||
119 | mod foo; | ||
120 | // src/foo.rs | ||
121 | |||
122 | /* cursor here*/ | ||
123 | ``` | ||
124 | |||
125 | `experimental/parentModule` returns a single `Link` to the `mod foo;` declaration. | ||
126 | |||
127 | ### Unresolved Question | ||
128 | |||
129 | * An alternative would be to use a more general "gotoSuper" request, which would work for super methods, super classes and super modules. | ||
130 | This is the approach IntelliJ Rust is takeing. | ||
131 | However, experience shows that super module (which generally has a feeling of navigation between files) should be separate. | ||
132 | If you want super module, but the cursor happens to be inside an overriden function, the behavior with single "gotoSuper" request is surprising. | ||
133 | |||
41 | ## Join Lines | 134 | ## Join Lines |
42 | 135 | ||
43 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/992 | 136 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/992 |
@@ -46,7 +139,7 @@ At the moment, rust-analyzer guarantees that only a single edit will have `Inser | |||
46 | 139 | ||
47 | This request is send from client to server to handle "Join Lines" editor action. | 140 | This request is send from client to server to handle "Join Lines" editor action. |
48 | 141 | ||
49 | **Method:** `experimental/JoinLines` | 142 | **Method:** `experimental/joinLines` |
50 | 143 | ||
51 | **Request:** | 144 | **Request:** |
52 | 145 | ||
@@ -59,11 +152,7 @@ interface JoinLinesParams { | |||
59 | } | 152 | } |
60 | ``` | 153 | ``` |
61 | 154 | ||
62 | **Response:** | 155 | **Response:** `TextEdit[]` |
63 | |||
64 | ```typescript | ||
65 | TextEdit[] | ||
66 | ``` | ||
67 | 156 | ||
68 | ### Example | 157 | ### Example |
69 | 158 | ||
@@ -75,7 +164,7 @@ fn main() { | |||
75 | } | 164 | } |
76 | ``` | 165 | ``` |
77 | 166 | ||
78 | `experimental/joinLines` yields (curly braces are automagiacally removed) | 167 | `experimental/joinLines` yields (curly braces are automagically removed) |
79 | 168 | ||
80 | ```rust | 169 | ```rust |
81 | fn main() { | 170 | fn main() { |
@@ -89,6 +178,59 @@ fn main() { | |||
89 | Currently this is left to editor's discretion, but it might be useful to specify on the server via snippets. | 178 | Currently this is left to editor's discretion, but it might be useful to specify on the server via snippets. |
90 | However, it then becomes unclear how it works with multi cursor. | 179 | However, it then becomes unclear how it works with multi cursor. |
91 | 180 | ||
181 | ## On Enter | ||
182 | |||
183 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/1001 | ||
184 | |||
185 | **Server Capability:** `{ "onEnter": boolean }` | ||
186 | |||
187 | This request is send from client to server to handle <kbd>Enter</kbd> keypress. | ||
188 | |||
189 | **Method:** `experimental/onEnter` | ||
190 | |||
191 | **Request:**: `TextDocumentPositionParams` | ||
192 | |||
193 | **Response:** | ||
194 | |||
195 | ```typescript | ||
196 | SnippetTextEdit[] | ||
197 | ``` | ||
198 | |||
199 | ### Example | ||
200 | |||
201 | ```rust | ||
202 | fn main() { | ||
203 | // Some /*cursor here*/ docs | ||
204 | let x = 92; | ||
205 | } | ||
206 | ``` | ||
207 | |||
208 | `experimental/onEnter` returns the following snippet | ||
209 | |||
210 | ```rust | ||
211 | fn main() { | ||
212 | // Some | ||
213 | // $0 docs | ||
214 | let x = 92; | ||
215 | } | ||
216 | ``` | ||
217 | |||
218 | The primary goal of `onEnter` is to handle automatic indentation when opening a new line. | ||
219 | This is not yet implemented. | ||
220 | The secondary goal is to handle fixing up syntax, like continuing doc strings and comments, and escaping `\n` in string literals. | ||
221 | |||
222 | As proper cursor positioning is raison-d'etat for `onEnter`, it uses `SnippetTextEdit`. | ||
223 | |||
224 | ### Unresolved Question | ||
225 | |||
226 | * How to deal with synchronicity of the request? | ||
227 | One option is to require the client to block until the server returns the response. | ||
228 | Another option is to do a OT-style merging of edits from client and server. | ||
229 | A third option is to do a record-replay: client applies heuristic on enter immediatelly, then applies all user's keypresses. | ||
230 | When the server is ready with the response, the client rollbacks all the changes and applies the recorded actions on top of the correct response. | ||
231 | * How to deal with multiple carets? | ||
232 | * Should we extend this to arbitrary typed events and not just `onEnter`? | ||
233 | |||
92 | ## Structural Search Replace (SSR) | 234 | ## Structural Search Replace (SSR) |
93 | 235 | ||
94 | **Server Capability:** `{ "ssr": boolean }` | 236 | **Server Capability:** `{ "ssr": boolean }` |
@@ -124,49 +266,180 @@ SSR with query `foo($a:expr, $b:expr) ==>> ($a).foo($b)` will transform, eg `foo | |||
124 | * Probably needs search without replace mode | 266 | * Probably needs search without replace mode |
125 | * Needs a way to limit the scope to certain files. | 267 | * Needs a way to limit the scope to certain files. |
126 | 268 | ||
127 | ## `CodeAction` Groups | 269 | ## Matching Brace |
128 | 270 | ||
129 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/994 | 271 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/999 |
130 | 272 | ||
131 | **Client Capability:** `{ "codeActionGroup": boolean }` | 273 | **Server Capability:** `{ "matchingBrace": boolean }` |
132 | 274 | ||
133 | If this capability is set, `CodeAction` returned from the server contain an additional field, `group`: | 275 | This request is send from client to server to handle "Matching Brace" editor action. |
276 | |||
277 | **Method:** `experimental/matchingBrace` | ||
278 | |||
279 | **Request:** | ||
134 | 280 | ||
135 | ```typescript | 281 | ```typescript |
136 | interface CodeAction { | 282 | interface MatchingBraceParams { |
137 | title: string; | 283 | textDocument: TextDocumentIdentifier, |
138 | group?: string; | 284 | /// Position for each cursor |
139 | ... | 285 | positions: Position[], |
140 | } | 286 | } |
141 | ``` | 287 | ``` |
142 | 288 | ||
143 | All code-actions with the same `group` should be grouped under single (extendable) entry in lightbulb menu. | 289 | **Response:** |
144 | The set of actions `[ { title: "foo" }, { group: "frobnicate", title: "bar" }, { group: "frobnicate", title: "baz" }]` should be rendered as | ||
145 | 290 | ||
146 | ``` | 291 | ```typescript |
147 | 💡 | 292 | Position[] |
148 | +-------------+ | ||
149 | | foo | | ||
150 | +-------------+-----+ | ||
151 | | frobnicate >| bar | | ||
152 | +-------------+-----+ | ||
153 | | baz | | ||
154 | +-----+ | ||
155 | ``` | 293 | ``` |
156 | 294 | ||
157 | Alternatively, selecting `frobnicate` could present a user with an additional menu to choose between `bar` and `baz`. | ||
158 | |||
159 | ### Example | 295 | ### Example |
160 | 296 | ||
161 | ```rust | 297 | ```rust |
162 | fn main() { | 298 | fn main() { |
163 | let x: Entry/*cursor here*/ = todo!(); | 299 | let x: Vec<()>/*cursor here*/ = vec![] |
164 | } | 300 | } |
165 | ``` | 301 | ``` |
166 | 302 | ||
167 | Invoking code action at this position will yield two code actions for importing `Entry` from either `collections::HashMap` or `collection::BTreeMap`, grouped under a single "import" group. | 303 | `experimental/matchingBrace` yields the position of `<`. |
304 | In many cases, matching braces can be handled by the editor. | ||
305 | However, some cases (like disambiguating between generics and comparison operations) need a real parser. | ||
306 | Moreover, it would be cool if editors didn't need to implement even basic language parsing | ||
168 | 307 | ||
169 | ### Unresolved Questions | 308 | ### Unresolved Question |
170 | 309 | ||
171 | * Is a fixed two-level structure enough? | 310 | * Should we return a a nested brace structure, to allow paredit-like actions of jump *out* of the current brace pair? |
172 | * Should we devise a general way to encode custom interaction protocols for GUI refactorings? | 311 | This is how `SelectionRange` request works. |
312 | * Alternatively, should we perhaps flag certain `SelectionRange`s as being brace pairs? | ||
313 | |||
314 | ## Runnables | ||
315 | |||
316 | **Issue:** https://github.com/microsoft/language-server-protocol/issues/944 | ||
317 | |||
318 | **Server Capability:** `{ "runnables": { "kinds": string[] } }` | ||
319 | |||
320 | This request is send from client to server to get the list of things that can be run (tests, binaries, `cargo check -p`). | ||
321 | |||
322 | **Method:** `experimental/runnables` | ||
323 | |||
324 | **Request:** | ||
325 | |||
326 | ```typescript | ||
327 | interface RunnablesParams { | ||
328 | textDocument: TextDocumentIdentifier; | ||
329 | /// If null, compute runnables for the whole file. | ||
330 | position?: Position; | ||
331 | } | ||
332 | ``` | ||
333 | |||
334 | **Response:** `Runnable[]` | ||
335 | |||
336 | ```typescript | ||
337 | interface Runnable { | ||
338 | label: string; | ||
339 | /// If this Runnable is associated with a specific function/module, etc, the location of this item | ||
340 | location?: LocationLink; | ||
341 | /// Running things is necessary technology specific, `kind` needs to be advertised via server capabilities, | ||
342 | // the type of `args` is specific to `kind`. The actual running is handled by the client. | ||
343 | kind: string; | ||
344 | args: any; | ||
345 | } | ||
346 | ``` | ||
347 | |||
348 | rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look like this: | ||
349 | |||
350 | ```typescript | ||
351 | { | ||
352 | workspaceRoot?: string; | ||
353 | cargoArgs: string[]; | ||
354 | executableArgs: string[]; | ||
355 | } | ||
356 | ``` | ||
357 | |||
358 | ## Analyzer Status | ||
359 | |||
360 | **Method:** `rust-analyzer/analyzerStatus` | ||
361 | |||
362 | **Request:** `null` | ||
363 | |||
364 | **Response:** `string` | ||
365 | |||
366 | Returns internal status message, mostly for debugging purposes. | ||
367 | |||
368 | ## Collect Garbage | ||
369 | |||
370 | **Method:** `rust-analyzer/collectGarbage` | ||
371 | |||
372 | **Request:** `null` | ||
373 | |||
374 | **Response:** `null` | ||
375 | |||
376 | Frees some caches. For internal use, and is mostly broken at the moment. | ||
377 | |||
378 | ## Syntax Tree | ||
379 | |||
380 | **Method:** `rust-analyzer/syntaxTree` | ||
381 | |||
382 | **Request:** | ||
383 | |||
384 | ```typescript | ||
385 | interface SyntaxTeeParams { | ||
386 | textDocument: TextDocumentIdentifier, | ||
387 | range?: Range, | ||
388 | } | ||
389 | ``` | ||
390 | |||
391 | **Response:** `string` | ||
392 | |||
393 | Returns textual representation of a parse tree for the file/selected region. | ||
394 | Primarily for debugging, but very useful for all people working on rust-analyzer itself. | ||
395 | |||
396 | ## Expand Macro | ||
397 | |||
398 | **Method:** `rust-analyzer/expandMacro` | ||
399 | |||
400 | **Request:** | ||
401 | |||
402 | ```typescript | ||
403 | interface ExpandMacroParams { | ||
404 | textDocument: TextDocumentIdentifier, | ||
405 | position: Position, | ||
406 | } | ||
407 | ``` | ||
408 | |||
409 | **Response:** | ||
410 | |||
411 | ```typescript | ||
412 | interface ExpandedMacro { | ||
413 | name: string, | ||
414 | expansion: string, | ||
415 | } | ||
416 | ``` | ||
417 | |||
418 | Expands macro call at a given position. | ||
419 | |||
420 | ## Inlay Hints | ||
421 | |||
422 | **Method:** `rust-analyzer/inlayHints` | ||
423 | |||
424 | This request is send from client to server to render "inlay hints" -- virtual text inserted into editor to show things like inferred types. | ||
425 | Generally, the client should re-query inlay hints after every modification. | ||
426 | Note that we plan to move this request to `experimental/inlayHints`, as it is not really Rust-specific, but the current API is not necessary the right one. | ||
427 | Upstream issue: https://github.com/microsoft/language-server-protocol/issues/956 | ||
428 | |||
429 | **Request:** | ||
430 | |||
431 | ```typescript | ||
432 | interface InlayHintsParams { | ||
433 | textDocument: TextDocumentIdentifier, | ||
434 | } | ||
435 | ``` | ||
436 | |||
437 | **Response:** `InlayHint[]` | ||
438 | |||
439 | ```typescript | ||
440 | interface InlayHint { | ||
441 | kind: "TypeHint" | "ParameterHint" | "ChainingHint", | ||
442 | range: Range, | ||
443 | label: string, | ||
444 | } | ||
445 | ``` | ||
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/assists.md b/docs/user/assists.md deleted file mode 100644 index 4ad7ea59d..000000000 --- a/docs/user/assists.md +++ /dev/null | |||
@@ -1,769 +0,0 @@ | |||
1 | # Assists | ||
2 | |||
3 | Cursor position or selection is signified by `┃` character. | ||
4 | |||
5 | |||
6 | ## `add_custom_impl` | ||
7 | |||
8 | Adds impl block for derived trait. | ||
9 | |||
10 | ```rust | ||
11 | // BEFORE | ||
12 | #[derive(Deb┃ug, Display)] | ||
13 | struct S; | ||
14 | |||
15 | // AFTER | ||
16 | #[derive(Display)] | ||
17 | struct S; | ||
18 | |||
19 | impl Debug for S { | ||
20 | $0 | ||
21 | } | ||
22 | ``` | ||
23 | |||
24 | ## `add_derive` | ||
25 | |||
26 | Adds a new `#[derive()]` clause to a struct or enum. | ||
27 | |||
28 | ```rust | ||
29 | // BEFORE | ||
30 | struct Point { | ||
31 | x: u32, | ||
32 | y: u32,┃ | ||
33 | } | ||
34 | |||
35 | // AFTER | ||
36 | #[derive($0)] | ||
37 | struct Point { | ||
38 | x: u32, | ||
39 | y: u32, | ||
40 | } | ||
41 | ``` | ||
42 | |||
43 | ## `add_explicit_type` | ||
44 | |||
45 | Specify type for a let binding. | ||
46 | |||
47 | ```rust | ||
48 | // BEFORE | ||
49 | fn main() { | ||
50 | let x┃ = 92; | ||
51 | } | ||
52 | |||
53 | // AFTER | ||
54 | fn main() { | ||
55 | let x: i32 = 92; | ||
56 | } | ||
57 | ``` | ||
58 | |||
59 | ## `add_function` | ||
60 | |||
61 | Adds a stub function with a signature matching the function under the cursor. | ||
62 | |||
63 | ```rust | ||
64 | // BEFORE | ||
65 | struct Baz; | ||
66 | fn baz() -> Baz { Baz } | ||
67 | fn foo() { | ||
68 | bar┃("", baz()); | ||
69 | } | ||
70 | |||
71 | |||
72 | // AFTER | ||
73 | struct Baz; | ||
74 | fn baz() -> Baz { Baz } | ||
75 | fn foo() { | ||
76 | bar("", baz()); | ||
77 | } | ||
78 | |||
79 | fn bar(arg: &str, baz: Baz) { | ||
80 | ${0:todo!()} | ||
81 | } | ||
82 | |||
83 | ``` | ||
84 | |||
85 | ## `add_hash` | ||
86 | |||
87 | Adds a hash to a raw string literal. | ||
88 | |||
89 | ```rust | ||
90 | // BEFORE | ||
91 | fn main() { | ||
92 | r#"Hello,┃ World!"#; | ||
93 | } | ||
94 | |||
95 | // AFTER | ||
96 | fn main() { | ||
97 | r##"Hello, World!"##; | ||
98 | } | ||
99 | ``` | ||
100 | |||
101 | ## `add_impl` | ||
102 | |||
103 | Adds a new inherent impl for a type. | ||
104 | |||
105 | ```rust | ||
106 | // BEFORE | ||
107 | struct Ctx<T: Clone> { | ||
108 | data: T,┃ | ||
109 | } | ||
110 | |||
111 | // AFTER | ||
112 | struct Ctx<T: Clone> { | ||
113 | data: T, | ||
114 | } | ||
115 | |||
116 | impl<T: Clone> Ctx<T> { | ||
117 | $0 | ||
118 | } | ||
119 | ``` | ||
120 | |||
121 | ## `add_impl_default_members` | ||
122 | |||
123 | Adds scaffold for overriding default impl members. | ||
124 | |||
125 | ```rust | ||
126 | // BEFORE | ||
127 | trait Trait { | ||
128 | Type X; | ||
129 | fn foo(&self); | ||
130 | fn bar(&self) {} | ||
131 | } | ||
132 | |||
133 | impl Trait for () { | ||
134 | Type X = (); | ||
135 | fn foo(&self) {}┃ | ||
136 | |||
137 | } | ||
138 | |||
139 | // AFTER | ||
140 | trait Trait { | ||
141 | Type X; | ||
142 | fn foo(&self); | ||
143 | fn bar(&self) {} | ||
144 | } | ||
145 | |||
146 | impl Trait for () { | ||
147 | Type X = (); | ||
148 | fn foo(&self) {} | ||
149 | $0fn bar(&self) {} | ||
150 | |||
151 | } | ||
152 | ``` | ||
153 | |||
154 | ## `add_impl_missing_members` | ||
155 | |||
156 | Adds scaffold for required impl members. | ||
157 | |||
158 | ```rust | ||
159 | // BEFORE | ||
160 | trait Trait<T> { | ||
161 | Type X; | ||
162 | fn foo(&self) -> T; | ||
163 | fn bar(&self) {} | ||
164 | } | ||
165 | |||
166 | impl Trait<u32> for () {┃ | ||
167 | |||
168 | } | ||
169 | |||
170 | // AFTER | ||
171 | trait Trait<T> { | ||
172 | Type X; | ||
173 | fn foo(&self) -> T; | ||
174 | fn bar(&self) {} | ||
175 | } | ||
176 | |||
177 | impl Trait<u32> for () { | ||
178 | fn foo(&self) -> u32 { | ||
179 | ${0:todo!()} | ||
180 | } | ||
181 | |||
182 | } | ||
183 | ``` | ||
184 | |||
185 | ## `add_new` | ||
186 | |||
187 | Adds a new inherent impl for a type. | ||
188 | |||
189 | ```rust | ||
190 | // BEFORE | ||
191 | struct Ctx<T: Clone> { | ||
192 | data: T,┃ | ||
193 | } | ||
194 | |||
195 | // AFTER | ||
196 | struct Ctx<T: Clone> { | ||
197 | data: T, | ||
198 | } | ||
199 | |||
200 | impl<T: Clone> Ctx<T> { | ||
201 | fn $0new(data: T) -> Self { Self { data } } | ||
202 | } | ||
203 | |||
204 | ``` | ||
205 | |||
206 | ## `add_turbo_fish` | ||
207 | |||
208 | Adds `::<_>` to a call of a generic method or function. | ||
209 | |||
210 | ```rust | ||
211 | // BEFORE | ||
212 | fn make<T>() -> T { todo!() } | ||
213 | fn main() { | ||
214 | let x = make┃(); | ||
215 | } | ||
216 | |||
217 | // AFTER | ||
218 | fn make<T>() -> T { todo!() } | ||
219 | fn main() { | ||
220 | let x = make::<${0:_}>(); | ||
221 | } | ||
222 | ``` | ||
223 | |||
224 | ## `apply_demorgan` | ||
225 | |||
226 | Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). | ||
227 | This transforms expressions of the form `!l || !r` into `!(l && r)`. | ||
228 | This also works with `&&`. This assist can only be applied with the cursor | ||
229 | on either `||` or `&&`, with both operands being a negation of some kind. | ||
230 | This means something of the form `!x` or `x != y`. | ||
231 | |||
232 | ```rust | ||
233 | // BEFORE | ||
234 | fn main() { | ||
235 | if x != 4 ||┃ !y {} | ||
236 | } | ||
237 | |||
238 | // AFTER | ||
239 | fn main() { | ||
240 | if !(x == 4 && y) {} | ||
241 | } | ||
242 | ``` | ||
243 | |||
244 | ## `auto_import` | ||
245 | |||
246 | If the name is unresolved, provides all possible imports for it. | ||
247 | |||
248 | ```rust | ||
249 | // BEFORE | ||
250 | fn main() { | ||
251 | let map = HashMap┃::new(); | ||
252 | } | ||
253 | |||
254 | // AFTER | ||
255 | use std::collections::HashMap; | ||
256 | |||
257 | fn main() { | ||
258 | let map = HashMap::new(); | ||
259 | } | ||
260 | ``` | ||
261 | |||
262 | ## `change_return_type_to_result` | ||
263 | |||
264 | Change the function's return type to Result. | ||
265 | |||
266 | ```rust | ||
267 | // BEFORE | ||
268 | fn foo() -> i32┃ { 42i32 } | ||
269 | |||
270 | // AFTER | ||
271 | fn foo() -> Result<i32, ${0:_}> { Ok(42i32) } | ||
272 | ``` | ||
273 | |||
274 | ## `change_visibility` | ||
275 | |||
276 | Adds or changes existing visibility specifier. | ||
277 | |||
278 | ```rust | ||
279 | // BEFORE | ||
280 | ┃fn frobnicate() {} | ||
281 | |||
282 | // AFTER | ||
283 | pub(crate) fn frobnicate() {} | ||
284 | ``` | ||
285 | |||
286 | ## `convert_to_guarded_return` | ||
287 | |||
288 | Replace a large conditional with a guarded return. | ||
289 | |||
290 | ```rust | ||
291 | // BEFORE | ||
292 | fn main() { | ||
293 | ┃if cond { | ||
294 | foo(); | ||
295 | bar(); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | // AFTER | ||
300 | fn main() { | ||
301 | if !cond { | ||
302 | return; | ||
303 | } | ||
304 | foo(); | ||
305 | bar(); | ||
306 | } | ||
307 | ``` | ||
308 | |||
309 | ## `fill_match_arms` | ||
310 | |||
311 | Adds missing clauses to a `match` expression. | ||
312 | |||
313 | ```rust | ||
314 | // BEFORE | ||
315 | enum Action { Move { distance: u32 }, Stop } | ||
316 | |||
317 | fn handle(action: Action) { | ||
318 | match action { | ||
319 | ┃ | ||
320 | } | ||
321 | } | ||
322 | |||
323 | // AFTER | ||
324 | enum Action { Move { distance: u32 }, Stop } | ||
325 | |||
326 | fn handle(action: Action) { | ||
327 | match action { | ||
328 | $0Action::Move { distance } => {} | ||
329 | Action::Stop => {} | ||
330 | } | ||
331 | } | ||
332 | ``` | ||
333 | |||
334 | ## `fix_visibility` | ||
335 | |||
336 | Makes inaccessible item public. | ||
337 | |||
338 | ```rust | ||
339 | // BEFORE | ||
340 | mod m { | ||
341 | fn frobnicate() {} | ||
342 | } | ||
343 | fn main() { | ||
344 | m::frobnicate┃() {} | ||
345 | } | ||
346 | |||
347 | // AFTER | ||
348 | mod m { | ||
349 | $0pub(crate) fn frobnicate() {} | ||
350 | } | ||
351 | fn main() { | ||
352 | m::frobnicate() {} | ||
353 | } | ||
354 | ``` | ||
355 | |||
356 | ## `flip_binexpr` | ||
357 | |||
358 | Flips operands of a binary expression. | ||
359 | |||
360 | ```rust | ||
361 | // BEFORE | ||
362 | fn main() { | ||
363 | let _ = 90 +┃ 2; | ||
364 | } | ||
365 | |||
366 | // AFTER | ||
367 | fn main() { | ||
368 | let _ = 2 + 90; | ||
369 | } | ||
370 | ``` | ||
371 | |||
372 | ## `flip_comma` | ||
373 | |||
374 | Flips two comma-separated items. | ||
375 | |||
376 | ```rust | ||
377 | // BEFORE | ||
378 | fn main() { | ||
379 | ((1, 2),┃ (3, 4)); | ||
380 | } | ||
381 | |||
382 | // AFTER | ||
383 | fn main() { | ||
384 | ((3, 4), (1, 2)); | ||
385 | } | ||
386 | ``` | ||
387 | |||
388 | ## `flip_trait_bound` | ||
389 | |||
390 | Flips two trait bounds. | ||
391 | |||
392 | ```rust | ||
393 | // BEFORE | ||
394 | fn foo<T: Clone +┃ Copy>() { } | ||
395 | |||
396 | // AFTER | ||
397 | fn foo<T: Copy + Clone>() { } | ||
398 | ``` | ||
399 | |||
400 | ## `inline_local_variable` | ||
401 | |||
402 | Inlines local variable. | ||
403 | |||
404 | ```rust | ||
405 | // BEFORE | ||
406 | fn main() { | ||
407 | let x┃ = 1 + 2; | ||
408 | x * 4; | ||
409 | } | ||
410 | |||
411 | // AFTER | ||
412 | fn main() { | ||
413 | (1 + 2) * 4; | ||
414 | } | ||
415 | ``` | ||
416 | |||
417 | ## `introduce_variable` | ||
418 | |||
419 | Extracts subexpression into a variable. | ||
420 | |||
421 | ```rust | ||
422 | // BEFORE | ||
423 | fn main() { | ||
424 | ┃(1 + 2)┃ * 4; | ||
425 | } | ||
426 | |||
427 | // AFTER | ||
428 | fn main() { | ||
429 | let $0var_name = (1 + 2); | ||
430 | var_name * 4; | ||
431 | } | ||
432 | ``` | ||
433 | |||
434 | ## `invert_if` | ||
435 | |||
436 | Apply invert_if | ||
437 | This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}` | ||
438 | This also works with `!=`. This assist can only be applied with the cursor | ||
439 | on `if`. | ||
440 | |||
441 | ```rust | ||
442 | // BEFORE | ||
443 | fn main() { | ||
444 | if┃ !y { A } else { B } | ||
445 | } | ||
446 | |||
447 | // AFTER | ||
448 | fn main() { | ||
449 | if y { B } else { A } | ||
450 | } | ||
451 | ``` | ||
452 | |||
453 | ## `make_raw_string` | ||
454 | |||
455 | Adds `r#` to a plain string literal. | ||
456 | |||
457 | ```rust | ||
458 | // BEFORE | ||
459 | fn main() { | ||
460 | "Hello,┃ World!"; | ||
461 | } | ||
462 | |||
463 | // AFTER | ||
464 | fn main() { | ||
465 | r#"Hello, World!"#; | ||
466 | } | ||
467 | ``` | ||
468 | |||
469 | ## `make_usual_string` | ||
470 | |||
471 | Turns a raw string into a plain string. | ||
472 | |||
473 | ```rust | ||
474 | // BEFORE | ||
475 | fn main() { | ||
476 | r#"Hello,┃ "World!""#; | ||
477 | } | ||
478 | |||
479 | // AFTER | ||
480 | fn main() { | ||
481 | "Hello, \"World!\""; | ||
482 | } | ||
483 | ``` | ||
484 | |||
485 | ## `merge_imports` | ||
486 | |||
487 | Merges two imports with a common prefix. | ||
488 | |||
489 | ```rust | ||
490 | // BEFORE | ||
491 | use std::┃fmt::Formatter; | ||
492 | use std::io; | ||
493 | |||
494 | // AFTER | ||
495 | use std::{fmt::Formatter, io}; | ||
496 | ``` | ||
497 | |||
498 | ## `merge_match_arms` | ||
499 | |||
500 | Merges identical match arms. | ||
501 | |||
502 | ```rust | ||
503 | // BEFORE | ||
504 | enum Action { Move { distance: u32 }, Stop } | ||
505 | |||
506 | fn handle(action: Action) { | ||
507 | match action { | ||
508 | ┃Action::Move(..) => foo(), | ||
509 | Action::Stop => foo(), | ||
510 | } | ||
511 | } | ||
512 | |||
513 | // AFTER | ||
514 | enum Action { Move { distance: u32 }, Stop } | ||
515 | |||
516 | fn handle(action: Action) { | ||
517 | match action { | ||
518 | Action::Move(..) | Action::Stop => foo(), | ||
519 | } | ||
520 | } | ||
521 | ``` | ||
522 | |||
523 | ## `move_arm_cond_to_match_guard` | ||
524 | |||
525 | Moves if expression from match arm body into a guard. | ||
526 | |||
527 | ```rust | ||
528 | // BEFORE | ||
529 | enum Action { Move { distance: u32 }, Stop } | ||
530 | |||
531 | fn handle(action: Action) { | ||
532 | match action { | ||
533 | Action::Move { distance } => ┃if distance > 10 { foo() }, | ||
534 | _ => (), | ||
535 | } | ||
536 | } | ||
537 | |||
538 | // AFTER | ||
539 | enum Action { Move { distance: u32 }, Stop } | ||
540 | |||
541 | fn handle(action: Action) { | ||
542 | match action { | ||
543 | Action::Move { distance } if distance > 10 => foo(), | ||
544 | _ => (), | ||
545 | } | ||
546 | } | ||
547 | ``` | ||
548 | |||
549 | ## `move_bounds_to_where_clause` | ||
550 | |||
551 | Moves inline type bounds to a where clause. | ||
552 | |||
553 | ```rust | ||
554 | // BEFORE | ||
555 | fn apply<T, U, ┃F: FnOnce(T) -> U>(f: F, x: T) -> U { | ||
556 | f(x) | ||
557 | } | ||
558 | |||
559 | // AFTER | ||
560 | fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U { | ||
561 | f(x) | ||
562 | } | ||
563 | ``` | ||
564 | |||
565 | ## `move_guard_to_arm_body` | ||
566 | |||
567 | Moves match guard into match arm body. | ||
568 | |||
569 | ```rust | ||
570 | // BEFORE | ||
571 | enum Action { Move { distance: u32 }, Stop } | ||
572 | |||
573 | fn handle(action: Action) { | ||
574 | match action { | ||
575 | Action::Move { distance } ┃if distance > 10 => foo(), | ||
576 | _ => (), | ||
577 | } | ||
578 | } | ||
579 | |||
580 | // AFTER | ||
581 | enum Action { Move { distance: u32 }, Stop } | ||
582 | |||
583 | fn handle(action: Action) { | ||
584 | match action { | ||
585 | Action::Move { distance } => if distance > 10 { foo() }, | ||
586 | _ => (), | ||
587 | } | ||
588 | } | ||
589 | ``` | ||
590 | |||
591 | ## `remove_dbg` | ||
592 | |||
593 | Removes `dbg!()` macro call. | ||
594 | |||
595 | ```rust | ||
596 | // BEFORE | ||
597 | fn main() { | ||
598 | ┃dbg!(92); | ||
599 | } | ||
600 | |||
601 | // AFTER | ||
602 | fn main() { | ||
603 | 92; | ||
604 | } | ||
605 | ``` | ||
606 | |||
607 | ## `remove_hash` | ||
608 | |||
609 | Removes a hash from a raw string literal. | ||
610 | |||
611 | ```rust | ||
612 | // BEFORE | ||
613 | fn main() { | ||
614 | r#"Hello,┃ World!"#; | ||
615 | } | ||
616 | |||
617 | // AFTER | ||
618 | fn main() { | ||
619 | r"Hello, World!"; | ||
620 | } | ||
621 | ``` | ||
622 | |||
623 | ## `remove_mut` | ||
624 | |||
625 | Removes the `mut` keyword. | ||
626 | |||
627 | ```rust | ||
628 | // BEFORE | ||
629 | impl Walrus { | ||
630 | fn feed(&mut┃ self, amount: u32) {} | ||
631 | } | ||
632 | |||
633 | // AFTER | ||
634 | impl Walrus { | ||
635 | fn feed(&self, amount: u32) {} | ||
636 | } | ||
637 | ``` | ||
638 | |||
639 | ## `reorder_fields` | ||
640 | |||
641 | Reorder the fields of record literals and record patterns in the same order as in | ||
642 | the definition. | ||
643 | |||
644 | ```rust | ||
645 | // BEFORE | ||
646 | struct Foo {foo: i32, bar: i32}; | ||
647 | const test: Foo = ┃Foo {bar: 0, foo: 1} | ||
648 | |||
649 | // AFTER | ||
650 | struct Foo {foo: i32, bar: i32}; | ||
651 | const test: Foo = Foo {foo: 1, bar: 0} | ||
652 | ``` | ||
653 | |||
654 | ## `replace_if_let_with_match` | ||
655 | |||
656 | Replaces `if let` with an else branch with a `match` expression. | ||
657 | |||
658 | ```rust | ||
659 | // BEFORE | ||
660 | enum Action { Move { distance: u32 }, Stop } | ||
661 | |||
662 | fn handle(action: Action) { | ||
663 | ┃if let Action::Move { distance } = action { | ||
664 | foo(distance) | ||
665 | } else { | ||
666 | bar() | ||
667 | } | ||
668 | } | ||
669 | |||
670 | // AFTER | ||
671 | enum Action { Move { distance: u32 }, Stop } | ||
672 | |||
673 | fn handle(action: Action) { | ||
674 | match action { | ||
675 | Action::Move { distance } => foo(distance), | ||
676 | _ => bar(), | ||
677 | } | ||
678 | } | ||
679 | ``` | ||
680 | |||
681 | ## `replace_let_with_if_let` | ||
682 | |||
683 | Replaces `let` with an `if-let`. | ||
684 | |||
685 | ```rust | ||
686 | // BEFORE | ||
687 | |||
688 | fn main(action: Action) { | ||
689 | ┃let x = compute(); | ||
690 | } | ||
691 | |||
692 | fn compute() -> Option<i32> { None } | ||
693 | |||
694 | // AFTER | ||
695 | |||
696 | fn main(action: Action) { | ||
697 | if let Some(x) = compute() { | ||
698 | } | ||
699 | } | ||
700 | |||
701 | fn compute() -> Option<i32> { None } | ||
702 | ``` | ||
703 | |||
704 | ## `replace_qualified_name_with_use` | ||
705 | |||
706 | Adds a use statement for a given fully-qualified name. | ||
707 | |||
708 | ```rust | ||
709 | // BEFORE | ||
710 | fn process(map: std::collections::┃HashMap<String, String>) {} | ||
711 | |||
712 | // AFTER | ||
713 | use std::collections::HashMap; | ||
714 | |||
715 | fn process(map: HashMap<String, String>) {} | ||
716 | ``` | ||
717 | |||
718 | ## `replace_unwrap_with_match` | ||
719 | |||
720 | Replaces `unwrap` a `match` expression. Works for Result and Option. | ||
721 | |||
722 | ```rust | ||
723 | // BEFORE | ||
724 | enum Result<T, E> { Ok(T), Err(E) } | ||
725 | fn main() { | ||
726 | let x: Result<i32, i32> = Result::Ok(92); | ||
727 | let y = x.┃unwrap(); | ||
728 | } | ||
729 | |||
730 | // AFTER | ||
731 | enum Result<T, E> { Ok(T), Err(E) } | ||
732 | fn main() { | ||
733 | let x: Result<i32, i32> = Result::Ok(92); | ||
734 | let y = match x { | ||
735 | Ok(a) => a, | ||
736 | $0_ => unreachable!(), | ||
737 | }; | ||
738 | } | ||
739 | ``` | ||
740 | |||
741 | ## `split_import` | ||
742 | |||
743 | Wraps the tail of import into braces. | ||
744 | |||
745 | ```rust | ||
746 | // BEFORE | ||
747 | use std::┃collections::HashMap; | ||
748 | |||
749 | // AFTER | ||
750 | use std::{collections::HashMap}; | ||
751 | ``` | ||
752 | |||
753 | ## `unwrap_block` | ||
754 | |||
755 | This assist removes if...else, for, while and loop control statements to just keep the body. | ||
756 | |||
757 | ```rust | ||
758 | // BEFORE | ||
759 | fn foo() { | ||
760 | if true {┃ | ||
761 | println!("foo"); | ||
762 | } | ||
763 | } | ||
764 | |||
765 | // AFTER | ||
766 | fn foo() { | ||
767 | println!("foo"); | ||
768 | } | ||
769 | ``` | ||
diff --git a/docs/user/features.md b/docs/user/features.md deleted file mode 100644 index 340bce835..000000000 --- a/docs/user/features.md +++ /dev/null | |||
@@ -1,212 +0,0 @@ | |||
1 | This document is an index of features that the rust-analyzer language server | ||
2 | provides. Shortcuts are for the default VS Code layout. If there's no shortcut, | ||
3 | you can use <kbd>Ctrl+Shift+P</kbd> to search for the corresponding action. | ||
4 | |||
5 | ### Workspace Symbol <kbd>ctrl+t</kbd> | ||
6 | |||
7 | Uses fuzzy-search to find types, modules and functions by name across your | ||
8 | project and dependencies. This is **the** most useful feature, which improves code | ||
9 | navigation tremendously. It mostly works on top of the built-in LSP | ||
10 | functionality, however `#` and `*` symbols can be used to narrow down the | ||
11 | search. Specifically, | ||
12 | |||
13 | - `Foo` searches for `Foo` type in the current workspace | ||
14 | - `foo#` searches for `foo` function in the current workspace | ||
15 | - `Foo*` searches for `Foo` type among dependencies, including `stdlib` | ||
16 | - `foo#*` searches for `foo` function among dependencies | ||
17 | |||
18 | That is, `#` switches from "types" to all symbols, `*` switches from the current | ||
19 | workspace to dependencies. | ||
20 | |||
21 | ### Document Symbol <kbd>ctrl+shift+o</kbd> | ||
22 | |||
23 | Provides a tree of the symbols defined in the file. Can be used to | ||
24 | |||
25 | * fuzzy search symbol in a file (super useful) | ||
26 | * draw breadcrumbs to describe the context around the cursor | ||
27 | * draw outline of the file | ||
28 | |||
29 | ### On Typing Assists | ||
30 | |||
31 | Some features trigger on typing certain characters: | ||
32 | |||
33 | - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression | ||
34 | - Enter inside comments automatically inserts `///` | ||
35 | - typing `.` in a chain method call auto-indents | ||
36 | |||
37 | ### Extend Selection | ||
38 | |||
39 | Extends the current selection to the encompassing syntactic construct | ||
40 | (expression, statement, item, module, etc). It works with multiple cursors. This | ||
41 | is a relatively new feature of LSP: | ||
42 | https://github.com/Microsoft/language-server-protocol/issues/613, check your | ||
43 | editor's LSP library to see if this feature is supported. | ||
44 | |||
45 | ### Go to Definition | ||
46 | |||
47 | Navigates to the definition of an identifier. | ||
48 | |||
49 | ### Go to Implementation | ||
50 | |||
51 | Navigates to the impl block of structs, enums or traits. Also implemented as a code lens. | ||
52 | |||
53 | ### Go to Type Defintion | ||
54 | |||
55 | Navigates to the type of an identifier. | ||
56 | |||
57 | ### Commands <kbd>ctrl+shift+p</kbd> | ||
58 | |||
59 | #### Run | ||
60 | |||
61 | Shows a popup suggesting to run a test/benchmark/binary **at the current cursor | ||
62 | location**. Super useful for repeatedly running just a single test. Do bind this | ||
63 | to a shortcut! | ||
64 | |||
65 | #### Parent Module | ||
66 | |||
67 | Navigates to the parent module of the current module. | ||
68 | |||
69 | #### Matching Brace | ||
70 | |||
71 | If the cursor is on any brace (`<>(){}[]`) which is a part of a brace-pair, | ||
72 | moves cursor to the matching brace. It uses the actual parser to determine | ||
73 | braces, so it won't confuse generics with comparisons. | ||
74 | |||
75 | #### Join Lines | ||
76 | |||
77 | Join selected lines into one, smartly fixing up whitespace and trailing commas. | ||
78 | |||
79 | #### Show Syntax Tree | ||
80 | |||
81 | Shows the parse tree of the current file. It exists mostly for debugging | ||
82 | rust-analyzer itself. | ||
83 | |||
84 | #### Expand Macro Recursively | ||
85 | |||
86 | Shows the full macro expansion of the macro at current cursor. | ||
87 | |||
88 | #### Status | ||
89 | |||
90 | Shows internal statistic about memory usage of rust-analyzer. | ||
91 | |||
92 | #### Show RA Version | ||
93 | |||
94 | Show current rust-analyzer version. | ||
95 | |||
96 | #### Run Garbage Collection | ||
97 | |||
98 | Manually triggers GC. | ||
99 | |||
100 | #### Start Cargo Watch | ||
101 | |||
102 | Start `cargo watch` for live error highlighting. Will prompt to install if it's not already installed. | ||
103 | |||
104 | #### Stop Cargo Watch | ||
105 | |||
106 | Stop `cargo watch`. | ||
107 | |||
108 | #### Structural Seach and Replace | ||
109 | |||
110 | Search and replace with named wildcards that will match any expression. | ||
111 | The syntax for a structural search replace command is `<search_pattern> ==>> <replace_pattern>`. A `$<name>:expr` placeholder in the search pattern will match any expression and `$<name>` will reference it in the replacement. Available via the command `rust-analyzer.ssr`. | ||
112 | |||
113 | ```rust | ||
114 | // Using structural search replace command [foo($a:expr, $b:expr) ==>> ($a).foo($b)] | ||
115 | |||
116 | // BEFORE | ||
117 | String::from(foo(y + 5, z)) | ||
118 | |||
119 | // AFTER | ||
120 | String::from((y + 5).foo(z)) | ||
121 | ``` | ||
122 | |||
123 | ### Assists (Code Actions) | ||
124 | |||
125 | Assists, or code actions, are small local refactorings, available in a particular context. | ||
126 | They are usually triggered by a shortcut or by clicking a light bulb icon in the editor. | ||
127 | |||
128 | See [assists.md](./assists.md) for the list of available assists. | ||
129 | |||
130 | ### Magic Completions | ||
131 | |||
132 | In addition to usual reference completion, rust-analyzer provides some ✨magic✨ | ||
133 | completions as well: | ||
134 | |||
135 | Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor | ||
136 | is placed at the appropriate position. Even though `if` is easy to type, you | ||
137 | still want to complete it, to get ` { }` for free! `return` is inserted with a | ||
138 | space or `;` depending on the return type of the function. | ||
139 | |||
140 | When completing a function call, `()` are automatically inserted. If a function | ||
141 | takes arguments, the cursor is positioned inside the parenthesis. | ||
142 | |||
143 | There are postfix completions, which can be triggered by typing something like | ||
144 | `foo().if`. The word after `.` determines postfix completion. Possible variants are: | ||
145 | |||
146 | - `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result` | ||
147 | - `expr.match` -> `match expr {}` | ||
148 | - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result` | ||
149 | - `expr.ref` -> `&expr` | ||
150 | - `expr.refm` -> `&mut expr` | ||
151 | - `expr.not` -> `!expr` | ||
152 | - `expr.dbg` -> `dbg!(expr)` | ||
153 | |||
154 | There also snippet completions: | ||
155 | |||
156 | #### Inside Expressions | ||
157 | |||
158 | - `pd` -> `println!("{:?}")` | ||
159 | - `ppd` -> `println!("{:#?}")` | ||
160 | |||
161 | #### Inside Modules | ||
162 | |||
163 | - `tfn` -> `#[test] fn f(){}` | ||
164 | - `tmod` -> | ||
165 | ```rust | ||
166 | #[cfg(test)] | ||
167 | mod tests { | ||
168 | use super::*; | ||
169 | |||
170 | #[test] | ||
171 | fn test_fn() {} | ||
172 | } | ||
173 | ``` | ||
174 | |||
175 | ### Code Highlighting | ||
176 | |||
177 | Experimental feature to let rust-analyzer highlight Rust code instead of using the | ||
178 | default highlighter. | ||
179 | |||
180 | #### Rainbow Highlighting | ||
181 | |||
182 | Experimental feature that, given code highlighting using rust-analyzer is | ||
183 | active, will pick unique colors for identifiers. | ||
184 | |||
185 | ### Code hints | ||
186 | |||
187 | Rust-analyzer has two types of hints to show the information about the code: | ||
188 | |||
189 | * hover hints, appearing on hover on any element. | ||
190 | |||
191 | These contain extended information on the hovered language item. | ||
192 | |||
193 | * inlay hints, shown near the element hinted directly in the editor. | ||
194 | |||
195 | Two types of inlay hints are displayed currently: | ||
196 | |||
197 | * type hints, displaying the minimal information on the type of the expression (if the information is available) | ||
198 | * method chaining hints, type information for multi-line method chains | ||
199 | * parameter name hints, displaying the names of the parameters in the corresponding methods | ||
200 | |||
201 | #### VS Code | ||
202 | |||
203 | In VS Code, the following settings can be used to configure the inlay hints: | ||
204 | |||
205 | * `rust-analyzer.inlayHints.typeHints` - enable hints for inferred types. | ||
206 | * `rust-analyzer.inlayHints.chainingHints` - enable hints for inferred types on method chains. | ||
207 | * `rust-analyzer.inlayHints.parameterHints` - enable hints for function parameters. | ||
208 | * `rust-analyzer.inlayHints.maxLength` — shortens the hints if their length exceeds the value specified. If no value is specified (`null`), no shortening is applied. | ||
209 | |||
210 | **Note:** VS Code does not have native support for inlay hints [yet](https://github.com/microsoft/vscode/issues/16221) and the hints are implemented using decorations. | ||
211 | This approach has limitations, the caret movement and bracket highlighting near the edges of the hint may be weird: | ||
212 | [1](https://github.com/rust-analyzer/rust-analyzer/issues/1623), [2](https://github.com/rust-analyzer/rust-analyzer/issues/3453). | ||
diff --git a/docs/user/readme.adoc b/docs/user/manual.adoc index 40ed54809..ea714f49a 100644 --- a/docs/user/readme.adoc +++ b/docs/user/manual.adoc | |||
@@ -2,14 +2,9 @@ | |||
2 | :toc: preamble | 2 | :toc: preamble |
3 | :sectanchors: | 3 | :sectanchors: |
4 | :page-layout: post | 4 | :page-layout: post |
5 | // https://gist.github.com/dcode/0cfbf2699a1fe9b46ff04c41721dda74#admonitions | 5 | :icons: font |
6 | :tip-caption: :bulb: | 6 | :source-highlighter: rouge |
7 | :note-caption: :information_source: | 7 | :experimental: |
8 | :important-caption: :heavy_exclamation_mark: | ||
9 | :caution-caption: :fire: | ||
10 | :warning-caption: :warning: | ||
11 | |||
12 | |||
13 | 8 | ||
14 | // Master copy of this document lives in the https://github.com/rust-analyzer/rust-analyzer repository | 9 | // Master copy of this document lives in the https://github.com/rust-analyzer/rust-analyzer repository |
15 | 10 | ||
@@ -19,7 +14,9 @@ https://microsoft.github.io/language-server-protocol/[Language Server Protocol] | |||
19 | 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. |
20 | 15 | ||
21 | To improve this document, send a pull request against | 16 | To improve this document, send a pull request against |
22 | https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/readme.adoc[this file]. | 17 | https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/manual.adoc[this file]. |
18 | |||
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 | 20 | ||
24 | == Installation | 21 | == Installation |
25 | 22 | ||
@@ -112,10 +109,23 @@ Here are some useful self-diagnostic commands: | |||
112 | * To log all LSP requests, add `"rust-analyzer.trace.server": "verbose"` to the settings and look for `Server Trace` in the panel. | 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 enable client-side logging, add `"rust-analyzer.trace.extension": true` to the settings and open the `Console` tab of VS Code developer tools. | 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 | 111 | ||
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 | |||
115 | === rust-analyzer Language Server Binary | 124 | === rust-analyzer Language Server Binary |
116 | 125 | ||
117 | Other editors generally require the `rust-analyzer` binary to be in `$PATH`. | 126 | Other editors generally require the `rust-analyzer` binary to be in `$PATH`. |
118 | You can download the pre-built binary from the https://github.com/rust-analyzer/rust-analyzer/releases[releases] page. Typically, you then need to rename the binary for your platform, e.g. `rust-analyzer-mac` if you're on Mac OS, to `rust-analyzer` and make it executable in addition to moving it into a directory in your `$PATH`. | 127 | You can download the pre-built binary from the https://github.com/rust-analyzer/rust-analyzer/releases[releases] page. |
128 | Typically, you then need to rename the binary for your platform, e.g. `rust-analyzer-mac` if you're on Mac OS, to `rust-analyzer` and make it executable in addition to moving it into a directory in your `$PATH`. | ||
119 | 129 | ||
120 | On Linux to install the `rust-analyzer` binary into `~/.local/bin`, this commands could be used | 130 | On Linux to install the `rust-analyzer` binary into `~/.local/bin`, this commands could be used |
121 | 131 | ||
@@ -135,7 +145,8 @@ $ git clone https://github.com/rust-analyzer/rust-analyzer.git && cd rust-analyz | |||
135 | $ cargo xtask install --server | 145 | $ cargo xtask install --server |
136 | ---- | 146 | ---- |
137 | 147 | ||
138 | If your editor can't find the binary even though the binary is on your `$PATH`, the likely explanation is that it doesn't see the same `$PATH` as the shell, see https://github.com/rust-analyzer/rust-analyzer/issues/1811[this issue]. On Unix, running the editor from a shell or changing the `.desktop` file to set the environment should help. | 148 | If your editor can't find the binary even though the binary is on your `$PATH`, the likely explanation is that it doesn't see the same `$PATH` as the shell, see https://github.com/rust-analyzer/rust-analyzer/issues/1811[this issue]. |
149 | On Unix, running the editor from a shell or changing the `.desktop` file to set the environment should help. | ||
139 | 150 | ||
140 | ==== Arch Linux | 151 | ==== Arch Linux |
141 | 152 | ||
@@ -258,6 +269,65 @@ Gnome Builder currently has support for RLS, and there's no way to configure the | |||
258 | 1. Rename, symlink or copy the `rust-analyzer` binary to `rls` and place it somewhere Builder can find (in `PATH`, or under `~/.cargo/bin`). | 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`). |
259 | 2. Enable the Rust Builder plugin. | 270 | 2. Enable the Rust Builder plugin. |
260 | 271 | ||
261 | == Usage | 272 | == Non-Cargo Based Projects |
273 | |||
274 | rust-analyzer does not require Cargo. | ||
275 | 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: | ||
276 | |||
277 | [source,TypeScript] | ||
278 | ---- | ||
279 | interface JsonProject { | ||
280 | /// The set of paths containing the crates for this project. | ||
281 | /// Any `Crate` must be nested inside some `root`. | ||
282 | roots: string[]; | ||
283 | /// The set of crates comprising the current project. | ||
284 | /// Must include all transitive dependencies as well as sysroot crate (libstd, libcore and such). | ||
285 | crates: Crate[]; | ||
286 | } | ||
287 | |||
288 | interface Crate { | ||
289 | /// Path to the root module of the crate. | ||
290 | root_module: string; | ||
291 | /// Edition of the crate. | ||
292 | edition: "2015" | "2018"; | ||
293 | /// Dependencies | ||
294 | deps: Dep[]; | ||
295 | /// The set of cfgs activated for a given crate, like `["unix", "feature=foo", "feature=bar"]`. | ||
296 | cfg: string[]; | ||
297 | |||
298 | /// value of the OUT_DIR env variable. | ||
299 | out_dir?: string; | ||
300 | /// For proc-macro crates, path to compiles proc-macro (.so file). | ||
301 | proc_macro_dylib_path?: string; | ||
302 | } | ||
303 | |||
304 | interface Dep { | ||
305 | /// Index of a crate in the `crates` array. | ||
306 | crate: number, | ||
307 | /// Name as should appear in the (implicit) `extern crate name` declaration. | ||
308 | name: string, | ||
309 | } | ||
310 | ---- | ||
311 | |||
312 | This format is provisional and subject to change. | ||
313 | Specifically, the `roots` setup will be different eventually. | ||
314 | |||
315 | There are tree ways to feed `rust-project.json` to rust-analyzer: | ||
316 | |||
317 | * Place `rust-project.json` file at the root of the project, and rust-anlayzer will discover it. | ||
318 | * 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). | ||
319 | * Specify `"rust-analyzer.linkedProjects": [ { "roots": [...], "crates": [...] }]` inline. | ||
320 | |||
321 | See https://github.com/rust-analyzer/rust-project.json-example for a small example. | ||
322 | |||
323 | == Features | ||
324 | |||
325 | include::./generated_features.adoc[] | ||
326 | |||
327 | == Assists (Code Actions) | ||
328 | |||
329 | Assists, or code actions, are small local refactorings, available in a particular context. | ||
330 | They are usually triggered by a shortcut or by clicking a light bulb icon in the editor. | ||
331 | Cursor position or selection is signified by `┃` character. | ||
262 | 332 | ||
263 | See https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/features.md[features.md]. | 333 | include::./generated_assists.adoc[] |