|
| 1 | +use either::Either; |
1 | 2 | use syntax::{ |
2 | 3 | AstNode, SyntaxElement, SyntaxKind, SyntaxNode, T, |
3 | 4 | ast::{ |
@@ -86,6 +87,55 @@ pub(crate) fn unwrap_branch(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio |
86 | 87 | }) |
87 | 88 | } |
88 | 89 |
|
| 90 | +// Assist: unwrap_block |
| 91 | +// |
| 92 | +// This assist removes braces and unwrap single expressions block. |
| 93 | +// |
| 94 | +// ``` |
| 95 | +// fn foo() { |
| 96 | +// match () { |
| 97 | +// _ => {$0 |
| 98 | +// bar() |
| 99 | +// } |
| 100 | +// } |
| 101 | +// } |
| 102 | +// ``` |
| 103 | +// -> |
| 104 | +// ``` |
| 105 | +// fn foo() { |
| 106 | +// match () { |
| 107 | +// _ => bar(), |
| 108 | +// } |
| 109 | +// } |
| 110 | +// ``` |
| 111 | +pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { |
| 112 | + let l_curly_token = ctx.find_token_syntax_at_offset(T!['{'])?; |
| 113 | + let block = l_curly_token.parent_ancestors().nth(1).and_then(ast::BlockExpr::cast)?; |
| 114 | + let target = block.syntax().text_range(); |
| 115 | + let tail_expr = block.tail_expr()?; |
| 116 | + let stmt_list = block.stmt_list()?; |
| 117 | + let container = Either::<ast::MatchArm, ast::ClosureExpr>::cast(block.syntax().parent()?)?; |
| 118 | + |
| 119 | + if stmt_list.statements().next().is_some() { |
| 120 | + return None; |
| 121 | + } |
| 122 | + |
| 123 | + acc.add(AssistId::refactor_rewrite("unwrap_block"), "Unwrap block", target, |builder| { |
| 124 | + let editor = builder.make_editor(block.syntax()); |
| 125 | + let replacement = stmt_list.dedent(tail_expr.indent_level()).indent(block.indent_level()); |
| 126 | + let mut replacement = extract_statements(replacement); |
| 127 | + |
| 128 | + if container.left().is_some_and(|it| it.comma_token().is_none()) |
| 129 | + && !tail_expr.is_block_like() |
| 130 | + { |
| 131 | + replacement.push(editor.make().token(T![,]).into()); |
| 132 | + } |
| 133 | + |
| 134 | + editor.replace_with_many(block.syntax(), replacement); |
| 135 | + builder.add_file_edits(ctx.vfs_file_id(), editor); |
| 136 | + }) |
| 137 | +} |
| 138 | + |
89 | 139 | fn delete_else_before(container: SyntaxNode, editor: &SyntaxEditor) { |
90 | 140 | let make = editor.make(); |
91 | 141 | let Some(else_token) = container |
@@ -158,7 +208,10 @@ fn wrap_block_raw(expr: &ast::Expr, make: &SyntaxFactory) -> ast::BlockExpr { |
158 | 208 |
|
159 | 209 | #[cfg(test)] |
160 | 210 | mod tests { |
161 | | - use crate::tests::{check_assist, check_assist_not_applicable, check_assist_with_label}; |
| 211 | + use crate::tests::{ |
| 212 | + check_assist, check_assist_by_label, check_assist_not_applicable, |
| 213 | + check_assist_not_applicable_by_label, check_assist_with_label, |
| 214 | + }; |
162 | 215 |
|
163 | 216 | use super::*; |
164 | 217 |
|
@@ -1037,4 +1090,114 @@ fn main() { |
1037 | 1090 | "Unwrap branch", |
1038 | 1091 | ); |
1039 | 1092 | } |
| 1093 | + |
| 1094 | + #[test] |
| 1095 | + fn unwrap_block_in_branch() { |
| 1096 | + check_assist_by_label( |
| 1097 | + unwrap_block, |
| 1098 | + r#" |
| 1099 | +fn main() { |
| 1100 | + match rel_path { |
| 1101 | + Ok(rel_path) => {$0 |
| 1102 | + if true { |
| 1103 | + foo() |
| 1104 | + } |
| 1105 | + } |
| 1106 | + Err(_) => None, |
| 1107 | + } |
| 1108 | +} |
| 1109 | +"#, |
| 1110 | + r#" |
| 1111 | +fn main() { |
| 1112 | + match rel_path { |
| 1113 | + Ok(rel_path) => if true { |
| 1114 | + foo() |
| 1115 | + } |
| 1116 | + Err(_) => None, |
| 1117 | + } |
| 1118 | +} |
| 1119 | +"#, |
| 1120 | + "Unwrap block", |
| 1121 | + ); |
| 1122 | + |
| 1123 | + check_assist_by_label( |
| 1124 | + unwrap_block, |
| 1125 | + r#" |
| 1126 | +fn main() { |
| 1127 | + match rel_path { |
| 1128 | + Ok(rel_path) => {$0 |
| 1129 | + 1 + 2 |
| 1130 | + } |
| 1131 | + Err(_) => None, |
| 1132 | + } |
| 1133 | +} |
| 1134 | +"#, |
| 1135 | + r#" |
| 1136 | +fn main() { |
| 1137 | + match rel_path { |
| 1138 | + Ok(rel_path) => 1 + 2, |
| 1139 | + Err(_) => None, |
| 1140 | + } |
| 1141 | +} |
| 1142 | +"#, |
| 1143 | + "Unwrap block", |
| 1144 | + ); |
| 1145 | + } |
| 1146 | + |
| 1147 | + #[test] |
| 1148 | + fn unwrap_block_in_branch_non_standalone() { |
| 1149 | + check_assist_not_applicable_by_label( |
| 1150 | + unwrap_block, |
| 1151 | + r#" |
| 1152 | +fn main() { |
| 1153 | + match rel_path { |
| 1154 | + Ok(rel_path) => { |
| 1155 | + if true {$0 |
| 1156 | + foo() |
| 1157 | + } |
| 1158 | + } |
| 1159 | + Err(_) => None, |
| 1160 | + } |
| 1161 | +} |
| 1162 | +"#, |
| 1163 | + "Unwrap block", |
| 1164 | + ); |
| 1165 | + } |
| 1166 | + |
| 1167 | + #[test] |
| 1168 | + fn unwrap_block_in_branch_non_tail_expr_only() { |
| 1169 | + check_assist_not_applicable_by_label( |
| 1170 | + unwrap_block, |
| 1171 | + r#" |
| 1172 | +fn main() { |
| 1173 | + match rel_path { |
| 1174 | + Ok(rel_path) => {$0 |
| 1175 | + x; |
| 1176 | + y |
| 1177 | + } |
| 1178 | + Err(_) => None, |
| 1179 | + } |
| 1180 | +} |
| 1181 | +"#, |
| 1182 | + "Unwrap block", |
| 1183 | + ); |
| 1184 | + } |
| 1185 | + |
| 1186 | + #[test] |
| 1187 | + fn unwrap_block_in_closure() { |
| 1188 | + check_assist_by_label( |
| 1189 | + unwrap_block, |
| 1190 | + r#" |
| 1191 | +fn main() { |
| 1192 | + let f = || {$0 foo() }; |
| 1193 | +} |
| 1194 | +"#, |
| 1195 | + r#" |
| 1196 | +fn main() { |
| 1197 | + let f = || foo(); |
| 1198 | +} |
| 1199 | +"#, |
| 1200 | + "Unwrap block", |
| 1201 | + ); |
| 1202 | + } |
1040 | 1203 | } |
0 commit comments