mirror of
https://github.com/astral-sh/ruff
synced 2026-01-25 07:20:50 -05:00
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.
74 lines
2.5 KiB
Rust
74 lines
2.5 KiB
Rust
use ruff_python_ast::{AnyStringFlags, InterpolatedStringElements};
|
|
use ruff_source_file::LineRanges;
|
|
use ruff_text_size::Ranged;
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
pub(crate) struct InterpolatedStringContext {
|
|
/// The string flags of the enclosing f/t-string part.
|
|
enclosing_flags: AnyStringFlags,
|
|
layout: InterpolatedStringLayout,
|
|
}
|
|
|
|
impl InterpolatedStringContext {
|
|
pub(crate) const fn new(flags: AnyStringFlags, layout: InterpolatedStringLayout) -> Self {
|
|
Self {
|
|
enclosing_flags: flags,
|
|
layout,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn flags(self) -> AnyStringFlags {
|
|
self.enclosing_flags
|
|
}
|
|
|
|
pub(crate) const fn layout(self) -> InterpolatedStringLayout {
|
|
self.layout
|
|
}
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub(crate) enum InterpolatedStringLayout {
|
|
/// Original f/t-string is flat.
|
|
/// Don't break expressions to keep the string flat.
|
|
Flat,
|
|
/// Original f/t-string has multiline expressions in the replacement fields.
|
|
/// Allow breaking expressions across multiple lines.
|
|
Multiline,
|
|
}
|
|
|
|
impl InterpolatedStringLayout {
|
|
// Heuristic: Allow breaking the f/t-string expressions across multiple lines
|
|
// only if there already is at least one multiline expression. This puts the
|
|
// control in the hands of the user to decide if they want to break the
|
|
// f/t-string expressions across multiple lines or not. This is similar to
|
|
// how Prettier does it for template literals in JavaScript.
|
|
//
|
|
// If it's single quoted f-string and it contains a multiline expression, then we
|
|
// assume that the target version of Python supports it (3.12+). If there are comments
|
|
// used in any of the expression of the f-string, then it's always going to be multiline
|
|
// and we assume that the target version of Python supports it (3.12+).
|
|
//
|
|
// Reference: https://prettier.io/docs/en/next/rationale.html#template-literals
|
|
pub(crate) fn from_interpolated_string_elements(
|
|
elements: &InterpolatedStringElements,
|
|
source: &str,
|
|
) -> Self {
|
|
if elements
|
|
.interpolations()
|
|
.any(|expr| source.contains_line_break(expr.range()))
|
|
{
|
|
Self::Multiline
|
|
} else {
|
|
Self::Flat
|
|
}
|
|
}
|
|
|
|
pub(crate) const fn is_flat(self) -> bool {
|
|
matches!(self, InterpolatedStringLayout::Flat)
|
|
}
|
|
|
|
pub(crate) const fn is_multiline(self) -> bool {
|
|
matches!(self, InterpolatedStringLayout::Multiline)
|
|
}
|
|
}
|