diff options
-rw-r--r-- | crates/ra_ide_api_light/src/join_lines.rs | 149 |
1 files changed, 147 insertions, 2 deletions
diff --git a/crates/ra_ide_api_light/src/join_lines.rs b/crates/ra_ide_api_light/src/join_lines.rs index 949ee1544..9f59fbd43 100644 --- a/crates/ra_ide_api_light/src/join_lines.rs +++ b/crates/ra_ide_api_light/src/join_lines.rs | |||
@@ -120,11 +120,47 @@ fn remove_newline( | |||
120 | } | 120 | } |
121 | } | 121 | } |
122 | 122 | ||
123 | /// fixes a comma after the given expression and optionally inserts a new trailing comma | ||
124 | /// if no comma was found and `comma_offset` is provided | ||
125 | fn fix_comma_after(edit: &mut TextEditBuilder, node: &SyntaxNode, comma_offset: Option<TextUnit>) { | ||
126 | let next = node.next_sibling(); | ||
127 | let nnext = node.next_sibling().and_then(|n| n.next_sibling()); | ||
128 | |||
129 | match (next, nnext) { | ||
130 | // Whitespace followed by a comma | ||
131 | // remove the whitespace | ||
132 | (Some(ws), Some(comma)) if ws.kind() == WHITESPACE && comma.kind() == COMMA => { | ||
133 | edit.delete(ws.range()); | ||
134 | } | ||
135 | |||
136 | // if we are not a comma and if comma_offset was provided, | ||
137 | // insert trailing comma after the block | ||
138 | (Some(n), _) if n.kind() != COMMA => { | ||
139 | if let Some(comma_offset) = comma_offset { | ||
140 | edit.insert(comma_offset, ",".to_owned()); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | _ => {} | ||
145 | } | ||
146 | } | ||
147 | |||
123 | fn join_single_expr_block(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> { | 148 | fn join_single_expr_block(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> { |
124 | let block = ast::Block::cast(node.parent()?)?; | 149 | let block = ast::Block::cast(node.parent()?)?; |
125 | let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?; | 150 | let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?; |
126 | let expr = extract_trivial_expression(block)?; | 151 | let expr = extract_trivial_expression(block)?; |
127 | edit.replace(block_expr.syntax().range(), expr.syntax().text().to_string()); | 152 | |
153 | let block_range = block_expr.syntax().range(); | ||
154 | edit.replace(block_range, expr.syntax().text().to_string()); | ||
155 | |||
156 | // Match block needs to have a comma after the block | ||
157 | // otherwise we'll maintain a comma after the block if such existed | ||
158 | // but we remove excess whitespace between the expression and the comma. | ||
159 | if let Some(match_arm) = block_expr.syntax().parent().and_then(ast::MatchArm::cast) { | ||
160 | fix_comma_after(edit, match_arm.syntax(), Some(block_range.end())); | ||
161 | } else { | ||
162 | fix_comma_after(edit, block_expr.syntax(), None); | ||
163 | } | ||
128 | Some(()) | 164 | Some(()) |
129 | } | 165 | } |
130 | 166 | ||
@@ -208,7 +244,6 @@ fn foo() { | |||
208 | } | 244 | } |
209 | 245 | ||
210 | #[test] | 246 | #[test] |
211 | #[ignore] // FIXME: https://github.com/rust-analyzer/rust-analyzer/issues/868 | ||
212 | fn join_lines_adds_comma_for_block_in_match_arm() { | 247 | fn join_lines_adds_comma_for_block_in_match_arm() { |
213 | check_join_lines( | 248 | check_join_lines( |
214 | r" | 249 | r" |
@@ -231,6 +266,116 @@ fn foo(e: Result<U, V>) { | |||
231 | } | 266 | } |
232 | 267 | ||
233 | #[test] | 268 | #[test] |
269 | fn join_lines_keeps_comma_for_block_in_match_arm() { | ||
270 | // We already have a comma | ||
271 | check_join_lines( | ||
272 | r" | ||
273 | fn foo(e: Result<U, V>) { | ||
274 | match e { | ||
275 | Ok(u) => <|>{ | ||
276 | u.foo() | ||
277 | }, | ||
278 | Err(v) => v, | ||
279 | } | ||
280 | }", | ||
281 | r" | ||
282 | fn foo(e: Result<U, V>) { | ||
283 | match e { | ||
284 | Ok(u) => <|>u.foo(), | ||
285 | Err(v) => v, | ||
286 | } | ||
287 | }", | ||
288 | ); | ||
289 | |||
290 | // comma with whitespace between brace and , | ||
291 | check_join_lines( | ||
292 | r" | ||
293 | fn foo(e: Result<U, V>) { | ||
294 | match e { | ||
295 | Ok(u) => <|>{ | ||
296 | u.foo() | ||
297 | } , | ||
298 | Err(v) => v, | ||
299 | } | ||
300 | }", | ||
301 | r" | ||
302 | fn foo(e: Result<U, V>) { | ||
303 | match e { | ||
304 | Ok(u) => <|>u.foo(), | ||
305 | Err(v) => v, | ||
306 | } | ||
307 | }", | ||
308 | ); | ||
309 | |||
310 | // comma with newline between brace and , | ||
311 | check_join_lines( | ||
312 | r" | ||
313 | fn foo(e: Result<U, V>) { | ||
314 | match e { | ||
315 | Ok(u) => <|>{ | ||
316 | u.foo() | ||
317 | } | ||
318 | , | ||
319 | Err(v) => v, | ||
320 | } | ||
321 | }", | ||
322 | r" | ||
323 | fn foo(e: Result<U, V>) { | ||
324 | match e { | ||
325 | Ok(u) => <|>u.foo(), | ||
326 | Err(v) => v, | ||
327 | } | ||
328 | }", | ||
329 | ); | ||
330 | } | ||
331 | |||
332 | #[test] | ||
333 | fn join_lines_keeps_comma_with_single_arg_tuple() { | ||
334 | // A single arg tuple | ||
335 | check_join_lines( | ||
336 | r" | ||
337 | fn foo() { | ||
338 | let x = (<|>{ | ||
339 | 4 | ||
340 | },); | ||
341 | }", | ||
342 | r" | ||
343 | fn foo() { | ||
344 | let x = (<|>4,); | ||
345 | }", | ||
346 | ); | ||
347 | |||
348 | // single arg tuple with whitespace between brace and comma | ||
349 | check_join_lines( | ||
350 | r" | ||
351 | fn foo() { | ||
352 | let x = (<|>{ | ||
353 | 4 | ||
354 | } ,); | ||
355 | }", | ||
356 | r" | ||
357 | fn foo() { | ||
358 | let x = (<|>4,); | ||
359 | }", | ||
360 | ); | ||
361 | |||
362 | // single arg tuple with newline between brace and comma | ||
363 | check_join_lines( | ||
364 | r" | ||
365 | fn foo() { | ||
366 | let x = (<|>{ | ||
367 | 4 | ||
368 | } | ||
369 | ,); | ||
370 | }", | ||
371 | r" | ||
372 | fn foo() { | ||
373 | let x = (<|>4,); | ||
374 | }", | ||
375 | ); | ||
376 | } | ||
377 | |||
378 | #[test] | ||
234 | fn test_join_lines_use_items_left() { | 379 | fn test_join_lines_use_items_left() { |
235 | // No space after the '{' | 380 | // No space after the '{' |
236 | check_join_lines( | 381 | check_join_lines( |