}
}
+/// fixes a comma after the given expression and optionally inserts a new trailing comma
+/// if no comma was found and `comma_offset` is provided
+fn fix_comma_after(edit: &mut TextEditBuilder, node: &SyntaxNode, comma_offset: Option<TextUnit>) {
+ let next = node.next_sibling();
+ let nnext = node.next_sibling().and_then(|n| n.next_sibling());
+
+ match (next, nnext) {
+ // Whitespace followed by a comma
+ // remove the whitespace
+ (Some(ws), Some(comma)) if ws.kind() == WHITESPACE && comma.kind() == COMMA => {
+ edit.delete(ws.range());
+ }
+
+ // if we are not a comma and if comma_offset was provided,
+ // insert trailing comma after the block
+ (Some(n), _) if n.kind() != COMMA => {
+ if let Some(comma_offset) = comma_offset {
+ edit.insert(comma_offset, ",".to_owned());
+ }
+ }
+
+ _ => {}
+ }
+}
+
fn join_single_expr_block(edit: &mut TextEditBuilder, node: &SyntaxNode) -> Option<()> {
let block = ast::Block::cast(node.parent()?)?;
let block_expr = ast::BlockExpr::cast(block.syntax().parent()?)?;
let expr = extract_trivial_expression(block)?;
- edit.replace(block_expr.syntax().range(), expr.syntax().text().to_string());
+
+ let block_range = block_expr.syntax().range();
+ edit.replace(block_range, expr.syntax().text().to_string());
+
+ // Match block needs to have a comma after the block
+ // otherwise we'll maintain a comma after the block if such existed
+ // but we remove excess whitespace between the expression and the comma.
+ if let Some(match_arm) = block_expr.syntax().parent().and_then(ast::MatchArm::cast) {
+ fix_comma_after(edit, match_arm.syntax(), Some(block_range.end()));
+ } else {
+ fix_comma_after(edit, block_expr.syntax(), None);
+ }
Some(())
}
}
#[test]
- #[ignore] // FIXME: https://github.com/rust-analyzer/rust-analyzer/issues/868
fn join_lines_adds_comma_for_block_in_match_arm() {
check_join_lines(
r"
);
}
+ #[test]
+ fn join_lines_keeps_comma_for_block_in_match_arm() {
+ // We already have a comma
+ check_join_lines(
+ r"
+fn foo(e: Result<U, V>) {
+ match e {
+ Ok(u) => <|>{
+ u.foo()
+ },
+ Err(v) => v,
+ }
+}",
+ r"
+fn foo(e: Result<U, V>) {
+ match e {
+ Ok(u) => <|>u.foo(),
+ Err(v) => v,
+ }
+}",
+ );
+
+ // comma with whitespace between brace and ,
+ check_join_lines(
+ r"
+fn foo(e: Result<U, V>) {
+ match e {
+ Ok(u) => <|>{
+ u.foo()
+ } ,
+ Err(v) => v,
+ }
+}",
+ r"
+fn foo(e: Result<U, V>) {
+ match e {
+ Ok(u) => <|>u.foo(),
+ Err(v) => v,
+ }
+}",
+ );
+
+ // comma with newline between brace and ,
+ check_join_lines(
+ r"
+fn foo(e: Result<U, V>) {
+ match e {
+ Ok(u) => <|>{
+ u.foo()
+ }
+ ,
+ Err(v) => v,
+ }
+}",
+ r"
+fn foo(e: Result<U, V>) {
+ match e {
+ Ok(u) => <|>u.foo(),
+ Err(v) => v,
+ }
+}",
+ );
+ }
+
+ #[test]
+ fn join_lines_keeps_comma_with_single_arg_tuple() {
+ // A single arg tuple
+ check_join_lines(
+ r"
+fn foo() {
+ let x = (<|>{
+ 4
+ },);
+}",
+ r"
+fn foo() {
+ let x = (<|>4,);
+}",
+ );
+
+ // single arg tuple with whitespace between brace and comma
+ check_join_lines(
+ r"
+fn foo() {
+ let x = (<|>{
+ 4
+ } ,);
+}",
+ r"
+fn foo() {
+ let x = (<|>4,);
+}",
+ );
+
+ // single arg tuple with newline between brace and comma
+ check_join_lines(
+ r"
+fn foo() {
+ let x = (<|>{
+ 4
+ }
+ ,);
+}",
+ r"
+fn foo() {
+ let x = (<|>4,);
+}",
+ );
+ }
+
#[test]
fn test_join_lines_use_items_left() {
// No space after the '{'