mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-27 12:29:28 +00:00
Add StaticTextSlice
kind to FormatElement
enum (#2873)
Given our current parser abstractions, we need the ability to tell `ruff_formatter` to print a pre-defined slice from a fixed string of source code, which we've introduced here as `FormatElement::StaticTextSlice`.
This commit is contained in:
parent
746e1d3436
commit
98ea94fdb7
4 changed files with 44 additions and 1 deletions
|
@ -8,6 +8,7 @@ use std::borrow::Cow;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::num::NonZeroU8;
|
use std::num::NonZeroU8;
|
||||||
|
use std::rc::Rc;
|
||||||
use Tag::*;
|
use Tag::*;
|
||||||
|
|
||||||
/// A line break that only gets printed if the enclosing `Group` doesn't fit on a single line.
|
/// A line break that only gets printed if the enclosing `Group` doesn't fit on a single line.
|
||||||
|
@ -303,6 +304,34 @@ impl std::fmt::Debug for DynamicText<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a text from a dynamic string and a range of the input source
|
||||||
|
pub fn static_text_slice(text: Rc<str>, range: TextRange) -> StaticTextSlice {
|
||||||
|
debug_assert_no_newlines(&text[range]);
|
||||||
|
|
||||||
|
StaticTextSlice { text, range }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq)]
|
||||||
|
pub struct StaticTextSlice {
|
||||||
|
text: Rc<str>,
|
||||||
|
range: TextRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Context> Format<Context> for StaticTextSlice {
|
||||||
|
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
||||||
|
f.write_element(FormatElement::StaticTextSlice {
|
||||||
|
text: self.text.clone(),
|
||||||
|
range: self.range,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Debug for StaticTextSlice {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
std::write!(f, "StaticTextSlice({})", &self.text[self.range])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// String that is the same as in the input source text if `text` is [`Cow::Borrowed`] or
|
/// String that is the same as in the input source text if `text` is [`Cow::Borrowed`] or
|
||||||
/// some replaced content if `text` is [`Cow::Owned`].
|
/// some replaced content if `text` is [`Cow::Owned`].
|
||||||
pub fn syntax_token_cow_slice<'a, L: Language>(
|
pub fn syntax_token_cow_slice<'a, L: Language>(
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::borrow::Cow;
|
||||||
use crate::{TagKind, TextSize};
|
use crate::{TagKind, TextSize};
|
||||||
#[cfg(target_pointer_width = "64")]
|
#[cfg(target_pointer_width = "64")]
|
||||||
use ruff_rowan::static_assert;
|
use ruff_rowan::static_assert;
|
||||||
use ruff_rowan::SyntaxTokenText;
|
use ruff_rowan::{SyntaxTokenText, TextRange};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
@ -38,6 +38,9 @@ pub enum FormatElement {
|
||||||
source_position: TextSize,
|
source_position: TextSize,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/// Token constructed by slicing a defined range from a static string.
|
||||||
|
StaticTextSlice { text: Rc<str>, range: TextRange },
|
||||||
|
|
||||||
/// A token for a text that is taken as is from the source code (input text and formatted representation are identical).
|
/// A token for a text that is taken as is from the source code (input text and formatted representation are identical).
|
||||||
/// Implementing by taking a slice from a `SyntaxToken` to avoid allocating a new string.
|
/// Implementing by taking a slice from a `SyntaxToken` to avoid allocating a new string.
|
||||||
SyntaxTokenTextSlice {
|
SyntaxTokenTextSlice {
|
||||||
|
@ -75,6 +78,9 @@ impl std::fmt::Debug for FormatElement {
|
||||||
FormatElement::DynamicText { text, .. } => {
|
FormatElement::DynamicText { text, .. } => {
|
||||||
fmt.debug_tuple("DynamicText").field(text).finish()
|
fmt.debug_tuple("DynamicText").field(text).finish()
|
||||||
}
|
}
|
||||||
|
FormatElement::StaticTextSlice { text, .. } => {
|
||||||
|
fmt.debug_tuple("Text").field(text).finish()
|
||||||
|
}
|
||||||
FormatElement::SyntaxTokenTextSlice { slice, .. } => fmt
|
FormatElement::SyntaxTokenTextSlice { slice, .. } => fmt
|
||||||
.debug_tuple("SyntaxTokenTextSlice")
|
.debug_tuple("SyntaxTokenTextSlice")
|
||||||
.field(slice)
|
.field(slice)
|
||||||
|
@ -225,6 +231,7 @@ impl FormatElement {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
FormatElement::SyntaxTokenTextSlice { .. }
|
FormatElement::SyntaxTokenTextSlice { .. }
|
||||||
|
| FormatElement::StaticTextSlice { .. }
|
||||||
| FormatElement::DynamicText { .. }
|
| FormatElement::DynamicText { .. }
|
||||||
| FormatElement::StaticText { .. }
|
| FormatElement::StaticText { .. }
|
||||||
)
|
)
|
||||||
|
@ -243,6 +250,7 @@ impl FormatElements for FormatElement {
|
||||||
FormatElement::Line(line_mode) => matches!(line_mode, LineMode::Hard | LineMode::Empty),
|
FormatElement::Line(line_mode) => matches!(line_mode, LineMode::Hard | LineMode::Empty),
|
||||||
FormatElement::StaticText { text } => text.contains('\n'),
|
FormatElement::StaticText { text } => text.contains('\n'),
|
||||||
FormatElement::DynamicText { text, .. } => text.contains('\n'),
|
FormatElement::DynamicText { text, .. } => text.contains('\n'),
|
||||||
|
FormatElement::StaticTextSlice { text, range } => text[*range].contains('\n'),
|
||||||
FormatElement::SyntaxTokenTextSlice { slice, .. } => slice.contains('\n'),
|
FormatElement::SyntaxTokenTextSlice { slice, .. } => slice.contains('\n'),
|
||||||
FormatElement::Interned(interned) => interned.will_break(),
|
FormatElement::Interned(interned) => interned.will_break(),
|
||||||
// Traverse into the most flat version because the content is guaranteed to expand when even
|
// Traverse into the most flat version because the content is guaranteed to expand when even
|
||||||
|
|
|
@ -81,6 +81,7 @@ impl Document {
|
||||||
}
|
}
|
||||||
FormatElement::StaticText { text } => text.contains('\n'),
|
FormatElement::StaticText { text } => text.contains('\n'),
|
||||||
FormatElement::DynamicText { text, .. } => text.contains('\n'),
|
FormatElement::DynamicText { text, .. } => text.contains('\n'),
|
||||||
|
FormatElement::StaticTextSlice { text, range } => text[*range].contains('\n'),
|
||||||
FormatElement::SyntaxTokenTextSlice { slice, .. } => slice.contains('\n'),
|
FormatElement::SyntaxTokenTextSlice { slice, .. } => slice.contains('\n'),
|
||||||
FormatElement::ExpandParent
|
FormatElement::ExpandParent
|
||||||
| FormatElement::Line(LineMode::Hard | LineMode::Empty) => true,
|
| FormatElement::Line(LineMode::Hard | LineMode::Empty) => true,
|
||||||
|
@ -194,6 +195,7 @@ impl Format<IrFormatContext> for &[FormatElement] {
|
||||||
element @ FormatElement::Space
|
element @ FormatElement::Space
|
||||||
| element @ FormatElement::StaticText { .. }
|
| element @ FormatElement::StaticText { .. }
|
||||||
| element @ FormatElement::DynamicText { .. }
|
| element @ FormatElement::DynamicText { .. }
|
||||||
|
| element @ FormatElement::StaticTextSlice { .. }
|
||||||
| element @ FormatElement::SyntaxTokenTextSlice { .. } => {
|
| element @ FormatElement::SyntaxTokenTextSlice { .. } => {
|
||||||
if !in_text {
|
if !in_text {
|
||||||
write!(f, [text("\"")])?;
|
write!(f, [text("\"")])?;
|
||||||
|
|
|
@ -99,6 +99,7 @@ impl<'a> Printer<'a> {
|
||||||
text,
|
text,
|
||||||
source_position,
|
source_position,
|
||||||
} => self.print_text(text, Some(*source_position)),
|
} => self.print_text(text, Some(*source_position)),
|
||||||
|
FormatElement::StaticTextSlice { text, range } => self.print_text(&text[*range], None),
|
||||||
FormatElement::SyntaxTokenTextSlice {
|
FormatElement::SyntaxTokenTextSlice {
|
||||||
slice,
|
slice,
|
||||||
source_position,
|
source_position,
|
||||||
|
@ -1001,6 +1002,9 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
||||||
|
|
||||||
FormatElement::StaticText { text } => return Ok(self.fits_text(text)),
|
FormatElement::StaticText { text } => return Ok(self.fits_text(text)),
|
||||||
FormatElement::DynamicText { text, .. } => return Ok(self.fits_text(text)),
|
FormatElement::DynamicText { text, .. } => return Ok(self.fits_text(text)),
|
||||||
|
FormatElement::StaticTextSlice { text, range } => {
|
||||||
|
return Ok(self.fits_text(&text[*range]))
|
||||||
|
}
|
||||||
FormatElement::SyntaxTokenTextSlice { slice, .. } => return Ok(self.fits_text(slice)),
|
FormatElement::SyntaxTokenTextSlice { slice, .. } => return Ok(self.fits_text(slice)),
|
||||||
|
|
||||||
FormatElement::LineSuffixBoundary => {
|
FormatElement::LineSuffixBoundary => {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue