diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/lib.rs | 5 | ||||
-rw-r--r-- | crates/ra_assists/src/raw_string.rs | 370 |
2 files changed, 375 insertions, 0 deletions
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 66cf32524..756acf415 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -96,6 +96,7 @@ mod fill_match_arms; | |||
96 | mod merge_match_arms; | 96 | mod merge_match_arms; |
97 | mod introduce_variable; | 97 | mod introduce_variable; |
98 | mod inline_local_variable; | 98 | mod inline_local_variable; |
99 | mod raw_string; | ||
99 | mod replace_if_let_with_match; | 100 | mod replace_if_let_with_match; |
100 | mod split_import; | 101 | mod split_import; |
101 | mod remove_dbg; | 102 | mod remove_dbg; |
@@ -125,6 +126,10 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis | |||
125 | move_guard::move_guard_to_arm_body, | 126 | move_guard::move_guard_to_arm_body, |
126 | move_guard::move_arm_cond_to_match_guard, | 127 | move_guard::move_arm_cond_to_match_guard, |
127 | move_bounds::move_bounds_to_where_clause, | 128 | move_bounds::move_bounds_to_where_clause, |
129 | raw_string::add_hash, | ||
130 | raw_string::make_raw_string, | ||
131 | raw_string::make_usual_string, | ||
132 | raw_string::remove_hash, | ||
128 | ] | 133 | ] |
129 | } | 134 | } |
130 | 135 | ||
diff --git a/crates/ra_assists/src/raw_string.rs b/crates/ra_assists/src/raw_string.rs new file mode 100644 index 000000000..e00267060 --- /dev/null +++ b/crates/ra_assists/src/raw_string.rs | |||
@@ -0,0 +1,370 @@ | |||
1 | use hir::db::HirDatabase; | ||
2 | use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; | ||
3 | |||
4 | use crate::{Assist, AssistCtx, AssistId}; | ||
5 | |||
6 | pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
7 | let literal = ctx.node_at_offset::<Literal>()?; | ||
8 | if literal.token().kind() != ra_syntax::SyntaxKind::STRING { | ||
9 | return None; | ||
10 | } | ||
11 | ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| { | ||
12 | edit.target(literal.syntax().text_range()); | ||
13 | edit.insert(literal.syntax().text_range().start(), "r"); | ||
14 | }); | ||
15 | ctx.build() | ||
16 | } | ||
17 | |||
18 | fn find_usual_string_range(s: &str) -> Option<TextRange> { | ||
19 | Some(TextRange::from_to( | ||
20 | TextUnit::from(s.find('"')? as u32), | ||
21 | TextUnit::from(s.rfind('"')? as u32), | ||
22 | )) | ||
23 | } | ||
24 | |||
25 | pub(crate) fn make_usual_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
26 | let literal = ctx.node_at_offset::<Literal>()?; | ||
27 | if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { | ||
28 | return None; | ||
29 | } | ||
30 | let token = literal.token(); | ||
31 | let text = token.text().as_str(); | ||
32 | let usual_string_range = find_usual_string_range(text)?; | ||
33 | ctx.add_action(AssistId("make_usual_string"), "make usual string", |edit| { | ||
34 | edit.target(literal.syntax().text_range()); | ||
35 | // parse inside string to escape `"` | ||
36 | let start_of_inside = usual_string_range.start().to_usize() + 1; | ||
37 | let end_of_inside = usual_string_range.end().to_usize(); | ||
38 | let inside_str = &text[start_of_inside..end_of_inside]; | ||
39 | let escaped = inside_str.escape_default().to_string(); | ||
40 | edit.replace(literal.syntax().text_range(), format!("\"{}\"", escaped)); | ||
41 | }); | ||
42 | ctx.build() | ||
43 | } | ||
44 | |||
45 | pub(crate) fn add_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
46 | let literal = ctx.node_at_offset::<Literal>()?; | ||
47 | if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { | ||
48 | return None; | ||
49 | } | ||
50 | ctx.add_action(AssistId("add_hash"), "add hash to raw string", |edit| { | ||
51 | edit.target(literal.syntax().text_range()); | ||
52 | edit.insert(literal.syntax().text_range().start() + TextUnit::of_char('r'), "#"); | ||
53 | edit.insert(literal.syntax().text_range().end(), "#"); | ||
54 | }); | ||
55 | ctx.build() | ||
56 | } | ||
57 | |||
58 | pub(crate) fn remove_hash(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
59 | let literal = ctx.node_at_offset::<Literal>()?; | ||
60 | if literal.token().kind() != ra_syntax::SyntaxKind::RAW_STRING { | ||
61 | return None; | ||
62 | } | ||
63 | let token = literal.token(); | ||
64 | let text = token.text().as_str(); | ||
65 | if text.starts_with("r\"") { | ||
66 | // no hash to remove | ||
67 | return None; | ||
68 | } | ||
69 | ctx.add_action(AssistId("remove_hash"), "remove hash from raw string", |edit| { | ||
70 | edit.target(literal.syntax().text_range()); | ||
71 | let result = &text[2..text.len() - 1]; | ||
72 | let result = if result.starts_with("\"") { | ||
73 | // no more hash, escape | ||
74 | let internal_str = &result[1..result.len() - 1]; | ||
75 | format!("\"{}\"", internal_str.escape_default().to_string()) | ||
76 | } else { | ||
77 | result.to_owned() | ||
78 | }; | ||
79 | edit.replace(literal.syntax().text_range(), format!("r{}", result)); | ||
80 | }); | ||
81 | ctx.build() | ||
82 | } | ||
83 | |||
84 | #[cfg(test)] | ||
85 | mod test { | ||
86 | use super::*; | ||
87 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | ||
88 | |||
89 | #[test] | ||
90 | fn make_raw_string_target() { | ||
91 | check_assist_target( | ||
92 | make_raw_string, | ||
93 | r#" | ||
94 | fn f() { | ||
95 | let s = <|>"random string"; | ||
96 | } | ||
97 | "#, | ||
98 | r#""random string""#, | ||
99 | ); | ||
100 | } | ||
101 | |||
102 | #[test] | ||
103 | fn make_raw_string_works() { | ||
104 | check_assist( | ||
105 | make_raw_string, | ||
106 | r#" | ||
107 | fn f() { | ||
108 | let s = <|>"random string"; | ||
109 | } | ||
110 | "#, | ||
111 | r#" | ||
112 | fn f() { | ||
113 | let s = <|>r"random string"; | ||
114 | } | ||
115 | "#, | ||
116 | ) | ||
117 | } | ||
118 | |||
119 | #[test] | ||
120 | fn make_raw_string_with_escaped_works() { | ||
121 | check_assist( | ||
122 | make_raw_string, | ||
123 | r#" | ||
124 | fn f() { | ||
125 | let s = <|>"random\nstring"; | ||
126 | } | ||
127 | "#, | ||
128 | r#" | ||
129 | fn f() { | ||
130 | let s = <|>r"random\nstring"; | ||
131 | } | ||
132 | "#, | ||
133 | ) | ||
134 | } | ||
135 | |||
136 | #[test] | ||
137 | fn make_raw_string_not_works() { | ||
138 | check_assist_not_applicable( | ||
139 | make_raw_string, | ||
140 | r#" | ||
141 | fn f() { | ||
142 | let s = <|>r"random string"; | ||
143 | } | ||
144 | "#, | ||
145 | ); | ||
146 | } | ||
147 | |||
148 | #[test] | ||
149 | fn add_hash_target() { | ||
150 | check_assist_target( | ||
151 | add_hash, | ||
152 | r#" | ||
153 | fn f() { | ||
154 | let s = <|>r"random string"; | ||
155 | } | ||
156 | "#, | ||
157 | r#"r"random string""#, | ||
158 | ); | ||
159 | } | ||
160 | |||
161 | #[test] | ||
162 | fn add_hash_works() { | ||
163 | check_assist( | ||
164 | add_hash, | ||
165 | r#" | ||
166 | fn f() { | ||
167 | let s = <|>r"random string"; | ||
168 | } | ||
169 | "#, | ||
170 | r##" | ||
171 | fn f() { | ||
172 | let s = <|>r#"random string"#; | ||
173 | } | ||
174 | "##, | ||
175 | ) | ||
176 | } | ||
177 | |||
178 | #[test] | ||
179 | fn add_more_hash_works() { | ||
180 | check_assist( | ||
181 | add_hash, | ||
182 | r##" | ||
183 | fn f() { | ||
184 | let s = <|>r#"random"string"#; | ||
185 | } | ||
186 | "##, | ||
187 | r###" | ||
188 | fn f() { | ||
189 | let s = <|>r##"random"string"##; | ||
190 | } | ||
191 | "###, | ||
192 | ) | ||
193 | } | ||
194 | |||
195 | #[test] | ||
196 | fn add_hash_not_works() { | ||
197 | check_assist_not_applicable( | ||
198 | add_hash, | ||
199 | r#" | ||
200 | fn f() { | ||
201 | let s = <|>"random string"; | ||
202 | } | ||
203 | "#, | ||
204 | ); | ||
205 | } | ||
206 | |||
207 | #[test] | ||
208 | fn remove_hash_target() { | ||
209 | check_assist_target( | ||
210 | remove_hash, | ||
211 | r##" | ||
212 | fn f() { | ||
213 | let s = <|>r#"random string"#; | ||
214 | } | ||
215 | "##, | ||
216 | r##"r#"random string"#"##, | ||
217 | ); | ||
218 | } | ||
219 | |||
220 | #[test] | ||
221 | fn remove_hash_works() { | ||
222 | check_assist( | ||
223 | remove_hash, | ||
224 | r##" | ||
225 | fn f() { | ||
226 | let s = <|>r#"random string"#; | ||
227 | } | ||
228 | "##, | ||
229 | r#" | ||
230 | fn f() { | ||
231 | let s = <|>r"random string"; | ||
232 | } | ||
233 | "#, | ||
234 | ) | ||
235 | } | ||
236 | |||
237 | #[test] | ||
238 | fn remove_hash_with_quote_works() { | ||
239 | check_assist( | ||
240 | remove_hash, | ||
241 | r##" | ||
242 | fn f() { | ||
243 | let s = <|>r#"random"str"ing"#; | ||
244 | } | ||
245 | "##, | ||
246 | r#" | ||
247 | fn f() { | ||
248 | let s = <|>r"random\"str\"ing"; | ||
249 | } | ||
250 | "#, | ||
251 | ) | ||
252 | } | ||
253 | |||
254 | #[test] | ||
255 | fn remove_more_hash_works() { | ||
256 | check_assist( | ||
257 | remove_hash, | ||
258 | r###" | ||
259 | fn f() { | ||
260 | let s = <|>r##"random string"##; | ||
261 | } | ||
262 | "###, | ||
263 | r##" | ||
264 | fn f() { | ||
265 | let s = <|>r#"random string"#; | ||
266 | } | ||
267 | "##, | ||
268 | ) | ||
269 | } | ||
270 | |||
271 | #[test] | ||
272 | fn remove_hash_not_works() { | ||
273 | check_assist_not_applicable( | ||
274 | remove_hash, | ||
275 | r#" | ||
276 | fn f() { | ||
277 | let s = <|>"random string"; | ||
278 | } | ||
279 | "#, | ||
280 | ); | ||
281 | } | ||
282 | |||
283 | #[test] | ||
284 | fn remove_hash_no_hash_not_works() { | ||
285 | check_assist_not_applicable( | ||
286 | remove_hash, | ||
287 | r#" | ||
288 | fn f() { | ||
289 | let s = <|>r"random string"; | ||
290 | } | ||
291 | "#, | ||
292 | ); | ||
293 | } | ||
294 | |||
295 | #[test] | ||
296 | fn make_usual_string_target() { | ||
297 | check_assist_target( | ||
298 | make_usual_string, | ||
299 | r##" | ||
300 | fn f() { | ||
301 | let s = <|>r#"random string"#; | ||
302 | } | ||
303 | "##, | ||
304 | r##"r#"random string"#"##, | ||
305 | ); | ||
306 | } | ||
307 | |||
308 | #[test] | ||
309 | fn make_usual_string_works() { | ||
310 | check_assist( | ||
311 | make_usual_string, | ||
312 | r##" | ||
313 | fn f() { | ||
314 | let s = <|>r#"random string"#; | ||
315 | } | ||
316 | "##, | ||
317 | r#" | ||
318 | fn f() { | ||
319 | let s = <|>"random string"; | ||
320 | } | ||
321 | "#, | ||
322 | ) | ||
323 | } | ||
324 | |||
325 | #[test] | ||
326 | fn make_usual_string_with_quote_works() { | ||
327 | check_assist( | ||
328 | make_usual_string, | ||
329 | r##" | ||
330 | fn f() { | ||
331 | let s = <|>r#"random"str"ing"#; | ||
332 | } | ||
333 | "##, | ||
334 | r#" | ||
335 | fn f() { | ||
336 | let s = <|>"random\"str\"ing"; | ||
337 | } | ||
338 | "#, | ||
339 | ) | ||
340 | } | ||
341 | |||
342 | #[test] | ||
343 | fn make_usual_string_more_hash_works() { | ||
344 | check_assist( | ||
345 | make_usual_string, | ||
346 | r###" | ||
347 | fn f() { | ||
348 | let s = <|>r##"random string"##; | ||
349 | } | ||
350 | "###, | ||
351 | r##" | ||
352 | fn f() { | ||
353 | let s = <|>"random string"; | ||
354 | } | ||
355 | "##, | ||
356 | ) | ||
357 | } | ||
358 | |||
359 | #[test] | ||
360 | fn make_usual_string_not_works() { | ||
361 | check_assist_not_applicable( | ||
362 | make_usual_string, | ||
363 | r#" | ||
364 | fn f() { | ||
365 | let s = <|>"random string"; | ||
366 | } | ||
367 | "#, | ||
368 | ); | ||
369 | } | ||
370 | } | ||