aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/dev/README.md2
-rw-r--r--docs/user/README.md19
-rw-r--r--docs/user/assists.md505
-rw-r--r--docs/user/features.md424
4 files changed, 528 insertions, 422 deletions
diff --git a/docs/dev/README.md b/docs/dev/README.md
index e5a7ea5f6..006518afc 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -14,7 +14,7 @@ To learn more about how rust-analyzer works, see
14 14
15We also publish rustdoc docs to pages: 15We also publish rustdoc docs to pages:
16 16
17https://rust-analyzer.github.io/rust-analyzer/api-docs/ra_ide_api/ 17https://rust-analyzer.github.io/rust-analyzer/ra_ide_api/
18 18
19Various organizational and process issues are discussed in this document. 19Various organizational and process issues are discussed in this document.
20 20
diff --git a/docs/user/README.md b/docs/user/README.md
index f1628d6a4..eb1d5ed14 100644
--- a/docs/user/README.md
+++ b/docs/user/README.md
@@ -83,8 +83,6 @@ host.
83### Settings 83### Settings
84 84
85* `rust-analyzer.highlightingOn`: enables experimental syntax highlighting 85* `rust-analyzer.highlightingOn`: enables experimental syntax highlighting
86* `rust-analyzer.showWorkspaceLoadedNotification`: to ease troubleshooting, a
87 notification is shown by default when a workspace is loaded
88* `rust-analyzer.enableEnhancedTyping`: by default, rust-analyzer intercepts 86* `rust-analyzer.enableEnhancedTyping`: by default, rust-analyzer intercepts
89 `Enter` key to make it easier to continue comments. Note that it may conflict with VIM emulation plugin. 87 `Enter` key to make it easier to continue comments. Note that it may conflict with VIM emulation plugin.
90* `rust-analyzer.raLspServerPath`: path to `ra_lsp_server` executable 88* `rust-analyzer.raLspServerPath`: path to `ra_lsp_server` executable
@@ -102,6 +100,17 @@ host.
102* `rust-analyzer.trace.server`: enables internal logging 100* `rust-analyzer.trace.server`: enables internal logging
103* `rust-analyzer.trace.cargo-watch`: enables cargo-watch logging 101* `rust-analyzer.trace.cargo-watch`: enables cargo-watch logging
104* `RUST_SRC_PATH`: environment variable that overwrites the sysroot 102* `RUST_SRC_PATH`: environment variable that overwrites the sysroot
103* `rust-analyzer.featureFlags` -- a JSON object to tweak fine-grained behavior:
104 ```js
105 {
106 // Show diagnostics produced by rust-analyzer itself.
107 "lsp.diagnostics": true,
108 // Automatically insert `()` and `<>` when completing functions and types.
109 "completion.insertion.add-call-parenthesis": true,
110 // Show notification when workspace is fully loaded
111 "notifications.workspace-loaded": true,
112 }
113 ```
105 114
106 115
107## Emacs 116## Emacs
@@ -173,7 +182,11 @@ Installation:
173 "syntaxes": [ 182 "syntaxes": [
174 "Packages/Rust/Rust.sublime-syntax", 183 "Packages/Rust/Rust.sublime-syntax",
175 "Packages/Rust Enhanced/RustEnhanced.sublime-syntax" 184 "Packages/Rust Enhanced/RustEnhanced.sublime-syntax"
176 ] 185 ],
186 "initializationOptions": {
187 "featureFlags": {
188 }
189 },
177} 190}
178``` 191```
179 192
diff --git a/docs/user/assists.md b/docs/user/assists.md
new file mode 100644
index 000000000..303353e74
--- /dev/null
+++ b/docs/user/assists.md
@@ -0,0 +1,505 @@
1# Assists
2
3Cursor position or selection is signified by `┃` character.
4
5
6## `add_derive`
7
8Adds a new `#[derive()]` clause to a struct or enum.
9
10```rust
11// BEFORE
12struct Point {
13 x: u32,
14 y: u32,┃
15}
16
17// AFTER
18#[derive()]
19struct Point {
20 x: u32,
21 y: u32,
22}
23```
24
25## `add_explicit_type`
26
27Specify type for a let binding.
28
29```rust
30// BEFORE
31fn main() {
32 let x┃ = 92;
33}
34
35// AFTER
36fn main() {
37 let x: i32 = 92;
38}
39```
40
41## `add_hash`
42
43Adds a hash to a raw string literal.
44
45```rust
46// BEFORE
47fn main() {
48 r#"Hello,┃ World!"#;
49}
50
51// AFTER
52fn main() {
53 r##"Hello, World!"##;
54}
55```
56
57## `add_impl`
58
59Adds a new inherent impl for a type.
60
61```rust
62// BEFORE
63struct Ctx<T: Clone> {
64 data: T,┃
65}
66
67// AFTER
68struct Ctx<T: Clone> {
69 data: T,
70}
71
72impl<T: Clone> Ctx<T> {
73
74}
75```
76
77## `add_impl_default_members`
78
79Adds scaffold for overriding default impl members.
80
81```rust
82// BEFORE
83trait T {
84 Type X;
85 fn foo(&self);
86 fn bar(&self) {}
87}
88
89impl T for () {
90 Type X = ();
91 fn foo(&self) {}┃
92
93}
94
95// AFTER
96trait T {
97 Type X;
98 fn foo(&self);
99 fn bar(&self) {}
100}
101
102impl T for () {
103 Type X = ();
104 fn foo(&self) {}
105 fn bar(&self) {}
106
107}
108```
109
110## `add_impl_missing_members`
111
112Adds scaffold for required impl members.
113
114```rust
115// BEFORE
116trait T {
117 Type X;
118 fn foo(&self);
119 fn bar(&self) {}
120}
121
122impl T for () {┃
123
124}
125
126// AFTER
127trait T {
128 Type X;
129 fn foo(&self);
130 fn bar(&self) {}
131}
132
133impl T for () {
134 fn foo(&self) { unimplemented!() }
135
136}
137```
138
139## `add_import`
140
141Adds a use statement for a given fully-qualified path.
142
143```rust
144// BEFORE
145fn process(map: std::collections::┃HashMap<String, String>) {}
146
147// AFTER
148use std::collections::HashMap;
149
150fn process(map: HashMap<String, String>) {}
151```
152
153## `apply_demorgan`
154
155Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
156This transforms expressions of the form `!l || !r` into `!(l && r)`.
157This also works with `&&`. This assist can only be applied with the cursor
158on either `||` or `&&`, with both operands being a negation of some kind.
159This means something of the form `!x` or `x != y`.
160
161```rust
162// BEFORE
163fn main() {
164 if x != 4 ||┃ !y {}
165}
166
167// AFTER
168fn main() {
169 if !(x == 4 && y) {}
170}
171```
172
173## `change_visibility`
174
175Adds or changes existing visibility specifier.
176
177```rust
178// BEFORE
179┃fn frobnicate() {}
180
181// AFTER
182pub(crate) fn frobnicate() {}
183```
184
185## `convert_to_guarded_return`
186
187Replace a large conditional with a guarded return.
188
189```rust
190// BEFORE
191fn main() {
192 ┃if cond {
193 foo();
194 bar();
195 }
196}
197
198// AFTER
199fn main() {
200 if !cond {
201 return;
202 }
203 foo();
204 bar();
205}
206```
207
208## `fill_match_arms`
209
210Adds missing clauses to a `match` expression.
211
212```rust
213// BEFORE
214enum Action { Move { distance: u32 }, Stop }
215
216fn handle(action: Action) {
217 match action {
218
219 }
220}
221
222// AFTER
223enum Action { Move { distance: u32 }, Stop }
224
225fn handle(action: Action) {
226 match action {
227 Action::Move { distance } => (),
228 Action::Stop => (),
229 }
230}
231```
232
233## `flip_binexpr`
234
235Flips operands of a binary expression.
236
237```rust
238// BEFORE
239fn main() {
240 let _ = 90 +┃ 2;
241}
242
243// AFTER
244fn main() {
245 let _ = 2 + 90;
246}
247```
248
249## `flip_comma`
250
251Flips two comma-separated items.
252
253```rust
254// BEFORE
255fn main() {
256 ((1, 2),┃ (3, 4));
257}
258
259// AFTER
260fn main() {
261 ((3, 4), (1, 2));
262}
263```
264
265## `flip_trait_bound`
266
267Flips two trait bounds.
268
269```rust
270// BEFORE
271fn foo<T: Clone +┃ Copy>() { }
272
273// AFTER
274fn foo<T: Copy + Clone>() { }
275```
276
277## `inline_local_variable`
278
279Inlines local variable.
280
281```rust
282// BEFORE
283fn main() {
284 let x┃ = 1 + 2;
285 x * 4;
286}
287
288// AFTER
289fn main() {
290 (1 + 2) * 4;
291}
292```
293
294## `introduce_variable`
295
296Extracts subexpression into a variable.
297
298```rust
299// BEFORE
300fn main() {
301 ┃(1 + 2)┃ * 4;
302}
303
304// AFTER
305fn main() {
306 let var_name = (1 + 2);
307 var_name * 4;
308}
309```
310
311## `make_raw_string`
312
313Adds `r#` to a plain string literal.
314
315```rust
316// BEFORE
317fn main() {
318 "Hello,┃ World!";
319}
320
321// AFTER
322fn main() {
323 r#"Hello, World!"#;
324}
325```
326
327## `make_usual_string`
328
329Turns a raw string into a plain string.
330
331```rust
332// BEFORE
333fn main() {
334 r#"Hello,┃ "World!""#;
335}
336
337// AFTER
338fn main() {
339 "Hello, \"World!\"";
340}
341```
342
343## `merge_match_arms`
344
345Merges identical match arms.
346
347```rust
348// BEFORE
349enum Action { Move { distance: u32 }, Stop }
350
351fn handle(action: Action) {
352 match action {
353 ┃Action::Move(..) => foo(),
354 Action::Stop => foo(),
355 }
356}
357
358// AFTER
359enum Action { Move { distance: u32 }, Stop }
360
361fn handle(action: Action) {
362 match action {
363 Action::Move(..) | Action::Stop => foo(),
364 }
365}
366```
367
368## `move_arm_cond_to_match_guard`
369
370Moves if expression from match arm body into a guard.
371
372```rust
373// BEFORE
374enum Action { Move { distance: u32 }, Stop }
375
376fn handle(action: Action) {
377 match action {
378 Action::Move { distance } => ┃if distance > 10 { foo() },
379 _ => (),
380 }
381}
382
383// AFTER
384enum Action { Move { distance: u32 }, Stop }
385
386fn handle(action: Action) {
387 match action {
388 Action::Move { distance } if distance > 10 => foo(),
389 _ => (),
390 }
391}
392```
393
394## `move_bounds_to_where_clause`
395
396Moves inline type bounds to a where clause.
397
398```rust
399// BEFORE
400fn apply<T, U, ┃F: FnOnce(T) -> U>(f: F, x: T) -> U {
401 f(x)
402}
403
404// AFTER
405fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
406 f(x)
407}
408```
409
410## `move_guard_to_arm_body`
411
412Moves match guard into match arm body.
413
414```rust
415// BEFORE
416enum Action { Move { distance: u32 }, Stop }
417
418fn handle(action: Action) {
419 match action {
420 Action::Move { distance } ┃if distance > 10 => foo(),
421 _ => (),
422 }
423}
424
425// AFTER
426enum Action { Move { distance: u32 }, Stop }
427
428fn handle(action: Action) {
429 match action {
430 Action::Move { distance } => if distance > 10 { foo() },
431 _ => (),
432 }
433}
434```
435
436## `remove_dbg`
437
438Removes `dbg!()` macro call.
439
440```rust
441// BEFORE
442fn main() {
443 ┃dbg!(92);
444}
445
446// AFTER
447fn main() {
448 92;
449}
450```
451
452## `remove_hash`
453
454Removes a hash from a raw string literal.
455
456```rust
457// BEFORE
458fn main() {
459 r#"Hello,┃ World!"#;
460}
461
462// AFTER
463fn main() {
464 r"Hello, World!";
465}
466```
467
468## `replace_if_let_with_match`
469
470Replaces `if let` with an else branch with a `match` expression.
471
472```rust
473// BEFORE
474enum Action { Move { distance: u32 }, Stop }
475
476fn handle(action: Action) {
477 ┃if let Action::Move { distance } = action {
478 foo(distance)
479 } else {
480 bar()
481 }
482}
483
484// AFTER
485enum Action { Move { distance: u32 }, Stop }
486
487fn handle(action: Action) {
488 match action {
489 Action::Move { distance } => foo(distance),
490 _ => bar(),
491 }
492}
493```
494
495## `split_import`
496
497Wraps the tail of import into braces.
498
499```rust
500// BEFORE
501use std::┃collections::HashMap;
502
503// AFTER
504use std::{collections::HashMap};
505```
diff --git a/docs/user/features.md b/docs/user/features.md
index 8b7a8d7fc..c160dd70b 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -97,424 +97,12 @@ Start `cargo watch` for live error highlighting. Will prompt to install if it's
97 97
98Stop `cargo watch` 98Stop `cargo watch`
99 99
100### Code Actions (Assists) 100### Assists (Code Actions)
101 101
102These are triggered in a particular context via light bulb. We use custom code on 102Assists, or code actions, are small local refactorings, available in a particular context.
103the VS Code side to be able to position cursor. `<|>` signifies cursor 103They are usually triggered by a shortcut or by clicking a light bulb icon in the editor.
104 104
105- Add `#[derive]` 105See [assists.md](./assists.md) for the list of available assists.
106
107```rust
108// before:
109struct Foo {
110 <|>x: i32
111}
112// after:
113#[derive(<|>)]
114struct Foo {
115 x: i32
116}
117```
118
119- Add `impl`
120
121```rust
122// before:
123struct Foo<'a, T: Debug> {
124 <|>t: T
125}
126// after:
127struct Foo<'a, T: Debug> {
128 t: T
129}
130
131impl<'a, T: Debug> Foo<'a, T> {
132 <|>
133}
134```
135
136- Add missing `impl` members
137
138```rust
139// before:
140trait Foo {
141 fn foo(&self);
142 fn bar(&self);
143 fn baz(&self);
144}
145
146struct S;
147
148impl Foo for S {
149 fn bar(&self) {}
150 <|>
151}
152
153// after:
154trait Foo {
155 fn foo(&self);
156 fn bar(&self);
157 fn baz(&self);
158}
159
160struct S;
161
162impl Foo for S {
163 fn bar(&self) {}
164 fn foo(&self) { unimplemented!() }
165 fn baz(&self) { unimplemented!() }<|>
166}
167```
168
169- Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws)
170
171```rust
172// before:
173fn example(x: bool) -> bool {
174 !x || !x
175}
176
177// after:
178fn example(x: bool) -> bool {
179 !(x && x)
180}
181```
182
183- Import path
184
185```rust
186// before:
187impl std::fmt::Debug<|> for Foo {
188}
189
190// after:
191use std::fmt::Debug;
192
193impl Debug<|> for Foo {
194}
195```
196
197- Change Visibility
198
199```rust
200// before:
201<|>fn foo() {}
202
203// after:
204<|>pub(crate) fn foo() {}
205
206// after:
207<|>pub fn foo() {}
208```
209
210- Fill match arms
211
212```rust
213// before:
214enum A {
215 As,
216 Bs,
217 Cs(String),
218 Ds(String, String),
219 Es{x: usize, y: usize}
220}
221
222fn main() {
223 let a = A::As;
224 match a<|> {}
225}
226
227// after:
228enum A {
229 As,
230 Bs,
231 Cs(String),
232 Ds(String, String),
233 Es{x: usize, y: usize}
234}
235
236fn main() {
237 let a = A::As;
238 match <|>a {
239 A::As => (),
240 A::Bs => (),
241 A::Cs(_) => (),
242 A::Ds(_, _) => (),
243 A::Es{x, y} => (),
244 }
245}
246```
247
248- Fill struct fields
249
250```rust
251// before:
252struct S<'a, D> {
253 a: u32,
254 b: String,
255 c: (i32, i32),
256 d: D,
257 r: &'a str,
258}
259
260fn main() {
261 let s = S<|> {}
262}
263
264// after:
265struct S<'a, D> {
266 a: u32,
267 b: String,
268 c: (i32, i32),
269 d: D,
270 r: &'a str,
271}
272
273fn main() {
274 let s = <|>S {
275 a: (),
276 b: (),
277 c: (),
278 d: (),
279 r: (),
280 }
281}
282```
283
284- Flip `,`
285
286```rust
287// before:
288fn foo(x: usize,<|> dim: (usize, usize)) {}
289// after:
290fn foo(dim: (usize, usize), x: usize) {}
291```
292
293- Introduce variable:
294
295```rust
296// before:
297fn foo() {
298 foo(<|>1 + 1<|>);
299}
300
301// after:
302fn foo() {
303 let var_name = 1 + 1;
304 foo(var_name);
305}
306```
307
308- Inline local variable:
309
310```rust
311// before:
312fn foo() {
313 let a<|> = 1 + 1;
314 let b = a * 10;
315}
316
317// after:
318fn foo() {
319 let b = (1 + 1) * 10;
320}
321```
322
323- Remove `dbg!`
324
325```rust
326// before:
327fn foo(n: usize) {
328 if let Some(_) = dbg!(n.<|>checked_sub(4)) {
329 // ...
330 }
331}
332
333// after:
334fn foo(n: usize) {
335 if let Some(_) = n.<|>checked_sub(4) {
336 // ...
337 }
338}
339```
340
341- Replace if-let with match:
342
343```rust
344// before:
345impl VariantData {
346 pub fn is_struct(&self) -> bool {
347 if <|>let VariantData::Struct(..) = *self {
348 true
349 } else {
350 false
351 }
352 }
353}
354
355// after:
356impl VariantData {
357 pub fn is_struct(&self) -> bool {
358 <|>match *self {
359 VariantData::Struct(..) => true,
360 _ => false,
361 }
362 }
363}
364```
365
366- Split import
367
368```rust
369// before:
370use crate:<|>:db::{RootDatabase, FileSymbol};
371// after:
372use crate::{<|>db::{RootDatabase, FileSymbol}};
373```
374
375- Flip binary expression
376
377```rust
378// before:
379fn foo() {
380 if 1 <<|> 2 {
381 println!("Who would have thought?");
382 }
383}
384// after:
385fn foo() {
386 if 2 ><|> 1 {
387 println!("Who would have thought?");
388 }
389}
390```
391
392- Add explicit type
393
394```rust
395// before:
396fn foo() {
397 let t<|> = (&2, Some(1));
398}
399// after:
400fn foo() {
401 let t<|>: (&i32, Option<i32>) = (&2, Some(1));
402}
403```
404
405- Move guard expression to match arm body
406```rust
407// before:
408fn f() {
409 match x {
410 <|>y @ 4 | y @ 5 if y > 5 => true,
411 _ => false
412 }
413}
414// after:
415fn f() {
416 match x {
417 y @ 4 | y @ 5 => if y > 5 { <|>true },
418 _ => false
419 }
420}
421```
422
423- Move if condition to match arm guard
424```rust
425// before:
426fn f() {
427 let mut t = 'a';
428 let chars = "abcd";
429 match t {
430 '\r' => if chars.clone().next().is_some() {
431 t = 'e';<|>
432 false
433 },
434 _ => true
435 }
436}
437
438// after:
439fn f() {
440 let mut t = 'a';
441 let chars = "abcd";
442 match t {
443 '\r' <|>if chars.clone().next().is_some() => {
444 t = 'e';
445 false
446 },
447 _ => true
448 }
449}
450```
451
452- Move type bounds to where clause
453
454```rust
455// before:
456fn foo<T: u32, F: FnOnce(T) -> T>() {}
457
458// after:
459fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {}
460```
461
462- Make raw string unescaped
463
464```rust
465// before:
466fn f() {
467 let s = <|>"ab\ncd";
468}
469
470// after:
471fn f() {
472 let s = <|>r#"ab
473cd"#;
474}
475```
476
477- Make usual string
478
479```rust
480// before:
481fn f() {
482 let s = <|>r#"abcd"#;
483}
484
485// after:
486fn f() {
487 let s = <|>"abcd";
488}
489```
490
491- Add hash
492
493```rust
494// before:
495fn f() {
496 let s = <|>r"abcd";
497}
498
499// after:
500fn f() {
501 let s = <|>r#"abcd"#;
502}
503```
504
505- Remove hash
506
507```rust
508// before:
509fn f() {
510 let s = <|>r#"abcd"#;
511}
512
513// after:
514fn f() {
515 let s = <|>r"abcd";
516}
517```
518 106
519### Magic Completions 107### Magic Completions
520 108