mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 18:58:26 +00:00
Fix \r
and \r\n
handling in t- and f-string debug texts (#18673)
This commit is contained in:
parent
5e02d839d5
commit
8237d4670c
6 changed files with 79 additions and 4 deletions
3
.gitattributes
vendored
3
.gitattributes
vendored
|
@ -5,6 +5,9 @@ crates/ruff_linter/resources/test/fixtures/pycodestyle/W605_1.py text eol=crlf
|
||||||
crates/ruff_linter/resources/test/fixtures/pycodestyle/W391_2.py text eol=crlf
|
crates/ruff_linter/resources/test/fixtures/pycodestyle/W391_2.py text eol=crlf
|
||||||
crates/ruff_linter/resources/test/fixtures/pycodestyle/W391_3.py text eol=crlf
|
crates/ruff_linter/resources/test/fixtures/pycodestyle/W391_3.py text eol=crlf
|
||||||
|
|
||||||
|
crates/ruff_python_formatter/resources/test/fixtures/ruff/f-string-carriage-return-newline.py text eol=crlf
|
||||||
|
crates/ruff_python_formatter/tests/snapshots/format@f-string-carriage-return-newline.py.snap text eol=crlf
|
||||||
|
|
||||||
crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.py text eol=crlf
|
crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.py text eol=crlf
|
||||||
crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap text eol=crlf
|
crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap text eol=crlf
|
||||||
|
|
||||||
|
|
|
@ -8,4 +8,8 @@ ij_formatter_enabled = false
|
||||||
|
|
||||||
[docstring_tab_indentation.py]
|
[docstring_tab_indentation.py]
|
||||||
generated_code = true
|
generated_code = true
|
||||||
ij_formatter_enabled = false
|
ij_formatter_enabled = false
|
||||||
|
|
||||||
|
[f-string-carriage-return-newline.py]
|
||||||
|
generated_code = true
|
||||||
|
ij_formatter_enabled = false
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
# Regression test for https://github.com/astral-sh/ruff/issues/18667
|
||||||
|
f"{
|
||||||
|
1=
|
||||||
|
}"
|
||||||
|
|
||||||
|
t"{
|
||||||
|
1=
|
||||||
|
}"
|
|
@ -1,6 +1,6 @@
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use ruff_formatter::{Buffer, RemoveSoftLinesBuffer, format_args, write};
|
use ruff_formatter::{Buffer, FormatOptions as _, RemoveSoftLinesBuffer, format_args, write};
|
||||||
use ruff_python_ast::{
|
use ruff_python_ast::{
|
||||||
AnyStringFlags, ConversionFlag, Expr, InterpolatedElement, InterpolatedStringElement,
|
AnyStringFlags, ConversionFlag, Expr, InterpolatedElement, InterpolatedStringElement,
|
||||||
InterpolatedStringLiteralElement, StringFlags,
|
InterpolatedStringLiteralElement, StringFlags,
|
||||||
|
@ -178,9 +178,9 @@ impl Format<PyFormatContext<'_>> for FormatInterpolatedElement<'_> {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
[
|
[
|
||||||
text(&debug_text.leading),
|
NormalizedDebugText(&debug_text.leading),
|
||||||
verbatim_text(&**expression),
|
verbatim_text(&**expression),
|
||||||
text(&debug_text.trailing),
|
NormalizedDebugText(&debug_text.trailing),
|
||||||
]
|
]
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -316,3 +316,18 @@ fn needs_bracket_spacing(expr: &Expr, context: &PyFormatContext) -> bool {
|
||||||
Expr::Dict(_) | Expr::DictComp(_) | Expr::Set(_) | Expr::SetComp(_)
|
Expr::Dict(_) | Expr::DictComp(_) | Expr::Set(_) | Expr::SetComp(_)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct NormalizedDebugText<'a>(&'a str);
|
||||||
|
|
||||||
|
impl Format<PyFormatContext<'_>> for NormalizedDebugText<'_> {
|
||||||
|
fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> {
|
||||||
|
let normalized = normalize_newlines(self.0, ['\r']);
|
||||||
|
|
||||||
|
f.write_element(FormatElement::Text {
|
||||||
|
text_width: TextWidth::from_text(&normalized, f.options().indent_width()),
|
||||||
|
text: normalized.into_owned().into_boxed_str(),
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -196,6 +196,24 @@ impl Transformer for Normalizer {
|
||||||
transformer::walk_expr(self, expr);
|
transformer::walk_expr(self, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_interpolated_string_element(
|
||||||
|
&self,
|
||||||
|
interpolated_string_element: &mut InterpolatedStringElement,
|
||||||
|
) {
|
||||||
|
let InterpolatedStringElement::Interpolation(interpolation) = interpolated_string_element
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Some(debug) = &mut interpolation.debug_text else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Changing the newlines to the configured newline is okay because Python normalizes all newlines to `\n`
|
||||||
|
debug.leading = debug.leading.replace("\r\n", "\n").replace('\r', "\n");
|
||||||
|
debug.trailing = debug.trailing.replace("\r\n", "\n").replace('\r', "\n");
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_string_literal(&self, string_literal: &mut ast::StringLiteral) {
|
fn visit_string_literal(&self, string_literal: &mut ast::StringLiteral) {
|
||||||
static STRIP_DOC_TESTS: LazyLock<Regex> = LazyLock::new(|| {
|
static STRIP_DOC_TESTS: LazyLock<Regex> = LazyLock::new(|| {
|
||||||
Regex::new(
|
Regex::new(
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/f-string-carriage-return-newline.py
|
||||||
|
---
|
||||||
|
## Input
|
||||||
|
```python
|
||||||
|
# Regression test for https://github.com/astral-sh/ruff/issues/18667
|
||||||
|
f"{
|
||||||
|
1=
|
||||||
|
}"
|
||||||
|
|
||||||
|
t"{
|
||||||
|
1=
|
||||||
|
}"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
```python
|
||||||
|
# Regression test for https://github.com/astral-sh/ruff/issues/18667
|
||||||
|
f"{
|
||||||
|
1=
|
||||||
|
}"
|
||||||
|
|
||||||
|
t"{
|
||||||
|
1=
|
||||||
|
}"
|
||||||
|
```
|
Loading…
Add table
Add a link
Reference in a new issue