aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/assists/add_derive.rs18
-rw-r--r--crates/ra_assists/src/assists/add_explicit_type.rs16
-rw-r--r--crates/ra_assists/src/assists/add_impl.rs19
-rw-r--r--crates/ra_assists/src/assists/add_missing_impl_members.rs58
-rw-r--r--crates/ra_assists/src/assists/apply_demorgan.rs26
-rw-r--r--crates/ra_assists/src/doc_tests.rs6
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs139
-rw-r--r--docs/user/assists.md137
-rw-r--r--docs/user/features.md91
-rw-r--r--xtask/src/codegen.rs13
-rw-r--r--xtask/src/codegen/gen_assists_docs.rs10
11 files changed, 419 insertions, 114 deletions
diff --git a/crates/ra_assists/src/assists/add_derive.rs b/crates/ra_assists/src/assists/add_derive.rs
index 77ecc33c9..d3ba634c4 100644
--- a/crates/ra_assists/src/assists/add_derive.rs
+++ b/crates/ra_assists/src/assists/add_derive.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::db::HirDatabase; 1use hir::db::HirDatabase;
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{self, AstNode, AttrsOwner}, 3 ast::{self, AstNode, AttrsOwner},
@@ -9,6 +7,22 @@ use ra_syntax::{
9 7
10use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
11 9
10// Assist: add_derive
11// Adds a new `#[derive()]` clause to a struct or enum.
12// ```
13// struct Point {
14// x: u32,
15// y: u32,<|>
16// }
17// ```
18// ->
19// ```
20// #[derive()]
21// struct Point {
22// x: u32,
23// y: u32,
24// }
25// ```
12pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 26pub(crate) fn add_derive(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
13 let nominal = ctx.node_at_offset::<ast::NominalDef>()?; 27 let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
14 let node_start = derive_insertion_offset(&nominal)?; 28 let node_start = derive_insertion_offset(&nominal)?;
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs
index 8c83dc987..33b7bea7f 100644
--- a/crates/ra_assists/src/assists/add_explicit_type.rs
+++ b/crates/ra_assists/src/assists/add_explicit_type.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::{db::HirDatabase, HirDisplay, Ty}; 1use hir::{db::HirDatabase, HirDisplay, Ty};
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{self, AstNode, LetStmt, NameOwner}, 3 ast::{self, AstNode, LetStmt, NameOwner},
@@ -8,7 +6,19 @@ use ra_syntax::{
8 6
9use crate::{Assist, AssistCtx, AssistId}; 7use crate::{Assist, AssistCtx, AssistId};
10 8
11/// Add explicit type assist. 9// Assist: add_explicit_type
10// Specify type for a let binding
11// ```
12// fn main() {
13// let x<|> = 92;
14// }
15// ```
16// ->
17// ```
18// fn main() {
19// let x: i32 = 92;
20// }
21// ```
12pub(crate) fn add_explicit_type(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 22pub(crate) fn add_explicit_type(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
13 let stmt = ctx.node_at_offset::<LetStmt>()?; 23 let stmt = ctx.node_at_offset::<LetStmt>()?;
14 let expr = stmt.initializer()?; 24 let expr = stmt.initializer()?;
diff --git a/crates/ra_assists/src/assists/add_impl.rs b/crates/ra_assists/src/assists/add_impl.rs
index 94801fbc9..40bc5c464 100644
--- a/crates/ra_assists/src/assists/add_impl.rs
+++ b/crates/ra_assists/src/assists/add_impl.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use format_buf::format; 1use format_buf::format;
4use hir::db::HirDatabase; 2use hir::db::HirDatabase;
5use join_to_string::join; 3use join_to_string::join;
@@ -10,6 +8,23 @@ use ra_syntax::{
10 8
11use crate::{Assist, AssistCtx, AssistId}; 9use crate::{Assist, AssistCtx, AssistId};
12 10
11// Assist: add_impl
12// Adds a new inherent impl for a type
13// ```
14// struct Ctx<T: Clone> {
15// data: T,<|>
16// }
17// ```
18// ->
19// ```
20// struct Ctx<T: Clone> {
21// data: T,
22// }
23//
24// impl<T: Clone> Ctx<T> {
25//
26// }
27// ```
13pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 28pub(crate) fn add_impl(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
14 let nominal = ctx.node_at_offset::<ast::NominalDef>()?; 29 let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
15 let name = nominal.name()?; 30 let name = nominal.name()?;
diff --git a/crates/ra_assists/src/assists/add_missing_impl_members.rs b/crates/ra_assists/src/assists/add_missing_impl_members.rs
index 565b96fb5..36fa6f9ea 100644
--- a/crates/ra_assists/src/assists/add_missing_impl_members.rs
+++ b/crates/ra_assists/src/assists/add_missing_impl_members.rs
@@ -1,5 +1,3 @@
1//! FIXME: write short doc here
2
3use hir::{db::HirDatabase, HasSource}; 1use hir::{db::HirDatabase, HasSource};
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{self, edit, make, AstNode, NameOwner}, 3 ast::{self, edit, make, AstNode, NameOwner},
@@ -14,6 +12,32 @@ enum AddMissingImplMembersMode {
14 NoDefaultMethods, 12 NoDefaultMethods,
15} 13}
16 14
15// Assist: add_impl_missing_members
16// Adds scaffold for required impl members
17// ```
18// trait T {
19// Type X;
20// fn foo(&self);
21// fn bar(&self) {}
22// }
23//
24// impl T for () {<|>
25//
26// }
27// ```
28// ->
29// ```
30// trait T {
31// Type X;
32// fn foo(&self);
33// fn bar(&self) {}
34// }
35//
36// impl T for () {
37// fn foo(&self) { unimplemented!() }
38//
39// }
40// ```
17pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 41pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
18 add_missing_impl_members_inner( 42 add_missing_impl_members_inner(
19 ctx, 43 ctx,
@@ -23,6 +47,36 @@ pub(crate) fn add_missing_impl_members(ctx: AssistCtx<impl HirDatabase>) -> Opti
23 ) 47 )
24} 48}
25 49
50// Assist: add_impl_default_members
51// Adds scaffold for overriding default impl members
52// ```
53// trait T {
54// Type X;
55// fn foo(&self);
56// fn bar(&self) {}
57// }
58//
59// impl T for () {
60// Type X = ();
61// fn foo(&self) {}<|>
62//
63// }
64// ```
65// ->
66// ```
67// trait T {
68// Type X;
69// fn foo(&self);
70// fn bar(&self) {}
71// }
72//
73// impl T for () {
74// Type X = ();
75// fn foo(&self) {}
76// fn bar(&self) {}
77//
78// }
79// ```
26pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 80pub(crate) fn add_missing_default_members(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
27 add_missing_impl_members_inner( 81 add_missing_impl_members_inner(
28 ctx, 82 ctx,
diff --git a/crates/ra_assists/src/assists/apply_demorgan.rs b/crates/ra_assists/src/assists/apply_demorgan.rs
index 5f2b0dd18..a072f63e7 100644
--- a/crates/ra_assists/src/assists/apply_demorgan.rs
+++ b/crates/ra_assists/src/assists/apply_demorgan.rs
@@ -1,18 +1,26 @@
1//! This contains the functions associated with the demorgan assist.
2//! This assist transforms boolean expressions of the form `!a || !b` into
3//! `!(a && b)`.
4use hir::db::HirDatabase; 1use hir::db::HirDatabase;
5use ra_syntax::ast::{self, AstNode}; 2use ra_syntax::ast::{self, AstNode};
6use ra_syntax::SyntaxNode; 3use ra_syntax::SyntaxNode;
7 4
8use crate::{Assist, AssistCtx, AssistId}; 5use crate::{Assist, AssistCtx, AssistId};
9 6
10/// Assist for applying demorgan's law 7// Assist: apply_demorgan
11/// 8// Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
12/// This transforms expressions of the form `!l || !r` into `!(l && r)`. 9// This transforms expressions of the form `!l || !r` into `!(l && r)`.
13/// This also works with `&&`. This assist can only be applied with the cursor 10// This also works with `&&`. This assist can only be applied with the cursor
14/// on either `||` or `&&`, with both operands being a negation of some kind. 11// on either `||` or `&&`, with both operands being a negation of some kind.
15/// This means something of the form `!x` or `x != y`. 12// This means something of the form `!x` or `x != y`.
13// ```
14// fn main() {
15// if x != 4 ||<|> !y {}
16// }
17// ```
18// ->
19// ```
20// fn main() {
21// if !(x == 4 && y) {}
22// }
23// ```
16pub(crate) fn apply_demorgan(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { 24pub(crate) fn apply_demorgan(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
17 let expr = ctx.node_at_offset::<ast::BinExpr>()?; 25 let expr = ctx.node_at_offset::<ast::BinExpr>()?;
18 let op = expr.op_kind()?; 26 let op = expr.op_kind()?;
diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs
index 88e901517..872bbdf17 100644
--- a/crates/ra_assists/src/doc_tests.rs
+++ b/crates/ra_assists/src/doc_tests.rs
@@ -15,8 +15,10 @@ fn check(assist_id: &str, before: &str, after: &str) {
15 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before); 15 let (db, _source_root, file_id) = MockDatabase::with_single_file(&before);
16 let frange = FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; 16 let frange = FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
17 17
18 let (_assist_id, action) = 18 let (_assist_id, action) = crate::assists(&db, frange)
19 crate::assists(&db, frange).into_iter().find(|(id, _)| id.id.0 == assist_id).unwrap(); 19 .into_iter()
20 .find(|(id, _)| id.id.0 == assist_id)
21 .unwrap_or_else(|| panic!("Assist {:?} is not applicable", assist_id));
20 22
21 let actual = action.edit.apply(&before); 23 let actual = action.edit.apply(&before);
22 assert_eq_text!(after, &actual); 24 assert_eq_text!(after, &actual);
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index e5f6910f1..76d86b93d 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -3,6 +3,145 @@
3use super::check; 3use super::check;
4 4
5#[test] 5#[test]
6fn doctest_add_derive() {
7 check(
8 "add_derive",
9 r#####"
10struct Point {
11 x: u32,
12 y: u32,<|>
13}
14"#####,
15 r#####"
16#[derive()]
17struct Point {
18 x: u32,
19 y: u32,
20}
21"#####,
22 )
23}
24
25#[test]
26fn doctest_add_explicit_type() {
27 check(
28 "add_explicit_type",
29 r#####"
30fn main() {
31 let x<|> = 92;
32}
33"#####,
34 r#####"
35fn main() {
36 let x: i32 = 92;
37}
38"#####,
39 )
40}
41
42#[test]
43fn doctest_add_impl() {
44 check(
45 "add_impl",
46 r#####"
47struct Ctx<T: Clone> {
48 data: T,<|>
49}
50"#####,
51 r#####"
52struct Ctx<T: Clone> {
53 data: T,
54}
55
56impl<T: Clone> Ctx<T> {
57
58}
59"#####,
60 )
61}
62
63#[test]
64fn doctest_add_impl_default_members() {
65 check(
66 "add_impl_default_members",
67 r#####"
68trait T {
69 Type X;
70 fn foo(&self);
71 fn bar(&self) {}
72}
73
74impl T for () {
75 Type X = ();
76 fn foo(&self) {}<|>
77
78}
79"#####,
80 r#####"
81trait T {
82 Type X;
83 fn foo(&self);
84 fn bar(&self) {}
85}
86
87impl T for () {
88 Type X = ();
89 fn foo(&self) {}
90 fn bar(&self) {}
91
92}
93"#####,
94 )
95}
96
97#[test]
98fn doctest_add_impl_missing_members() {
99 check(
100 "add_impl_missing_members",
101 r#####"
102trait T {
103 Type X;
104 fn foo(&self);
105 fn bar(&self) {}
106}
107
108impl T for () {<|>
109
110}
111"#####,
112 r#####"
113trait T {
114 Type X;
115 fn foo(&self);
116 fn bar(&self) {}
117}
118
119impl T for () {
120 fn foo(&self) { unimplemented!() }
121
122}
123"#####,
124 )
125}
126
127#[test]
128fn doctest_apply_demorgan() {
129 check(
130 "apply_demorgan",
131 r#####"
132fn main() {
133 if x != 4 ||<|> !y {}
134}
135"#####,
136 r#####"
137fn main() {
138 if !(x == 4 && y) {}
139}
140"#####,
141 )
142}
143
144#[test]
6fn doctest_convert_to_guarded_return() { 145fn doctest_convert_to_guarded_return() {
7 check( 146 check(
8 "convert_to_guarded_return", 147 "convert_to_guarded_return",
diff --git a/docs/user/assists.md b/docs/user/assists.md
index cb4b0b9fb..eeb486832 100644
--- a/docs/user/assists.md
+++ b/docs/user/assists.md
@@ -1,5 +1,142 @@
1# Assists 1# Assists
2 2
3## `add_derive`
4
5Adds a new `#[derive()]` clause to a struct or enum.
6
7```rust
8// BEFORE
9struct Point {
10 x: u32,
11 y: u32,<|>
12}
13
14// AFTER
15#[derive()]
16struct Point {
17 x: u32,
18 y: u32,
19}
20```
21
22## `add_explicit_type`
23
24Specify type for a let binding
25
26```rust
27// BEFORE
28fn main() {
29 let x<|> = 92;
30}
31
32// AFTER
33fn main() {
34 let x: i32 = 92;
35}
36```
37
38## `add_impl`
39
40Adds a new inherent impl for a type
41
42```rust
43// BEFORE
44struct Ctx<T: Clone> {
45 data: T,<|>
46}
47
48// AFTER
49struct Ctx<T: Clone> {
50 data: T,
51}
52
53impl<T: Clone> Ctx<T> {
54
55}
56```
57
58## `add_impl_default_members`
59
60Adds scaffold for overriding default impl members
61
62```rust
63// BEFORE
64trait T {
65 Type X;
66 fn foo(&self);
67 fn bar(&self) {}
68}
69
70impl T for () {
71 Type X = ();
72 fn foo(&self) {}<|>
73
74}
75
76// AFTER
77trait T {
78 Type X;
79 fn foo(&self);
80 fn bar(&self) {}
81}
82
83impl T for () {
84 Type X = ();
85 fn foo(&self) {}
86 fn bar(&self) {}
87
88}
89```
90
91## `add_impl_missing_members`
92
93Adds scaffold for required impl members
94
95```rust
96// BEFORE
97trait T {
98 Type X;
99 fn foo(&self);
100 fn bar(&self) {}
101}
102
103impl T for () {<|>
104
105}
106
107// AFTER
108trait T {
109 Type X;
110 fn foo(&self);
111 fn bar(&self) {}
112}
113
114impl T for () {
115 fn foo(&self) { unimplemented!() }
116
117}
118```
119
120## `apply_demorgan`
121
122Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
123This transforms expressions of the form `!l || !r` into `!(l && r)`.
124This also works with `&&`. This assist can only be applied with the cursor
125on either `||` or `&&`, with both operands being a negation of some kind.
126This means something of the form `!x` or `x != y`.
127
128```rust
129// BEFORE
130fn main() {
131 if x != 4 ||<|> !y {}
132}
133
134// AFTER
135fn main() {
136 if !(x == 4 && y) {}
137}
138```
139
3## `convert_to_guarded_return` 140## `convert_to_guarded_return`
4 141
5Replace a large conditional with a guarded return. 142Replace a large conditional with a guarded return.
diff --git a/docs/user/features.md b/docs/user/features.md
index a94b65ad4..acf092cec 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -104,84 +104,6 @@ the VS Code side to be able to position cursor. `<|>` signifies cursor
104 104
105See [assists.md](./assists.md) 105See [assists.md](./assists.md)
106 106
107- Add `#[derive]`
108
109```rust
110// before:
111struct Foo {
112 <|>x: i32
113}
114// after:
115#[derive(<|>)]
116struct Foo {
117 x: i32
118}
119```
120
121- Add `impl`
122
123```rust
124// before:
125struct Foo<'a, T: Debug> {
126 <|>t: T
127}
128// after:
129struct Foo<'a, T: Debug> {
130 t: T
131}
132
133impl<'a, T: Debug> Foo<'a, T> {
134 <|>
135}
136```
137
138- Add missing `impl` members
139
140```rust
141// before:
142trait Foo {
143 fn foo(&self);
144 fn bar(&self);
145 fn baz(&self);
146}
147
148struct S;
149
150impl Foo for S {
151 fn bar(&self) {}
152 <|>
153}
154
155// after:
156trait Foo {
157 fn foo(&self);
158 fn bar(&self);
159 fn baz(&self);
160}
161
162struct S;
163
164impl Foo for S {
165 fn bar(&self) {}
166 fn foo(&self) { unimplemented!() }
167 fn baz(&self) { unimplemented!() }<|>
168}
169```
170
171- Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws)
172
173```rust
174// before:
175fn example(x: bool) -> bool {
176 !x || !x
177}
178
179// after:
180fn example(x: bool) -> bool {
181 !(x && x)
182}
183```
184
185- Import path 107- Import path
186 108
187```rust 109```rust
@@ -391,19 +313,6 @@ fn foo() {
391} 313}
392``` 314```
393 315
394- Add explicit type
395
396```rust
397// before:
398fn foo() {
399 let t<|> = (&2, Some(1));
400}
401// after:
402fn foo() {
403 let t<|>: (&i32, Option<i32>) = (&2, Some(1));
404}
405```
406
407- Move guard expression to match arm body 316- Move guard expression to match arm body
408```rust 317```rust
409// before: 318// before:
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index 44729cd57..4ec8ab75a 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -74,6 +74,14 @@ fn reformat(text: impl std::fmt::Display) -> Result<String> {
74} 74}
75 75
76fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> { 76fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> {
77 do_extract_comment_blocks(text, false)
78}
79
80fn extract_comment_blocks_with_empty_lines(text: &str) -> Vec<Vec<String>> {
81 do_extract_comment_blocks(text, true)
82}
83
84fn do_extract_comment_blocks(text: &str, allow_blocks_with_empty_lins: bool) -> Vec<Vec<String>> {
77 let mut res = Vec::new(); 85 let mut res = Vec::new();
78 86
79 let prefix = "// "; 87 let prefix = "// ";
@@ -81,6 +89,11 @@ fn extract_comment_blocks(text: &str) -> Vec<Vec<String>> {
81 89
82 let mut block = vec![]; 90 let mut block = vec![];
83 for line in lines { 91 for line in lines {
92 if line == "//" && allow_blocks_with_empty_lins {
93 block.push(String::new());
94 continue;
95 }
96
84 let is_comment = line.starts_with(prefix); 97 let is_comment = line.starts_with(prefix);
85 if is_comment { 98 if is_comment {
86 block.push(line[prefix.len()..].to_string()); 99 block.push(line[prefix.len()..].to_string());
diff --git a/xtask/src/codegen/gen_assists_docs.rs b/xtask/src/codegen/gen_assists_docs.rs
index 654ae09d6..e313820d1 100644
--- a/xtask/src/codegen/gen_assists_docs.rs
+++ b/xtask/src/codegen/gen_assists_docs.rs
@@ -1,7 +1,7 @@
1use std::{fs, path::Path}; 1use std::{fs, path::Path};
2 2
3use crate::{ 3use crate::{
4 codegen::{self, extract_comment_blocks, Mode}, 4 codegen::{self, extract_comment_blocks_with_empty_lines, Mode},
5 project_root, Result, 5 project_root, Result,
6}; 6};
7 7
@@ -34,7 +34,7 @@ fn collect_assists() -> Result<Vec<Assist>> {
34 34
35 fn collect_file(acc: &mut Vec<Assist>, path: &Path) -> Result<()> { 35 fn collect_file(acc: &mut Vec<Assist>, path: &Path) -> Result<()> {
36 let text = fs::read_to_string(path)?; 36 let text = fs::read_to_string(path)?;
37 let comment_blocks = extract_comment_blocks(&text); 37 let comment_blocks = extract_comment_blocks_with_empty_lines(&text);
38 38
39 for block in comment_blocks { 39 for block in comment_blocks {
40 // FIXME: doesn't support blank lines yet, need to tweak 40 // FIXME: doesn't support blank lines yet, need to tweak
@@ -45,7 +45,11 @@ fn collect_assists() -> Result<Vec<Assist>> {
45 continue; 45 continue;
46 } 46 }
47 let id = first_line["Assist: ".len()..].to_string(); 47 let id = first_line["Assist: ".len()..].to_string();
48 assert!(id.chars().all(|it| it.is_ascii_lowercase() || it == '_')); 48 assert!(
49 id.chars().all(|it| it.is_ascii_lowercase() || it == '_'),
50 "invalid assist id: {:?}",
51 id
52 );
49 53
50 let doc = take_until(lines.by_ref(), "```"); 54 let doc = take_until(lines.by_ref(), "```");
51 let before = take_until(lines.by_ref(), "```"); 55 let before = take_until(lines.by_ref(), "```");