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

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,