aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/handlers/unwrap_block.rs128
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 @@
1use ra_fmt::unwrap_trivial_block; 1use ra_fmt::unwrap_trivial_block;
2use ra_syntax::{ 2use ra_syntax::{ast, AstNode, TextRange, T};
3 ast::{self, ElseBranch, Expr, LoopBodyOwner},
4 match_ast, AstNode, TextRange, T,
5};
6 3
7use crate::{AssistContext, AssistId, Assists}; 4use 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
105fn 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
115fn update_expr_string(expr_str: String, trim_start_pat: &[char]) -> String { 85fn 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();