diff --git a/crates/ruff_python_formatter/src/preview.rs b/crates/ruff_python_formatter/src/preview.rs index ff94f66081ba9..3876317c3014f 100644 --- a/crates/ruff_python_formatter/src/preview.rs +++ b/crates/ruff_python_formatter/src/preview.rs @@ -14,13 +14,6 @@ pub(crate) const fn is_hug_parens_with_braces_and_square_brackets_enabled( context.is_preview() } -/// Returns `true` if the [`no_chaperone_for_escaped_quote_in_triple_quoted_docstring`](https://github.com/astral-sh/ruff/pull/17216) preview style is enabled. -pub(crate) const fn is_no_chaperone_for_escaped_quote_in_triple_quoted_docstring_enabled( - context: &PyFormatContext, -) -> bool { - context.is_preview() -} - /// Returns `true` if the [`blank_line_before_decorated_class_in_stub`](https://github.com/astral-sh/ruff/issues/18865) preview style is enabled. pub(crate) const fn is_blank_line_before_decorated_class_in_stub_enabled( context: &PyFormatContext, diff --git a/crates/ruff_python_formatter/src/string/docstring.rs b/crates/ruff_python_formatter/src/string/docstring.rs index c4554175d55d1..f5c73c3f70952 100644 --- a/crates/ruff_python_formatter/src/string/docstring.rs +++ b/crates/ruff_python_formatter/src/string/docstring.rs @@ -20,7 +20,6 @@ use { }; use super::NormalizedString; -use crate::preview::is_no_chaperone_for_escaped_quote_in_triple_quoted_docstring_enabled; use crate::string::StringQuotes; use crate::{DocstringCodeLineWidth, FormatModuleError, prelude::*}; @@ -168,7 +167,7 @@ pub(crate) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> Form if docstring[first.len()..].trim().is_empty() { // For `"""\n"""` or other whitespace between the quotes, black keeps a single whitespace, // but `""""""` doesn't get one inserted. - if needs_chaperone_space(normalized.flags(), trim_end, f.context()) + if needs_chaperone_space(normalized.flags(), trim_end) || (trim_end.is_empty() && !docstring.is_empty()) { space().fmt(f)?; @@ -208,7 +207,7 @@ pub(crate) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> Form let trim_end = docstring .as_ref() .trim_end_matches(|c: char| c.is_whitespace() && c != '\n'); - if needs_chaperone_space(normalized.flags(), trim_end, f.context()) { + if needs_chaperone_space(normalized.flags(), trim_end) { space().fmt(f)?; } @@ -1599,36 +1598,28 @@ fn docstring_format_source( /// If the last line of the docstring is `content""""` or `content\"""`, we need a chaperone space /// that avoids `content""""` and `content\"""`. This only applies to un-escaped backslashes, /// so `content\\"""` doesn't need a space while `content\\\"""` does. -pub(super) fn needs_chaperone_space( - flags: AnyStringFlags, - trim_end: &str, - context: &PyFormatContext, -) -> bool { +pub(super) fn needs_chaperone_space(flags: AnyStringFlags, trim_end: &str) -> bool { if count_consecutive_chars_from_end(trim_end, '\\') % 2 == 1 { // Odd backslash count; chaperone avoids escaping closing quotes // `"\ "` -> prevent that this becomes `"\"` which escapes the closing quote. return true; } - if is_no_chaperone_for_escaped_quote_in_triple_quoted_docstring_enabled(context) { - if flags.is_triple_quoted() { - if let Some(before_quote) = trim_end.strip_suffix(flags.quote_style().as_char()) { - if count_consecutive_chars_from_end(before_quote, '\\').is_multiple_of(2) { - // Even backslash count preceding quote; - // ```py - // """a " """ - // """a \\" """ - // ``` - // The chaperon is needed or the triple quoted string "ends" with 4 instead of 3 quotes. - return true; - } + if flags.is_triple_quoted() { + if let Some(before_quote) = trim_end.strip_suffix(flags.quote_style().as_char()) { + if count_consecutive_chars_from_end(before_quote, '\\').is_multiple_of(2) { + // Even backslash count preceding quote; + // ```py + // """a " """ + // """a \\" """ + // ``` + // The chaperon is needed or the triple quoted string "ends" with 4 instead of 3 quotes. + return true; } } - - false - } else { - flags.is_triple_quoted() && trim_end.ends_with(flags.quote_style().as_char()) } + + false } fn count_consecutive_chars_from_end(s: &str, target: char) -> usize { diff --git a/crates/ruff_python_formatter/src/string/implicit.rs b/crates/ruff_python_formatter/src/string/implicit.rs index fc25d030aa8c2..3acb0aae19a50 100644 --- a/crates/ruff_python_formatter/src/string/implicit.rs +++ b/crates/ruff_python_formatter/src/string/implicit.rs @@ -407,7 +407,7 @@ impl Format> for FormatLiteralContent { Cow::Owned(normalized) => text(normalized).fmt(f)?, } - if self.trim_end && needs_chaperone_space(self.flags, &normalized, f.context()) { + if self.trim_end && needs_chaperone_space(self.flags, &normalized) { space().fmt(f)?; } } diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_chaperones.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_chaperones.py.snap index a70158a84ed18..a424033eba90d 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_chaperones.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_chaperones.py.snap @@ -1,6 +1,5 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs -input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_chaperones.py --- ## Input ```python @@ -99,7 +98,7 @@ def a6(): def a7(): - """Doesn't need chaperone\" """ + """Doesn't need chaperone\"""" def a8(): @@ -107,7 +106,7 @@ def a8(): def a9(): - """Doesn't need chaperone\\\" """ + """Doesn't need chaperone\\\"""" def a10(): @@ -127,7 +126,7 @@ def a12(): def a13(): - """Doesn't need chaperone\\\"\"\" """ + """Doesn't need chaperone\\\"\"\"""" def a14(): @@ -159,37 +158,3 @@ def a18(): doesn't need chaperone\ """ ``` - - -## Preview changes -```diff ---- Stable -+++ Preview -@@ -23,7 +23,7 @@ - - - def a7(): -- """Doesn't need chaperone\" """ -+ """Doesn't need chaperone\"""" - - - def a8(): -@@ -31,7 +31,7 @@ - - - def a9(): -- """Doesn't need chaperone\\\" """ -+ """Doesn't need chaperone\\\"""" - - - def a10(): -@@ -51,7 +51,7 @@ - - - def a13(): -- """Doesn't need chaperone\\\"\"\" """ -+ """Doesn't need chaperone\\\"\"\"""" - - - def a14(): -```