diff options
Diffstat (limited to 'crates/ra_editor/src/assists')
-rw-r--r-- | crates/ra_editor/src/assists/replace_if_let_with_match.rs | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/crates/ra_editor/src/assists/replace_if_let_with_match.rs b/crates/ra_editor/src/assists/replace_if_let_with_match.rs new file mode 100644 index 000000000..30c371480 --- /dev/null +++ b/crates/ra_editor/src/assists/replace_if_let_with_match.rs | |||
@@ -0,0 +1,92 @@ | |||
1 | use ra_syntax::{ | ||
2 | AstNode, SyntaxKind::{L_CURLY, R_CURLY, WHITESPACE}, | ||
3 | ast, | ||
4 | }; | ||
5 | |||
6 | use crate::assists::{AssistCtx, Assist}; | ||
7 | |||
8 | pub fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> { | ||
9 | let if_expr: &ast::IfExpr = ctx.node_at_offset()?; | ||
10 | let cond = if_expr.condition()?; | ||
11 | let pat = cond.pat()?; | ||
12 | let expr = cond.expr()?; | ||
13 | let then_block = if_expr.then_branch()?; | ||
14 | let else_block = if_expr.else_branch()?; | ||
15 | |||
16 | ctx.build("replace with match", |edit| { | ||
17 | let match_expr = build_match_expr(expr, pat, then_block, else_block); | ||
18 | edit.replace_node_and_indent(if_expr.syntax(), match_expr); | ||
19 | edit.set_cursor(if_expr.syntax().range().start()) | ||
20 | }) | ||
21 | } | ||
22 | |||
23 | fn build_match_expr( | ||
24 | expr: &ast::Expr, | ||
25 | pat1: &ast::Pat, | ||
26 | arm1: &ast::Block, | ||
27 | arm2: &ast::Block, | ||
28 | ) -> String { | ||
29 | let mut buf = String::new(); | ||
30 | buf.push_str(&format!("match {} {{\n", expr.syntax().text())); | ||
31 | buf.push_str(&format!( | ||
32 | " {} => {}\n", | ||
33 | pat1.syntax().text(), | ||
34 | format_arm(arm1) | ||
35 | )); | ||
36 | buf.push_str(&format!(" _ => {}\n", format_arm(arm2))); | ||
37 | buf.push_str("}"); | ||
38 | buf | ||
39 | } | ||
40 | |||
41 | fn format_arm(block: &ast::Block) -> String { | ||
42 | match extract_expression(block) { | ||
43 | None => block.syntax().text().to_string(), | ||
44 | Some(e) => format!("{},", e.syntax().text()), | ||
45 | } | ||
46 | } | ||
47 | |||
48 | fn extract_expression(block: &ast::Block) -> Option<&ast::Expr> { | ||
49 | let expr = block.expr()?; | ||
50 | let non_trivial_children = block.syntax().children().filter(|it| { | ||
51 | !(it == &expr.syntax() | ||
52 | || it.kind() == L_CURLY | ||
53 | || it.kind() == R_CURLY | ||
54 | || it.kind() == WHITESPACE) | ||
55 | }); | ||
56 | if non_trivial_children.count() > 0 { | ||
57 | return None; | ||
58 | } | ||
59 | Some(expr) | ||
60 | } | ||
61 | |||
62 | #[cfg(test)] | ||
63 | mod tests { | ||
64 | use super::*; | ||
65 | use crate::assists::check_assist; | ||
66 | |||
67 | #[test] | ||
68 | fn test_replace_if_let_with_match_unwraps_simple_expressions() { | ||
69 | check_assist( | ||
70 | replace_if_let_with_match, | ||
71 | " | ||
72 | impl VariantData { | ||
73 | pub fn is_struct(&self) -> bool { | ||
74 | if <|>let VariantData::Struct(..) = *self { | ||
75 | true | ||
76 | } else { | ||
77 | false | ||
78 | } | ||
79 | } | ||
80 | } ", | ||
81 | " | ||
82 | impl VariantData { | ||
83 | pub fn is_struct(&self) -> bool { | ||
84 | <|>match *self { | ||
85 | VariantData::Struct(..) => true, | ||
86 | _ => false, | ||
87 | } | ||
88 | } | ||
89 | } ", | ||
90 | ) | ||
91 | } | ||
92 | } | ||