diff options
author | Aleksey Kladov <[email protected]> | 2020-02-07 14:53:31 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-02-07 16:28:02 +0000 |
commit | 561b4b11ff1d87ea1ff2477dcba6ae1f396573a3 (patch) | |
tree | 0da58d08d5a2ff27f43c3eb6163ba9aced2f5782 /crates/ra_assists/src/assists/add_custom_impl.rs | |
parent | aa64a84b493aa9c0b22f36b472a445d622cd2172 (diff) |
Name assist handlers
Diffstat (limited to 'crates/ra_assists/src/assists/add_custom_impl.rs')
-rw-r--r-- | crates/ra_assists/src/assists/add_custom_impl.rs | 209 |
1 files changed, 0 insertions, 209 deletions
diff --git a/crates/ra_assists/src/assists/add_custom_impl.rs b/crates/ra_assists/src/assists/add_custom_impl.rs deleted file mode 100644 index 7fdd816bf..000000000 --- a/crates/ra_assists/src/assists/add_custom_impl.rs +++ /dev/null | |||
@@ -1,209 +0,0 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | use crate::{Assist, AssistCtx, AssistId}; | ||
4 | |||
5 | use join_to_string::join; | ||
6 | use ra_syntax::{ | ||
7 | ast::{self, AstNode}, | ||
8 | Direction, SmolStr, | ||
9 | SyntaxKind::{IDENT, WHITESPACE}, | ||
10 | TextRange, TextUnit, | ||
11 | }; | ||
12 | |||
13 | const DERIVE_TRAIT: &str = "derive"; | ||
14 | |||
15 | // Assist: add_custom_impl | ||
16 | // | ||
17 | // Adds impl block for derived trait. | ||
18 | // | ||
19 | // ``` | ||
20 | // #[derive(Deb<|>ug, Display)] | ||
21 | // struct S; | ||
22 | // ``` | ||
23 | // -> | ||
24 | // ``` | ||
25 | // #[derive(Display)] | ||
26 | // struct S; | ||
27 | // | ||
28 | // impl Debug for S { | ||
29 | // | ||
30 | // } | ||
31 | // ``` | ||
32 | pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> { | ||
33 | let input = ctx.find_node_at_offset::<ast::AttrInput>()?; | ||
34 | let attr = input.syntax().parent().and_then(ast::Attr::cast)?; | ||
35 | |||
36 | let attr_name = attr | ||
37 | .syntax() | ||
38 | .descendants_with_tokens() | ||
39 | .filter(|t| t.kind() == IDENT) | ||
40 | .find_map(|i| i.into_token()) | ||
41 | .filter(|t| *t.text() == DERIVE_TRAIT)? | ||
42 | .text() | ||
43 | .clone(); | ||
44 | |||
45 | let trait_token = | ||
46 | ctx.token_at_offset().filter(|t| t.kind() == IDENT && *t.text() != attr_name).next()?; | ||
47 | |||
48 | let annotated = attr.syntax().siblings(Direction::Next).find_map(|s| ast::Name::cast(s))?; | ||
49 | let annotated_name = annotated.syntax().text().to_string(); | ||
50 | let start_offset = annotated.syntax().parent()?.text_range().end(); | ||
51 | |||
52 | let label = | ||
53 | format!("Add custom impl '{}' for '{}'", trait_token.text().as_str(), annotated_name); | ||
54 | |||
55 | ctx.add_assist(AssistId("add_custom_impl"), label, |edit| { | ||
56 | edit.target(attr.syntax().text_range()); | ||
57 | |||
58 | let new_attr_input = input | ||
59 | .syntax() | ||
60 | .descendants_with_tokens() | ||
61 | .filter(|t| t.kind() == IDENT) | ||
62 | .filter_map(|t| t.into_token().map(|t| t.text().clone())) | ||
63 | .filter(|t| t != trait_token.text()) | ||
64 | .collect::<Vec<SmolStr>>(); | ||
65 | let has_more_derives = new_attr_input.len() > 0; | ||
66 | let new_attr_input = | ||
67 | join(new_attr_input.iter()).separator(", ").surround_with("(", ")").to_string(); | ||
68 | let new_attr_input_len = new_attr_input.len(); | ||
69 | |||
70 | let mut buf = String::new(); | ||
71 | buf.push_str("\n\nimpl "); | ||
72 | buf.push_str(trait_token.text().as_str()); | ||
73 | buf.push_str(" for "); | ||
74 | buf.push_str(annotated_name.as_str()); | ||
75 | buf.push_str(" {\n"); | ||
76 | |||
77 | let cursor_delta = if has_more_derives { | ||
78 | edit.replace(input.syntax().text_range(), new_attr_input); | ||
79 | input.syntax().text_range().len() - TextUnit::from_usize(new_attr_input_len) | ||
80 | } else { | ||
81 | let attr_range = attr.syntax().text_range(); | ||
82 | edit.delete(attr_range); | ||
83 | |||
84 | let line_break_range = attr | ||
85 | .syntax() | ||
86 | .next_sibling_or_token() | ||
87 | .filter(|t| t.kind() == WHITESPACE) | ||
88 | .map(|t| t.text_range()) | ||
89 | .unwrap_or(TextRange::from_to(TextUnit::from(0), TextUnit::from(0))); | ||
90 | edit.delete(line_break_range); | ||
91 | |||
92 | attr_range.len() + line_break_range.len() | ||
93 | }; | ||
94 | |||
95 | edit.set_cursor(start_offset + TextUnit::of_str(&buf) - cursor_delta); | ||
96 | buf.push_str("\n}"); | ||
97 | edit.insert(start_offset, buf); | ||
98 | }) | ||
99 | } | ||
100 | |||
101 | #[cfg(test)] | ||
102 | mod tests { | ||
103 | use super::*; | ||
104 | use crate::helpers::{check_assist, check_assist_not_applicable}; | ||
105 | |||
106 | #[test] | ||
107 | fn add_custom_impl_for_unique_input() { | ||
108 | check_assist( | ||
109 | add_custom_impl, | ||
110 | " | ||
111 | #[derive(Debu<|>g)] | ||
112 | struct Foo { | ||
113 | bar: String, | ||
114 | } | ||
115 | ", | ||
116 | " | ||
117 | struct Foo { | ||
118 | bar: String, | ||
119 | } | ||
120 | |||
121 | impl Debug for Foo { | ||
122 | <|> | ||
123 | } | ||
124 | ", | ||
125 | ) | ||
126 | } | ||
127 | |||
128 | #[test] | ||
129 | fn add_custom_impl_for_with_visibility_modifier() { | ||
130 | check_assist( | ||
131 | add_custom_impl, | ||
132 | " | ||
133 | #[derive(Debug<|>)] | ||
134 | pub struct Foo { | ||
135 | bar: String, | ||
136 | } | ||
137 | ", | ||
138 | " | ||
139 | pub struct Foo { | ||
140 | bar: String, | ||
141 | } | ||
142 | |||
143 | impl Debug for Foo { | ||
144 | <|> | ||
145 | } | ||
146 | ", | ||
147 | ) | ||
148 | } | ||
149 | |||
150 | #[test] | ||
151 | fn add_custom_impl_when_multiple_inputs() { | ||
152 | check_assist( | ||
153 | add_custom_impl, | ||
154 | " | ||
155 | #[derive(Display, Debug<|>, Serialize)] | ||
156 | struct Foo {} | ||
157 | ", | ||
158 | " | ||
159 | #[derive(Display, Serialize)] | ||
160 | struct Foo {} | ||
161 | |||
162 | impl Debug for Foo { | ||
163 | <|> | ||
164 | } | ||
165 | ", | ||
166 | ) | ||
167 | } | ||
168 | |||
169 | #[test] | ||
170 | fn test_ignore_derive_macro_without_input() { | ||
171 | check_assist_not_applicable( | ||
172 | add_custom_impl, | ||
173 | " | ||
174 | #[derive(<|>)] | ||
175 | struct Foo {} | ||
176 | ", | ||
177 | ) | ||
178 | } | ||
179 | |||
180 | #[test] | ||
181 | fn test_ignore_if_cursor_on_param() { | ||
182 | check_assist_not_applicable( | ||
183 | add_custom_impl, | ||
184 | " | ||
185 | #[derive<|>(Debug)] | ||
186 | struct Foo {} | ||
187 | ", | ||
188 | ); | ||
189 | |||
190 | check_assist_not_applicable( | ||
191 | add_custom_impl, | ||
192 | " | ||
193 | #[derive(Debug)<|>] | ||
194 | struct Foo {} | ||
195 | ", | ||
196 | ) | ||
197 | } | ||
198 | |||
199 | #[test] | ||
200 | fn test_ignore_if_not_derive() { | ||
201 | check_assist_not_applicable( | ||
202 | add_custom_impl, | ||
203 | " | ||
204 | #[allow(non_camel_<|>case_types)] | ||
205 | struct Foo {} | ||
206 | ", | ||
207 | ) | ||
208 | } | ||
209 | } | ||