diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/parentheses/best_fit.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/parentheses/best_fit.py new file mode 100644 index 0000000000000..f9b99466bbaf3 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/parentheses/best_fit.py @@ -0,0 +1,14 @@ +UNUSABLE_PASSWORD_SUFFIX_LENGTH = 40 # number of random chars to add after UNUSABLE_PASSWORD_PREFIX + + +UNUSABLE_PASSWORD_SUFFIX_LENGTH = ( + 40 +) # number of random chars to add after UNUSABLE_PASSWORD_PREFIX + + + +UNUSABLE_PASSWORD_SUFFIX_LENGTH = ( + 40 # number of random chars to add after UNUSABLE_PASSWORD_PREFIX +) + + diff --git a/crates/ruff_python_formatter/src/expression/expr_constant.rs b/crates/ruff_python_formatter/src/expression/expr_constant.rs index 8f3de76916a80..263f741935972 100644 --- a/crates/ruff_python_formatter/src/expression/expr_constant.rs +++ b/crates/ruff_python_formatter/src/expression/expr_constant.rs @@ -75,7 +75,7 @@ impl FormatNodeRule for FormatExprConstant { impl NeedsParentheses for ExprConstant { fn needs_parentheses( &self, - _parent: AnyNodeRef, + parent: AnyNodeRef, context: &PyFormatContext, ) -> OptionalParentheses { if self.value.is_implicit_concatenated() { @@ -86,7 +86,7 @@ impl NeedsParentheses for ExprConstant { || self.value.is_ellipsis() { OptionalParentheses::Never - } else if should_use_best_fit(self, context) { + } else if should_use_best_fit(self, parent, context) { OptionalParentheses::BestFit } else { OptionalParentheses::Never diff --git a/crates/ruff_python_formatter/src/expression/expr_f_string.rs b/crates/ruff_python_formatter/src/expression/expr_f_string.rs index 054990fb7ebcb..441db5aecd6a6 100644 --- a/crates/ruff_python_formatter/src/expression/expr_f_string.rs +++ b/crates/ruff_python_formatter/src/expression/expr_f_string.rs @@ -21,13 +21,13 @@ impl FormatNodeRule for FormatExprFString { impl NeedsParentheses for ExprFString { fn needs_parentheses( &self, - _parent: AnyNodeRef, + parent: AnyNodeRef, context: &PyFormatContext, ) -> OptionalParentheses { if self.implicit_concatenated { OptionalParentheses::Multiline } else if memchr2(b'\n', b'\r', context.source()[self.range].as_bytes()).is_none() - && should_use_best_fit(self, context) + && should_use_best_fit(self, parent, context) { OptionalParentheses::BestFit } else { diff --git a/crates/ruff_python_formatter/src/expression/expr_name.rs b/crates/ruff_python_formatter/src/expression/expr_name.rs index e0585f55abee5..305698cfe630c 100644 --- a/crates/ruff_python_formatter/src/expression/expr_name.rs +++ b/crates/ruff_python_formatter/src/expression/expr_name.rs @@ -37,10 +37,10 @@ impl FormatNodeRule for FormatExprName { impl NeedsParentheses for ExprName { fn needs_parentheses( &self, - _parent: AnyNodeRef, + parent: AnyNodeRef, context: &PyFormatContext, ) -> OptionalParentheses { - if should_use_best_fit(self, context) { + if should_use_best_fit(self, parent, context) { OptionalParentheses::BestFit } else { OptionalParentheses::Never diff --git a/crates/ruff_python_formatter/src/expression/parentheses.rs b/crates/ruff_python_formatter/src/expression/parentheses.rs index 0a0b85a864d5e..fb507056c5319 100644 --- a/crates/ruff_python_formatter/src/expression/parentheses.rs +++ b/crates/ruff_python_formatter/src/expression/parentheses.rs @@ -4,6 +4,7 @@ use ruff_python_ast::node::AnyNodeRef; use ruff_python_ast::ExpressionRef; use ruff_python_trivia::{first_non_trivia_token, SimpleToken, SimpleTokenKind, SimpleTokenizer}; use ruff_text_size::Ranged; +use ruff_text_size::TextSize; use crate::comments::{ dangling_comments, dangling_open_parenthesis_comments, trailing_comments, SourceComment, @@ -29,11 +30,18 @@ pub(crate) enum OptionalParentheses { Never, } -pub(super) fn should_use_best_fit(value: T, context: &PyFormatContext) -> bool +pub(super) fn should_use_best_fit<'a, T, U>(value: T, parent: U, context: &PyFormatContext) -> bool where T: Ranged, + U: Into>, { let text_len = context.source()[value.range()].len(); + let trailing_comments = context.comments().trailing(parent.into()); + let eol_comment_length: TextSize = trailing_comments + .iter() + .filter(|c| c.line_position().is_end_of_line()) + .map(|c| c.range().len()) + .sum(); // Only use best fits if: // * The text is longer than 5 characters: @@ -44,7 +52,7 @@ where // of 5 characters to avoid it exceeding the line width by 1 reduces the readability. // * The text is know to never fit: The text can never fit even when parenthesizing if it is longer // than the configured line width (minus indent). - text_len > 5 + text_len + Into::::into(eol_comment_length) > 5 && text_len <= context.options().line_width().value() as usize - context.options().indent_width() as usize diff --git a/crates/ruff_python_formatter/tests/snapshots/format@parentheses__best_fit.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@parentheses__best_fit.py.snap new file mode 100644 index 0000000000000..9c216e8c4b6dd --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/format@parentheses__best_fit.py.snap @@ -0,0 +1,30 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/parentheses/best_fit.py +--- +## Input +```py +UNUSABLE_PASSWORD_SUFFIX_LENGTH = 40 # number of random chars to add after UNUSABLE_PASSWORD_PREFIX + + +UNUSABLE_PASSWORD_SUFFIX_LENGTH = ( + 40 +) # number of random chars to add after UNUSABLE_PASSWORD_PREFIX + + +``` + +## Output +```py +UNUSABLE_PASSWORD_SUFFIX_LENGTH = ( + 40 +) # number of random chars to add after UNUSABLE_PASSWORD_PREFIX + + +UNUSABLE_PASSWORD_SUFFIX_LENGTH = ( + 40 +) # number of random chars to add after UNUSABLE_PASSWORD_PREFIX +``` + + +