diff --git a/crates/ruff_formatter/src/printer/mod.rs b/crates/ruff_formatter/src/printer/mod.rs index 2bcb7fe582..df74c7ae36 100644 --- a/crates/ruff_formatter/src/printer/mod.rs +++ b/crates/ruff_formatter/src/printer/mod.rs @@ -116,7 +116,6 @@ impl<'a> Printer<'a> { self.print_str("\n"); } - self.state.pending_space = false; self.state.pending_indent = args.indention(); } } @@ -744,7 +743,6 @@ struct PrinterState<'a> { source_markers: Vec, source_position: TextSize, pending_indent: Indention, - pending_space: bool, measured_group_fits: bool, generated_line: usize, generated_column: usize, @@ -1009,12 +1007,12 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> { let args = self.stack.top(); match element { - FormatElement::Space => return Ok(self.fits_text(" ")), + FormatElement::Space => return Ok(self.fits_text(" ", args)), FormatElement::Line(line_mode) => { match args.mode() { PrintMode::Flat => match line_mode { - LineMode::SoftOrSpace => return Ok(self.fits_text(" ")), + LineMode::SoftOrSpace => return Ok(self.fits_text(" ", args)), LineMode::Soft => {} LineMode::Hard | LineMode::Empty => { return Ok(if self.must_be_flat { @@ -1036,17 +1034,18 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> { MeasureMode::AllLines => { // Continue measuring on the next line self.state.line_width = 0; + self.state.pending_indent = args.indention(); } } } } } - FormatElement::StaticText { text } => return Ok(self.fits_text(text)), - FormatElement::DynamicText { text, .. } => return Ok(self.fits_text(text)), + FormatElement::StaticText { text } => return Ok(self.fits_text(text, args)), + FormatElement::DynamicText { text, .. } => return Ok(self.fits_text(text, args)), FormatElement::SourceCodeSlice { slice, .. } => { let text = slice.text(self.printer.source_code); - return Ok(self.fits_text(text)); + return Ok(self.fits_text(text, args)); } FormatElement::LineSuffixBoundary => { if self.state.has_line_suffix { @@ -1255,7 +1254,7 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> { Ok(Fits::Maybe) } - fn fits_text(&mut self, text: &str) -> Fits { + fn fits_text(&mut self, text: &str, args: PrintElementArgs) -> Fits { let indent = std::mem::take(&mut self.state.pending_indent); self.state.line_width += indent.level() as usize * self.options().indent_width() as usize + indent.align() as usize; @@ -1264,10 +1263,17 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> { let char_width = match c { '\t' => self.options().tab_width as usize, '\n' => { - return if self.must_be_flat { - Fits::No + if self.must_be_flat { + return Fits::No; } else { - Fits::Yes + match args.measure_mode() { + MeasureMode::FirstLine => return Fits::Yes, + MeasureMode::AllLines => { + self.state.line_width = 0; + self.state.pending_indent = args.indention(); + continue; + } + } }; } c => c.width().unwrap_or(0), diff --git a/crates/ruff_python_formatter/src/expression/expr_attribute.rs b/crates/ruff_python_formatter/src/expression/expr_attribute.rs index ed8ca6cd3f..a577ae88d0 100644 --- a/crates/ruff_python_formatter/src/expression/expr_attribute.rs +++ b/crates/ruff_python_formatter/src/expression/expr_attribute.rs @@ -75,7 +75,7 @@ impl FormatNodeRule for FormatExprAttribute { impl NeedsParentheses for ExprAttribute { fn needs_parentheses( &self, - parent: AnyNodeRef, + _parent: AnyNodeRef, context: &PyFormatContext, ) -> OptionalParentheses { // Checks if there are any own line comments in an attribute chain (a.b.c). @@ -88,7 +88,7 @@ impl NeedsParentheses for ExprAttribute { { OptionalParentheses::Always } else { - self.value.needs_parentheses(parent, context) + self.value.needs_parentheses(self.into(), context) } } } diff --git a/crates/ruff_python_formatter/src/expression/expr_call.rs b/crates/ruff_python_formatter/src/expression/expr_call.rs index 1f204bc382..85ecfff06b 100644 --- a/crates/ruff_python_formatter/src/expression/expr_call.rs +++ b/crates/ruff_python_formatter/src/expression/expr_call.rs @@ -119,10 +119,10 @@ impl FormatNodeRule for FormatExprCall { impl NeedsParentheses for ExprCall { fn needs_parentheses( &self, - parent: AnyNodeRef, + _parent: AnyNodeRef, context: &PyFormatContext, ) -> OptionalParentheses { - self.func.needs_parentheses(parent, context) + self.func.needs_parentheses(self.into(), context) } } diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition.py.snap index c1e0f895db..e012b766e5 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition.py.snap @@ -203,18 +203,41 @@ class C: print(i) xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy( push_manager=context.request.resource_manager, -@@ -120,9 +120,7 @@ - key7: value7, - key8: value8, - key9: value9, +@@ -110,19 +110,20 @@ + value, is_going_to_be="too long to fit in a single line", srsly=True + ), "Not what we expected" + +- assert { +- key1: value1, +- key2: value2, +- key3: value3, +- key4: value4, +- key5: value5, +- key6: value6, +- key7: value7, +- key8: value8, +- key9: value9, - } == expected, ( - "Not what we expected and the message is too long to fit in one line" - ) -+ } == expected, "Not what we expected and the message is too long to fit in one line" ++ assert ( ++ { ++ key1: value1, ++ key2: value2, ++ key3: value3, ++ key4: value4, ++ key5: value5, ++ key6: value6, ++ key7: value7, ++ key8: value8, ++ key9: value9, ++ } ++ == expected ++ ), "Not what we expected and the message is too long to fit in one line" assert expected( value, is_going_to_be="too long to fit in a single line", srsly=True -@@ -153,7 +151,8 @@ +@@ -153,7 +154,8 @@ " because it's too long" ) @@ -224,7 +247,7 @@ class C: %3d 0 LOAD_FAST 1 (x) 2 LOAD_CONST 1 (1) 4 COMPARE_OP 2 (==) -@@ -161,8 +160,8 @@ +@@ -161,8 +163,8 @@ 8 STORE_ATTR 0 (x) 10 LOAD_CONST 0 (None) 12 RETURN_VALUE @@ -352,17 +375,20 @@ class C: value, is_going_to_be="too long to fit in a single line", srsly=True ), "Not what we expected" - assert { - key1: value1, - key2: value2, - key3: value3, - key4: value4, - key5: value5, - key6: value6, - key7: value7, - key8: value8, - key9: value9, - } == expected, "Not what we expected and the message is too long to fit in one line" + assert ( + { + key1: value1, + key2: value2, + key3: value3, + key4: value4, + key5: value5, + key6: value6, + key7: value7, + key8: value8, + key9: value9, + } + == expected + ), "Not what we expected and the message is too long to fit in one line" assert expected( value, is_going_to_be="too long to fit in a single line", srsly=True diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition_no_trailing_comma.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition_no_trailing_comma.py.snap index 3374be58a3..8de3059b3b 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition_no_trailing_comma.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition_no_trailing_comma.py.snap @@ -203,18 +203,41 @@ class C: print(i) xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy( push_manager=context.request.resource_manager, -@@ -120,9 +120,7 @@ - key7: value7, - key8: value8, - key9: value9, +@@ -110,19 +110,20 @@ + value, is_going_to_be="too long to fit in a single line", srsly=True + ), "Not what we expected" + +- assert { +- key1: value1, +- key2: value2, +- key3: value3, +- key4: value4, +- key5: value5, +- key6: value6, +- key7: value7, +- key8: value8, +- key9: value9, - } == expected, ( - "Not what we expected and the message is too long to fit in one line" - ) -+ } == expected, "Not what we expected and the message is too long to fit in one line" ++ assert ( ++ { ++ key1: value1, ++ key2: value2, ++ key3: value3, ++ key4: value4, ++ key5: value5, ++ key6: value6, ++ key7: value7, ++ key8: value8, ++ key9: value9, ++ } ++ == expected ++ ), "Not what we expected and the message is too long to fit in one line" assert expected( value, is_going_to_be="too long to fit in a single line", srsly=True -@@ -153,7 +151,8 @@ +@@ -153,7 +154,8 @@ " because it's too long" ) @@ -224,7 +247,7 @@ class C: %3d 0 LOAD_FAST 1 (x) 2 LOAD_CONST 1 (1) 4 COMPARE_OP 2 (==) -@@ -161,8 +160,8 @@ +@@ -161,8 +163,8 @@ 8 STORE_ATTR 0 (x) 10 LOAD_CONST 0 (None) 12 RETURN_VALUE @@ -352,17 +375,20 @@ class C: value, is_going_to_be="too long to fit in a single line", srsly=True ), "Not what we expected" - assert { - key1: value1, - key2: value2, - key3: value3, - key4: value4, - key5: value5, - key6: value6, - key7: value7, - key8: value8, - key9: value9, - } == expected, "Not what we expected and the message is too long to fit in one line" + assert ( + { + key1: value1, + key2: value2, + key3: value3, + key4: value4, + key5: value5, + key6: value6, + key7: value7, + key8: value8, + key9: value9, + } + == expected + ), "Not what we expected and the message is too long to fit in one line" assert expected( value, is_going_to_be="too long to fit in a single line", srsly=True