mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-10 18:32:28 +00:00
Implement template strings (#17851)
This PR implements template strings (t-strings) in the parser and formatter for Ruff. Minimal changes necessary to compile were made in other parts of the code (e.g. ty, the linter, etc.). These will be covered properly in follow-up PRs.
This commit is contained in:
parent
ad024f9a09
commit
9bbf4987e8
261 changed files with 18023 additions and 1802 deletions
|
@ -7,7 +7,7 @@ use ruff_python_parser::Tokens;
|
|||
|
||||
use crate::PyFormatOptions;
|
||||
use crate::comments::Comments;
|
||||
use crate::other::f_string_element::FStringExpressionElementContext;
|
||||
use crate::other::interpolated_string_element::InterpolatedElementContext;
|
||||
|
||||
pub struct PyFormatContext<'a> {
|
||||
options: PyFormatOptions,
|
||||
|
@ -25,8 +25,8 @@ pub struct PyFormatContext<'a> {
|
|||
/// quote style that is inverted from the one here in order to ensure that
|
||||
/// the formatted Python code will be valid.
|
||||
docstring: Option<Quote>,
|
||||
/// The state of the formatter with respect to f-strings.
|
||||
f_string_state: FStringState,
|
||||
/// The state of the formatter with respect to f-strings and t-strings.
|
||||
interpolated_string_state: InterpolatedStringState,
|
||||
}
|
||||
|
||||
impl<'a> PyFormatContext<'a> {
|
||||
|
@ -44,7 +44,7 @@ impl<'a> PyFormatContext<'a> {
|
|||
node_level: NodeLevel::TopLevel(TopLevelStatementPosition::Other),
|
||||
indent_level: IndentLevel::new(0),
|
||||
docstring: None,
|
||||
f_string_state: FStringState::Outside,
|
||||
interpolated_string_state: InterpolatedStringState::Outside,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,12 +97,15 @@ impl<'a> PyFormatContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn f_string_state(&self) -> FStringState {
|
||||
self.f_string_state
|
||||
pub(crate) fn interpolated_string_state(&self) -> InterpolatedStringState {
|
||||
self.interpolated_string_state
|
||||
}
|
||||
|
||||
pub(crate) fn set_f_string_state(&mut self, f_string_state: FStringState) {
|
||||
self.f_string_state = f_string_state;
|
||||
pub(crate) fn set_interpolated_string_state(
|
||||
&mut self,
|
||||
interpolated_string_state: InterpolatedStringState,
|
||||
) {
|
||||
self.interpolated_string_state = interpolated_string_state;
|
||||
}
|
||||
|
||||
/// Returns `true` if preview mode is enabled.
|
||||
|
@ -135,24 +138,24 @@ impl Debug for PyFormatContext<'_> {
|
|||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub(crate) enum FStringState {
|
||||
pub(crate) enum InterpolatedStringState {
|
||||
/// The formatter is inside an f-string expression element i.e., between the
|
||||
/// curly brace in `f"foo {x}"`.
|
||||
///
|
||||
/// The containing `FStringContext` is the surrounding f-string context.
|
||||
InsideExpressionElement(FStringExpressionElementContext),
|
||||
InsideInterpolatedElement(InterpolatedElementContext),
|
||||
/// The formatter is outside an f-string.
|
||||
#[default]
|
||||
Outside,
|
||||
}
|
||||
|
||||
impl FStringState {
|
||||
impl InterpolatedStringState {
|
||||
pub(crate) fn can_contain_line_breaks(self) -> Option<bool> {
|
||||
match self {
|
||||
FStringState::InsideExpressionElement(context) => {
|
||||
InterpolatedStringState::InsideInterpolatedElement(context) => {
|
||||
Some(context.can_contain_line_breaks())
|
||||
}
|
||||
FStringState::Outside => None,
|
||||
InterpolatedStringState::Outside => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -375,25 +378,25 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct WithFStringState<'a, B, D>
|
||||
pub(crate) struct WithInterpolatedStringState<'a, B, D>
|
||||
where
|
||||
D: DerefMut<Target = B>,
|
||||
B: Buffer<Context = PyFormatContext<'a>>,
|
||||
{
|
||||
buffer: D,
|
||||
saved_location: FStringState,
|
||||
saved_location: InterpolatedStringState,
|
||||
}
|
||||
|
||||
impl<'a, B, D> WithFStringState<'a, B, D>
|
||||
impl<'a, B, D> WithInterpolatedStringState<'a, B, D>
|
||||
where
|
||||
D: DerefMut<Target = B>,
|
||||
B: Buffer<Context = PyFormatContext<'a>>,
|
||||
{
|
||||
pub(crate) fn new(expr_location: FStringState, mut buffer: D) -> Self {
|
||||
pub(crate) fn new(expr_location: InterpolatedStringState, mut buffer: D) -> Self {
|
||||
let context = buffer.state_mut().context_mut();
|
||||
let saved_location = context.f_string_state();
|
||||
let saved_location = context.interpolated_string_state();
|
||||
|
||||
context.set_f_string_state(expr_location);
|
||||
context.set_interpolated_string_state(expr_location);
|
||||
|
||||
Self {
|
||||
buffer,
|
||||
|
@ -402,7 +405,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, B, D> Deref for WithFStringState<'a, B, D>
|
||||
impl<'a, B, D> Deref for WithInterpolatedStringState<'a, B, D>
|
||||
where
|
||||
D: DerefMut<Target = B>,
|
||||
B: Buffer<Context = PyFormatContext<'a>>,
|
||||
|
@ -414,7 +417,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, B, D> DerefMut for WithFStringState<'a, B, D>
|
||||
impl<'a, B, D> DerefMut for WithInterpolatedStringState<'a, B, D>
|
||||
where
|
||||
D: DerefMut<Target = B>,
|
||||
B: Buffer<Context = PyFormatContext<'a>>,
|
||||
|
@ -424,7 +427,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, B, D> Drop for WithFStringState<'a, B, D>
|
||||
impl<'a, B, D> Drop for WithInterpolatedStringState<'a, B, D>
|
||||
where
|
||||
D: DerefMut<Target = B>,
|
||||
B: Buffer<Context = PyFormatContext<'a>>,
|
||||
|
@ -433,6 +436,6 @@ where
|
|||
self.buffer
|
||||
.state_mut()
|
||||
.context_mut()
|
||||
.set_f_string_state(self.saved_location);
|
||||
.set_interpolated_string_state(self.saved_location);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue