From 49724236b07cc0176da5b99c1f847bf0039b8af2 Mon Sep 17 00:00:00 2001 From: Reese Williams Date: Thu, 15 Jan 2026 19:41:03 +0100 Subject: [PATCH 1/2] [prism] Add tests around comments after call chains with leading expressions --- .../small/prism/expression_calls_actual.rb | 47 ++++++++++++++++++ .../small/prism/expression_calls_expected.rb | 48 +++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 fixtures/small/prism/expression_calls_actual.rb create mode 100644 fixtures/small/prism/expression_calls_expected.rb diff --git a/fixtures/small/prism/expression_calls_actual.rb b/fixtures/small/prism/expression_calls_actual.rb new file mode 100644 index 00000000..71d8250e --- /dev/null +++ b/fixtures/small/prism/expression_calls_actual.rb @@ -0,0 +1,47 @@ +[ + CommonFields::OBVIOUSLY, + CommonFields::THESE, + CommonFields::ARE, + CommonFields::FAKE_RESOURCE.with_wombo(true).with_combo(true).with_explosion(true) +].map do |field| + # Swap things out, to make sure. + override || field +end + +{ + having: "Having a Coke With You", + with: you +}.freeze + +{ + having: "Having a Coke With You", + with: you +} # by Mark Leidner + .freeze + +{ + having: "Having a Coke With You", + with: you +}.# by Mark Leidner +freeze + +{ + having: "Having a Coke With You", + with: you +} +# by Mark Leidner +.freeze + +{ + something: "wicked" +}.this_way { + comes + # spookyyyy +} + +{musical: "wicked"} + # The original broadway cast recording! + .sing("Defying Gravity") + +{musical: "wicked"} + .sing("Defying Gravity") # The original broadway cast recording! diff --git a/fixtures/small/prism/expression_calls_expected.rb b/fixtures/small/prism/expression_calls_expected.rb new file mode 100644 index 00000000..0db74275 --- /dev/null +++ b/fixtures/small/prism/expression_calls_expected.rb @@ -0,0 +1,48 @@ +[ + CommonFields::OBVIOUSLY, + CommonFields::THESE, + CommonFields::ARE, + CommonFields::FAKE_RESOURCE.with_wombo(true).with_combo(true).with_explosion(true) +].map do |field| + # Swap things out, to make sure. + override || field +end + +{ + having: "Having a Coke With You", + with: you +}.freeze + +{ + having: "Having a Coke With You", + with: you + # by Mark Leidner +}.freeze + +{ + having: "Having a Coke With You", + with: you + # by Mark Leidner +}.freeze + +{ + having: "Having a Coke With You", + with: you +} + # by Mark Leidner + .freeze + +{ + something: "wicked" +}.this_way { + comes + # spookyyyy +} + +{musical: "wicked"} + # The original broadway cast recording! + .sing("Defying Gravity") + +{musical: "wicked"} + # The original broadway cast recording! + .sing("Defying Gravity") From a91ccf2a1dde2ae69cc2c12ced2d0203919b42a1 Mon Sep 17 00:00:00 2001 From: Reese Williams Date: Thu, 15 Jan 2026 20:20:53 +0100 Subject: [PATCH 2/2] Fix comment check for expression-led call chains --- librubyfmt/src/format_prism.rs | 45 +++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/librubyfmt/src/format_prism.rs b/librubyfmt/src/format_prism.rs index f79483e5..50b11856 100644 --- a/librubyfmt/src/format_prism.rs +++ b/librubyfmt/src/format_prism.rs @@ -2351,23 +2351,34 @@ fn call_chain_elements_are_user_multilined<'src>( | prism::Node::ParenthesesNode { .. } ); - // _However_, don't ignore this if there are comments in the call chain though; this check may - // cause it to single-lined, which breaks comment rendering. Specifically, we're checking - // for comments in between the receiver expression and the following message, e.g. - // ```ruby - // [stuff] - // # spooky comment - // .freeze - // ``` - // For cases without the comment, we'd usually put this all on one line, but if we force - // it all on one line, this will break the comment insertion logic, and given the comment's - // placement, the user probably intended to break this onto multiple lines anyways. - let has_comment = ps.has_comment_in_offset_span( - call_chain_elements[0].location().end_offset(), - start_loc_for_call_node_in_chain(&call_chain_elements[1].as_call_node().unwrap()), - ); - if is_literal_expression && !has_comment { - call_chain_elements = &call_chain_elements[1..]; + if is_literal_expression { + // _However_, don't ignore this if there are comments in the call chain though; this check may + // cause it to single-lined, which breaks comment rendering. Specifically, we're checking + // for comments in between the receiver expression and the following message, e.g. + // ```ruby + // [stuff] + // # spooky comment + // .freeze + // ``` + // For cases without the comment, we'd usually put this all on one line, but if we force + // it all on one line, this will break the comment insertion logic, and given the comment's + // placement, the user probably intended to break this onto multiple lines anyways. + let first_call_start_line = ps.get_line_number_for_offset( + start_loc_for_call_node_in_chain(&call_chain_elements[1].as_call_node().unwrap()), + ); + let leading_expr_end_line = + ps.get_line_number_for_offset(call_chain_elements[0].location().end_offset()); + + // Note: We check from `leading_expr_end_line + 1` because comments on the same line as + // the closing brace will be rendered into the breakable during formatting, so they don't + // affect whether we should multiline the call chain. We check `first_call_start_line + 1` + // because the range checked by `has_comments_in_line` is non-inclusive. + let has_comment_between_expression_and_call = + ps.has_comments_in_line(leading_expr_end_line + 1, first_call_start_line + 1); + + if !has_comment_between_expression_and_call { + call_chain_elements = &call_chain_elements[1..]; + } } }