diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f285c8f..a55abdc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fixed malformed formatting when a binary expression inside of a function call with comments around the operators is incorrectly collapsed onto one line ([#996](https://github.com/JohnnyMorganz/StyLua/issues/996)) +- Fixed repeated unary minus on long lines being collapsed into a comment, e.g. `- - - - -5` becoming `-----5` ([#1075](https://github.com/JohnnyMorganz/StyLua/issues/1075)) ## [2.3.1] - 2025-11-01 diff --git a/src/formatters/expression.rs b/src/formatters/expression.rs index 39e4865c..39f3e44d 100644 --- a/src/formatters/expression.rs +++ b/src/formatters/expression.rs @@ -271,44 +271,13 @@ fn format_expression_internal( Expression::UnaryOperator { unop, expression } => { let unop = format_unop(ctx, unop, shape); let shape = shape + strip_leading_trivia(&unop).to_string().len(); - let mut expression = format_expression_internal( + let expression = format_expression_internal( ctx, expression, ExpressionContext::UnaryOrBinary, shape, ); - - // Special case: if we have `- -foo`, or `-(-foo)` where we have already removed the parentheses, then - // it will lead to `--foo`, which is invalid syntax. We must explicitly add/keep the parentheses `-(-foo)`. - if let UnOp::Minus(_) = unop { - let require_parentheses = match expression { - Expression::UnaryOperator { - unop: UnOp::Minus(_), - .. - } => true, - Expression::Parentheses { ref expression, .. } => matches!( - &**expression, - Expression::UnaryOperator { - unop: UnOp::Minus(_), - .. - } - ), - _ => false, - }; - - if require_parentheses { - let (new_expression, trailing_comments) = - trivia_util::take_trailing_comments(&expression); - expression = Expression::Parentheses { - contained: ContainedSpan::new( - TokenReference::symbol("(").unwrap(), - TokenReference::symbol(")").unwrap(), - ) - .update_trailing_trivia(FormatTriviaType::Append(trailing_comments)), - expression: Box::new(new_expression), - } - } - } + let expression = parenthesise_double_minus(&unop, expression); Expression::UnaryOperator { unop, @@ -916,6 +885,43 @@ pub fn format_unop(ctx: &Context, unop: &UnOp, shape: Shape) -> UnOp { }, |other| panic!("unknown node {:?}", other)) } +/// If we have a unary minus whose operand is also a unary minus (e.g. `- -foo`), +/// the two minus signs would collapse into `--foo`, which is a comment in Lua. +/// This function wraps the operand in parentheses when necessary: `- -foo` → `-(-foo)`. +fn parenthesise_double_minus(unop: &UnOp, expression: Expression) -> Expression { + if let UnOp::Minus(_) = unop { + let require_parentheses = match expression { + Expression::UnaryOperator { + unop: UnOp::Minus(_), + .. + } => true, + Expression::Parentheses { ref expression, .. } => matches!( + &**expression, + Expression::UnaryOperator { + unop: UnOp::Minus(_), + .. + } + ), + _ => false, + }; + + if require_parentheses { + let (new_expression, trailing_comments) = + trivia_util::take_trailing_comments(&expression); + return Expression::Parentheses { + contained: ContainedSpan::new( + TokenReference::symbol("(").unwrap(), + TokenReference::symbol(")").unwrap(), + ) + .update_trailing_trivia(FormatTriviaType::Append(trailing_comments)), + expression: Box::new(new_expression), + }; + } + } + + expression +} + /// Pushes a [`BinOp`] onto a newline, and indent its depending on indent_level. /// Preserves any leading comments, and moves trailing comments to before the BinOp. /// Also takes in the [`Expression`] present on the RHS of the BinOp - this is needed so that we can take any @@ -1438,6 +1444,7 @@ fn format_hanging_expression_( ExpressionContext::UnaryOrBinary, lhs_range, ); + let expression = parenthesise_double_minus(&unop, expression); Expression::UnaryOperator { unop, diff --git a/tests/inputs/double-unary-minus.lua b/tests/inputs/double-unary-minus.lua index 434dbf05..a3802fa6 100644 --- a/tests/inputs/double-unary-minus.lua +++ b/tests/inputs/double-unary-minus.lua @@ -2,4 +2,7 @@ local x = -(-foo) local y = - -foo local z1 = -(-foo) -- bar -local z2 = - -foo -- baz \ No newline at end of file +local z2 = - -foo -- baz + +-- Repeated unary minus that exceeds column width should not collapse into a comment (https://github.com/JohnnyMorganz/StyLua/issues/1075) +_ = (- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5) \ No newline at end of file diff --git a/tests/snapshots/tests__standard@double-unary-minus.lua.snap b/tests/snapshots/tests__standard@double-unary-minus.lua.snap index 047724e7..0de484d9 100644 --- a/tests/snapshots/tests__standard@double-unary-minus.lua.snap +++ b/tests/snapshots/tests__standard@double-unary-minus.lua.snap @@ -1,6 +1,7 @@ --- source: tests/tests.rs -expression: format(&contents) +expression: "format(&contents, LuaVersion::Lua51)" +input_file: tests/inputs/double-unary-minus.lua --- local x = -(-foo) local y = -(-foo) @@ -8,3 +9,5 @@ local y = -(-foo) local z1 = -(-foo) -- bar local z2 = -(-foo) -- baz +-- Repeated unary minus that exceeds column width should not collapse into a comment (https://github.com/JohnnyMorganz/StyLua/issues/1075) +_ = -(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-(-5)))))))))))))))))))))))))))))))))))))))