diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fbbd9c6..090ba3bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Luau: fixed parentheses incorrectly removed in `(expr :: assertion) < foo` when multilining the expression, leading to a syntax error ([#940](https://github.com/JohnnyMorganz/StyLua/issues/940)) - Fixed panic when attempting to format a file outside of the current working directory when `--respect-ignores` is enabled ([#969](https://github.com/JohnnyMorganz/StyLua/pull/969)) - Fixed unnecessary semicolons being introduced at the end of statements when incorrectly determined as ambiguous ([#963](https://github.com/JohnnyMorganz/StyLua/issues/963)) +- Fixed malformed formatting of function calls where parentheses are removed but there are comments in between the parentheses and the expression. Now, we will keep the parentheses in these cases, except for trailing comments ([#964](https://github.com/JohnnyMorganz/StyLua/issues/964)) ## [2.0.2] - 2024-12-07 diff --git a/src/formatters/functions.rs b/src/formatters/functions.rs index b6056f5c..cb5393a2 100644 --- a/src/formatters/functions.rs +++ b/src/formatters/functions.rs @@ -397,11 +397,20 @@ pub fn format_function_args( parentheses, arguments, } => { + let (start_parens, end_parens) = parentheses.tokens(); + // Handle config where parentheses are omitted, and there is only one argument if ctx.config().call_parentheses != CallParenType::Input && (ctx.should_omit_string_parens() || ctx.should_omit_table_parens()) && arguments.len() == 1 && !matches!(call_next_node, FunctionCallNextNode::ObscureWithoutParens) + && !start_parens.has_trailing_comments(CommentSearch::Single) + && !end_parens.has_leading_comments(CommentSearch::Single) + && !arguments + .first() + .unwrap() + .value() + .has_leading_comments(CommentSearch::Single) { let argument = arguments.iter().next().unwrap(); @@ -473,7 +482,6 @@ pub fn format_function_args( // parentheses as well. Otherwise, we just use 1 = opening parentheses. let shape_increment = if hug_table_constructor { 2 } else { 1 }; - let (start_parens, end_parens) = parentheses.tokens(); let start_parens = format_token_reference(ctx, start_parens, shape); let start_parens = if start_parens.has_trailing_comments(CommentSearch::All) && !arguments.is_empty() diff --git a/tests/test_no_call_parens.rs b/tests/test_no_call_parens.rs index 221b10fc..ed46be1c 100644 --- a/tests/test_no_call_parens.rs +++ b/tests/test_no_call_parens.rs @@ -184,3 +184,113 @@ local still_got_em = my_function({ "### ); } + +#[test] +fn test_keep_parens_for_leading_comment() { + insta::assert_snapshot!( + format( + r#" +foo( -- test +"string") + +foo( + -- test +"string") + +foo( -- test + {}) + +foo( + -- test + {}) +"# + ), + @r#" + foo( -- test + "string" + ) + + foo( + -- test + "string" + ) + + foo( -- test + {} + ) + + foo( + -- test + {} + ) + "# + ); +} + +#[test] +fn test_keep_parens_for_trailing_comment() { + insta::assert_snapshot!( + format( + r#" +foo("string" -- test +) + +foo("string" + -- test +) + +foo({} -- test +) + +foo({} + -- test +) +"# + ), + @r#" + foo "string" -- test + + foo( + "string" + -- test + ) + + foo {} -- test + + foo( + {} + -- test + ) + "# + ); +} + +#[test] +fn test_keep_parentheses_large_example() { + insta::assert_snapshot!( + format( + r#" +wk.add( + { { key, "zv" .. key, "Same, but open folds" } } + -- { noremap = true, mode = { 'n', key:find '^<' and 'v' or 'x' } } +) + +wk.add( + -- { noremap = true, mode = { 'n', key:find '^<' and 'v' or 'x' } } + { { key, "zv" .. key, "Same, but open folds" } } +) +"# + ), + @r#" + wk.add( + { { key, "zv" .. key, "Same, but open folds" } } + -- { noremap = true, mode = { 'n', key:find '^<' and 'v' or 'x' } } + ) + + wk.add( + -- { noremap = true, mode = { 'n', key:find '^<' and 'v' or 'x' } } + { { key, "zv" .. key, "Same, but open folds" } } + ) + "# + ); +}