aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src')
-rw-r--r--crates/ra_editor/src/code_actions.rs41
1 files changed, 36 insertions, 5 deletions
diff --git a/crates/ra_editor/src/code_actions.rs b/crates/ra_editor/src/code_actions.rs
index 0139b19d3..37e963bbd 100644
--- a/crates/ra_editor/src/code_actions.rs
+++ b/crates/ra_editor/src/code_actions.rs
@@ -4,7 +4,7 @@ use ra_syntax::{
4 algo::{find_covering_node, find_leaf_at_offset}, 4 algo::{find_covering_node, find_leaf_at_offset},
5 ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner}, 5 ast::{self, AstNode, AttrsOwner, NameOwner, TypeParamsOwner},
6 Direction, SourceFileNode, 6 Direction, SourceFileNode,
7 SyntaxKind::{COMMA, WHITESPACE}, 7 SyntaxKind::{COMMA, WHITESPACE, COMMENT},
8 SyntaxNodeRef, TextRange, TextUnit, 8 SyntaxNodeRef, TextRange, TextUnit,
9}; 9};
10 10
@@ -41,7 +41,8 @@ pub fn add_derive<'a>(
41 offset: TextUnit, 41 offset: TextUnit,
42) -> Option<impl FnOnce() -> LocalEdit + 'a> { 42) -> Option<impl FnOnce() -> LocalEdit + 'a> {
43 let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?; 43 let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
44 Some(move || { 44 let node_start = derive_insertion_offset(nominal)?;
45 return Some(move || {
45 let derive_attr = nominal 46 let derive_attr = nominal
46 .attrs() 47 .attrs()
47 .filter_map(|x| x.as_call()) 48 .filter_map(|x| x.as_call())
@@ -51,7 +52,6 @@ pub fn add_derive<'a>(
51 let mut edit = EditBuilder::new(); 52 let mut edit = EditBuilder::new();
52 let offset = match derive_attr { 53 let offset = match derive_attr {
53 None => { 54 None => {
54 let node_start = nominal.syntax().range().start();
55 edit.insert(node_start, "#[derive()]\n".to_string()); 55 edit.insert(node_start, "#[derive()]\n".to_string());
56 node_start + TextUnit::of_str("#[derive(") 56 node_start + TextUnit::of_str("#[derive(")
57 } 57 }
@@ -61,7 +61,16 @@ pub fn add_derive<'a>(
61 edit: edit.finish(), 61 edit: edit.finish(),
62 cursor_position: Some(offset), 62 cursor_position: Some(offset),
63 } 63 }
64 }) 64 });
65
66 // Insert `derive` after doc comments.
67 fn derive_insertion_offset(nominal: ast::NominalDef) -> Option<TextUnit> {
68 let non_ws_child = nominal
69 .syntax()
70 .children()
71 .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?;
72 Some(non_ws_child.range().start())
73 }
65} 74}
66 75
67pub fn add_impl<'a>( 76pub fn add_impl<'a>(
@@ -181,7 +190,7 @@ mod tests {
181 } 190 }
182 191
183 #[test] 192 #[test]
184 fn test_add_derive() { 193 fn add_derive_new() {
185 check_action( 194 check_action(
186 "struct Foo { a: i32, <|>}", 195 "struct Foo { a: i32, <|>}",
187 "#[derive(<|>)]\nstruct Foo { a: i32, }", 196 "#[derive(<|>)]\nstruct Foo { a: i32, }",
@@ -192,6 +201,10 @@ mod tests {
192 "#[derive(<|>)]\nstruct Foo { a: i32, }", 201 "#[derive(<|>)]\nstruct Foo { a: i32, }",
193 |file, off| add_derive(file, off).map(|f| f()), 202 |file, off| add_derive(file, off).map(|f| f()),
194 ); 203 );
204 }
205
206 #[test]
207 fn add_derive_existing() {
195 check_action( 208 check_action(
196 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }", 209 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
197 "#[derive(Clone<|>)]\nstruct Foo { a: i32, }", 210 "#[derive(Clone<|>)]\nstruct Foo { a: i32, }",
@@ -200,6 +213,24 @@ mod tests {
200 } 213 }
201 214
202 #[test] 215 #[test]
216 fn add_derive_new_with_doc_comment() {
217 check_action(
218 "
219/// `Foo` is a pretty important struct.
220/// It does stuff.
221struct Foo { a: i32<|>, }
222 ",
223 "
224/// `Foo` is a pretty important struct.
225/// It does stuff.
226#[derive(<|>)]
227struct Foo { a: i32, }
228 ",
229 |file, off| add_derive(file, off).map(|f| f()),
230 );
231 }
232
233 #[test]
203 fn test_add_impl() { 234 fn test_add_impl() {
204 check_action( 235 check_action(
205 "struct Foo {<|>}\n", 236 "struct Foo {<|>}\n",