diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/list.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/list.py index 4478fc6e2211d..432885abd2b57 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/list.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/list.py @@ -44,3 +44,9 @@ [ # end-of-line comment 1 ] + +[ # inner comment + first, + second, + third +] # outer comment diff --git a/crates/ruff_python_formatter/src/comments/format.rs b/crates/ruff_python_formatter/src/comments/format.rs index 3ac6cb68c831d..29781c38a66e2 100644 --- a/crates/ruff_python_formatter/src/comments/format.rs +++ b/crates/ruff_python_formatter/src/comments/format.rs @@ -227,6 +227,57 @@ impl Format> for FormatDanglingComments<'_> { } } +/// Formats the dangling comments within a parenthesized expression, for example: +/// ```python +/// [ # comment +/// 1, +/// 2, +/// 3, +/// ] +/// ``` +pub(crate) fn dangling_open_parenthesis_comments( + comments: &[SourceComment], +) -> FormatDanglingOpenParenthesisComments { + FormatDanglingOpenParenthesisComments { comments } +} + +pub(crate) struct FormatDanglingOpenParenthesisComments<'a> { + comments: &'a [SourceComment], +} + +impl Format> for FormatDanglingOpenParenthesisComments<'_> { + fn fmt(&self, f: &mut Formatter) -> FormatResult<()> { + let mut comments = self + .comments + .iter() + .filter(|comment| comment.is_unformatted()); + + if let Some(comment) = comments.next() { + debug_assert!( + comment.line_position().is_end_of_line(), + "Expected dangling comment to be at the end of the line" + ); + + write!( + f, + [line_suffix(&format_args![ + space(), + space(), + format_comment(comment) + ])] + )?; + comment.mark_formatted(); + + debug_assert!( + comments.next().is_none(), + "Expected at most one dangling comment" + ); + } + + Ok(()) + } +} + /// Formats the content of the passed comment. /// /// * Adds a whitespace between `#` and the comment text except if the first character is a `#`, `:`, `'`, or `!` diff --git a/crates/ruff_python_formatter/src/comments/mod.rs b/crates/ruff_python_formatter/src/comments/mod.rs index 9cfb280e3d747..141a7e2c3e6ee 100644 --- a/crates/ruff_python_formatter/src/comments/mod.rs +++ b/crates/ruff_python_formatter/src/comments/mod.rs @@ -95,8 +95,9 @@ use std::rc::Rc; use ruff_python_ast::{Mod, Ranged}; pub(crate) use format::{ - dangling_comments, dangling_node_comments, leading_alternate_branch_comments, leading_comments, - leading_node_comments, trailing_comments, trailing_node_comments, + dangling_comments, dangling_node_comments, dangling_open_parenthesis_comments, + leading_alternate_branch_comments, leading_comments, leading_node_comments, trailing_comments, + trailing_node_comments, }; use ruff_formatter::{SourceCode, SourceCodeSlice}; use ruff_python_ast::node::AnyNodeRef; diff --git a/crates/ruff_python_formatter/src/expression/parentheses.rs b/crates/ruff_python_formatter/src/expression/parentheses.rs index 0a0a04a411838..cc61902ce937a 100644 --- a/crates/ruff_python_formatter/src/expression/parentheses.rs +++ b/crates/ruff_python_formatter/src/expression/parentheses.rs @@ -4,7 +4,7 @@ use ruff_python_ast::node::AnyNodeRef; use ruff_python_ast::Ranged; use ruff_python_trivia::{first_non_trivia_token, SimpleToken, SimpleTokenKind, SimpleTokenizer}; -use crate::comments::{dangling_comments, SourceComment}; +use crate::comments::{dangling_open_parenthesis_comments, SourceComment}; use crate::context::{NodeLevel, WithNodeLevel}; use crate::prelude::*; @@ -117,7 +117,7 @@ where } /// Formats `content` enclosed by the `left` and `right` parentheses, along with any dangling -/// comments that on the parentheses themselves. +/// comments on the opening parenthesis itself. pub(crate) fn parenthesized_with_dangling_comments<'content, 'ast, Content>( left: &'static str, comments: &'content [SourceComment], @@ -155,8 +155,8 @@ impl<'ast> Format> for FormatParenthesized<'_, 'ast> { } else { group(&format_args![ text(self.left), - &line_suffix(&dangling_comments(self.comments)), - &group(&soft_block_indent(&Arguments::from(&self.content))), + &dangling_open_parenthesis_comments(self.comments), + &soft_block_indent(&Arguments::from(&self.content)), text(self.right) ]) .fmt(f) @@ -319,10 +319,11 @@ impl<'ast> Format> for FormatInParenthesesOnlyGroup<'_, 'a #[cfg(test)] mod tests { - use crate::expression::parentheses::is_expression_parenthesized; use ruff_python_ast::node::AnyNodeRef; use ruff_python_parser::parse_expression; + use crate::expression::parentheses::is_expression_parenthesized; + #[test] fn test_has_parentheses() { let expression = r#"(b().c("")).d()"#; diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__multiline_consecutive_open_parentheses_ignore.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__multiline_consecutive_open_parentheses_ignore.py.snap index 8e1c160ff4912..1c0ac7dd11127 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__multiline_consecutive_open_parentheses_ignore.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__multiline_consecutive_open_parentheses_ignore.py.snap @@ -33,18 +33,19 @@ print( "111" ) # type: ignore ```diff --- Black +++ Ruff -@@ -1,10 +1,8 @@ +@@ -1,12 +1,6 @@ # This is a regression test. Issue #3737 -a = ( # type: ignore -+a = int( # type: ignore # type: ignore - int( # type: ignore +- int( # type: ignore - int( # type: ignore - int(6) # type: ignore - ) -+ int(6) # type: ignore - ) - ) +- ) +-) ++a = int(int(int(6))) # type: ignore # type: ignore # type: ignore # type: ignore + + b = int(6) ``` @@ -53,11 +54,7 @@ print( "111" ) # type: ignore ```py # This is a regression test. Issue #3737 -a = int( # type: ignore # type: ignore - int( # type: ignore - int(6) # type: ignore - ) -) +a = int(int(int(6))) # type: ignore # type: ignore # type: ignore # type: ignore b = int(6) diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__list.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__list.py.snap index e94d3cf33fec5..04f9c816e3229 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__list.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__list.py.snap @@ -50,6 +50,12 @@ c1 = [ # trailing open bracket [ # end-of-line comment 1 ] + +[ # inner comment + first, + second, + third +] # outer comment ``` ## Output @@ -94,6 +100,8 @@ c1 = [ # trailing open bracket ] [1] # end-of-line comment + +[first, second, third] # inner comment # outer comment ```