mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 02:38:25 +00:00
Rename AnyStringKind
-> AnyStringFlags
(#11405)
## Summary This PR renames `AnyStringKind` to `AnyStringFlags` and `AnyStringFlags` to `AnyStringFlagsInner`. The main motivation is to have consistent usage of "kind" and "flags". For each string kind, it's "flags" like `StringLiteralFlags`, `BytesLiteralFlags`, and `FStringFlags` but it was `AnyStringKind` for the "any" variant.
This commit is contained in:
parent
be0ccabbaa
commit
6ecb4776de
54 changed files with 378 additions and 371 deletions
|
@ -1,5 +1,5 @@
|
|||
use ruff_formatter::write;
|
||||
use ruff_python_ast::{AnyStringKind, FString};
|
||||
use ruff_python_ast::{AnyStringFlags, FString};
|
||||
use ruff_source_file::Locator;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
@ -56,7 +56,9 @@ impl Format<PyFormatContext<'_>> for FormatFString<'_> {
|
|||
return result;
|
||||
}
|
||||
|
||||
let string_kind = normalizer.choose_quotes(self.value.into(), &locator).kind();
|
||||
let string_kind = normalizer
|
||||
.choose_quotes(self.value.into(), &locator)
|
||||
.flags();
|
||||
|
||||
let context = FStringContext::new(
|
||||
string_kind,
|
||||
|
@ -83,17 +85,17 @@ impl Format<PyFormatContext<'_>> for FormatFString<'_> {
|
|||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) struct FStringContext {
|
||||
kind: AnyStringKind,
|
||||
flags: AnyStringFlags,
|
||||
layout: FStringLayout,
|
||||
}
|
||||
|
||||
impl FStringContext {
|
||||
const fn new(kind: AnyStringKind, layout: FStringLayout) -> Self {
|
||||
Self { kind, layout }
|
||||
const fn new(flags: AnyStringFlags, layout: FStringLayout) -> Self {
|
||||
Self { flags, layout }
|
||||
}
|
||||
|
||||
pub(crate) fn kind(self) -> AnyStringKind {
|
||||
self.kind
|
||||
pub(crate) fn flags(self) -> AnyStringFlags {
|
||||
self.flags
|
||||
}
|
||||
|
||||
pub(crate) const fn layout(self) -> FStringLayout {
|
||||
|
|
|
@ -56,7 +56,7 @@ impl<'a> FormatFStringLiteralElement<'a> {
|
|||
impl Format<PyFormatContext<'_>> for FormatFStringLiteralElement<'_> {
|
||||
fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> {
|
||||
let literal_content = f.context().locator().slice(self.element.range());
|
||||
let normalized = normalize_string(literal_content, 0, self.context.kind(), true);
|
||||
let normalized = normalize_string(literal_content, 0, self.context.flags(), true);
|
||||
match &normalized {
|
||||
Cow::Borrowed(_) => source_text_slice(self.element.range()).fmt(f),
|
||||
Cow::Owned(normalized) => text(normalized).fmt(f),
|
||||
|
@ -102,7 +102,7 @@ impl FStringExpressionElementContext {
|
|||
// But, if the original source code already contained a newline, they'll be preserved.
|
||||
//
|
||||
// The Python version is irrelevant in this case.
|
||||
&& !(self.parent_context.kind().is_triple_quoted() && self.has_format_spec)
|
||||
&& !(self.parent_context.flags().is_triple_quoted() && self.has_format_spec)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ use std::iter::FusedIterator;
|
|||
use memchr::memchr2;
|
||||
|
||||
use ruff_python_ast::{
|
||||
self as ast, AnyNodeRef, AnyStringKind, Expr, ExprBytesLiteral, ExprFString, ExprStringLiteral,
|
||||
ExpressionRef, StringLiteral,
|
||||
self as ast, AnyNodeRef, AnyStringFlags, Expr, ExprBytesLiteral, ExprFString,
|
||||
ExprStringLiteral, ExpressionRef, StringLiteral,
|
||||
};
|
||||
use ruff_source_file::Locator;
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
@ -72,7 +72,7 @@ impl<'a> AnyString<'a> {
|
|||
AnyString::String(_) | AnyString::Bytes(_) => {
|
||||
self.parts(Quoting::default())
|
||||
.next()
|
||||
.is_some_and(|part| part.kind().is_triple_quoted())
|
||||
.is_some_and(|part| part.flags().is_triple_quoted())
|
||||
&& memchr2(b'\n', b'\r', source[self.range()].as_bytes()).is_some()
|
||||
}
|
||||
AnyString::FString(fstring) => {
|
||||
|
@ -176,7 +176,7 @@ pub(super) enum AnyStringPart<'a> {
|
|||
}
|
||||
|
||||
impl AnyStringPart<'_> {
|
||||
fn kind(&self) -> AnyStringKind {
|
||||
fn flags(&self) -> AnyStringFlags {
|
||||
match self {
|
||||
Self::String { part, .. } => part.flags.into(),
|
||||
Self::Bytes(bytes_literal) => bytes_literal.flags.into(),
|
||||
|
|
|
@ -127,7 +127,7 @@ pub(crate) fn format(normalized: &NormalizedString, f: &mut PyFormatter) -> Form
|
|||
let mut lines = docstring.split('\n').peekable();
|
||||
|
||||
// Start the string
|
||||
let kind = normalized.kind();
|
||||
let kind = normalized.flags();
|
||||
let quotes = StringQuotes::from(kind);
|
||||
write!(f, [kind.prefix(), quotes])?;
|
||||
// We track where in the source docstring we are (in source code byte offsets)
|
||||
|
@ -1573,7 +1573,7 @@ fn docstring_format_source(
|
|||
/// that avoids `content""""` and `content\"""`. This does only applies to un-escaped backslashes,
|
||||
/// so `content\\ """` doesn't need a space while `content\\\ """` does.
|
||||
fn needs_chaperone_space(normalized: &NormalizedString, trim_end: &str) -> bool {
|
||||
trim_end.ends_with(normalized.kind().quote_style().as_char())
|
||||
trim_end.ends_with(normalized.flags().quote_style().as_char())
|
||||
|| trim_end.chars().rev().take_while(|c| *c == '\\').count() % 2 == 1
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ pub(crate) use any::AnyString;
|
|||
pub(crate) use normalize::{normalize_string, NormalizedString, StringNormalizer};
|
||||
use ruff_formatter::format_args;
|
||||
use ruff_python_ast::str::Quote;
|
||||
use ruff_python_ast::{self as ast, AnyStringKind, AnyStringPrefix};
|
||||
use ruff_python_ast::{self as ast, AnyStringFlags, AnyStringPrefix};
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
use crate::comments::{leading_comments, trailing_comments};
|
||||
|
@ -87,8 +87,8 @@ impl Format<PyFormatContext<'_>> for StringQuotes {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<AnyStringKind> for StringQuotes {
|
||||
fn from(value: AnyStringKind) -> Self {
|
||||
impl From<AnyStringFlags> for StringQuotes {
|
||||
fn from(value: AnyStringFlags) -> Self {
|
||||
Self {
|
||||
triple: value.is_triple_quoted(),
|
||||
quote_char: value.quote_style(),
|
||||
|
@ -119,7 +119,7 @@ impl From<Quote> for QuoteStyle {
|
|||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct StringPart {
|
||||
kind: AnyStringKind,
|
||||
flags: AnyStringFlags,
|
||||
range: TextRange,
|
||||
}
|
||||
|
||||
|
@ -131,13 +131,13 @@ impl Ranged for StringPart {
|
|||
|
||||
impl StringPart {
|
||||
/// Use the `kind()` method to retrieve information about the
|
||||
fn kind(self) -> AnyStringKind {
|
||||
self.kind
|
||||
fn flags(self) -> AnyStringFlags {
|
||||
self.flags
|
||||
}
|
||||
|
||||
/// Returns the range of the string's content in the source (minus prefix and quotes).
|
||||
fn content_range(self) -> TextRange {
|
||||
let kind = self.kind();
|
||||
let kind = self.flags();
|
||||
TextRange::new(
|
||||
self.start() + kind.opener_len(),
|
||||
self.end() - kind.closer_len(),
|
||||
|
@ -149,7 +149,7 @@ impl From<&ast::StringLiteral> for StringPart {
|
|||
fn from(value: &ast::StringLiteral) -> Self {
|
||||
Self {
|
||||
range: value.range,
|
||||
kind: value.flags.into(),
|
||||
flags: value.flags.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +158,7 @@ impl From<&ast::BytesLiteral> for StringPart {
|
|||
fn from(value: &ast::BytesLiteral) -> Self {
|
||||
Self {
|
||||
range: value.range,
|
||||
kind: value.flags.into(),
|
||||
flags: value.flags.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ impl From<&ast::FString> for StringPart {
|
|||
fn from(value: &ast::FString) -> Self {
|
||||
Self {
|
||||
range: value.range,
|
||||
kind: value.flags.into(),
|
||||
flags: value.flags.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::borrow::Cow;
|
|||
use std::iter::FusedIterator;
|
||||
|
||||
use ruff_formatter::FormatContext;
|
||||
use ruff_python_ast::{str::Quote, AnyStringKind};
|
||||
use ruff_python_ast::{str::Quote, AnyStringFlags};
|
||||
use ruff_source_file::Locator;
|
||||
use ruff_text_size::{Ranged, TextRange};
|
||||
|
||||
|
@ -60,7 +60,7 @@ impl StringNormalizer {
|
|||
// The reason to preserve the quotes is based on the assumption that
|
||||
// the original f-string is valid in terms of quoting, and we don't
|
||||
// want to change that to make it invalid.
|
||||
if (context.f_string().kind().is_triple_quoted() && !string.kind().is_triple_quoted())
|
||||
if (context.f_string().flags().is_triple_quoted() && !string.flags().is_triple_quoted())
|
||||
|| self.target_version.supports_pep_701()
|
||||
{
|
||||
self.quoting
|
||||
|
@ -78,14 +78,14 @@ impl StringNormalizer {
|
|||
let first_quote_or_normalized_char_offset = raw_content
|
||||
.bytes()
|
||||
.position(|b| matches!(b, b'\\' | b'"' | b'\'' | b'\r' | b'{'));
|
||||
let string_kind = string.kind();
|
||||
let string_flags = string.flags();
|
||||
|
||||
let new_kind = match self.quoting(string) {
|
||||
Quoting::Preserve => string_kind,
|
||||
Quoting::Preserve => string_flags,
|
||||
Quoting::CanChange => {
|
||||
// Per PEP 8, always prefer double quotes for triple-quoted strings.
|
||||
// Except when using quote-style-preserve.
|
||||
let preferred_style = if string_kind.is_triple_quoted() {
|
||||
let preferred_style = if string_flags.is_triple_quoted() {
|
||||
// ... unless we're formatting a code snippet inside a docstring,
|
||||
// then we specifically want to invert our quote style to avoid
|
||||
// writing out invalid Python.
|
||||
|
@ -146,30 +146,30 @@ impl StringNormalizer {
|
|||
if let Some(first_quote_or_normalized_char_offset) =
|
||||
first_quote_or_normalized_char_offset
|
||||
{
|
||||
if string_kind.is_raw_string() {
|
||||
if string_flags.is_raw_string() {
|
||||
choose_quotes_for_raw_string(
|
||||
&raw_content[first_quote_or_normalized_char_offset..],
|
||||
string_kind,
|
||||
string_flags,
|
||||
preferred_quote,
|
||||
)
|
||||
} else {
|
||||
choose_quotes_impl(
|
||||
&raw_content[first_quote_or_normalized_char_offset..],
|
||||
string_kind,
|
||||
string_flags,
|
||||
preferred_quote,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
string_kind.with_quote_style(preferred_quote)
|
||||
string_flags.with_quote_style(preferred_quote)
|
||||
}
|
||||
} else {
|
||||
string_kind
|
||||
string_flags
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
QuoteSelection {
|
||||
kind: new_kind,
|
||||
flags: new_kind,
|
||||
first_quote_or_normalized_char_offset,
|
||||
}
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ impl StringNormalizer {
|
|||
normalize_string(
|
||||
raw_content,
|
||||
first_quote_or_escape_offset,
|
||||
quote_selection.kind,
|
||||
quote_selection.flags,
|
||||
// TODO: Remove the `b'{'` in `choose_quotes` when promoting the
|
||||
// `format_fstring` preview style
|
||||
self.format_fstring,
|
||||
|
@ -199,7 +199,7 @@ impl StringNormalizer {
|
|||
};
|
||||
|
||||
NormalizedString {
|
||||
kind: quote_selection.kind,
|
||||
flags: quote_selection.flags,
|
||||
content_range: string.content_range(),
|
||||
text: normalized,
|
||||
}
|
||||
|
@ -208,22 +208,22 @@ impl StringNormalizer {
|
|||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct QuoteSelection {
|
||||
kind: AnyStringKind,
|
||||
flags: AnyStringFlags,
|
||||
|
||||
/// Offset to the first quote character or character that needs special handling in [`normalize_string`].
|
||||
first_quote_or_normalized_char_offset: Option<usize>,
|
||||
}
|
||||
|
||||
impl QuoteSelection {
|
||||
pub(crate) fn kind(&self) -> AnyStringKind {
|
||||
self.kind
|
||||
pub(crate) fn flags(&self) -> AnyStringFlags {
|
||||
self.flags
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct NormalizedString<'a> {
|
||||
/// Holds data about the quotes and prefix of the string
|
||||
kind: AnyStringKind,
|
||||
flags: AnyStringFlags,
|
||||
|
||||
/// The range of the string's content in the source (minus prefix and quotes).
|
||||
content_range: TextRange,
|
||||
|
@ -237,8 +237,8 @@ impl<'a> NormalizedString<'a> {
|
|||
&self.text
|
||||
}
|
||||
|
||||
pub(crate) fn kind(&self) -> AnyStringKind {
|
||||
self.kind
|
||||
pub(crate) fn flags(&self) -> AnyStringFlags {
|
||||
self.flags
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,8 +250,8 @@ impl Ranged for NormalizedString<'_> {
|
|||
|
||||
impl Format<PyFormatContext<'_>> for NormalizedString<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
|
||||
let quotes = StringQuotes::from(self.kind);
|
||||
ruff_formatter::write!(f, [self.kind.prefix(), quotes])?;
|
||||
let quotes = StringQuotes::from(self.flags);
|
||||
ruff_formatter::write!(f, [self.flags.prefix(), quotes])?;
|
||||
match &self.text {
|
||||
Cow::Borrowed(_) => {
|
||||
source_text_slice(self.range()).fmt(f)?;
|
||||
|
@ -271,9 +271,9 @@ impl Format<PyFormatContext<'_>> for NormalizedString<'_> {
|
|||
/// style is double quotes.
|
||||
fn choose_quotes_for_raw_string(
|
||||
input: &str,
|
||||
kind: AnyStringKind,
|
||||
flags: AnyStringFlags,
|
||||
preferred_quote: Quote,
|
||||
) -> AnyStringKind {
|
||||
) -> AnyStringFlags {
|
||||
let preferred_quote_char = preferred_quote.as_char();
|
||||
let mut chars = input.chars().peekable();
|
||||
let contains_unescaped_configured_quotes = loop {
|
||||
|
@ -284,7 +284,7 @@ fn choose_quotes_for_raw_string(
|
|||
}
|
||||
// `"` or `'`
|
||||
Some(c) if c == preferred_quote_char => {
|
||||
if !kind.is_triple_quoted() {
|
||||
if !flags.is_triple_quoted() {
|
||||
break true;
|
||||
}
|
||||
|
||||
|
@ -310,9 +310,9 @@ fn choose_quotes_for_raw_string(
|
|||
}
|
||||
};
|
||||
if contains_unescaped_configured_quotes {
|
||||
kind
|
||||
flags
|
||||
} else {
|
||||
kind.with_quote_style(preferred_quote)
|
||||
flags.with_quote_style(preferred_quote)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -324,8 +324,12 @@ fn choose_quotes_for_raw_string(
|
|||
/// For triple quoted strings, the preferred quote style is always used, unless the string contains
|
||||
/// a triplet of the quote character (e.g., if double quotes are preferred, double quotes will be
|
||||
/// used unless the string contains `"""`).
|
||||
fn choose_quotes_impl(input: &str, kind: AnyStringKind, preferred_quote: Quote) -> AnyStringKind {
|
||||
let quote = if kind.is_triple_quoted() {
|
||||
fn choose_quotes_impl(
|
||||
input: &str,
|
||||
flags: AnyStringFlags,
|
||||
preferred_quote: Quote,
|
||||
) -> AnyStringFlags {
|
||||
let quote = if flags.is_triple_quoted() {
|
||||
// True if the string contains a triple quote sequence of the configured quote style.
|
||||
let mut uses_triple_quotes = false;
|
||||
let mut chars = input.chars().peekable();
|
||||
|
@ -379,7 +383,7 @@ fn choose_quotes_impl(input: &str, kind: AnyStringKind, preferred_quote: Quote)
|
|||
if uses_triple_quotes {
|
||||
// String contains a triple quote sequence of the configured quote style.
|
||||
// Keep the existing quote style.
|
||||
kind.quote_style()
|
||||
flags.quote_style()
|
||||
} else {
|
||||
preferred_quote
|
||||
}
|
||||
|
@ -419,7 +423,7 @@ fn choose_quotes_impl(input: &str, kind: AnyStringKind, preferred_quote: Quote)
|
|||
}
|
||||
};
|
||||
|
||||
kind.with_quote_style(quote)
|
||||
flags.with_quote_style(quote)
|
||||
}
|
||||
|
||||
/// Adds the necessary quote escapes and removes unnecessary escape sequences when quoting `input`
|
||||
|
@ -429,7 +433,7 @@ fn choose_quotes_impl(input: &str, kind: AnyStringKind, preferred_quote: Quote)
|
|||
pub(crate) fn normalize_string(
|
||||
input: &str,
|
||||
start_offset: usize,
|
||||
kind: AnyStringKind,
|
||||
flags: AnyStringFlags,
|
||||
format_fstring: bool,
|
||||
) -> Cow<str> {
|
||||
// The normalized string if `input` is not yet normalized.
|
||||
|
@ -439,14 +443,14 @@ pub(crate) fn normalize_string(
|
|||
// If `last_index` is `0` at the end, then the input is already normalized and can be returned as is.
|
||||
let mut last_index = 0;
|
||||
|
||||
let quote = kind.quote_style();
|
||||
let quote = flags.quote_style();
|
||||
let preferred_quote = quote.as_char();
|
||||
let opposite_quote = quote.opposite().as_char();
|
||||
|
||||
let mut chars = CharIndicesWithOffset::new(input, start_offset).peekable();
|
||||
|
||||
let is_raw = kind.is_raw_string();
|
||||
let is_fstring = !format_fstring && kind.is_f_string();
|
||||
let is_raw = flags.is_raw_string();
|
||||
let is_fstring = !format_fstring && flags.is_f_string();
|
||||
let mut formatted_value_nesting = 0u32;
|
||||
|
||||
while let Some((index, c)) = chars.next() {
|
||||
|
@ -484,7 +488,7 @@ pub(crate) fn normalize_string(
|
|||
} else {
|
||||
// Length of the `\` plus the length of the escape sequence character (`u` | `U` | `x`)
|
||||
let escape_start_len = '\\'.len_utf8() + next.len_utf8();
|
||||
if let Some(normalised) = UnicodeEscape::new(next, !kind.is_byte_string())
|
||||
if let Some(normalised) = UnicodeEscape::new(next, !flags.is_byte_string())
|
||||
.and_then(|escape| escape.normalize(&input[index + escape_start_len..]))
|
||||
{
|
||||
let escape_start_offset = index + escape_start_len;
|
||||
|
@ -503,7 +507,7 @@ pub(crate) fn normalize_string(
|
|||
}
|
||||
}
|
||||
|
||||
if !kind.is_triple_quoted() {
|
||||
if !flags.is_triple_quoted() {
|
||||
#[allow(clippy::if_same_then_else)]
|
||||
if next == opposite_quote && formatted_value_nesting == 0 {
|
||||
// Remove the escape by ending before the backslash and starting again with the quote
|
||||
|
@ -516,7 +520,7 @@ pub(crate) fn normalize_string(
|
|||
}
|
||||
}
|
||||
}
|
||||
} else if !kind.is_triple_quoted()
|
||||
} else if !flags.is_triple_quoted()
|
||||
&& c == preferred_quote
|
||||
&& formatted_value_nesting == 0
|
||||
{
|
||||
|
@ -689,7 +693,7 @@ impl UnicodeEscape {
|
|||
mod tests {
|
||||
use std::borrow::Cow;
|
||||
|
||||
use ruff_python_ast::{str::Quote, AnyStringKind, AnyStringPrefix, ByteStringPrefix};
|
||||
use ruff_python_ast::{str::Quote, AnyStringFlags, AnyStringPrefix, ByteStringPrefix};
|
||||
|
||||
use super::{normalize_string, UnicodeEscape};
|
||||
|
||||
|
@ -710,7 +714,7 @@ mod tests {
|
|||
let normalized = normalize_string(
|
||||
input,
|
||||
0,
|
||||
AnyStringKind::new(
|
||||
AnyStringFlags::new(
|
||||
AnyStringPrefix::Bytes(ByteStringPrefix::Regular),
|
||||
Quote::Double,
|
||||
false,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue