diff options
author | Zac Pullar-Strecker <[email protected]> | 2020-08-24 10:19:53 +0100 |
---|---|---|
committer | Zac Pullar-Strecker <[email protected]> | 2020-08-24 10:20:13 +0100 |
commit | 7bbca7a1b3f9293d2f5cc5745199bc5f8396f2f0 (patch) | |
tree | bdb47765991cb973b2cd5481a088fac636bd326c /crates/assists/src/handlers/unwrap_block.rs | |
parent | ca464650eeaca6195891199a93f4f76cf3e7e697 (diff) | |
parent | e65d48d1fb3d4d91d9dc1148a7a836ff5c9a3c87 (diff) |
Merge remote-tracking branch 'upstream/master' into 503-hover-doc-links
Diffstat (limited to 'crates/assists/src/handlers/unwrap_block.rs')
-rw-r--r-- | crates/assists/src/handlers/unwrap_block.rs | 517 |
1 files changed, 517 insertions, 0 deletions
diff --git a/crates/assists/src/handlers/unwrap_block.rs b/crates/assists/src/handlers/unwrap_block.rs new file mode 100644 index 000000000..3851aeb3e --- /dev/null +++ b/crates/assists/src/handlers/unwrap_block.rs | |||
@@ -0,0 +1,517 @@ | |||
1 | use syntax::{ | ||
2 | ast::{ | ||
3 | self, | ||
4 | edit::{AstNodeEdit, IndentLevel}, | ||
5 | }, | ||
6 | AstNode, TextRange, T, | ||
7 | }; | ||
8 | |||
9 | use crate::{utils::unwrap_trivial_block, AssistContext, AssistId, AssistKind, Assists}; | ||
10 | |||
11 | // Assist: unwrap_block | ||
12 | // | ||
13 | // This assist removes if...else, for, while and loop control statements to just keep the body. | ||
14 | // | ||
15 | // ``` | ||
16 | // fn foo() { | ||
17 | // if true {<|> | ||
18 | // println!("foo"); | ||
19 | // } | ||
20 | // } | ||
21 | // ``` | ||
22 | // -> | ||
23 | // ``` | ||
24 | // fn foo() { | ||
25 | // println!("foo"); | ||
26 | // } | ||
27 | // ``` | ||
28 | pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
29 | let assist_id = AssistId("unwrap_block", AssistKind::RefactorRewrite); | ||
30 | let assist_label = "Unwrap block"; | ||
31 | |||
32 | let l_curly_token = ctx.find_token_at_offset(T!['{'])?; | ||
33 | let mut block = ast::BlockExpr::cast(l_curly_token.parent())?; | ||
34 | let mut parent = block.syntax().parent()?; | ||
35 | if ast::MatchArm::can_cast(parent.kind()) { | ||
36 | parent = parent.ancestors().find(|it| ast::MatchExpr::can_cast(it.kind()))? | ||
37 | } | ||
38 | |||
39 | let parent = ast::Expr::cast(parent)?; | ||
40 | |||
41 | match parent.clone() { | ||
42 | ast::Expr::ForExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::LoopExpr(_) => (), | ||
43 | ast::Expr::MatchExpr(_) => block = block.dedent(IndentLevel(1)), | ||
44 | ast::Expr::IfExpr(if_expr) => { | ||
45 | let then_branch = if_expr.then_branch()?; | ||
46 | if then_branch == block { | ||
47 | if let Some(ancestor) = if_expr.syntax().parent().and_then(ast::IfExpr::cast) { | ||
48 | // For `else if` blocks | ||
49 | let ancestor_then_branch = ancestor.then_branch()?; | ||
50 | |||
51 | let target = then_branch.syntax().text_range(); | ||
52 | return acc.add(assist_id, assist_label, target, |edit| { | ||
53 | let range_to_del_else_if = TextRange::new( | ||
54 | ancestor_then_branch.syntax().text_range().end(), | ||
55 | l_curly_token.text_range().start(), | ||
56 | ); | ||
57 | let range_to_del_rest = TextRange::new( | ||
58 | then_branch.syntax().text_range().end(), | ||
59 | if_expr.syntax().text_range().end(), | ||
60 | ); | ||
61 | |||
62 | edit.delete(range_to_del_rest); | ||
63 | edit.delete(range_to_del_else_if); | ||
64 | edit.replace( | ||
65 | target, | ||
66 | update_expr_string(then_branch.to_string(), &[' ', '{']), | ||
67 | ); | ||
68 | }); | ||
69 | } | ||
70 | } else { | ||
71 | let target = block.syntax().text_range(); | ||
72 | return acc.add(assist_id, assist_label, target, |edit| { | ||
73 | let range_to_del = TextRange::new( | ||
74 | then_branch.syntax().text_range().end(), | ||
75 | l_curly_token.text_range().start(), | ||
76 | ); | ||
77 | |||
78 | edit.delete(range_to_del); | ||
79 | edit.replace(target, update_expr_string(block.to_string(), &[' ', '{'])); | ||
80 | }); | ||
81 | } | ||
82 | } | ||
83 | _ => return None, | ||
84 | }; | ||
85 | |||
86 | let unwrapped = unwrap_trivial_block(block); | ||
87 | let target = unwrapped.syntax().text_range(); | ||
88 | acc.add(assist_id, assist_label, target, |builder| { | ||
89 | builder.replace( | ||
90 | parent.syntax().text_range(), | ||
91 | update_expr_string(unwrapped.to_string(), &[' ', '{', '\n']), | ||
92 | ); | ||
93 | }) | ||
94 | } | ||
95 | |||
96 | fn update_expr_string(expr_str: String, trim_start_pat: &[char]) -> String { | ||
97 | let expr_string = expr_str.trim_start_matches(trim_start_pat); | ||
98 | let mut expr_string_lines: Vec<&str> = expr_string.lines().collect(); | ||
99 | expr_string_lines.pop(); // Delete last line | ||
100 | |||
101 | expr_string_lines | ||
102 | .into_iter() | ||
103 | .map(|line| line.replacen(" ", "", 1)) // Delete indentation | ||
104 | .collect::<Vec<String>>() | ||
105 | .join("\n") | ||
106 | } | ||
107 | |||
108 | #[cfg(test)] | ||
109 | mod tests { | ||
110 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
111 | |||
112 | use super::*; | ||
113 | |||
114 | #[test] | ||
115 | fn simple_if() { | ||
116 | check_assist( | ||
117 | unwrap_block, | ||
118 | r#" | ||
119 | fn main() { | ||
120 | bar(); | ||
121 | if true {<|> | ||
122 | foo(); | ||
123 | |||
124 | //comment | ||
125 | bar(); | ||
126 | } else { | ||
127 | println!("bar"); | ||
128 | } | ||
129 | } | ||
130 | "#, | ||
131 | r#" | ||
132 | fn main() { | ||
133 | bar(); | ||
134 | foo(); | ||
135 | |||
136 | //comment | ||
137 | bar(); | ||
138 | } | ||
139 | "#, | ||
140 | ); | ||
141 | } | ||
142 | |||
143 | #[test] | ||
144 | fn simple_if_else() { | ||
145 | check_assist( | ||
146 | unwrap_block, | ||
147 | r#" | ||
148 | fn main() { | ||
149 | bar(); | ||
150 | if true { | ||
151 | foo(); | ||
152 | |||
153 | //comment | ||
154 | bar(); | ||
155 | } else {<|> | ||
156 | println!("bar"); | ||
157 | } | ||
158 | } | ||
159 | "#, | ||
160 | r#" | ||
161 | fn main() { | ||
162 | bar(); | ||
163 | if true { | ||
164 | foo(); | ||
165 | |||
166 | //comment | ||
167 | bar(); | ||
168 | } | ||
169 | println!("bar"); | ||
170 | } | ||
171 | "#, | ||
172 | ); | ||
173 | } | ||
174 | |||
175 | #[test] | ||
176 | fn simple_if_else_if() { | ||
177 | check_assist( | ||
178 | unwrap_block, | ||
179 | r#" | ||
180 | fn main() { | ||
181 | //bar(); | ||
182 | if true { | ||
183 | println!("true"); | ||
184 | |||
185 | //comment | ||
186 | //bar(); | ||
187 | } else if false {<|> | ||
188 | println!("bar"); | ||
189 | } else { | ||
190 | println!("foo"); | ||
191 | } | ||
192 | } | ||
193 | "#, | ||
194 | r#" | ||
195 | fn main() { | ||
196 | //bar(); | ||
197 | if true { | ||
198 | println!("true"); | ||
199 | |||
200 | //comment | ||
201 | //bar(); | ||
202 | } | ||
203 | println!("bar"); | ||
204 | } | ||
205 | "#, | ||
206 | ); | ||
207 | } | ||
208 | |||
209 | #[test] | ||
210 | fn simple_if_else_if_nested() { | ||
211 | check_assist( | ||
212 | unwrap_block, | ||
213 | r#" | ||
214 | fn main() { | ||
215 | //bar(); | ||
216 | if true { | ||
217 | println!("true"); | ||
218 | |||
219 | //comment | ||
220 | //bar(); | ||
221 | } else if false { | ||
222 | println!("bar"); | ||
223 | } else if true {<|> | ||
224 | println!("foo"); | ||
225 | } | ||
226 | } | ||
227 | "#, | ||
228 | r#" | ||
229 | fn main() { | ||
230 | //bar(); | ||
231 | if true { | ||
232 | println!("true"); | ||
233 | |||
234 | //comment | ||
235 | //bar(); | ||
236 | } else if false { | ||
237 | println!("bar"); | ||
238 | } | ||
239 | println!("foo"); | ||
240 | } | ||
241 | "#, | ||
242 | ); | ||
243 | } | ||
244 | |||
245 | #[test] | ||
246 | fn simple_if_else_if_nested_else() { | ||
247 | check_assist( | ||
248 | unwrap_block, | ||
249 | r#" | ||
250 | fn main() { | ||
251 | //bar(); | ||
252 | if true { | ||
253 | println!("true"); | ||
254 | |||
255 | //comment | ||
256 | //bar(); | ||
257 | } else if false { | ||
258 | println!("bar"); | ||
259 | } else if true { | ||
260 | println!("foo"); | ||
261 | } else {<|> | ||
262 | println!("else"); | ||
263 | } | ||
264 | } | ||
265 | "#, | ||
266 | r#" | ||
267 | fn main() { | ||
268 | //bar(); | ||
269 | if true { | ||
270 | println!("true"); | ||
271 | |||
272 | //comment | ||
273 | //bar(); | ||
274 | } else if false { | ||
275 | println!("bar"); | ||
276 | } else if true { | ||
277 | println!("foo"); | ||
278 | } | ||
279 | println!("else"); | ||
280 | } | ||
281 | "#, | ||
282 | ); | ||
283 | } | ||
284 | |||
285 | #[test] | ||
286 | fn simple_if_else_if_nested_middle() { | ||
287 | check_assist( | ||
288 | unwrap_block, | ||
289 | r#" | ||
290 | fn main() { | ||
291 | //bar(); | ||
292 | if true { | ||
293 | println!("true"); | ||
294 | |||
295 | //comment | ||
296 | //bar(); | ||
297 | } else if false { | ||
298 | println!("bar"); | ||
299 | } else if true {<|> | ||
300 | println!("foo"); | ||
301 | } else { | ||
302 | println!("else"); | ||
303 | } | ||
304 | } | ||
305 | "#, | ||
306 | r#" | ||
307 | fn main() { | ||
308 | //bar(); | ||
309 | if true { | ||
310 | println!("true"); | ||
311 | |||
312 | //comment | ||
313 | //bar(); | ||
314 | } else if false { | ||
315 | println!("bar"); | ||
316 | } | ||
317 | println!("foo"); | ||
318 | } | ||
319 | "#, | ||
320 | ); | ||
321 | } | ||
322 | |||
323 | #[test] | ||
324 | fn simple_if_bad_cursor_position() { | ||
325 | check_assist_not_applicable( | ||
326 | unwrap_block, | ||
327 | r#" | ||
328 | fn main() { | ||
329 | bar();<|> | ||
330 | if true { | ||
331 | foo(); | ||
332 | |||
333 | //comment | ||
334 | bar(); | ||
335 | } else { | ||
336 | println!("bar"); | ||
337 | } | ||
338 | } | ||
339 | "#, | ||
340 | ); | ||
341 | } | ||
342 | |||
343 | #[test] | ||
344 | fn simple_for() { | ||
345 | check_assist( | ||
346 | unwrap_block, | ||
347 | r#" | ||
348 | fn main() { | ||
349 | for i in 0..5 {<|> | ||
350 | if true { | ||
351 | foo(); | ||
352 | |||
353 | //comment | ||
354 | bar(); | ||
355 | } else { | ||
356 | println!("bar"); | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | "#, | ||
361 | r#" | ||
362 | fn main() { | ||
363 | if true { | ||
364 | foo(); | ||
365 | |||
366 | //comment | ||
367 | bar(); | ||
368 | } else { | ||
369 | println!("bar"); | ||
370 | } | ||
371 | } | ||
372 | "#, | ||
373 | ); | ||
374 | } | ||
375 | |||
376 | #[test] | ||
377 | fn simple_if_in_for() { | ||
378 | check_assist( | ||
379 | unwrap_block, | ||
380 | r#" | ||
381 | fn main() { | ||
382 | for i in 0..5 { | ||
383 | if true {<|> | ||
384 | foo(); | ||
385 | |||
386 | //comment | ||
387 | bar(); | ||
388 | } else { | ||
389 | println!("bar"); | ||
390 | } | ||
391 | } | ||
392 | } | ||
393 | "#, | ||
394 | r#" | ||
395 | fn main() { | ||
396 | for i in 0..5 { | ||
397 | foo(); | ||
398 | |||
399 | //comment | ||
400 | bar(); | ||
401 | } | ||
402 | } | ||
403 | "#, | ||
404 | ); | ||
405 | } | ||
406 | |||
407 | #[test] | ||
408 | fn simple_loop() { | ||
409 | check_assist( | ||
410 | unwrap_block, | ||
411 | r#" | ||
412 | fn main() { | ||
413 | loop {<|> | ||
414 | if true { | ||
415 | foo(); | ||
416 | |||
417 | //comment | ||
418 | bar(); | ||
419 | } else { | ||
420 | println!("bar"); | ||
421 | } | ||
422 | } | ||
423 | } | ||
424 | "#, | ||
425 | r#" | ||
426 | fn main() { | ||
427 | if true { | ||
428 | foo(); | ||
429 | |||
430 | //comment | ||
431 | bar(); | ||
432 | } else { | ||
433 | println!("bar"); | ||
434 | } | ||
435 | } | ||
436 | "#, | ||
437 | ); | ||
438 | } | ||
439 | |||
440 | #[test] | ||
441 | fn simple_while() { | ||
442 | check_assist( | ||
443 | unwrap_block, | ||
444 | r#" | ||
445 | fn main() { | ||
446 | while true {<|> | ||
447 | if true { | ||
448 | foo(); | ||
449 | |||
450 | //comment | ||
451 | bar(); | ||
452 | } else { | ||
453 | println!("bar"); | ||
454 | } | ||
455 | } | ||
456 | } | ||
457 | "#, | ||
458 | r#" | ||
459 | fn main() { | ||
460 | if true { | ||
461 | foo(); | ||
462 | |||
463 | //comment | ||
464 | bar(); | ||
465 | } else { | ||
466 | println!("bar"); | ||
467 | } | ||
468 | } | ||
469 | "#, | ||
470 | ); | ||
471 | } | ||
472 | |||
473 | #[test] | ||
474 | fn unwrap_match_arm() { | ||
475 | check_assist( | ||
476 | unwrap_block, | ||
477 | r#" | ||
478 | fn main() { | ||
479 | match rel_path { | ||
480 | Ok(rel_path) => {<|> | ||
481 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | ||
482 | Some((*id, rel_path)) | ||
483 | } | ||
484 | Err(_) => None, | ||
485 | } | ||
486 | } | ||
487 | "#, | ||
488 | r#" | ||
489 | fn main() { | ||
490 | let rel_path = RelativePathBuf::from_path(rel_path).ok()?; | ||
491 | Some((*id, rel_path)) | ||
492 | } | ||
493 | "#, | ||
494 | ); | ||
495 | } | ||
496 | |||
497 | #[test] | ||
498 | fn simple_if_in_while_bad_cursor_position() { | ||
499 | check_assist_not_applicable( | ||
500 | unwrap_block, | ||
501 | r#" | ||
502 | fn main() { | ||
503 | while true { | ||
504 | if true { | ||
505 | foo();<|> | ||
506 | |||
507 | //comment | ||
508 | bar(); | ||
509 | } else { | ||
510 | println!("bar"); | ||
511 | } | ||
512 | } | ||
513 | } | ||
514 | "#, | ||
515 | ); | ||
516 | } | ||
517 | } | ||