Unify enums used for internal representation of quoting style (#10383)

This commit is contained in:
Alex Waygood 2024-03-13 17:19:17 +00:00 committed by GitHub
parent d59433b12e
commit c2e15f38ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 148 additions and 228 deletions

1
Cargo.lock generated
View file

@ -2345,6 +2345,7 @@ dependencies = [
"itertools 0.12.1",
"lexical-parse-float",
"rand",
"ruff_python_ast",
"unic-ucd-category",
]

View file

@ -44,10 +44,10 @@ use ruff_python_ast::helpers::{
};
use ruff_python_ast::identifier::Identifier;
use ruff_python_ast::name::QualifiedName;
use ruff_python_ast::str::trailing_quote;
use ruff_python_ast::str::Quote;
use ruff_python_ast::visitor::{walk_except_handler, walk_f_string_element, walk_pattern, Visitor};
use ruff_python_ast::{helpers, str, visitor, PySourceType};
use ruff_python_codegen::{Generator, Quote, Stylist};
use ruff_python_codegen::{Generator, Stylist};
use ruff_python_index::Indexer;
use ruff_python_parser::typing::{parse_type_annotation, AnnotationKind};
use ruff_python_semantic::analyze::{imports, typing, visibility};
@ -228,16 +228,11 @@ impl<'a> Checker<'a> {
}
// Find the quote character used to start the containing f-string.
let expr = self.semantic.current_expression()?;
let string_range = self.indexer.fstring_ranges().innermost(expr.start())?;
let trailing_quote = trailing_quote(self.locator.slice(string_range))?;
// Invert the quote character, if it's a single quote.
match trailing_quote {
"'" => Some(Quote::Double),
"\"" => Some(Quote::Single),
_ => None,
}
let ast::ExprFString { value, .. } = self
.semantic
.current_expressions()
.find_map(|expr| expr.as_f_string_expr())?;
Some(value.iter().next()?.quote_style().opposite())
}
/// Returns the [`SourceRow`] for the given offset.

View file

@ -22,11 +22,11 @@ impl Default for Quote {
}
}
impl From<ruff_python_ast::str::QuoteStyle> for Quote {
fn from(value: ruff_python_ast::str::QuoteStyle) -> Self {
impl From<ruff_python_ast::str::Quote> for Quote {
fn from(value: ruff_python_ast::str::Quote) -> Self {
match value {
ruff_python_ast::str::QuoteStyle::Double => Self::Double,
ruff_python_ast::str::QuoteStyle::Single => Self::Single,
ruff_python_ast::str::Quote::Double => Self::Double,
ruff_python_ast::str::Quote::Single => Self::Single,
}
}
}

View file

@ -1,6 +1,6 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_codegen::Quote;
use ruff_python_ast::str::Quote;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;

View file

@ -11,7 +11,7 @@ use itertools::Itertools;
use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::{int, str::QuoteStyle, LiteralExpressionRef};
use crate::{int, str::Quote, LiteralExpressionRef};
/// See also [mod](https://docs.python.org/3/library/ast.html#ast.mod)
#[derive(Clone, Debug, PartialEq, is_macro::Is)]
@ -1159,6 +1159,15 @@ pub enum FStringPart {
FString(FString),
}
impl FStringPart {
pub fn quote_style(&self) -> Quote {
match self {
Self::Literal(string_literal) => string_literal.flags.quote_style(),
Self::FString(f_string) => f_string.flags.quote_style(),
}
}
}
impl Ranged for FStringPart {
fn range(&self) -> TextRange {
match self {
@ -1221,11 +1230,11 @@ impl FStringFlags {
}
/// Does the f-string use single or double quotes in its opener and closer?
pub const fn quote_style(self) -> QuoteStyle {
pub const fn quote_style(self) -> Quote {
if self.0.contains(FStringFlagsInner::DOUBLE) {
QuoteStyle::Double
Quote::Double
} else {
QuoteStyle::Single
Quote::Single
}
}
}
@ -1535,11 +1544,11 @@ impl StringLiteralFlags {
}
/// Does the string use single or double quotes in its opener and closer?
pub const fn quote_style(self) -> QuoteStyle {
pub const fn quote_style(self) -> Quote {
if self.0.contains(StringLiteralFlagsInner::DOUBLE) {
QuoteStyle::Double
Quote::Double
} else {
QuoteStyle::Single
Quote::Single
}
}
@ -1864,11 +1873,11 @@ impl BytesLiteralFlags {
}
/// Does the bytestring use single or double quotes in its opener and closer?
pub const fn quote_style(self) -> QuoteStyle {
pub const fn quote_style(self) -> Quote {
if self.0.contains(BytesLiteralFlagsInner::DOUBLE) {
QuoteStyle::Double
Quote::Double
} else {
QuoteStyle::Single
Quote::Single
}
}
}

View file

@ -1,18 +1,23 @@
use std::fmt;
use aho_corasick::{AhoCorasick, AhoCorasickKind, Anchored, Input, MatchKind, StartKind};
use once_cell::sync::Lazy;
use ruff_text_size::{TextLen, TextRange};
/// Enumeration of the two kinds of quotes that can be used
/// for Python string/f-string/bytestring literals
#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq, is_macro::Is)]
pub enum QuoteStyle {
/// E.g. '
pub enum Quote {
/// E.g. `'`
Single,
/// E.g. "
/// E.g. `"`
#[default]
Double,
}
impl QuoteStyle {
impl Quote {
#[inline]
pub const fn as_char(self) -> char {
match self {
Self::Single => '\'',
@ -21,12 +26,39 @@ impl QuoteStyle {
}
#[must_use]
#[inline]
pub const fn opposite(self) -> Self {
match self {
Self::Single => Self::Double,
Self::Double => Self::Single,
}
}
#[inline]
pub const fn as_byte(self) -> u8 {
match self {
Self::Single => b'\'',
Self::Double => b'"',
}
}
}
impl fmt::Display for Quote {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_char())
}
}
impl TryFrom<char> for Quote {
type Error = ();
fn try_from(value: char) -> Result<Self, Self::Error> {
match value {
'\'' => Ok(Quote::Single),
'"' => Ok(Quote::Double),
_ => Err(()),
}
}
}
/// Includes all permutations of `r`, `u`, `f`, and `fr` (`ur` is invalid, as is `uf`). This

View file

@ -2,6 +2,7 @@
use std::ops::Deref;
use ruff_python_ast::str::Quote;
use ruff_python_ast::{
self as ast, Alias, ArgOrKeyword, BoolOp, CmpOp, Comprehension, ConversionFlag, DebugText,
ExceptHandler, Expr, Identifier, MatchCase, Operator, Parameter, Parameters, Pattern,
@ -12,7 +13,7 @@ use ruff_python_ast::{ParameterWithDefault, TypeParams};
use ruff_python_literal::escape::{AsciiEscape, Escape, UnicodeEscape};
use ruff_source_file::LineEnding;
use super::stylist::{Indentation, Quote, Stylist};
use super::stylist::{Indentation, Stylist};
mod precedence {
pub(crate) const NAMED_EXPR: u8 = 1;
@ -150,7 +151,7 @@ impl<'a> Generator<'a> {
}
fn p_bytes_repr(&mut self, s: &[u8]) {
let escape = AsciiEscape::with_preferred_quote(s, self.quote.into());
let escape = AsciiEscape::with_preferred_quote(s, self.quote);
if let Some(len) = escape.layout().len {
self.buffer.reserve(len);
}
@ -158,7 +159,7 @@ impl<'a> Generator<'a> {
}
fn p_str_repr(&mut self, s: &str) {
let escape = UnicodeEscape::with_preferred_quote(s, self.quote.into());
let escape = UnicodeEscape::with_preferred_quote(s, self.quote);
if let Some(len) = escape.layout().len {
self.buffer.reserve(len);
}
@ -1373,14 +1374,8 @@ impl<'a> Generator<'a> {
self.unparse_f_string_body(values);
} else {
self.p("f");
let mut generator = Generator::new(
self.indent,
match self.quote {
Quote::Single => Quote::Double,
Quote::Double => Quote::Single,
},
self.line_ending,
);
let mut generator =
Generator::new(self.indent, self.quote.opposite(), self.line_ending);
generator.unparse_f_string_body(values);
let body = &generator.buffer;
self.p_str_repr(body);
@ -1406,11 +1401,11 @@ impl<'a> Generator<'a> {
#[cfg(test)]
mod tests {
use ruff_python_ast::{Mod, ModModule};
use ruff_python_ast::{str::Quote, Mod, ModModule};
use ruff_python_parser::{self, parse_suite, Mode};
use ruff_source_file::LineEnding;
use crate::stylist::{Indentation, Quote};
use crate::stylist::Indentation;
use super::Generator;

View file

@ -4,7 +4,7 @@ mod stylist;
pub use generator::Generator;
use ruff_python_parser::{lexer, parse_suite, Mode, ParseError};
use ruff_source_file::Locator;
pub use stylist::{Quote, Stylist};
pub use stylist::Stylist;
/// Run round-trip source code generation on a given Python code.
pub fn round_trip(code: &str) -> Result<String, ParseError> {

View file

@ -1,15 +1,13 @@
//! Detect code style from Python source code.
use std::fmt;
use std::ops::Deref;
use once_cell::unsync::OnceCell;
use ruff_python_literal::escape::Quote as StrQuote;
use ruff_python_ast::str::Quote;
use ruff_python_parser::lexer::LexResult;
use ruff_python_parser::Tok;
use ruff_source_file::{find_newline, LineEnding};
use ruff_source_file::Locator;
use ruff_source_file::{find_newline, LineEnding, Locator};
#[derive(Debug, Clone)]
pub struct Stylist<'a> {
@ -52,10 +50,8 @@ impl<'a> Stylist<'a> {
fn detect_quote(tokens: &[LexResult]) -> Quote {
for (token, _) in tokens.iter().flatten() {
match token {
Tok::String { kind, .. } if !kind.is_triple_quoted() => {
return kind.quote_style().into()
}
Tok::FStringStart(kind) => return kind.quote_style().into(),
Tok::String { kind, .. } if !kind.is_triple_quoted() => return kind.quote_style(),
Tok::FStringStart(kind) => return kind.quote_style(),
_ => continue,
}
}
@ -94,50 +90,6 @@ fn detect_indention(tokens: &[LexResult], locator: &Locator) -> Indentation {
}
}
/// The quotation style used in Python source code.
#[derive(Debug, Default, PartialEq, Eq, Copy, Clone)]
pub enum Quote {
Single,
#[default]
Double,
}
impl From<ruff_python_ast::str::QuoteStyle> for Quote {
fn from(value: ruff_python_ast::str::QuoteStyle) -> Self {
match value {
ruff_python_ast::str::QuoteStyle::Double => Self::Double,
ruff_python_ast::str::QuoteStyle::Single => Self::Single,
}
}
}
impl From<Quote> for char {
fn from(val: Quote) -> Self {
match val {
Quote::Single => '\'',
Quote::Double => '"',
}
}
}
impl From<Quote> for StrQuote {
fn from(val: Quote) -> Self {
match val {
Quote::Single => StrQuote::Single,
Quote::Double => StrQuote::Double,
}
}
}
impl fmt::Display for Quote {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Quote::Single => write!(f, "\'"),
Quote::Double => write!(f, "\""),
}
}
}
/// The indentation style used in Python source code.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Indentation(String);

View file

@ -1,8 +1,8 @@
use crate::comments::Comments;
use crate::other::f_string::FStringContext;
use crate::string::QuoteChar;
use crate::PyFormatOptions;
use ruff_formatter::{Buffer, FormatContext, GroupId, IndentWidth, SourceCode};
use ruff_python_ast::str::Quote;
use ruff_source_file::Locator;
use std::fmt::{Debug, Formatter};
use std::ops::{Deref, DerefMut};
@ -22,7 +22,7 @@ pub struct PyFormatContext<'a> {
/// works. For example, multi-line strings will always be written with a
/// quote style that is inverted from the one here in order to ensure that
/// the formatted Python code will be valid.
docstring: Option<QuoteChar>,
docstring: Option<Quote>,
/// The state of the formatter with respect to f-strings.
f_string_state: FStringState,
}
@ -74,7 +74,7 @@ impl<'a> PyFormatContext<'a> {
///
/// The quote character returned corresponds to the quoting used for the
/// docstring containing the code snippet currently being formatted.
pub(crate) fn docstring(&self) -> Option<QuoteChar> {
pub(crate) fn docstring(&self) -> Option<Quote> {
self.docstring
}
@ -83,7 +83,7 @@ impl<'a> PyFormatContext<'a> {
///
/// The quote character given should correspond to the quote character used
/// for the docstring containing the code snippets.
pub(crate) fn in_docstring(self, quote: QuoteChar) -> PyFormatContext<'a> {
pub(crate) fn in_docstring(self, quote: Quote) -> PyFormatContext<'a> {
PyFormatContext {
docstring: Some(quote),
..self

View file

@ -8,6 +8,7 @@ use std::{borrow::Cow, collections::VecDeque};
use itertools::Itertools;
use ruff_formatter::printer::SourceMapGeneration;
use ruff_python_ast::str::Quote;
use ruff_python_parser::ParseError;
use {once_cell::sync::Lazy, regex::Regex};
use {
@ -19,7 +20,7 @@ use {
use crate::{prelude::*, DocstringCodeLineWidth, FormatModuleError};
use super::{NormalizedString, QuoteChar};
use super::NormalizedString;
/// Format a docstring by trimming whitespace and adjusting the indentation.
///
@ -253,7 +254,7 @@ struct DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> {
already_normalized: bool,
/// The quote character used by the docstring being printed.
quote_char: QuoteChar,
quote_char: Quote,
/// The current code example detected in the docstring.
code_example: CodeExample<'src>,
@ -550,8 +551,8 @@ impl<'ast, 'buf, 'fmt, 'src> DocstringLinePrinter<'ast, 'buf, 'fmt, 'src> {
// remove this check. See the `doctest_invalid_skipped` tests in
// `docstring_code_examples.py` for when this check is relevant.
let wrapped = match self.quote_char {
QuoteChar::Single => std::format!("'''{}'''", printed.as_code()),
QuoteChar::Double => {
Quote::Single => std::format!("'''{}'''", printed.as_code()),
Quote::Double => {
std::format!(r#""""{}""""#, printed.as_code())
}
};
@ -1542,7 +1543,7 @@ enum CodeExampleAddAction<'src> {
/// inside of a docstring.
fn docstring_format_source(
options: crate::PyFormatOptions,
docstring_quote_style: QuoteChar,
docstring_quote_style: Quote,
source: &str,
) -> Result<Printed, FormatModuleError> {
use ruff_python_parser::AsMode;

View file

@ -3,6 +3,7 @@ use bitflags::bitflags;
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_source_file::Locator;
use ruff_text_size::{TextLen, TextRange, TextSize};
@ -187,7 +188,7 @@ impl Format<PyFormatContext<'_>> for StringPrefix {
#[derive(Copy, Clone, Debug)]
pub(crate) struct StringQuotes {
triple: bool,
quote_char: QuoteChar,
quote_char: Quote,
}
impl StringQuotes {
@ -195,7 +196,7 @@ impl StringQuotes {
let mut chars = input.chars();
let quote_char = chars.next()?;
let quote = QuoteChar::try_from(quote_char).ok()?;
let quote = Quote::try_from(quote_char).ok()?;
let triple = chars.next() == Some(quote_char) && chars.next() == Some(quote_char);
@ -221,69 +222,33 @@ impl StringQuotes {
impl Format<PyFormatContext<'_>> for StringQuotes {
fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> {
let quotes = match (self.quote_char, self.triple) {
(QuoteChar::Single, false) => "'",
(QuoteChar::Single, true) => "'''",
(QuoteChar::Double, false) => "\"",
(QuoteChar::Double, true) => "\"\"\"",
(Quote::Single, false) => "'",
(Quote::Single, true) => "'''",
(Quote::Double, false) => "\"",
(Quote::Double, true) => "\"\"\"",
};
token(quotes).fmt(f)
}
}
/// The quotation character used to quote a string, byte, or fstring literal.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum QuoteChar {
/// A single quote: `'`
Single,
/// A double quote: '"'
Double,
}
impl QuoteChar {
pub const fn as_char(self) -> char {
match self {
QuoteChar::Single => '\'',
QuoteChar::Double => '"',
}
}
#[must_use]
pub const fn invert(self) -> QuoteChar {
match self {
QuoteChar::Single => QuoteChar::Double,
QuoteChar::Double => QuoteChar::Single,
}
}
#[must_use]
pub const fn from_style(style: QuoteStyle) -> Option<QuoteChar> {
match style {
QuoteStyle::Single => Some(QuoteChar::Single),
QuoteStyle::Double => Some(QuoteChar::Double),
QuoteStyle::Preserve => None,
}
}
}
impl From<QuoteChar> for QuoteStyle {
fn from(value: QuoteChar) -> Self {
match value {
QuoteChar::Single => QuoteStyle::Single,
QuoteChar::Double => QuoteStyle::Double,
}
}
}
impl TryFrom<char> for QuoteChar {
impl TryFrom<QuoteStyle> for Quote {
type Error = ();
fn try_from(value: char) -> Result<Self, Self::Error> {
match value {
'\'' => Ok(QuoteChar::Single),
'"' => Ok(QuoteChar::Double),
_ => Err(()),
fn try_from(style: QuoteStyle) -> Result<Quote, ()> {
match style {
QuoteStyle::Single => Ok(Quote::Single),
QuoteStyle::Double => Ok(Quote::Double),
QuoteStyle::Preserve => Err(()),
}
}
}
impl From<Quote> for QuoteStyle {
fn from(value: Quote) -> Self {
match value {
Quote::Single => QuoteStyle::Single,
Quote::Double => QuoteStyle::Double,
}
}
}

View file

@ -2,6 +2,7 @@ use std::borrow::Cow;
use std::iter::FusedIterator;
use ruff_formatter::FormatContext;
use ruff_python_ast::str::Quote;
use ruff_source_file::Locator;
use ruff_text_size::{Ranged, TextRange};
@ -9,13 +10,13 @@ use crate::context::FStringState;
use crate::options::PythonVersion;
use crate::prelude::*;
use crate::preview::is_f_string_formatting_enabled;
use crate::string::{QuoteChar, Quoting, StringPart, StringPrefix, StringQuotes};
use crate::string::{Quoting, StringPart, StringPrefix, StringQuotes};
use crate::QuoteStyle;
pub(crate) struct StringNormalizer {
quoting: Quoting,
preferred_quote_style: QuoteStyle,
parent_docstring_quote_char: Option<QuoteChar>,
parent_docstring_quote_char: Option<Quote>,
f_string_state: FStringState,
target_version: PythonVersion,
format_fstring: bool,
@ -130,7 +131,7 @@ impl StringNormalizer {
// style from what the parent ultimately decided upon works, even
// if it doesn't have perfect alignment with PEP8.
if let Some(quote) = self.parent_docstring_quote_char {
QuoteStyle::from(quote.invert())
QuoteStyle::from(quote.opposite())
} else if self.preferred_quote_style.is_preserve() {
QuoteStyle::Preserve
} else {
@ -140,7 +141,7 @@ impl StringNormalizer {
self.preferred_quote_style
};
if let Some(preferred_quote) = QuoteChar::from_style(preferred_style) {
if let Ok(preferred_quote) = Quote::try_from(preferred_style) {
if let Some(first_quote_or_normalized_char_offset) =
first_quote_or_normalized_char_offset
{
@ -281,7 +282,7 @@ impl Format<PyFormatContext<'_>> for NormalizedString<'_> {
fn choose_quotes_for_raw_string(
input: &str,
quotes: StringQuotes,
preferred_quote: QuoteChar,
preferred_quote: Quote,
) -> StringQuotes {
let preferred_quote_char = preferred_quote.as_char();
let mut chars = input.chars().peekable();
@ -337,11 +338,7 @@ 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,
quotes: StringQuotes,
preferred_quote: QuoteChar,
) -> StringQuotes {
fn choose_quotes_impl(input: &str, quotes: StringQuotes, preferred_quote: Quote) -> StringQuotes {
let quote = if quotes.triple {
// True if the string contains a triple quote sequence of the configured quote style.
let mut uses_triple_quotes = false;
@ -419,18 +416,18 @@ fn choose_quotes_impl(
}
match preferred_quote {
QuoteChar::Single => {
Quote::Single => {
if single_quotes > double_quotes {
QuoteChar::Double
Quote::Double
} else {
QuoteChar::Single
Quote::Single
}
}
QuoteChar::Double => {
Quote::Double => {
if double_quotes > single_quotes {
QuoteChar::Single
Quote::Single
} else {
QuoteChar::Double
Quote::Double
}
}
}
@ -462,7 +459,7 @@ pub(crate) fn normalize_string(
let quote = quotes.quote_char;
let preferred_quote = quote.as_char();
let opposite_quote = quote.invert().as_char();
let opposite_quote = quote.opposite().as_char();
let mut chars = CharIndicesWithOffset::new(input, start_offset).peekable();
@ -707,7 +704,9 @@ impl UnicodeEscape {
mod tests {
use std::borrow::Cow;
use crate::string::{QuoteChar, StringPrefix, StringQuotes};
use ruff_python_ast::str::Quote;
use crate::string::{StringPrefix, StringQuotes};
use super::{normalize_string, UnicodeEscape};
@ -730,7 +729,7 @@ mod tests {
0,
StringQuotes {
triple: false,
quote_char: QuoteChar::Double,
quote_char: Quote::Double,
},
StringPrefix::BYTE,
true,

View file

@ -15,6 +15,8 @@ license = { workspace = true }
doctest = false
[dependencies]
ruff_python_ast = { path = "../ruff_python_ast" }
bitflags = { workspace = true }
hexf-parse = { workspace = true }
is-macro = { workspace = true }

View file

@ -1,35 +1,4 @@
#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, is_macro::Is)]
pub enum Quote {
Single,
Double,
}
impl Quote {
#[inline]
#[must_use]
pub const fn swap(self) -> Self {
match self {
Quote::Single => Quote::Double,
Quote::Double => Quote::Single,
}
}
#[inline]
pub const fn to_byte(&self) -> u8 {
match self {
Quote::Single => b'\'',
Quote::Double => b'"',
}
}
#[inline]
pub const fn to_char(&self) -> char {
match self {
Quote::Single => '\'',
Quote::Double => '"',
}
}
}
use ruff_python_ast::str::Quote;
pub struct EscapeLayout {
pub quote: Quote,
@ -69,7 +38,7 @@ pub(crate) const fn choose_quote(
// always use primary unless we have primary but no secondary
let use_secondary = primary_count > 0 && secondary_count == 0;
if use_secondary {
(preferred_quote.swap(), secondary_count)
(preferred_quote.opposite(), secondary_count)
} else {
(preferred_quote, primary_count)
}
@ -105,7 +74,7 @@ pub struct StrRepr<'r, 'a>(&'r UnicodeEscape<'a>);
impl StrRepr<'_, '_> {
pub fn write(&self, formatter: &mut impl std::fmt::Write) -> std::fmt::Result {
let quote = self.0.layout().quote.to_char();
let quote = self.0.layout().quote.as_char();
formatter.write_char(quote)?;
self.0.write_body(formatter)?;
formatter.write_char(quote)
@ -216,7 +185,7 @@ impl UnicodeEscape<'_> {
// unicodedata lookup just for ascii characters
'\x20'..='\x7e' => {
// printable ascii range
if ch == quote.to_char() || ch == '\\' {
if ch == quote.as_char() || ch == '\\' {
formatter.write_char('\\')?;
}
formatter.write_char(ch)
@ -379,7 +348,7 @@ impl AsciiEscape<'_> {
b'\r' => formatter.write_str("\\r"),
0x20..=0x7e => {
// printable ascii range
if ch == quote.to_byte() || ch == b'\\' {
if ch == quote.as_byte() || ch == b'\\' {
formatter.write_char('\\')?;
}
formatter.write_char(ch as char)
@ -416,7 +385,7 @@ pub struct BytesRepr<'r, 'a>(&'r AsciiEscape<'a>);
impl BytesRepr<'_, '_> {
pub fn write(&self, formatter: &mut impl std::fmt::Write) -> std::fmt::Result {
let quote = self.0.layout().quote.to_char();
let quote = self.0.layout().quote.as_char();
formatter.write_char('b')?;
formatter.write_char(quote)?;
self.0.write_body(formatter)?;

View file

@ -2,7 +2,7 @@ use std::fmt;
use bitflags::bitflags;
use ruff_python_ast::{str::QuoteStyle, StringLiteralPrefix};
use ruff_python_ast::{str::Quote, StringLiteralPrefix};
use ruff_text_size::{TextLen, TextSize};
bitflags! {
@ -171,11 +171,11 @@ impl StringKind {
}
/// Does the string use single or double quotes in its opener and closer?
pub const fn quote_style(self) -> QuoteStyle {
pub const fn quote_style(self) -> Quote {
if self.0.contains(StringFlags::DOUBLE) {
QuoteStyle::Double
Quote::Double
} else {
QuoteStyle::Single
Quote::Single
}
}
@ -190,13 +190,13 @@ impl StringKind {
pub const fn quote_str(self) -> &'static str {
if self.is_triple_quoted() {
match self.quote_style() {
QuoteStyle::Single => "'''",
QuoteStyle::Double => r#"""""#,
Quote::Single => "'''",
Quote::Double => r#"""""#,
}
} else {
match self.quote_style() {
QuoteStyle::Single => "'",
QuoteStyle::Double => "\"",
Quote::Single => "'",
Quote::Double => "\"",
}
}
}