diff options
Diffstat (limited to 'crates/ra_assists/src/handlers/early_return.rs')
-rw-r--r-- | crates/ra_assists/src/handlers/early_return.rs | 159 |
1 files changed, 82 insertions, 77 deletions
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index 55ccc37b0..4bd6040b2 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs | |||
@@ -95,89 +95,94 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
95 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; | 95 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; |
96 | let cursor_position = ctx.frange.range.start(); | 96 | let cursor_position = ctx.frange.range.start(); |
97 | 97 | ||
98 | ctx.add_assist(AssistId("convert_to_guarded_return"), "Convert to guarded return", |edit| { | 98 | let target = if_expr.syntax().text_range(); |
99 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); | 99 | ctx.add_assist( |
100 | let new_block = match if_let_pat { | 100 | AssistId("convert_to_guarded_return"), |
101 | None => { | 101 | "Convert to guarded return", |
102 | // If. | 102 | target, |
103 | let new_expr = { | 103 | |edit| { |
104 | let then_branch = | 104 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); |
105 | make::block_expr(once(make::expr_stmt(early_expression).into()), None); | 105 | let new_block = match if_let_pat { |
106 | let cond = invert_boolean_expression(cond_expr); | 106 | None => { |
107 | let e = make::expr_if(make::condition(cond, None), then_branch); | 107 | // If. |
108 | if_indent_level.increase_indent(e) | 108 | let new_expr = { |
109 | }; | 109 | let then_branch = |
110 | replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) | 110 | make::block_expr(once(make::expr_stmt(early_expression).into()), None); |
111 | } | 111 | let cond = invert_boolean_expression(cond_expr); |
112 | Some((path, bound_ident)) => { | 112 | let e = make::expr_if(make::condition(cond, None), then_branch); |
113 | // If-let. | 113 | if_indent_level.increase_indent(e) |
114 | let match_expr = { | ||
115 | let happy_arm = { | ||
116 | let pat = make::tuple_struct_pat( | ||
117 | path, | ||
118 | once(make::bind_pat(make::name("it")).into()), | ||
119 | ); | ||
120 | let expr = { | ||
121 | let name_ref = make::name_ref("it"); | ||
122 | let segment = make::path_segment(name_ref); | ||
123 | let path = make::path_unqualified(segment); | ||
124 | make::expr_path(path) | ||
125 | }; | ||
126 | make::match_arm(once(pat.into()), expr) | ||
127 | }; | 114 | }; |
115 | replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) | ||
116 | } | ||
117 | Some((path, bound_ident)) => { | ||
118 | // If-let. | ||
119 | let match_expr = { | ||
120 | let happy_arm = { | ||
121 | let pat = make::tuple_struct_pat( | ||
122 | path, | ||
123 | once(make::bind_pat(make::name("it")).into()), | ||
124 | ); | ||
125 | let expr = { | ||
126 | let name_ref = make::name_ref("it"); | ||
127 | let segment = make::path_segment(name_ref); | ||
128 | let path = make::path_unqualified(segment); | ||
129 | make::expr_path(path) | ||
130 | }; | ||
131 | make::match_arm(once(pat.into()), expr) | ||
132 | }; | ||
128 | 133 | ||
129 | let sad_arm = make::match_arm( | 134 | let sad_arm = make::match_arm( |
130 | // FIXME: would be cool to use `None` or `Err(_)` if appropriate | 135 | // FIXME: would be cool to use `None` or `Err(_)` if appropriate |
131 | once(make::placeholder_pat().into()), | 136 | once(make::placeholder_pat().into()), |
132 | early_expression, | 137 | early_expression, |
133 | ); | 138 | ); |
134 | 139 | ||
135 | make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) | 140 | make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) |
136 | }; | 141 | }; |
137 | 142 | ||
138 | let let_stmt = make::let_stmt( | 143 | let let_stmt = make::let_stmt( |
139 | make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), | 144 | make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), |
140 | Some(match_expr), | 145 | Some(match_expr), |
146 | ); | ||
147 | let let_stmt = if_indent_level.increase_indent(let_stmt); | ||
148 | replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) | ||
149 | } | ||
150 | }; | ||
151 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); | ||
152 | edit.set_cursor(cursor_position); | ||
153 | |||
154 | fn replace( | ||
155 | new_expr: &SyntaxNode, | ||
156 | then_block: &ast::BlockExpr, | ||
157 | parent_block: &ast::BlockExpr, | ||
158 | if_expr: &ast::IfExpr, | ||
159 | ) -> SyntaxNode { | ||
160 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); | ||
161 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); | ||
162 | let end_of_then = | ||
163 | if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { | ||
164 | end_of_then.prev_sibling_or_token().unwrap() | ||
165 | } else { | ||
166 | end_of_then | ||
167 | }; | ||
168 | let mut then_statements = new_expr.children_with_tokens().chain( | ||
169 | then_block_items | ||
170 | .syntax() | ||
171 | .children_with_tokens() | ||
172 | .skip(1) | ||
173 | .take_while(|i| *i != end_of_then), | ||
141 | ); | 174 | ); |
142 | let let_stmt = if_indent_level.increase_indent(let_stmt); | 175 | replace_children( |
143 | replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) | 176 | &parent_block.syntax(), |
177 | RangeInclusive::new( | ||
178 | if_expr.clone().syntax().clone().into(), | ||
179 | if_expr.syntax().clone().into(), | ||
180 | ), | ||
181 | &mut then_statements, | ||
182 | ) | ||
144 | } | 183 | } |
145 | }; | 184 | }, |
146 | edit.target(if_expr.syntax().text_range()); | 185 | ) |
147 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); | ||
148 | edit.set_cursor(cursor_position); | ||
149 | |||
150 | fn replace( | ||
151 | new_expr: &SyntaxNode, | ||
152 | then_block: &ast::BlockExpr, | ||
153 | parent_block: &ast::BlockExpr, | ||
154 | if_expr: &ast::IfExpr, | ||
155 | ) -> SyntaxNode { | ||
156 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); | ||
157 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); | ||
158 | let end_of_then = | ||
159 | if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { | ||
160 | end_of_then.prev_sibling_or_token().unwrap() | ||
161 | } else { | ||
162 | end_of_then | ||
163 | }; | ||
164 | let mut then_statements = new_expr.children_with_tokens().chain( | ||
165 | then_block_items | ||
166 | .syntax() | ||
167 | .children_with_tokens() | ||
168 | .skip(1) | ||
169 | .take_while(|i| *i != end_of_then), | ||
170 | ); | ||
171 | replace_children( | ||
172 | &parent_block.syntax(), | ||
173 | RangeInclusive::new( | ||
174 | if_expr.clone().syntax().clone().into(), | ||
175 | if_expr.syntax().clone().into(), | ||
176 | ), | ||
177 | &mut then_statements, | ||
178 | ) | ||
179 | } | ||
180 | }) | ||
181 | } | 186 | } |
182 | 187 | ||
183 | #[cfg(test)] | 188 | #[cfg(test)] |