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