aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src/code_actions.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src/code_actions.rs')
-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 bc0e120d3..6979251d1 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>(
@@ -186,7 +195,7 @@ mod tests {
186 } 195 }
187 196
188 #[test] 197 #[test]
189 fn test_add_derive() { 198 fn add_derive_new() {
190 check_action( 199 check_action(
191 "struct Foo { a: i32, <|>}", 200 "struct Foo { a: i32, <|>}",
192 "#[derive(<|>)]\nstruct Foo { a: i32, }", 201 "#[derive(<|>)]\nstruct Foo { a: i32, }",
@@ -197,6 +206,10 @@ mod tests {
197 "#[derive(<|>)]\nstruct Foo { a: i32, }", 206 "#[derive(<|>)]\nstruct Foo { a: i32, }",
198 |file, off| add_derive(file, off).map(|f| f()), 207 |file, off| add_derive(file, off).map(|f| f()),
199 ); 208 );
209 }
210
211 #[test]
212 fn add_derive_existing() {
200 check_action( 213 check_action(
201 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }", 214 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
202 "#[derive(Clone<|>)]\nstruct Foo { a: i32, }", 215 "#[derive(Clone<|>)]\nstruct Foo { a: i32, }",
@@ -205,6 +218,24 @@ mod tests {
205 } 218 }
206 219
207 #[test] 220 #[test]
221 fn add_derive_new_with_doc_comment() {
222 check_action(
223 "
224/// `Foo` is a pretty important struct.
225/// It does stuff.
226struct Foo { a: i32<|>, }
227 ",
228 "
229/// `Foo` is a pretty important struct.
230/// It does stuff.
231#[derive(<|>)]
232struct Foo { a: i32, }
233 ",
234 |file, off| add_derive(file, off).map(|f| f()),
235 );
236 }
237
238 #[test]
208 fn test_add_impl() { 239 fn test_add_impl() {
209 check_action( 240 check_action(
210 "struct Foo {<|>}\n", 241 "struct Foo {<|>}\n",