aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/user/generated_assists.adoc (renamed from docs/user/assists.md)424
-rw-r--r--docs/user/manual.adoc3
-rw-r--r--xtask/src/codegen.rs33
-rw-r--r--xtask/src/codegen/gen_assists_docs.rs71
-rw-r--r--xtask/src/codegen/gen_feature_docs.rs22
-rw-r--r--xtask/src/lib.rs2
6 files changed, 366 insertions, 189 deletions
diff --git a/docs/user/assists.md b/docs/user/generated_assists.adoc
index 04387e3b0..b8cdfb1cd 100644
--- a/docs/user/assists.md
+++ b/docs/user/generated_assists.adoc
@@ -1,18 +1,16 @@
1# Assists 1[discrete]
2 2=== `add_custom_impl`
3Cursor position or selection is signified by `┃` character.
4
5
6## `add_custom_impl`
7 3
8Adds impl block for derived trait. 4Adds impl block for derived trait.
9 5
6.Before
10```rust 7```rust
11// BEFORE
12#[derive(Deb┃ug, Display)] 8#[derive(Deb┃ug, Display)]
13struct S; 9struct S;
10```
14 11
15// AFTER 12.After
13```rust
16#[derive(Display)] 14#[derive(Display)]
17struct S; 15struct S;
18 16
@@ -21,18 +19,22 @@ impl Debug for S {
21} 19}
22``` 20```
23 21
24## `add_derive` 22
23[discrete]
24=== `add_derive`
25 25
26Adds a new `#[derive()]` clause to a struct or enum. 26Adds a new `#[derive()]` clause to a struct or enum.
27 27
28.Before
28```rust 29```rust
29// BEFORE
30struct Point { 30struct Point {
31 x: u32, 31 x: u32,
32 y: u32,┃ 32 y: u32,┃
33} 33}
34```
34 35
35// AFTER 36.After
37```rust
36#[derive($0)] 38#[derive($0)]
37struct Point { 39struct Point {
38 x: u32, 40 x: u32,
@@ -40,31 +42,39 @@ struct Point {
40} 42}
41``` 43```
42 44
43## `add_explicit_type` 45
46[discrete]
47=== `add_explicit_type`
44 48
45Specify type for a let binding. 49Specify type for a let binding.
46 50
51.Before
47```rust 52```rust
48// BEFORE
49fn main() { 53fn main() {
50 let x┃ = 92; 54 let x┃ = 92;
51} 55}
56```
52 57
53// AFTER 58.After
59```rust
54fn main() { 60fn main() {
55 let x: i32 = 92; 61 let x: i32 = 92;
56} 62}
57``` 63```
58 64
59## `add_from_impl_for_enum` 65
66[discrete]
67=== `add_from_impl_for_enum`
60 68
61Adds a From impl for an enum variant with one tuple field. 69Adds a From impl for an enum variant with one tuple field.
62 70
71.Before
63```rust 72```rust
64// BEFORE
65enum A { ┃One(u32) } 73enum A { ┃One(u32) }
74```
66 75
67// AFTER 76.After
77```rust
68enum A { One(u32) } 78enum A { One(u32) }
69 79
70impl From<u32> for A { 80impl From<u32> for A {
@@ -74,20 +84,24 @@ impl From<u32> for A {
74} 84}
75``` 85```
76 86
77## `add_function` 87
88[discrete]
89=== `add_function`
78 90
79Adds a stub function with a signature matching the function under the cursor. 91Adds a stub function with a signature matching the function under the cursor.
80 92
93.Before
81```rust 94```rust
82// BEFORE
83struct Baz; 95struct Baz;
84fn baz() -> Baz { Baz } 96fn baz() -> Baz { Baz }
85fn foo() { 97fn foo() {
86 bar┃("", baz()); 98 bar┃("", baz());
87} 99}
88 100
101```
89 102
90// AFTER 103.After
104```rust
91struct Baz; 105struct Baz;
92fn baz() -> Baz { Baz } 106fn baz() -> Baz { Baz }
93fn foo() { 107fn foo() {
@@ -100,33 +114,41 @@ fn bar(arg: &str, baz: Baz) {
100 114
101``` 115```
102 116
103## `add_hash` 117
118[discrete]
119=== `add_hash`
104 120
105Adds a hash to a raw string literal. 121Adds a hash to a raw string literal.
106 122
123.Before
107```rust 124```rust
108// BEFORE
109fn main() { 125fn main() {
110 r#"Hello,┃ World!"#; 126 r#"Hello,┃ World!"#;
111} 127}
128```
112 129
113// AFTER 130.After
131```rust
114fn main() { 132fn main() {
115 r##"Hello, World!"##; 133 r##"Hello, World!"##;
116} 134}
117``` 135```
118 136
119## `add_impl` 137
138[discrete]
139=== `add_impl`
120 140
121Adds a new inherent impl for a type. 141Adds a new inherent impl for a type.
122 142
143.Before
123```rust 144```rust
124// BEFORE
125struct Ctx<T: Clone> { 145struct Ctx<T: Clone> {
126 data: T,┃ 146 data: T,┃
127} 147}
148```
128 149
129// AFTER 150.After
151```rust
130struct Ctx<T: Clone> { 152struct Ctx<T: Clone> {
131 data: T, 153 data: T,
132} 154}
@@ -136,12 +158,14 @@ impl<T: Clone> Ctx<T> {
136} 158}
137``` 159```
138 160
139## `add_impl_default_members` 161
162[discrete]
163=== `add_impl_default_members`
140 164
141Adds scaffold for overriding default impl members. 165Adds scaffold for overriding default impl members.
142 166
167.Before
143```rust 168```rust
144// BEFORE
145trait Trait { 169trait Trait {
146 Type X; 170 Type X;
147 fn foo(&self); 171 fn foo(&self);
@@ -153,8 +177,10 @@ impl Trait for () {
153 fn foo(&self) {}┃ 177 fn foo(&self) {}┃
154 178
155} 179}
180```
156 181
157// AFTER 182.After
183```rust
158trait Trait { 184trait Trait {
159 Type X; 185 Type X;
160 fn foo(&self); 186 fn foo(&self);
@@ -169,12 +195,14 @@ impl Trait for () {
169} 195}
170``` 196```
171 197
172## `add_impl_missing_members` 198
199[discrete]
200=== `add_impl_missing_members`
173 201
174Adds scaffold for required impl members. 202Adds scaffold for required impl members.
175 203
204.Before
176```rust 205```rust
177// BEFORE
178trait Trait<T> { 206trait Trait<T> {
179 Type X; 207 Type X;
180 fn foo(&self) -> T; 208 fn foo(&self) -> T;
@@ -184,8 +212,10 @@ trait Trait<T> {
184impl Trait<u32> for () {┃ 212impl Trait<u32> for () {┃
185 213
186} 214}
215```
187 216
188// AFTER 217.After
218```rust
189trait Trait<T> { 219trait Trait<T> {
190 Type X; 220 Type X;
191 fn foo(&self) -> T; 221 fn foo(&self) -> T;
@@ -200,17 +230,21 @@ impl Trait<u32> for () {
200} 230}
201``` 231```
202 232
203## `add_new` 233
234[discrete]
235=== `add_new`
204 236
205Adds a new inherent impl for a type. 237Adds a new inherent impl for a type.
206 238
239.Before
207```rust 240```rust
208// BEFORE
209struct Ctx<T: Clone> { 241struct Ctx<T: Clone> {
210 data: T,┃ 242 data: T,┃
211} 243}
244```
212 245
213// AFTER 246.After
247```rust
214struct Ctx<T: Clone> { 248struct Ctx<T: Clone> {
215 data: T, 249 data: T,
216} 250}
@@ -221,25 +255,31 @@ impl<T: Clone> Ctx<T> {
221 255
222``` 256```
223 257
224## `add_turbo_fish` 258
259[discrete]
260=== `add_turbo_fish`
225 261
226Adds `::<_>` to a call of a generic method or function. 262Adds `::<_>` to a call of a generic method or function.
227 263
264.Before
228```rust 265```rust
229// BEFORE
230fn make<T>() -> T { todo!() } 266fn make<T>() -> T { todo!() }
231fn main() { 267fn main() {
232 let x = make┃(); 268 let x = make┃();
233} 269}
270```
234 271
235// AFTER 272.After
273```rust
236fn make<T>() -> T { todo!() } 274fn make<T>() -> T { todo!() }
237fn main() { 275fn main() {
238 let x = make::<${0:_}>(); 276 let x = make::<${0:_}>();
239} 277}
240``` 278```
241 279
242## `apply_demorgan` 280
281[discrete]
282=== `apply_demorgan`
243 283
244Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). 284Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
245This transforms expressions of the form `!l || !r` into `!(l && r)`. 285This transforms expressions of the form `!l || !r` into `!(l && r)`.
@@ -247,29 +287,35 @@ This also works with `&&`. This assist can only be applied with the cursor
247on either `||` or `&&`, with both operands being a negation of some kind. 287on either `||` or `&&`, with both operands being a negation of some kind.
248This means something of the form `!x` or `x != y`. 288This means something of the form `!x` or `x != y`.
249 289
290.Before
250```rust 291```rust
251// BEFORE
252fn main() { 292fn main() {
253 if x != 4 ||┃ !y {} 293 if x != 4 ||┃ !y {}
254} 294}
295```
255 296
256// AFTER 297.After
298```rust
257fn main() { 299fn main() {
258 if !(x == 4 && y) {} 300 if !(x == 4 && y) {}
259} 301}
260``` 302```
261 303
262## `auto_import` 304
305[discrete]
306=== `auto_import`
263 307
264If the name is unresolved, provides all possible imports for it. 308If the name is unresolved, provides all possible imports for it.
265 309
310.Before
266```rust 311```rust
267// BEFORE
268fn main() { 312fn main() {
269 let map = HashMap┃::new(); 313 let map = HashMap┃::new();
270} 314}
315```
271 316
272// AFTER 317.After
318```rust
273use std::collections::HashMap; 319use std::collections::HashMap;
274 320
275fn main() { 321fn main() {
@@ -277,12 +323,14 @@ fn main() {
277} 323}
278``` 324```
279 325
280## `change_lifetime_anon_to_named` 326
327[discrete]
328=== `change_lifetime_anon_to_named`
281 329
282Change an anonymous lifetime to a named lifetime. 330Change an anonymous lifetime to a named lifetime.
283 331
332.Before
284```rust 333```rust
285// BEFORE
286impl Cursor<'_┃> { 334impl Cursor<'_┃> {
287 fn node(self) -> &SyntaxNode { 335 fn node(self) -> &SyntaxNode {
288 match self { 336 match self {
@@ -290,8 +338,10 @@ impl Cursor<'_┃> {
290 } 338 }
291 } 339 }
292} 340}
341```
293 342
294// AFTER 343.After
344```rust
295impl<'a> Cursor<'a> { 345impl<'a> Cursor<'a> {
296 fn node(self) -> &SyntaxNode { 346 fn node(self) -> &SyntaxNode {
297 match self { 347 match self {
@@ -301,44 +351,56 @@ impl<'a> Cursor<'a> {
301} 351}
302``` 352```
303 353
304## `change_return_type_to_result` 354
355[discrete]
356=== `change_return_type_to_result`
305 357
306Change the function's return type to Result. 358Change the function's return type to Result.
307 359
360.Before
308```rust 361```rust
309// BEFORE
310fn foo() -> i32┃ { 42i32 } 362fn foo() -> i32┃ { 42i32 }
363```
311 364
312// AFTER 365.After
366```rust
313fn foo() -> Result<i32, ${0:_}> { Ok(42i32) } 367fn foo() -> Result<i32, ${0:_}> { Ok(42i32) }
314``` 368```
315 369
316## `change_visibility` 370
371[discrete]
372=== `change_visibility`
317 373
318Adds or changes existing visibility specifier. 374Adds or changes existing visibility specifier.
319 375
376.Before
320```rust 377```rust
321// BEFORE
322┃fn frobnicate() {} 378┃fn frobnicate() {}
379```
323 380
324// AFTER 381.After
382```rust
325pub(crate) fn frobnicate() {} 383pub(crate) fn frobnicate() {}
326``` 384```
327 385
328## `convert_to_guarded_return` 386
387[discrete]
388=== `convert_to_guarded_return`
329 389
330Replace a large conditional with a guarded return. 390Replace a large conditional with a guarded return.
331 391
392.Before
332```rust 393```rust
333// BEFORE
334fn main() { 394fn main() {
335 ┃if cond { 395 ┃if cond {
336 foo(); 396 foo();
337 bar(); 397 bar();
338 } 398 }
339} 399}
400```
340 401
341// AFTER 402.After
403```rust
342fn main() { 404fn main() {
343 if !cond { 405 if !cond {
344 return; 406 return;
@@ -348,12 +410,14 @@ fn main() {
348} 410}
349``` 411```
350 412
351## `fill_match_arms` 413
414[discrete]
415=== `fill_match_arms`
352 416
353Adds missing clauses to a `match` expression. 417Adds missing clauses to a `match` expression.
354 418
419.Before
355```rust 420```rust
356// BEFORE
357enum Action { Move { distance: u32 }, Stop } 421enum Action { Move { distance: u32 }, Stop }
358 422
359fn handle(action: Action) { 423fn handle(action: Action) {
@@ -361,8 +425,10 @@ fn handle(action: Action) {
361 425
362 } 426 }
363} 427}
428```
364 429
365// AFTER 430.After
431```rust
366enum Action { Move { distance: u32 }, Stop } 432enum Action { Move { distance: u32 }, Stop }
367 433
368fn handle(action: Action) { 434fn handle(action: Action) {
@@ -373,20 +439,24 @@ fn handle(action: Action) {
373} 439}
374``` 440```
375 441
376## `fix_visibility` 442
443[discrete]
444=== `fix_visibility`
377 445
378Makes inaccessible item public. 446Makes inaccessible item public.
379 447
448.Before
380```rust 449```rust
381// BEFORE
382mod m { 450mod m {
383 fn frobnicate() {} 451 fn frobnicate() {}
384} 452}
385fn main() { 453fn main() {
386 m::frobnicate┃() {} 454 m::frobnicate┃() {}
387} 455}
456```
388 457
389// AFTER 458.After
459```rust
390mod m { 460mod m {
391 $0pub(crate) fn frobnicate() {} 461 $0pub(crate) fn frobnicate() {}
392} 462}
@@ -395,154 +465,192 @@ fn main() {
395} 465}
396``` 466```
397 467
398## `flip_binexpr` 468
469[discrete]
470=== `flip_binexpr`
399 471
400Flips operands of a binary expression. 472Flips operands of a binary expression.
401 473
474.Before
402```rust 475```rust
403// BEFORE
404fn main() { 476fn main() {
405 let _ = 90 +┃ 2; 477 let _ = 90 +┃ 2;
406} 478}
479```
407 480
408// AFTER 481.After
482```rust
409fn main() { 483fn main() {
410 let _ = 2 + 90; 484 let _ = 2 + 90;
411} 485}
412``` 486```
413 487
414## `flip_comma` 488
489[discrete]
490=== `flip_comma`
415 491
416Flips two comma-separated items. 492Flips two comma-separated items.
417 493
494.Before
418```rust 495```rust
419// BEFORE
420fn main() { 496fn main() {
421 ((1, 2),┃ (3, 4)); 497 ((1, 2),┃ (3, 4));
422} 498}
499```
423 500
424// AFTER 501.After
502```rust
425fn main() { 503fn main() {
426 ((3, 4), (1, 2)); 504 ((3, 4), (1, 2));
427} 505}
428``` 506```
429 507
430## `flip_trait_bound` 508
509[discrete]
510=== `flip_trait_bound`
431 511
432Flips two trait bounds. 512Flips two trait bounds.
433 513
514.Before
434```rust 515```rust
435// BEFORE
436fn foo<T: Clone +┃ Copy>() { } 516fn foo<T: Clone +┃ Copy>() { }
517```
437 518
438// AFTER 519.After
520```rust
439fn foo<T: Copy + Clone>() { } 521fn foo<T: Copy + Clone>() { }
440``` 522```
441 523
442## `inline_local_variable` 524
525[discrete]
526=== `inline_local_variable`
443 527
444Inlines local variable. 528Inlines local variable.
445 529
530.Before
446```rust 531```rust
447// BEFORE
448fn main() { 532fn main() {
449 let x┃ = 1 + 2; 533 let x┃ = 1 + 2;
450 x * 4; 534 x * 4;
451} 535}
536```
452 537
453// AFTER 538.After
539```rust
454fn main() { 540fn main() {
455 (1 + 2) * 4; 541 (1 + 2) * 4;
456} 542}
457``` 543```
458 544
459## `introduce_variable` 545
546[discrete]
547=== `introduce_variable`
460 548
461Extracts subexpression into a variable. 549Extracts subexpression into a variable.
462 550
551.Before
463```rust 552```rust
464// BEFORE
465fn main() { 553fn main() {
466 ┃(1 + 2)┃ * 4; 554 ┃(1 + 2)┃ * 4;
467} 555}
556```
468 557
469// AFTER 558.After
559```rust
470fn main() { 560fn main() {
471 let $0var_name = (1 + 2); 561 let $0var_name = (1 + 2);
472 var_name * 4; 562 var_name * 4;
473} 563}
474``` 564```
475 565
476## `invert_if` 566
567[discrete]
568=== `invert_if`
477 569
478Apply invert_if 570Apply invert_if
479This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}` 571This transforms if expressions of the form `if !x {A} else {B}` into `if x {B} else {A}`
480This also works with `!=`. This assist can only be applied with the cursor 572This also works with `!=`. This assist can only be applied with the cursor
481on `if`. 573on `if`.
482 574
575.Before
483```rust 576```rust
484// BEFORE
485fn main() { 577fn main() {
486 if┃ !y { A } else { B } 578 if┃ !y { A } else { B }
487} 579}
580```
488 581
489// AFTER 582.After
583```rust
490fn main() { 584fn main() {
491 if y { B } else { A } 585 if y { B } else { A }
492} 586}
493``` 587```
494 588
495## `make_raw_string` 589
590[discrete]
591=== `make_raw_string`
496 592
497Adds `r#` to a plain string literal. 593Adds `r#` to a plain string literal.
498 594
595.Before
499```rust 596```rust
500// BEFORE
501fn main() { 597fn main() {
502 "Hello,┃ World!"; 598 "Hello,┃ World!";
503} 599}
600```
504 601
505// AFTER 602.After
603```rust
506fn main() { 604fn main() {
507 r#"Hello, World!"#; 605 r#"Hello, World!"#;
508} 606}
509``` 607```
510 608
511## `make_usual_string` 609
610[discrete]
611=== `make_usual_string`
512 612
513Turns a raw string into a plain string. 613Turns a raw string into a plain string.
514 614
615.Before
515```rust 616```rust
516// BEFORE
517fn main() { 617fn main() {
518 r#"Hello,┃ "World!""#; 618 r#"Hello,┃ "World!""#;
519} 619}
620```
520 621
521// AFTER 622.After
623```rust
522fn main() { 624fn main() {
523 "Hello, \"World!\""; 625 "Hello, \"World!\"";
524} 626}
525``` 627```
526 628
527## `merge_imports` 629
630[discrete]
631=== `merge_imports`
528 632
529Merges two imports with a common prefix. 633Merges two imports with a common prefix.
530 634
635.Before
531```rust 636```rust
532// BEFORE
533use std::┃fmt::Formatter; 637use std::┃fmt::Formatter;
534use std::io; 638use std::io;
639```
535 640
536// AFTER 641.After
642```rust
537use std::{fmt::Formatter, io}; 643use std::{fmt::Formatter, io};
538``` 644```
539 645
540## `merge_match_arms` 646
647[discrete]
648=== `merge_match_arms`
541 649
542Merges identical match arms. 650Merges identical match arms.
543 651
652.Before
544```rust 653```rust
545// BEFORE
546enum Action { Move { distance: u32 }, Stop } 654enum Action { Move { distance: u32 }, Stop }
547 655
548fn handle(action: Action) { 656fn handle(action: Action) {
@@ -551,8 +659,10 @@ fn handle(action: Action) {
551 Action::Stop => foo(), 659 Action::Stop => foo(),
552 } 660 }
553} 661}
662```
554 663
555// AFTER 664.After
665```rust
556enum Action { Move { distance: u32 }, Stop } 666enum Action { Move { distance: u32 }, Stop }
557 667
558fn handle(action: Action) { 668fn handle(action: Action) {
@@ -562,12 +672,14 @@ fn handle(action: Action) {
562} 672}
563``` 673```
564 674
565## `move_arm_cond_to_match_guard` 675
676[discrete]
677=== `move_arm_cond_to_match_guard`
566 678
567Moves if expression from match arm body into a guard. 679Moves if expression from match arm body into a guard.
568 680
681.Before
569```rust 682```rust
570// BEFORE
571enum Action { Move { distance: u32 }, Stop } 683enum Action { Move { distance: u32 }, Stop }
572 684
573fn handle(action: Action) { 685fn handle(action: Action) {
@@ -576,8 +688,10 @@ fn handle(action: Action) {
576 _ => (), 688 _ => (),
577 } 689 }
578} 690}
691```
579 692
580// AFTER 693.After
694```rust
581enum Action { Move { distance: u32 }, Stop } 695enum Action { Move { distance: u32 }, Stop }
582 696
583fn handle(action: Action) { 697fn handle(action: Action) {
@@ -588,28 +702,34 @@ fn handle(action: Action) {
588} 702}
589``` 703```
590 704
591## `move_bounds_to_where_clause` 705
706[discrete]
707=== `move_bounds_to_where_clause`
592 708
593Moves inline type bounds to a where clause. 709Moves inline type bounds to a where clause.
594 710
711.Before
595```rust 712```rust
596// BEFORE
597fn apply<T, U, ┃F: FnOnce(T) -> U>(f: F, x: T) -> U { 713fn apply<T, U, ┃F: FnOnce(T) -> U>(f: F, x: T) -> U {
598 f(x) 714 f(x)
599} 715}
716```
600 717
601// AFTER 718.After
719```rust
602fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U { 720fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
603 f(x) 721 f(x)
604} 722}
605``` 723```
606 724
607## `move_guard_to_arm_body` 725
726[discrete]
727=== `move_guard_to_arm_body`
608 728
609Moves match guard into match arm body. 729Moves match guard into match arm body.
610 730
731.Before
611```rust 732```rust
612// BEFORE
613enum Action { Move { distance: u32 }, Stop } 733enum Action { Move { distance: u32 }, Stop }
614 734
615fn handle(action: Action) { 735fn handle(action: Action) {
@@ -618,8 +738,10 @@ fn handle(action: Action) {
618 _ => (), 738 _ => (),
619 } 739 }
620} 740}
741```
621 742
622// AFTER 743.After
744```rust
623enum Action { Move { distance: u32 }, Stop } 745enum Action { Move { distance: u32 }, Stop }
624 746
625fn handle(action: Action) { 747fn handle(action: Action) {
@@ -630,75 +752,93 @@ fn handle(action: Action) {
630} 752}
631``` 753```
632 754
633## `remove_dbg` 755
756[discrete]
757=== `remove_dbg`
634 758
635Removes `dbg!()` macro call. 759Removes `dbg!()` macro call.
636 760
761.Before
637```rust 762```rust
638// BEFORE
639fn main() { 763fn main() {
640 ┃dbg!(92); 764 ┃dbg!(92);
641} 765}
766```
642 767
643// AFTER 768.After
769```rust
644fn main() { 770fn main() {
645 92; 771 92;
646} 772}
647``` 773```
648 774
649## `remove_hash` 775
776[discrete]
777=== `remove_hash`
650 778
651Removes a hash from a raw string literal. 779Removes a hash from a raw string literal.
652 780
781.Before
653```rust 782```rust
654// BEFORE
655fn main() { 783fn main() {
656 r#"Hello,┃ World!"#; 784 r#"Hello,┃ World!"#;
657} 785}
786```
658 787
659// AFTER 788.After
789```rust
660fn main() { 790fn main() {
661 r"Hello, World!"; 791 r"Hello, World!";
662} 792}
663``` 793```
664 794
665## `remove_mut` 795
796[discrete]
797=== `remove_mut`
666 798
667Removes the `mut` keyword. 799Removes the `mut` keyword.
668 800
801.Before
669```rust 802```rust
670// BEFORE
671impl Walrus { 803impl Walrus {
672 fn feed(&mut┃ self, amount: u32) {} 804 fn feed(&mut┃ self, amount: u32) {}
673} 805}
806```
674 807
675// AFTER 808.After
809```rust
676impl Walrus { 810impl Walrus {
677 fn feed(&self, amount: u32) {} 811 fn feed(&self, amount: u32) {}
678} 812}
679``` 813```
680 814
681## `reorder_fields` 815
816[discrete]
817=== `reorder_fields`
682 818
683Reorder the fields of record literals and record patterns in the same order as in 819Reorder the fields of record literals and record patterns in the same order as in
684the definition. 820the definition.
685 821
822.Before
686```rust 823```rust
687// BEFORE
688struct Foo {foo: i32, bar: i32}; 824struct Foo {foo: i32, bar: i32};
689const test: Foo = ┃Foo {bar: 0, foo: 1} 825const test: Foo = ┃Foo {bar: 0, foo: 1}
826```
690 827
691// AFTER 828.After
829```rust
692struct Foo {foo: i32, bar: i32}; 830struct Foo {foo: i32, bar: i32};
693const test: Foo = Foo {foo: 1, bar: 0} 831const test: Foo = Foo {foo: 1, bar: 0}
694``` 832```
695 833
696## `replace_if_let_with_match` 834
835[discrete]
836=== `replace_if_let_with_match`
697 837
698Replaces `if let` with an else branch with a `match` expression. 838Replaces `if let` with an else branch with a `match` expression.
699 839
840.Before
700```rust 841```rust
701// BEFORE
702enum Action { Move { distance: u32 }, Stop } 842enum Action { Move { distance: u32 }, Stop }
703 843
704fn handle(action: Action) { 844fn handle(action: Action) {
@@ -708,8 +848,10 @@ fn handle(action: Action) {
708 bar() 848 bar()
709 } 849 }
710} 850}
851```
711 852
712// AFTER 853.After
854```rust
713enum Action { Move { distance: u32 }, Stop } 855enum Action { Move { distance: u32 }, Stop }
714 856
715fn handle(action: Action) { 857fn handle(action: Action) {
@@ -720,20 +862,24 @@ fn handle(action: Action) {
720} 862}
721``` 863```
722 864
723## `replace_let_with_if_let` 865
866[discrete]
867=== `replace_let_with_if_let`
724 868
725Replaces `let` with an `if-let`. 869Replaces `let` with an `if-let`.
726 870
871.Before
727```rust 872```rust
728// BEFORE
729 873
730fn main(action: Action) { 874fn main(action: Action) {
731 ┃let x = compute(); 875 ┃let x = compute();
732} 876}
733 877
734fn compute() -> Option<i32> { None } 878fn compute() -> Option<i32> { None }
879```
735 880
736// AFTER 881.After
882```rust
737 883
738fn main(action: Action) { 884fn main(action: Action) {
739 if let Some(x) = compute() { 885 if let Some(x) = compute() {
@@ -743,33 +889,41 @@ fn main(action: Action) {
743fn compute() -> Option<i32> { None } 889fn compute() -> Option<i32> { None }
744``` 890```
745 891
746## `replace_qualified_name_with_use` 892
893[discrete]
894=== `replace_qualified_name_with_use`
747 895
748Adds a use statement for a given fully-qualified name. 896Adds a use statement for a given fully-qualified name.
749 897
898.Before
750```rust 899```rust
751// BEFORE
752fn process(map: std::collections::┃HashMap<String, String>) {} 900fn process(map: std::collections::┃HashMap<String, String>) {}
901```
753 902
754// AFTER 903.After
904```rust
755use std::collections::HashMap; 905use std::collections::HashMap;
756 906
757fn process(map: HashMap<String, String>) {} 907fn process(map: HashMap<String, String>) {}
758``` 908```
759 909
760## `replace_unwrap_with_match` 910
911[discrete]
912=== `replace_unwrap_with_match`
761 913
762Replaces `unwrap` a `match` expression. Works for Result and Option. 914Replaces `unwrap` a `match` expression. Works for Result and Option.
763 915
916.Before
764```rust 917```rust
765// BEFORE
766enum Result<T, E> { Ok(T), Err(E) } 918enum Result<T, E> { Ok(T), Err(E) }
767fn main() { 919fn main() {
768 let x: Result<i32, i32> = Result::Ok(92); 920 let x: Result<i32, i32> = Result::Ok(92);
769 let y = x.┃unwrap(); 921 let y = x.┃unwrap();
770} 922}
923```
771 924
772// AFTER 925.After
926```rust
773enum Result<T, E> { Ok(T), Err(E) } 927enum Result<T, E> { Ok(T), Err(E) }
774fn main() { 928fn main() {
775 let x: Result<i32, i32> = Result::Ok(92); 929 let x: Result<i32, i32> = Result::Ok(92);
@@ -780,31 +934,39 @@ fn main() {
780} 934}
781``` 935```
782 936
783## `split_import` 937
938[discrete]
939=== `split_import`
784 940
785Wraps the tail of import into braces. 941Wraps the tail of import into braces.
786 942
943.Before
787```rust 944```rust
788// BEFORE
789use std::┃collections::HashMap; 945use std::┃collections::HashMap;
946```
790 947
791// AFTER 948.After
949```rust
792use std::{collections::HashMap}; 950use std::{collections::HashMap};
793``` 951```
794 952
795## `unwrap_block` 953
954[discrete]
955=== `unwrap_block`
796 956
797This assist removes if...else, for, while and loop control statements to just keep the body. 957This assist removes if...else, for, while and loop control statements to just keep the body.
798 958
959.Before
799```rust 960```rust
800// BEFORE
801fn foo() { 961fn foo() {
802 if true {┃ 962 if true {┃
803 println!("foo"); 963 println!("foo");
804 } 964 }
805} 965}
966```
806 967
807// AFTER 968.After
969```rust
808fn foo() { 970fn foo() {
809 println!("foo"); 971 println!("foo");
810} 972}
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index f40139804..27b379213 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -278,5 +278,6 @@ include::./generated_features.adoc[]
278 278
279Assists, or code actions, are small local refactorings, available in a particular context. 279Assists, or code actions, are small local refactorings, available in a particular context.
280They are usually triggered by a shortcut or by clicking a light bulb icon in the editor. 280They are usually triggered by a shortcut or by clicking a light bulb icon in the editor.
281Cursor position or selection is signified by `┃` character.
281 282
282See [assists.md](./assists.md) for the list of available assists. 283include::./generated_assists.adoc[]
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index f47d54125..f3917a244 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -10,9 +10,12 @@ mod gen_parser_tests;
10mod gen_assists_docs; 10mod gen_assists_docs;
11mod gen_feature_docs; 11mod gen_feature_docs;
12 12
13use std::{mem, path::Path}; 13use std::{
14 fmt, mem,
15 path::{Path, PathBuf},
16};
14 17
15use crate::{not_bash::fs2, Result}; 18use crate::{not_bash::fs2, project_root, Result};
16 19
17pub use self::{ 20pub use self::{
18 gen_assists_docs::generate_assists_docs, gen_feature_docs::generate_feature_docs, 21 gen_assists_docs::generate_assists_docs, gen_feature_docs::generate_feature_docs,
@@ -29,7 +32,6 @@ const AST_TOKENS: &str = "crates/ra_syntax/src/ast/generated/tokens.rs";
29 32
30const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers"; 33const ASSISTS_DIR: &str = "crates/ra_assists/src/handlers";
31const ASSISTS_TESTS: &str = "crates/ra_assists/src/tests/generated.rs"; 34const ASSISTS_TESTS: &str = "crates/ra_assists/src/tests/generated.rs";
32const ASSISTS_DOCS: &str = "docs/user/assists.md";
33 35
34#[derive(Debug, PartialEq, Eq, Clone, Copy)] 36#[derive(Debug, PartialEq, Eq, Clone, Copy)]
35pub enum Mode { 37pub enum Mode {
@@ -107,3 +109,28 @@ fn do_extract_comment_blocks(text: &str, allow_blocks_with_empty_lines: bool) ->
107 } 109 }
108 res 110 res
109} 111}
112
113#[derive(Debug)]
114struct Location {
115 file: PathBuf,
116}
117
118impl Location {
119 fn new(file: PathBuf) -> Self {
120 Self { file }
121 }
122}
123
124impl fmt::Display for Location {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 let path = self.file.strip_prefix(&project_root()).unwrap().display().to_string();
127 let path = path.replace('\\', "/");
128 let name = self.file.file_name().unwrap();
129 write!(
130 f,
131 "https://github.com/rust-analyzer/rust-analyzer/blob/master/{}[{}]",
132 path,
133 name.to_str().unwrap()
134 )
135 }
136}
diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs
index 6ebeb8aea..15a02d317 100644
--- a/xtask/src/codegen/gen_assists_docs.rs
+++ b/xtask/src/codegen/gen_assists_docs.rs
@@ -1,22 +1,28 @@
1//! Generates `assists.md` documentation. 1//! Generates `assists.md` documentation.
2 2
3use std::{fs, path::Path}; 3use std::{fmt, fs, path::Path};
4 4
5use crate::{ 5use crate::{
6 codegen::{self, extract_comment_blocks_with_empty_lines, Mode}, 6 codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode},
7 project_root, rust_files, Result, 7 project_root, rust_files, Result,
8}; 8};
9 9
10pub fn generate_assists_docs(mode: Mode) -> Result<()> { 10pub fn generate_assists_docs(mode: Mode) -> Result<()> {
11 let assists = Assist::collect()?; 11 let assists = Assist::collect()?;
12 generate_tests(&assists, mode)?; 12 generate_tests(&assists, mode)?;
13 generate_docs(&assists, mode)?; 13
14 let contents = assists.into_iter().map(|it| it.to_string()).collect::<Vec<_>>().join("\n\n");
15 let contents = contents.trim().to_string() + "\n";
16 let dst = project_root().join("docs/user/generated_assists.adoc");
17 codegen::update(&dst, &contents, mode)?;
18
14 Ok(()) 19 Ok(())
15} 20}
16 21
17#[derive(Debug)] 22#[derive(Debug)]
18struct Assist { 23struct Assist {
19 id: String, 24 id: String,
25 location: Location,
20 doc: String, 26 doc: String,
21 before: String, 27 before: String,
22 after: String, 28 after: String,
@@ -58,7 +64,8 @@ impl Assist {
58 assert_eq!(lines.next().unwrap().as_str(), "->"); 64 assert_eq!(lines.next().unwrap().as_str(), "->");
59 assert_eq!(lines.next().unwrap().as_str(), "```"); 65 assert_eq!(lines.next().unwrap().as_str(), "```");
60 let after = take_until(lines.by_ref(), "```"); 66 let after = take_until(lines.by_ref(), "```");
61 acc.push(Assist { id, doc, before, after }) 67 let location = Location::new(path.to_path_buf());
68 acc.push(Assist { id, location, doc, before, after })
62 } 69 }
63 70
64 fn take_until<'a>(lines: impl Iterator<Item = &'a String>, marker: &str) -> String { 71 fn take_until<'a>(lines: impl Iterator<Item = &'a String>, marker: &str) -> String {
@@ -76,6 +83,31 @@ impl Assist {
76 } 83 }
77} 84}
78 85
86impl fmt::Display for Assist {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 let before = self.before.replace("<|>", "┃"); // Unicode pseudo-graphics bar
89 let after = self.after.replace("<|>", "┃");
90 writeln!(
91 f,
92 "[discrete]\n=== `{}`
93
94{}
95
96.Before
97```rust
98{}```
99
100.After
101```rust
102{}```",
103 self.id,
104 self.doc,
105 hide_hash_comments(&before),
106 hide_hash_comments(&after)
107 )
108 }
109}
110
79fn generate_tests(assists: &[Assist], mode: Mode) -> Result<()> { 111fn generate_tests(assists: &[Assist], mode: Mode) -> Result<()> {
80 let mut buf = String::from("use super::check_doc_test;\n"); 112 let mut buf = String::from("use super::check_doc_test;\n");
81 113
@@ -103,37 +135,6 @@ r#####"
103 codegen::update(&project_root().join(codegen::ASSISTS_TESTS), &buf, mode) 135 codegen::update(&project_root().join(codegen::ASSISTS_TESTS), &buf, mode)
104} 136}
105 137
106fn generate_docs(assists: &[Assist], mode: Mode) -> Result<()> {
107 let mut buf = String::from(
108 "# Assists\n\nCursor position or selection is signified by `┃` character.\n\n",
109 );
110
111 for assist in assists {
112 let before = assist.before.replace("<|>", "┃"); // Unicode pseudo-graphics bar
113 let after = assist.after.replace("<|>", "┃");
114 let docs = format!(
115 "
116## `{}`
117
118{}
119
120```rust
121// BEFORE
122{}
123// AFTER
124{}```
125",
126 assist.id,
127 assist.doc,
128 hide_hash_comments(&before),
129 hide_hash_comments(&after)
130 );
131 buf.push_str(&docs);
132 }
133
134 codegen::update(&project_root().join(codegen::ASSISTS_DOCS), &buf, mode)
135}
136
137fn hide_hash_comments(text: &str) -> String { 138fn hide_hash_comments(text: &str) -> String {
138 text.split('\n') // want final newline 139 text.split('\n') // want final newline
139 .filter(|&it| !(it.starts_with("# ") || it == "#")) 140 .filter(|&it| !(it.starts_with("# ") || it == "#"))
diff --git a/xtask/src/codegen/gen_feature_docs.rs b/xtask/src/codegen/gen_feature_docs.rs
index dbe583e8e..731e7ecf2 100644
--- a/xtask/src/codegen/gen_feature_docs.rs
+++ b/xtask/src/codegen/gen_feature_docs.rs
@@ -3,7 +3,7 @@
3use std::{fmt, fs, path::PathBuf}; 3use std::{fmt, fs, path::PathBuf};
4 4
5use crate::{ 5use crate::{
6 codegen::{self, extract_comment_blocks_with_empty_lines, Mode}, 6 codegen::{self, extract_comment_blocks_with_empty_lines, Location, Mode},
7 project_root, rust_files, Result, 7 project_root, rust_files, Result,
8}; 8};
9 9
@@ -19,7 +19,7 @@ pub fn generate_feature_docs(mode: Mode) -> Result<()> {
19#[derive(Debug)] 19#[derive(Debug)]
20struct Feature { 20struct Feature {
21 id: String, 21 id: String,
22 path: PathBuf, 22 location: Location,
23 doc: String, 23 doc: String,
24} 24}
25 25
@@ -40,7 +40,7 @@ impl Feature {
40 let id = block.id; 40 let id = block.id;
41 assert!(is_valid_feature_name(&id), "invalid feature name: {:?}", id); 41 assert!(is_valid_feature_name(&id), "invalid feature name: {:?}", id);
42 let doc = block.contents.join("\n"); 42 let doc = block.contents.join("\n");
43 acc.push(Feature { id, path: path.clone(), doc }) 43 acc.push(Feature { id, location: Location::new(path.clone()), doc })
44 } 44 }
45 45
46 Ok(()) 46 Ok(())
@@ -69,20 +69,6 @@ fn is_valid_feature_name(feature: &str) -> bool {
69 69
70impl fmt::Display for Feature { 70impl fmt::Display for Feature {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 writeln!(f, "=== {}", self.id)?; 72 writeln!(f, "=== {}\n**Source:** {}\n{}", self.id, self.location, self.doc)
73 let path = self.path.strip_prefix(&project_root()).unwrap().display().to_string();
74 let path = path.replace('\\', "/");
75 let name = self.path.file_name().unwrap();
76
77 //FIXME: generate line number as well
78 writeln!(
79 f,
80 "**Source:** https://github.com/rust-analyzer/rust-analyzer/blob/master/{}[{}]",
81 path,
82 name.to_str().unwrap(),
83 )?;
84
85 writeln!(f, "{}", self.doc)?;
86 Ok(())
87 } 73 }
88} 74}
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index 06043d19f..874957885 100644
--- a/xtask/src/lib.rs
+++ b/xtask/src/lib.rs
@@ -191,7 +191,7 @@ Release: release:{}[]
191 let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n)); 191 let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
192 fs2::write(&path, &contents)?; 192 fs2::write(&path, &contents)?;
193 193
194 for &adoc in ["manual.adoc", "generated_features.adoc"].iter() { 194 for &adoc in ["manual.adoc", "generated_features.adoc", "generated_assists.adoc"].iter() {
195 let src = project_root().join("./docs/user/").join(adoc); 195 let src = project_root().join("./docs/user/").join(adoc);
196 let dst = website_root.join(adoc); 196 let dst = website_root.join(adoc);
197 fs2::copy(src, dst)?; 197 fs2::copy(src, dst)?;