diff options
-rw-r--r-- | crates/ra_assists/src/handlers/unwrap_block.rs | 128 |
1 files changed, 49 insertions, 79 deletions
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs index 8440c7d0f..c48ecaae8 100644 --- a/crates/ra_assists/src/handlers/unwrap_block.rs +++ b/crates/ra_assists/src/handlers/unwrap_block.rs | |||
@@ -1,8 +1,5 @@ | |||
1 | use ra_fmt::unwrap_trivial_block; | 1 | use ra_fmt::unwrap_trivial_block; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ast, AstNode, TextRange, T}; |
3 | ast::{self, ElseBranch, Expr, LoopBodyOwner}, | ||
4 | match_ast, AstNode, TextRange, T, | ||
5 | }; | ||
6 | 3 | ||
7 | use crate::{AssistContext, AssistId, Assists}; | 4 | use crate::{AssistContext, AssistId, Assists}; |
8 | 5 | ||
@@ -29,89 +26,62 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
29 | let parent = block.syntax().parent()?; | 26 | let parent = block.syntax().parent()?; |
30 | let assist_id = AssistId("unwrap_block"); | 27 | let assist_id = AssistId("unwrap_block"); |
31 | let assist_label = "Unwrap block"; | 28 | let assist_label = "Unwrap block"; |
32 | 29 | let parent = ast::Expr::cast(parent)?; | |
33 | let (expr, expr_to_unwrap) = match_ast! { | 30 | |
34 | match parent { | 31 | match parent.clone() { |
35 | ast::ForExpr(for_expr) => { | 32 | ast::Expr::ForExpr(_) | ast::Expr::WhileExpr(_) | ast::Expr::LoopExpr(_) => (), |
36 | let block_expr = for_expr.loop_body()?; | 33 | ast::Expr::IfExpr(if_expr) => { |
37 | let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; | 34 | let then_branch = if_expr.then_branch()?; |
38 | (ast::Expr::ForExpr(for_expr), expr_to_unwrap) | 35 | if then_branch == block { |
39 | }, | 36 | if let Some(ancestor) = if_expr.syntax().parent().and_then(ast::IfExpr::cast) { |
40 | ast::WhileExpr(while_expr) => { | 37 | // For `else if` blocks |
41 | let block_expr = while_expr.loop_body()?; | 38 | let ancestor_then_branch = ancestor.then_branch()?; |
42 | let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; | 39 | |
43 | (ast::Expr::WhileExpr(while_expr), expr_to_unwrap) | 40 | let target = then_branch.syntax().text_range(); |
44 | }, | 41 | return acc.add(assist_id, assist_label, target, |edit| { |
45 | ast::LoopExpr(loop_expr) => { | 42 | let range_to_del_else_if = TextRange::new( |
46 | let block_expr = loop_expr.loop_body()?; | 43 | ancestor_then_branch.syntax().text_range().end(), |
47 | let expr_to_unwrap = extract_expr(ctx.frange.range, block_expr)?; | 44 | l_curly_token.text_range().start(), |
48 | (ast::Expr::LoopExpr(loop_expr), expr_to_unwrap) | 45 | ); |
49 | }, | 46 | let range_to_del_rest = TextRange::new( |
50 | ast::IfExpr(if_expr) => { | 47 | then_branch.syntax().text_range().end(), |
51 | let mut resp = None; | 48 | if_expr.syntax().text_range().end(), |
52 | 49 | ); | |
53 | let then_branch = if_expr.then_branch()?; | 50 | |
54 | if then_branch.l_curly_token()?.text_range().contains_range(ctx.frange.range) { | 51 | edit.delete(range_to_del_rest); |
55 | if let Some(ancestor) = if_expr.syntax().parent().and_then(ast::IfExpr::cast) { | 52 | edit.delete(range_to_del_else_if); |
56 | // For `else if` blocks | 53 | edit.replace( |
57 | let ancestor_then_branch = ancestor.then_branch()?; | 54 | target, |
58 | let l_curly_token = then_branch.l_curly_token()?; | 55 | update_expr_string(then_branch.to_string(), &[' ', '{']), |
59 | 56 | ); | |
60 | let target = then_branch.syntax().text_range(); | 57 | }); |
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 | } | 58 | } |
89 | 59 | } else { | |
90 | resp? | 60 | let target = block.syntax().text_range(); |
91 | }, | 61 | return acc.add(assist_id, assist_label, target, |edit| { |
92 | _ => return None, | 62 | let range_to_del = TextRange::new( |
63 | then_branch.syntax().text_range().end(), | ||
64 | l_curly_token.text_range().start(), | ||
65 | ); | ||
66 | |||
67 | edit.delete(range_to_del); | ||
68 | edit.replace(target, update_expr_string(block.to_string(), &[' ', '{'])); | ||
69 | }); | ||
70 | } | ||
93 | } | 71 | } |
72 | _ => return None, | ||
94 | }; | 73 | }; |
95 | 74 | ||
96 | let target = expr_to_unwrap.syntax().text_range(); | 75 | let unwrapped = unwrap_trivial_block(block); |
97 | acc.add(assist_id, assist_label, target, |edit| { | 76 | let target = unwrapped.syntax().text_range(); |
98 | edit.replace( | 77 | acc.add(assist_id, assist_label, target, |builder| { |
99 | expr.syntax().text_range(), | 78 | builder.replace( |
100 | update_expr_string(expr_to_unwrap.to_string(), &[' ', '{', '\n']), | 79 | parent.syntax().text_range(), |
80 | update_expr_string(unwrapped.to_string(), &[' ', '{', '\n']), | ||
101 | ); | 81 | ); |
102 | }) | 82 | }) |
103 | } | 83 | } |
104 | 84 | ||
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 { | 85 | fn update_expr_string(expr_str: String, trim_start_pat: &[char]) -> String { |
116 | let expr_string = expr_str.trim_start_matches(trim_start_pat); | 86 | let expr_string = expr_str.trim_start_matches(trim_start_pat); |
117 | let mut expr_string_lines: Vec<&str> = expr_string.lines().collect(); | 87 | let mut expr_string_lines: Vec<&str> = expr_string.lines().collect(); |