From 3a9ba0e506b7267b2bacc399d59822b829ea2bae Mon Sep 17 00:00:00 2001 From: unexge Date: Sun, 22 Aug 2021 21:28:39 +0300 Subject: [PATCH] feat: join lines merges assignments --- crates/ide/src/join_lines.rs | 93 ++++++++++++++++++++++++++++++ crates/rust-analyzer/src/config.rs | 3 + docs/user/generated_config.adoc | 5 ++ editors/code/package.json | 5 ++ 4 files changed, 106 insertions(+) diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs index 30334ffcc8..ec67c02757 100644 --- a/crates/ide/src/join_lines.rs +++ b/crates/ide/src/join_lines.rs @@ -15,6 +15,7 @@ pub struct JoinLinesConfig { pub join_else_if: bool, pub remove_trailing_comma: bool, pub unwrap_trivial_blocks: bool, + pub join_assignments: bool, } // Feature: Join Lines @@ -162,6 +163,12 @@ fn remove_newline( } } + if config.join_assignments { + if join_assignments(edit, &prev, &next).is_some() { + return; + } + } + if config.unwrap_trivial_blocks { // Special case that turns something like: // @@ -232,6 +239,41 @@ fn join_single_use_tree(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Opti Some(()) } +fn join_assignments( + edit: &mut TextEditBuilder, + prev: &SyntaxElement, + next: &SyntaxElement, +) -> Option<()> { + let let_stmt = ast::LetStmt::cast(prev.as_node()?.clone())?; + if let_stmt.eq_token().is_some() { + cov_mark::hit!(join_assignments_already_initialized); + return None; + } + let let_ident_pat = match let_stmt.pat()? { + ast::Pat::IdentPat(it) => it, + _ => return None, + }; + + let expr_stmt = ast::ExprStmt::cast(next.as_node()?.clone())?; + let bin_expr = match expr_stmt.expr()? { + ast::Expr::BinExpr(it) => it, + _ => return None, + }; + if !matches!(bin_expr.op_kind()?, ast::BinaryOp::Assignment { op: None }) { + return None; + } + let lhs = bin_expr.lhs()?; + let name_ref = lhs.name_ref()?; + + if name_ref.to_string() != let_ident_pat.syntax().to_string() { + cov_mark::hit!(join_assignments_mismatch); + return None; + } + + edit.delete(let_stmt.semicolon_token()?.text_range().cover(lhs.syntax().text_range())); + Some(()) +} + fn as_if_expr(element: &SyntaxElement) -> Option { let mut node = element.as_node()?.clone(); if let Some(stmt) = ast::ExprStmt::cast(node.clone()) { @@ -275,6 +317,7 @@ mod tests { join_else_if: true, remove_trailing_comma: true, unwrap_trivial_blocks: true, + join_assignments: true, }; let (before_cursor_pos, before) = extract_offset(ra_fixture_before); @@ -300,6 +343,7 @@ mod tests { join_else_if: true, remove_trailing_comma: true, unwrap_trivial_blocks: true, + join_assignments: true, }; let (sel, before) = extract_range(ra_fixture_before); @@ -990,6 +1034,55 @@ fn main() { } } +"#, + ); + } + + #[test] + fn join_assignments() { + check_join_lines( + r#" +fn foo() { + $0let foo; + foo = "bar"; +} +"#, + r#" +fn foo() { + $0let foo = "bar"; +} +"#, + ); + + cov_mark::check!(join_assignments_mismatch); + check_join_lines( + r#" +fn foo() { + let foo; + let qux;$0 + foo = "bar"; +} +"#, + r#" +fn foo() { + let foo; + let qux;$0 foo = "bar"; +} +"#, + ); + + cov_mark::check!(join_assignments_already_initialized); + check_join_lines( + r#" +fn foo() { + let foo = "bar";$0 + foo = "bar"; +} +"#, + r#" +fn foo() { + let foo = "bar";$0 foo = "bar"; +} "#, ); } diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index e71513034c..22da92779e 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -206,6 +206,8 @@ config_data! { joinLines_removeTrailingComma: bool = "true", /// Join lines unwraps trivial blocks. joinLines_unwrapTrivialBlock: bool = "true", + /// Join lines merges consecutive declaration and initialization of an assignment. + joinLines_joinAssignments: bool = "true", /// Whether to show `Debug` lens. Only applies when /// `#rust-analyzer.lens.enable#` is set. @@ -786,6 +788,7 @@ impl Config { join_else_if: self.data.joinLines_joinElseIf, remove_trailing_comma: self.data.joinLines_removeTrailingComma, unwrap_trivial_blocks: self.data.joinLines_unwrapTrivialBlock, + join_assignments: self.data.joinLines_joinAssignments, } } pub fn call_info_full(&self) -> bool { diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index c40b6d6936..f73e542037 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -318,6 +318,11 @@ Join lines removes trailing commas. -- Join lines unwraps trivial blocks. -- +[[rust-analyzer.joinLines.joinAssignments]]rust-analyzer.joinLines.joinAssignments (default: `true`):: ++ +-- +Join lines merges consecutive declaration and initialization of an assignment. +-- [[rust-analyzer.lens.debug]]rust-analyzer.lens.debug (default: `true`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index 453abb6b1c..33bc4dc9a9 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -761,6 +761,11 @@ "default": true, "type": "boolean" }, + "rust-analyzer.joinLines.joinAssignments": { + "markdownDescription": "Join lines merges consecutive declaration and initialization of an assignment.", + "default": true, + "type": "boolean" + }, "rust-analyzer.lens.debug": { "markdownDescription": "Whether to show `Debug` lens. Only applies when\n`#rust-analyzer.lens.enable#` is set.", "default": true,