aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/assists/replace_if_let_with_match.rs49
-rw-r--r--crates/ra_fmt/src/lib.rs10
-rw-r--r--crates/ra_syntax/src/ast/expr_extensions.rs15
-rw-r--r--crates/ra_syntax/src/ast/make.rs13
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 @@
1use format_buf::format;
2use hir::db::HirDatabase; 1use hir::db::HirDatabase;
3use ra_fmt::extract_trivial_expression; 2use ra_fmt::unwrap_trivial_block;
4use ra_syntax::{ast, AstNode}; 3use ra_syntax::{
4 ast::{self, make},
5 AstNode,
6};
5 7
6use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
9use 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
53fn 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
67fn 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
38pub fn extract_trivial_expression(expr: &ast::BlockExpr) -> Option<ast::Expr> { 38pub 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
44pub 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
10impl 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)]
11pub enum ElseBranch { 26pub 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
124pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList { 124pub 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