mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-09 21:28:04 +00:00
Preserve triple quotes and prefixes for strings (#15818)
## Summary This is a follow-up to #15726, #15778, and #15794 to preserve the triple quote and prefix flags in plain strings, bytestrings, and f-strings. I also added a `StringLiteralFlags::without_triple_quotes` method to avoid passing along triple quotes in rules like SIM905 where it might not make sense, as discussed [here](https://github.com/astral-sh/ruff/pull/15726#discussion_r1930532426). ## Test Plan Existing tests, plus many new cases in the `generator::tests::quote` test that should cover all combinations of quotes and prefixes, at least for simple string bodies. Closes #7799 when combined with #15694, #15726, #15778, and #15794. --------- Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
9a33924a65
commit
b5e5271adf
16 changed files with 318 additions and 141 deletions
|
@ -1,6 +1,6 @@
|
|||
use itertools::Itertools;
|
||||
use ruff_formatter::{format_args, write, FormatContext};
|
||||
use ruff_python_ast::str::Quote;
|
||||
use ruff_python_ast::str::{Quote, TripleQuotes};
|
||||
use ruff_python_ast::str_prefix::{
|
||||
AnyStringPrefix, ByteStringPrefix, FStringPrefix, StringLiteralPrefix,
|
||||
};
|
||||
|
@ -230,7 +230,7 @@ impl<'a> FormatImplicitConcatenatedStringFlat<'a> {
|
|||
}
|
||||
};
|
||||
|
||||
Some(AnyStringFlags::new(prefix, quote, false))
|
||||
Some(AnyStringFlags::new(prefix, quote, TripleQuotes::No))
|
||||
}
|
||||
|
||||
if !string.is_implicit_concatenated() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use memchr::memchr2;
|
||||
pub(crate) use normalize::{normalize_string, NormalizedString, StringNormalizer};
|
||||
use ruff_python_ast::str::Quote;
|
||||
use ruff_python_ast::str::{Quote, TripleQuotes};
|
||||
use ruff_python_ast::StringLikePart;
|
||||
use ruff_python_ast::{
|
||||
self as ast,
|
||||
|
@ -95,11 +95,11 @@ impl StringLikeExtensions for ast::StringLike<'_> {
|
|||
fn contains_line_break_or_comments(
|
||||
elements: &ast::FStringElements,
|
||||
context: &PyFormatContext,
|
||||
is_triple_quoted: bool,
|
||||
triple_quotes: TripleQuotes,
|
||||
) -> bool {
|
||||
elements.iter().any(|element| match element {
|
||||
ast::FStringElement::Literal(literal) => {
|
||||
is_triple_quoted
|
||||
triple_quotes.is_yes()
|
||||
&& context.source().contains_line_break(literal.range())
|
||||
}
|
||||
ast::FStringElement::Expression(expression) => {
|
||||
|
@ -119,7 +119,7 @@ impl StringLikeExtensions for ast::StringLike<'_> {
|
|||
contains_line_break_or_comments(
|
||||
&spec.elements,
|
||||
context,
|
||||
is_triple_quoted,
|
||||
triple_quotes,
|
||||
)
|
||||
})
|
||||
|| expression.debug_text.as_ref().is_some_and(|debug_text| {
|
||||
|
@ -134,7 +134,7 @@ impl StringLikeExtensions for ast::StringLike<'_> {
|
|||
contains_line_break_or_comments(
|
||||
&f_string.elements,
|
||||
context,
|
||||
f_string.flags.is_triple_quoted(),
|
||||
f_string.flags.triple_quotes(),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -5,8 +5,9 @@ use std::iter::FusedIterator;
|
|||
use ruff_formatter::FormatContext;
|
||||
use ruff_python_ast::visitor::source_order::SourceOrderVisitor;
|
||||
use ruff_python_ast::{
|
||||
str::Quote, AnyStringFlags, BytesLiteral, FString, FStringElement, FStringElements,
|
||||
FStringFlags, StringFlags, StringLikePart, StringLiteral,
|
||||
str::{Quote, TripleQuotes},
|
||||
AnyStringFlags, BytesLiteral, FString, FStringElement, FStringElements, FStringFlags,
|
||||
StringFlags, StringLikePart, StringLiteral,
|
||||
};
|
||||
use ruff_text_size::{Ranged, TextRange, TextSlice};
|
||||
|
||||
|
@ -273,7 +274,7 @@ impl QuoteMetadata {
|
|||
|
||||
pub(crate) fn from_str(text: &str, flags: AnyStringFlags, preferred_quote: Quote) -> Self {
|
||||
let kind = if flags.is_raw_string() {
|
||||
QuoteMetadataKind::raw(text, preferred_quote, flags.is_triple_quoted())
|
||||
QuoteMetadataKind::raw(text, preferred_quote, flags.triple_quotes())
|
||||
} else if flags.is_triple_quoted() {
|
||||
QuoteMetadataKind::triple_quoted(text, preferred_quote)
|
||||
} else {
|
||||
|
@ -528,7 +529,7 @@ impl QuoteMetadataKind {
|
|||
|
||||
/// Computes if a raw string uses the preferred quote. If it does, then it's not possible
|
||||
/// to change the quote style because it would require escaping which isn't possible in raw strings.
|
||||
fn raw(text: &str, preferred: Quote, triple_quoted: bool) -> Self {
|
||||
fn raw(text: &str, preferred: Quote, triple_quotes: TripleQuotes) -> Self {
|
||||
let mut chars = text.chars().peekable();
|
||||
let preferred_quote_char = preferred.as_char();
|
||||
|
||||
|
@ -540,7 +541,7 @@ impl QuoteMetadataKind {
|
|||
}
|
||||
// `"` or `'`
|
||||
Some(c) if c == preferred_quote_char => {
|
||||
if !triple_quoted {
|
||||
if triple_quotes.is_no() {
|
||||
break true;
|
||||
}
|
||||
|
||||
|
@ -1057,7 +1058,7 @@ mod tests {
|
|||
use std::borrow::Cow;
|
||||
|
||||
use ruff_python_ast::{
|
||||
str::Quote,
|
||||
str::{Quote, TripleQuotes},
|
||||
str_prefix::{AnyStringPrefix, ByteStringPrefix},
|
||||
AnyStringFlags,
|
||||
};
|
||||
|
@ -1086,7 +1087,7 @@ mod tests {
|
|||
AnyStringFlags::new(
|
||||
AnyStringPrefix::Bytes(ByteStringPrefix::Regular),
|
||||
Quote::Double,
|
||||
false,
|
||||
TripleQuotes::No,
|
||||
),
|
||||
false,
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue