diff options
author | Aleksey Kladov <[email protected]> | 2019-01-03 15:59:17 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2019-01-03 15:59:17 +0000 |
commit | a4635a199bc446bd103aa5821e57dc19b8a15751 (patch) | |
tree | 5dcdd940d8627f021062245cb79589a790b60e04 /crates/ra_editor/src/assists/add_derive.rs | |
parent | aea2183799e7975d3d9000cec9bb9a3c001a3d4e (diff) |
more enterprisey assists API
Diffstat (limited to 'crates/ra_editor/src/assists/add_derive.rs')
-rw-r--r-- | crates/ra_editor/src/assists/add_derive.rs | 61 |
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 @@ | |||
1 | use ra_text_edit::TextEditBuilder; | ||
2 | use ra_syntax::{ | 1 | use 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 | ||
9 | use crate::{ | 7 | use crate::assists::{AssistCtx, Assist}; |
10 | find_node_at_offset, | ||
11 | assists::LocalEdit, | ||
12 | }; | ||
13 | 8 | ||
14 | pub fn add_derive<'a>( | 9 | pub 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> { | 31 | fn 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)] |
53 | mod tests { | 40 | mod 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(<|>)] |
92 | struct Foo { a: i32, } | 80 | struct Foo { a: i32, } |
93 | ", | 81 | ", |
94 | |file, off| add_derive(file, off).map(|f| f()), | ||
95 | ); | 82 | ); |
96 | } | 83 | } |
97 | } | 84 | } |