diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/assists/replace_if_let_with_match.rs | 49 | ||||
-rw-r--r-- | crates/ra_fmt/src/lib.rs | 10 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/expr_extensions.rs | 15 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/make.rs | 13 |
4 files changed, 55 insertions, 32 deletions
diff --git a/crates/ra_assists/src/assists/replace_if_let_with_match.rs b/crates/ra_assists/src/assists/replace_if_let_with_match.rs index c9b62e5ff..c8b13b7b3 100644 --- a/crates/ra_assists/src/assists/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/assists/replace_if_let_with_match.rs | |||
@@ -1,9 +1,12 @@ | |||
1 | use format_buf::format; | ||
2 | use hir::db::HirDatabase; | 1 | use hir::db::HirDatabase; |
3 | use ra_fmt::extract_trivial_expression; | 2 | use ra_fmt::unwrap_trivial_block; |
4 | use ra_syntax::{ast, AstNode}; | 3 | use ra_syntax::{ |
4 | ast::{self, make}, | ||
5 | AstNode, | ||
6 | }; | ||
5 | 7 | ||
6 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{Assist, AssistCtx, AssistId}; |
9 | use ast::edit::IndentLevel; | ||
7 | 10 | ||
8 | // Assist: replace_if_let_with_match | 11 | // Assist: replace_if_let_with_match |
9 | // | 12 | // |
@@ -43,32 +46,24 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx<impl HirDatabase>) -> Opt | |||
43 | }; | 46 | }; |
44 | 47 | ||
45 | ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", |edit| { | 48 | ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", |edit| { |
46 | let match_expr = build_match_expr(expr, pat, then_block, else_block); | 49 | let match_expr = { |
47 | edit.target(if_expr.syntax().text_range()); | 50 | let then_arm = { |
48 | edit.replace_node_and_indent(if_expr.syntax(), match_expr); | 51 | let then_expr = unwrap_trivial_block(then_block); |
49 | edit.set_cursor(if_expr.syntax().text_range().start()) | 52 | make::match_arm(vec![pat], then_expr) |
50 | }) | 53 | }; |
51 | } | 54 | let else_arm = { |
55 | let else_expr = unwrap_trivial_block(else_block); | ||
56 | make::match_arm(vec![make::placeholder_pat().into()], else_expr) | ||
57 | }; | ||
58 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) | ||
59 | }; | ||
52 | 60 | ||
53 | fn build_match_expr( | 61 | let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr); |
54 | expr: ast::Expr, | ||
55 | pat1: ast::Pat, | ||
56 | arm1: ast::BlockExpr, | ||
57 | arm2: ast::BlockExpr, | ||
58 | ) -> String { | ||
59 | let mut buf = String::new(); | ||
60 | format!(buf, "match {} {{\n", expr.syntax().text()); | ||
61 | format!(buf, " {} => {}\n", pat1.syntax().text(), format_arm(&arm1)); | ||
62 | format!(buf, " _ => {}\n", format_arm(&arm2)); | ||
63 | buf.push_str("}"); | ||
64 | buf | ||
65 | } | ||
66 | 62 | ||
67 | fn format_arm(block: &ast::BlockExpr) -> String { | 63 | edit.target(if_expr.syntax().text_range()); |
68 | match extract_trivial_expression(block) { | 64 | edit.set_cursor(if_expr.syntax().text_range().start()); |
69 | Some(e) if !e.syntax().text().contains_char('\n') => format!("{},", e.syntax().text()), | 65 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr.into()); |
70 | _ => block.syntax().text().to_string(), | 66 | }) |
71 | } | ||
72 | } | 67 | } |
73 | 68 | ||
74 | #[cfg(test)] | 69 | #[cfg(test)] |
diff --git a/crates/ra_fmt/src/lib.rs b/crates/ra_fmt/src/lib.rs index 10f592257..4bca27b5c 100644 --- a/crates/ra_fmt/src/lib.rs +++ b/crates/ra_fmt/src/lib.rs | |||
@@ -35,8 +35,14 @@ fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> { | |||
35 | successors(token.prev_token(), |token| token.prev_token()) | 35 | successors(token.prev_token(), |token| token.prev_token()) |
36 | } | 36 | } |
37 | 37 | ||
38 | pub fn extract_trivial_expression(expr: &ast::BlockExpr) -> Option<ast::Expr> { | 38 | pub fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { |
39 | let block = expr.block()?; | 39 | extract_trivial_expression(&block) |
40 | .filter(|expr| !expr.syntax().text().contains_char('\n')) | ||
41 | .unwrap_or_else(|| block.into()) | ||
42 | } | ||
43 | |||
44 | pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> { | ||
45 | let block = block.block()?; | ||
40 | let expr = block.expr()?; | 46 | let expr = block.expr()?; |
41 | let non_trivial_children = block.syntax().children().filter(|it| match it.kind() { | 47 | let non_trivial_children = block.syntax().children().filter(|it| match it.kind() { |
42 | WHITESPACE | T!['{'] | T!['}'] => false, | 48 | WHITESPACE | T!['{'] | T!['}'] => false, |
diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs index 539759450..2e50a095c 100644 --- a/crates/ra_syntax/src/ast/expr_extensions.rs +++ b/crates/ra_syntax/src/ast/expr_extensions.rs | |||
@@ -7,6 +7,21 @@ use crate::{ | |||
7 | SyntaxToken, T, | 7 | SyntaxToken, T, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | impl ast::Expr { | ||
11 | pub fn is_block_like(&self) -> bool { | ||
12 | match self { | ||
13 | ast::Expr::IfExpr(_) | ||
14 | | ast::Expr::LoopExpr(_) | ||
15 | | ast::Expr::ForExpr(_) | ||
16 | | ast::Expr::WhileExpr(_) | ||
17 | | ast::Expr::BlockExpr(_) | ||
18 | | ast::Expr::MatchExpr(_) | ||
19 | | ast::Expr::TryBlockExpr(_) => true, | ||
20 | _ => false, | ||
21 | } | ||
22 | } | ||
23 | } | ||
24 | |||
10 | #[derive(Debug, Clone, PartialEq, Eq)] | 25 | #[derive(Debug, Clone, PartialEq, Eq)] |
11 | pub enum ElseBranch { | 26 | pub enum ElseBranch { |
12 | Block(ast::BlockExpr), | 27 | Block(ast::BlockExpr), |
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 38c0e9a66..629503dc5 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs | |||
@@ -122,11 +122,18 @@ pub fn match_arm(pats: impl IntoIterator<Item = ast::Pat>, expr: ast::Expr) -> a | |||
122 | } | 122 | } |
123 | 123 | ||
124 | pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList { | 124 | pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList { |
125 | let arms_str = arms.into_iter().map(|arm| format!("\n {}", arm.syntax())).join(","); | 125 | let arms_str = arms |
126 | return from_text(&format!("{},\n", arms_str)); | 126 | .into_iter() |
127 | .map(|arm| { | ||
128 | let needs_comma = arm.expr().map_or(true, |it| !it.is_block_like()); | ||
129 | let comma = if needs_comma { "," } else { "" }; | ||
130 | format!(" {}{}\n", arm.syntax(), comma) | ||
131 | }) | ||
132 | .collect::<String>(); | ||
133 | return from_text(&format!("{}", arms_str)); | ||
127 | 134 | ||
128 | fn from_text(text: &str) -> ast::MatchArmList { | 135 | fn from_text(text: &str) -> ast::MatchArmList { |
129 | ast_from_text(&format!("fn f() {{ match () {{{}}} }}", text)) | 136 | ast_from_text(&format!("fn f() {{ match () {{\n{}}} }}", text)) |
130 | } | 137 | } |
131 | } | 138 | } |
132 | 139 | ||