aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_editor/src/assists/add_derive.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_editor/src/assists/add_derive.rs')
-rw-r--r--crates/ra_editor/src/assists/add_derive.rs61
1 files changed, 24 insertions, 37 deletions
diff --git a/crates/ra_editor/src/assists/add_derive.rs b/crates/ra_editor/src/assists/add_derive.rs
index 33d9d2c31..1e2cd4f30 100644
--- a/crates/ra_editor/src/assists/add_derive.rs
+++ b/crates/ra_editor/src/assists/add_derive.rs
@@ -1,85 +1,73 @@
1use ra_text_edit::TextEditBuilder;
2use ra_syntax::{ 1use ra_syntax::{
3 ast::{self, AstNode, AttrsOwner}, 2 ast::{self, AstNode, AttrsOwner},
4 SourceFileNode,
5 SyntaxKind::{WHITESPACE, COMMENT}, 3 SyntaxKind::{WHITESPACE, COMMENT},
6 TextUnit, 4 TextUnit,
7}; 5};
8 6
9use crate::{ 7use crate::assists::{AssistCtx, Assist};
10 find_node_at_offset,
11 assists::LocalEdit,
12};
13 8
14pub fn add_derive<'a>( 9pub fn add_derive(ctx: AssistCtx) -> Option<Assist> {
15 file: &'a SourceFileNode, 10 let nominal = ctx.node_at_offset::<ast::NominalDef>()?;
16 offset: TextUnit,
17) -> Option<impl FnOnce() -> LocalEdit + 'a> {
18 let nominal = find_node_at_offset::<ast::NominalDef>(file.syntax(), offset)?;
19 let node_start = derive_insertion_offset(nominal)?; 11 let node_start = derive_insertion_offset(nominal)?;
20 return Some(move || { 12 ctx.build("add `#[derive]`", |edit| {
21 let derive_attr = nominal 13 let derive_attr = nominal
22 .attrs() 14 .attrs()
23 .filter_map(|x| x.as_call()) 15 .filter_map(|x| x.as_call())
24 .filter(|(name, _arg)| name == "derive") 16 .filter(|(name, _arg)| name == "derive")
25 .map(|(_name, arg)| arg) 17 .map(|(_name, arg)| arg)
26 .next(); 18 .next();
27 let mut edit = TextEditBuilder::new();
28 let offset = match derive_attr { 19 let offset = match derive_attr {
29 None => { 20 None => {
30 edit.insert(node_start, "#[derive()]\n".to_string()); 21 edit.insert(node_start, "#[derive()]\n");
31 node_start + TextUnit::of_str("#[derive(") 22 node_start + TextUnit::of_str("#[derive(")
32 } 23 }
33 Some(tt) => tt.syntax().range().end() - TextUnit::of_char(')'), 24 Some(tt) => tt.syntax().range().end() - TextUnit::of_char(')'),
34 }; 25 };
35 LocalEdit { 26 edit.set_cursor(offset)
36 label: "add `#[derive]`".to_string(), 27 })
37 edit: edit.finish(), 28}
38 cursor_position: Some(offset),
39 }
40 });
41 29
42 // Insert `derive` after doc comments. 30// Insert `derive` after doc comments.
43 fn derive_insertion_offset(nominal: ast::NominalDef) -> Option<TextUnit> { 31fn derive_insertion_offset(nominal: ast::NominalDef) -> Option<TextUnit> {
44 let non_ws_child = nominal 32 let non_ws_child = nominal
45 .syntax() 33 .syntax()
46 .children() 34 .children()
47 .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?; 35 .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?;
48 Some(non_ws_child.range().start()) 36 Some(non_ws_child.range().start())
49 }
50} 37}
51 38
52#[cfg(test)] 39#[cfg(test)]
53mod tests { 40mod tests {
54 use super::*; 41 use super::*;
55 use crate::test_utils::check_action; 42 use crate::assists::check_assist;
56 43
57 #[test] 44 #[test]
58 fn add_derive_new() { 45 fn add_derive_new() {
59 check_action( 46 check_assist(
47 add_derive,
60 "struct Foo { a: i32, <|>}", 48 "struct Foo { a: i32, <|>}",
61 "#[derive(<|>)]\nstruct Foo { a: i32, }", 49 "#[derive(<|>)]\nstruct Foo { a: i32, }",
62 |file, off| add_derive(file, off).map(|f| f()),
63 ); 50 );
64 check_action( 51 check_assist(
52 add_derive,
65 "struct Foo { <|> a: i32, }", 53 "struct Foo { <|> a: i32, }",
66 "#[derive(<|>)]\nstruct Foo { a: i32, }", 54 "#[derive(<|>)]\nstruct Foo { a: i32, }",
67 |file, off| add_derive(file, off).map(|f| f()),
68 ); 55 );
69 } 56 }
70 57
71 #[test] 58 #[test]
72 fn add_derive_existing() { 59 fn add_derive_existing() {
73 check_action( 60 check_assist(
61 add_derive,
74 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }", 62 "#[derive(Clone)]\nstruct Foo { a: i32<|>, }",
75 "#[derive(Clone<|>)]\nstruct Foo { a: i32, }", 63 "#[derive(Clone<|>)]\nstruct Foo { a: i32, }",
76 |file, off| add_derive(file, off).map(|f| f()),
77 ); 64 );
78 } 65 }
79 66
80 #[test] 67 #[test]
81 fn add_derive_new_with_doc_comment() { 68 fn add_derive_new_with_doc_comment() {
82 check_action( 69 check_assist(
70 add_derive,
83 " 71 "
84/// `Foo` is a pretty important struct. 72/// `Foo` is a pretty important struct.
85/// It does stuff. 73/// It does stuff.
@@ -91,7 +79,6 @@ struct Foo { a: i32<|>, }
91#[derive(<|>)] 79#[derive(<|>)]
92struct Foo { a: i32, } 80struct Foo { a: i32, }
93 ", 81 ",
94 |file, off| add_derive(file, off).map(|f| f()),
95 ); 82 );
96 } 83 }
97} 84}