From 6662fc996e9c91c79cb89ff0d8023bcab99e8ede Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Fri, 27 Oct 2023 17:54:39 +0900 Subject: [PATCH 1/2] Preserve trailing semicolons when using `fmt: off` --- .../ruff/fmt_on_off/trailing_semicolon.py | 27 ++++++++ crates/ruff_python_formatter/src/lib.rs | 12 ++-- crates/ruff_python_formatter/src/verbatim.rs | 20 +++--- ...mat@fmt_on_off__trailing_semicolon.py.snap | 69 +++++++++++++++++++ 4 files changed, 114 insertions(+), 14 deletions(-) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/fmt_on_off/trailing_semicolon.py create mode 100644 crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__trailing_semicolon.py.snap diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/fmt_on_off/trailing_semicolon.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/fmt_on_off/trailing_semicolon.py new file mode 100644 index 0000000000000..f7de6e457f348 --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/fmt_on_off/trailing_semicolon.py @@ -0,0 +1,27 @@ +def f(): + # fmt: off + a = 10 + + if True: + with_semicolon = 10 \ + ; + +formatted = true; + + +def f(): + # fmt: off + + if True: + with_semicolon = 20 \ + ; # comment + + +# fmt: off +statement = 0 \ + ; +# fmt: on +a = 10 + +# fmt: off +last_statement_with_semi ; diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index 7697789fe072c..2762063dca16f 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -206,13 +206,13 @@ if True: #[test] fn quick_test() { let source = r#" -def main() -> None: +def f(): + # fmt: off + if True: - some_very_long_variable_name_abcdefghijk = Foo() - some_very_long_variable_name_abcdefghijk = some_very_long_variable_name_abcdefghijk[ - some_very_long_variable_name_abcdefghijk.some_very_long_attribute_name - == "This is a very long string abcdefghijk" - ] + with_semicolon = 20 \ + ; # comment + "#; let source_type = PySourceType::Python; diff --git a/crates/ruff_python_formatter/src/verbatim.rs b/crates/ruff_python_formatter/src/verbatim.rs index 00f8e149609ec..99e8e22e2de19 100644 --- a/crates/ruff_python_formatter/src/verbatim.rs +++ b/crates/ruff_python_formatter/src/verbatim.rs @@ -395,14 +395,18 @@ fn write_suppressed_statements<'a>( statement = SuiteChildStatement::Other(next_statement); leading_node_comments = comments.leading(next_statement); } else { - let mut nodes = - std::iter::successors(Some(AnyNodeRef::from(statement.statement())), |statement| { - statement.last_child_in_body() - }); - - let end = nodes - .find_map(|statement| comments.trailing(statement).last().map(Ranged::end)) - .unwrap_or(statement.end()); + let mut current = AnyNodeRef::from(statement.statement()); + // Expand the range of the statement to include any trailing comments or semicolons. + let end = loop { + if let Some(comment) = comments.trailing(current).last() { + break comment.end(); + } else if let Some(child) = AnyNodeRef::from(current).last_child_in_body() { + current = child; + } else { + break trailing_semicolon(current, source) + .map_or(statement.end(), TextRange::end); + } + }; FormatVerbatimStatementRange { verbatim_range: TextRange::new(format_off_comment.end(), end), diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__trailing_semicolon.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__trailing_semicolon.py.snap new file mode 100644 index 0000000000000..463294c542dc0 --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__trailing_semicolon.py.snap @@ -0,0 +1,69 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/fmt_on_off/trailing_semicolon.py +--- +## Input +```py +def f(): + # fmt: off + a = 10 + + if True: + with_semicolon = 10 \ + ; + +formatted = true; + + +def f(): + # fmt: off + + if True: + with_semicolon = 20 \ + ; # comment + + +# fmt: off +statement = 0 \ + ; +# fmt: on +a = 10 + +# fmt: off +last_statement_with_semi ; +``` + +## Output +```py +def f(): + # fmt: off + a = 10 + + if True: + with_semicolon = 10 \ + ; + + +formatted = true + + +def f(): + # fmt: off + + if True: + with_semicolon = 20 \ + ; # comment + + +# fmt: off +statement = 0 \ + ; +# fmt: on +a = 10 + +# fmt: off +last_statement_with_semi ; +``` + + + From d47483b70f824ba47ee5efbc8cede388cfd14a80 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Fri, 27 Oct 2023 17:58:31 +0900 Subject: [PATCH 2/2] Discard changes to crates/ruff_python_formatter/src/lib.rs --- crates/ruff_python_formatter/src/lib.rs | 12 ++++++------ crates/ruff_python_formatter/src/verbatim.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index 2762063dca16f..7697789fe072c 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -206,13 +206,13 @@ if True: #[test] fn quick_test() { let source = r#" -def f(): - # fmt: off - +def main() -> None: if True: - with_semicolon = 20 \ - ; # comment - + some_very_long_variable_name_abcdefghijk = Foo() + some_very_long_variable_name_abcdefghijk = some_very_long_variable_name_abcdefghijk[ + some_very_long_variable_name_abcdefghijk.some_very_long_attribute_name + == "This is a very long string abcdefghijk" + ] "#; let source_type = PySourceType::Python; diff --git a/crates/ruff_python_formatter/src/verbatim.rs b/crates/ruff_python_formatter/src/verbatim.rs index 99e8e22e2de19..5c29b0039d2b5 100644 --- a/crates/ruff_python_formatter/src/verbatim.rs +++ b/crates/ruff_python_formatter/src/verbatim.rs @@ -400,7 +400,7 @@ fn write_suppressed_statements<'a>( let end = loop { if let Some(comment) = comments.trailing(current).last() { break comment.end(); - } else if let Some(child) = AnyNodeRef::from(current).last_child_in_body() { + } else if let Some(child) = current.last_child_in_body() { current = child; } else { break trailing_semicolon(current, source)