mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 02:38:25 +00:00
Unify enums used for internal representation of quoting style (#10383)
This commit is contained in:
parent
d59433b12e
commit
c2e15f38ee
16 changed files with 148 additions and 228 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue