mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-24 05:25:17 +00:00
Introduce SourceCodeSlice
to reduce the size of FormatElement
(#4622)
Introduce `SourceCodeSlice` to reduce the size of `FormatElement`
This commit is contained in:
parent
6943beee66
commit
86ced3516b
26 changed files with 408 additions and 171 deletions
|
@ -1,14 +1,13 @@
|
|||
use crate::format_element::tag::{Condition, Tag};
|
||||
use crate::prelude::tag::{DedentMode, GroupMode, LabelId};
|
||||
use crate::prelude::*;
|
||||
use crate::{format_element, write, Argument, Arguments, GroupId, TextSize};
|
||||
use crate::{format_element, write, Argument, Arguments, FormatContext, GroupId, TextSize};
|
||||
use crate::{Buffer, VecBuffer};
|
||||
|
||||
use ruff_text_size::TextRange;
|
||||
use std::cell::Cell;
|
||||
use std::marker::PhantomData;
|
||||
use std::num::NonZeroU8;
|
||||
use std::rc::Rc;
|
||||
use Tag::*;
|
||||
|
||||
/// A line break that only gets printed if the enclosing `Group` doesn't fit on a single line.
|
||||
|
@ -361,31 +360,65 @@ 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>,
|
||||
/// Emits a text as it is written in the source document. Optimized to avoid allocations.
|
||||
pub const fn source_text_slice(
|
||||
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,
|
||||
})
|
||||
newlines: ContainsNewlines,
|
||||
) -> SourceTextSliceBuilder {
|
||||
SourceTextSliceBuilder {
|
||||
range,
|
||||
new_lines: newlines,
|
||||
}
|
||||
}
|
||||
|
||||
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])
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum ContainsNewlines {
|
||||
/// The string contains newline characters
|
||||
Yes,
|
||||
/// The string contains no newline characters
|
||||
No,
|
||||
|
||||
/// The string may contain newline characters, search the string to determine if there are any newlines.
|
||||
Detect,
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
pub struct SourceTextSliceBuilder {
|
||||
range: TextRange,
|
||||
new_lines: ContainsNewlines,
|
||||
}
|
||||
|
||||
impl<Context> Format<Context> for SourceTextSliceBuilder
|
||||
where
|
||||
Context: FormatContext,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
|
||||
let source_code = f.context().source_code();
|
||||
let slice = source_code.slice(self.range);
|
||||
debug_assert_no_newlines(slice.text(source_code));
|
||||
|
||||
let contains_newlines = match self.new_lines {
|
||||
ContainsNewlines::Yes => {
|
||||
debug_assert!(
|
||||
slice.text(source_code).contains('\n'),
|
||||
"Text contains no new line characters but the caller specified that it does."
|
||||
);
|
||||
true
|
||||
}
|
||||
ContainsNewlines::No => {
|
||||
debug_assert!(
|
||||
!slice.text(source_code).contains('\n'),
|
||||
"Text contains new line characters but the caller specified that it does not."
|
||||
);
|
||||
false
|
||||
}
|
||||
ContainsNewlines::Detect => slice.text(source_code).contains('\n'),
|
||||
};
|
||||
|
||||
f.write_element(FormatElement::SourceCodeSlice {
|
||||
slice,
|
||||
contains_newlines,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,8 +7,9 @@ use std::ops::Deref;
|
|||
use std::rc::Rc;
|
||||
|
||||
use crate::format_element::tag::{LabelId, Tag};
|
||||
use crate::source_code::SourceCodeSlice;
|
||||
use crate::TagKind;
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
use ruff_text_size::TextSize;
|
||||
|
||||
/// Language agnostic IR for formatting source code.
|
||||
///
|
||||
|
@ -39,8 +40,12 @@ pub enum FormatElement {
|
|||
text: Box<str>,
|
||||
},
|
||||
|
||||
/// Token constructed by slicing a defined range from a static string.
|
||||
StaticTextSlice { text: Rc<str>, range: TextRange },
|
||||
/// Text that gets emitted as it is in the source code. Optimized to avoid any allocations.
|
||||
SourceCodeSlice {
|
||||
slice: SourceCodeSlice,
|
||||
/// Whether the string contains any new line characters
|
||||
contains_newlines: bool,
|
||||
},
|
||||
|
||||
/// Prevents that line suffixes move past this boundary. Forces the printer to print any pending
|
||||
/// line suffixes, potentially by inserting a hard line break.
|
||||
|
@ -70,9 +75,14 @@ impl std::fmt::Debug for FormatElement {
|
|||
FormatElement::DynamicText { text, .. } => {
|
||||
fmt.debug_tuple("DynamicText").field(text).finish()
|
||||
}
|
||||
FormatElement::StaticTextSlice { text, .. } => {
|
||||
fmt.debug_tuple("Text").field(text).finish()
|
||||
}
|
||||
FormatElement::SourceCodeSlice {
|
||||
slice,
|
||||
contains_newlines,
|
||||
} => fmt
|
||||
.debug_tuple("Text")
|
||||
.field(slice)
|
||||
.field(contains_newlines)
|
||||
.finish(),
|
||||
FormatElement::LineSuffixBoundary => write!(fmt, "LineSuffixBoundary"),
|
||||
FormatElement::BestFitting(best_fitting) => {
|
||||
fmt.debug_tuple("BestFitting").field(&best_fitting).finish()
|
||||
|
@ -221,7 +231,7 @@ impl FormatElement {
|
|||
pub const fn is_text(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
FormatElement::StaticTextSlice { .. }
|
||||
FormatElement::SourceCodeSlice { .. }
|
||||
| FormatElement::DynamicText { .. }
|
||||
| FormatElement::StaticText { .. }
|
||||
)
|
||||
|
@ -240,7 +250,9 @@ impl FormatElements for FormatElement {
|
|||
FormatElement::Line(line_mode) => matches!(line_mode, LineMode::Hard | LineMode::Empty),
|
||||
FormatElement::StaticText { text } => text.contains('\n'),
|
||||
FormatElement::DynamicText { text, .. } => text.contains('\n'),
|
||||
FormatElement::StaticTextSlice { text, range } => text[*range].contains('\n'),
|
||||
FormatElement::SourceCodeSlice {
|
||||
contains_newlines, ..
|
||||
} => *contains_newlines,
|
||||
FormatElement::Interned(interned) => interned.will_break(),
|
||||
// Traverse into the most flat version because the content is guaranteed to expand when even
|
||||
// the most flat version contains some content that forces a break.
|
||||
|
@ -380,20 +392,19 @@ mod sizes {
|
|||
// be recomputed at a later point in time?
|
||||
// You reduced the size of a format element? Excellent work!
|
||||
|
||||
use crate::format_element::BestFitting;
|
||||
use crate::prelude::tag::VerbatimKind;
|
||||
use crate::prelude::Interned;
|
||||
use ruff_text_size::TextRange;
|
||||
use static_assertions::assert_eq_size;
|
||||
|
||||
assert_eq_size!(TextRange, [u8; 8]);
|
||||
assert_eq_size!(VerbatimKind, [u8; 8]);
|
||||
assert_eq_size!(Interned, [u8; 16]);
|
||||
assert_eq_size!(BestFitting, [u8; 16]);
|
||||
assert_eq_size!(ruff_text_size::TextRange, [u8; 8]);
|
||||
assert_eq_size!(crate::prelude::tag::VerbatimKind, [u8; 8]);
|
||||
assert_eq_size!(crate::prelude::Interned, [u8; 16]);
|
||||
assert_eq_size!(crate::format_element::BestFitting, [u8; 16]);
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
assert_eq_size!(crate::SourceCodeSlice, [u8; 8]);
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
assert_eq_size!(crate::format_element::Tag, [u8; 16]);
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
assert_eq_size!(crate::FormatElement, [u8; 32]);
|
||||
assert_eq_size!(crate::FormatElement, [u8; 24]);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::format_element::tag::DedentMode;
|
|||
use crate::prelude::tag::GroupMode;
|
||||
use crate::prelude::*;
|
||||
use crate::printer::LineEnding;
|
||||
use crate::source_code::SourceCode;
|
||||
use crate::{format, write};
|
||||
use crate::{
|
||||
BufferExtensions, Format, FormatContext, FormatElement, FormatOptions, FormatResult, Formatter,
|
||||
|
@ -80,7 +81,9 @@ impl Document {
|
|||
}
|
||||
FormatElement::StaticText { text } => text.contains('\n'),
|
||||
FormatElement::DynamicText { text, .. } => text.contains('\n'),
|
||||
FormatElement::StaticTextSlice { text, range } => text[*range].contains('\n'),
|
||||
FormatElement::SourceCodeSlice {
|
||||
contains_newlines, ..
|
||||
} => *contains_newlines,
|
||||
FormatElement::ExpandParent
|
||||
| FormatElement::Line(LineMode::Hard | LineMode::Empty) => true,
|
||||
_ => false,
|
||||
|
@ -99,6 +102,13 @@ impl Document {
|
|||
let mut interned: FxHashMap<&Interned, bool> = FxHashMap::default();
|
||||
propagate_expands(self, &mut enclosing, &mut interned);
|
||||
}
|
||||
|
||||
pub fn display<'a>(&'a self, source_code: SourceCode<'a>) -> DisplayDocument {
|
||||
DisplayDocument {
|
||||
elements: self.elements.as_slice(),
|
||||
source_code,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<FormatElement>> for Document {
|
||||
|
@ -115,9 +125,14 @@ impl Deref for Document {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Document {
|
||||
pub struct DisplayDocument<'a> {
|
||||
elements: &'a [FormatElement],
|
||||
source_code: SourceCode<'a>,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for DisplayDocument<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let formatted = format!(IrFormatContext::default(), [self.elements.as_slice()])
|
||||
let formatted = format!(IrFormatContext::new(self.source_code), [self.elements])
|
||||
.expect("Formatting not to throw any FormatErrors");
|
||||
|
||||
f.write_str(
|
||||
|
@ -129,18 +144,33 @@ impl std::fmt::Display for Document {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
struct IrFormatContext {
|
||||
#[derive(Clone, Debug)]
|
||||
struct IrFormatContext<'a> {
|
||||
/// The interned elements that have been printed to this point
|
||||
printed_interned_elements: HashMap<Interned, usize>,
|
||||
|
||||
source_code: SourceCode<'a>,
|
||||
}
|
||||
|
||||
impl FormatContext for IrFormatContext {
|
||||
impl<'a> IrFormatContext<'a> {
|
||||
fn new(source_code: SourceCode<'a>) -> Self {
|
||||
Self {
|
||||
source_code,
|
||||
printed_interned_elements: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FormatContext for IrFormatContext<'_> {
|
||||
type Options = IrFormatOptions;
|
||||
|
||||
fn options(&self) -> &Self::Options {
|
||||
&IrFormatOptions
|
||||
}
|
||||
|
||||
fn source_code(&self) -> SourceCode {
|
||||
self.source_code
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
|
@ -165,7 +195,7 @@ impl FormatOptions for IrFormatOptions {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<IrFormatContext> for &[FormatElement] {
|
||||
impl Format<IrFormatContext<'_>> for &[FormatElement] {
|
||||
fn fmt(&self, f: &mut Formatter<IrFormatContext>) -> FormatResult<()> {
|
||||
use Tag::*;
|
||||
|
||||
|
@ -189,7 +219,7 @@ impl Format<IrFormatContext> for &[FormatElement] {
|
|||
element @ FormatElement::Space
|
||||
| element @ FormatElement::StaticText { .. }
|
||||
| element @ FormatElement::DynamicText { .. }
|
||||
| element @ FormatElement::StaticTextSlice { .. } => {
|
||||
| element @ FormatElement::SourceCodeSlice { .. } => {
|
||||
if !in_text {
|
||||
write!(f, [text("\"")])?;
|
||||
}
|
||||
|
@ -489,7 +519,7 @@ impl Format<IrFormatContext> for &[FormatElement] {
|
|||
|
||||
struct ContentArrayStart;
|
||||
|
||||
impl Format<IrFormatContext> for ContentArrayStart {
|
||||
impl Format<IrFormatContext<'_>> for ContentArrayStart {
|
||||
fn fmt(&self, f: &mut Formatter<IrFormatContext>) -> FormatResult<()> {
|
||||
use Tag::*;
|
||||
|
||||
|
@ -505,7 +535,7 @@ impl Format<IrFormatContext> for ContentArrayStart {
|
|||
|
||||
struct ContentArrayEnd;
|
||||
|
||||
impl Format<IrFormatContext> for ContentArrayEnd {
|
||||
impl Format<IrFormatContext<'_>> for ContentArrayEnd {
|
||||
fn fmt(&self, f: &mut Formatter<IrFormatContext>) -> FormatResult<()> {
|
||||
use Tag::*;
|
||||
f.write_elements([
|
||||
|
@ -615,8 +645,9 @@ impl FormatElements for [FormatElement] {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::prelude::*;
|
||||
use crate::SimpleFormatContext;
|
||||
use crate::{format, format_args, write};
|
||||
use crate::{SimpleFormatContext, SourceCode};
|
||||
use ruff_text_size::{TextRange, TextSize};
|
||||
|
||||
#[test]
|
||||
fn display_elements() {
|
||||
|
@ -641,7 +672,51 @@ mod tests {
|
|||
let document = formatted.into_document();
|
||||
|
||||
assert_eq!(
|
||||
&std::format!("{document}"),
|
||||
&std::format!("{}", document.display(SourceCode::default())),
|
||||
r#"[
|
||||
group([
|
||||
"(",
|
||||
indent([
|
||||
soft_line_break,
|
||||
"Some longer content That should ultimately break"
|
||||
]),
|
||||
soft_line_break
|
||||
])
|
||||
]"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_elements_with_source_text_slice() {
|
||||
let source_code = "Some longer content\nThat should ultimately break";
|
||||
let formatted = format!(
|
||||
SimpleFormatContext::default().with_source_code(source_code),
|
||||
[format_with(|f| {
|
||||
write!(
|
||||
f,
|
||||
[group(&format_args![
|
||||
text("("),
|
||||
soft_block_indent(&format_args![
|
||||
source_text_slice(
|
||||
TextRange::at(TextSize::new(0), TextSize::new(19)),
|
||||
ContainsNewlines::No
|
||||
),
|
||||
space(),
|
||||
source_text_slice(
|
||||
TextRange::at(TextSize::new(20), TextSize::new(28)),
|
||||
ContainsNewlines::No
|
||||
),
|
||||
])
|
||||
])]
|
||||
)
|
||||
})]
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let document = formatted.into_document();
|
||||
|
||||
assert_eq!(
|
||||
&std::format!("{}", document.display(SourceCode::new(source_code))),
|
||||
r#"[
|
||||
group([
|
||||
"(",
|
||||
|
@ -677,7 +752,7 @@ mod tests {
|
|||
]);
|
||||
|
||||
assert_eq!(
|
||||
&std::format!("{document}"),
|
||||
&std::format!("{}", document.display(SourceCode::default())),
|
||||
r#"[
|
||||
"[",
|
||||
group([
|
||||
|
|
|
@ -33,6 +33,7 @@ pub mod group_id;
|
|||
pub mod macros;
|
||||
pub mod prelude;
|
||||
pub mod printer;
|
||||
mod source_code;
|
||||
|
||||
use crate::formatter::Formatter;
|
||||
use crate::group_id::UniqueGroupIdBuilder;
|
||||
|
@ -47,6 +48,7 @@ pub use buffer::{
|
|||
VecBuffer,
|
||||
};
|
||||
pub use builders::BestFitting;
|
||||
pub use source_code::{SourceCode, SourceCodeSlice};
|
||||
|
||||
pub use crate::diagnostics::{ActualStart, FormatError, InvalidDocumentError, PrintError};
|
||||
pub use format_element::{normalize_newlines, FormatElement, LINE_TERMINATORS};
|
||||
|
@ -202,6 +204,9 @@ pub trait FormatContext {
|
|||
|
||||
/// Returns the formatting options
|
||||
fn options(&self) -> &Self::Options;
|
||||
|
||||
/// Returns the source code from the document that gets formatted.
|
||||
fn source_code(&self) -> SourceCode;
|
||||
}
|
||||
|
||||
/// Options customizing how the source code should be formatted.
|
||||
|
@ -219,11 +224,20 @@ pub trait FormatOptions {
|
|||
#[derive(Debug, Default, Eq, PartialEq)]
|
||||
pub struct SimpleFormatContext {
|
||||
options: SimpleFormatOptions,
|
||||
source_code: String,
|
||||
}
|
||||
|
||||
impl SimpleFormatContext {
|
||||
pub fn new(options: SimpleFormatOptions) -> Self {
|
||||
Self { options }
|
||||
Self {
|
||||
options,
|
||||
source_code: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_source_code(mut self, code: &str) -> Self {
|
||||
self.source_code = String::from(code);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -233,9 +247,13 @@ impl FormatContext for SimpleFormatContext {
|
|||
fn options(&self) -> &Self::Options {
|
||||
&self.options
|
||||
}
|
||||
|
||||
fn source_code(&self) -> SourceCode {
|
||||
SourceCode::new(&self.source_code)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Eq, PartialEq)]
|
||||
#[derive(Debug, Default, Eq, PartialEq, Clone)]
|
||||
pub struct SimpleFormatOptions {
|
||||
pub indent_style: IndentStyle,
|
||||
pub line_width: LineWidth,
|
||||
|
@ -302,15 +320,18 @@ where
|
|||
Context: FormatContext,
|
||||
{
|
||||
pub fn print(&self) -> PrintResult<Printed> {
|
||||
let source_code = self.context.source_code();
|
||||
let print_options = self.context.options().as_print_options();
|
||||
let printed = Printer::new(print_options).print(&self.document)?;
|
||||
let printed = Printer::new(source_code, print_options).print(&self.document)?;
|
||||
|
||||
Ok(printed)
|
||||
}
|
||||
|
||||
pub fn print_with_indent(&self, indent: u16) -> PrintResult<Printed> {
|
||||
let source_code = self.context.source_code();
|
||||
let print_options = self.context.options().as_print_options();
|
||||
let printed = Printer::new(print_options).print_with_indent(&self.document, indent)?;
|
||||
let printed =
|
||||
Printer::new(source_code, print_options).print_with_indent(&self.document, indent)?;
|
||||
|
||||
Ok(printed)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ use crate::printer::line_suffixes::{LineSuffixEntry, LineSuffixes};
|
|||
use crate::printer::queue::{
|
||||
AllPredicate, FitsEndPredicate, FitsQueue, PrintQueue, Queue, SingleEntryPredicate,
|
||||
};
|
||||
use crate::source_code::SourceCode;
|
||||
use drop_bomb::DebugDropBomb;
|
||||
use ruff_text_size::{TextLen, TextSize};
|
||||
use std::num::NonZeroU8;
|
||||
|
@ -32,12 +33,14 @@ use unicode_width::UnicodeWidthChar;
|
|||
#[derive(Debug, Default)]
|
||||
pub struct Printer<'a> {
|
||||
options: PrinterOptions,
|
||||
source_code: SourceCode<'a>,
|
||||
state: PrinterState<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Printer<'a> {
|
||||
pub fn new(options: PrinterOptions) -> Self {
|
||||
pub fn new(source_code: SourceCode<'a>, options: PrinterOptions) -> Self {
|
||||
Self {
|
||||
source_code,
|
||||
options,
|
||||
state: PrinterState::default(),
|
||||
}
|
||||
|
@ -96,7 +99,10 @@ impl<'a> Printer<'a> {
|
|||
|
||||
FormatElement::StaticText { text } => self.print_text(text, None),
|
||||
FormatElement::DynamicText { text } => self.print_text(text, None),
|
||||
FormatElement::StaticTextSlice { text, range } => self.print_text(&text[*range], None),
|
||||
FormatElement::SourceCodeSlice { slice, .. } => {
|
||||
let text = slice.text(self.source_code);
|
||||
self.print_text(text, Some(slice.range()))
|
||||
}
|
||||
FormatElement::Line(line_mode) => {
|
||||
if args.mode().is_flat()
|
||||
&& matches!(line_mode, LineMode::Soft | LineMode::SoftOrSpace)
|
||||
|
@ -994,8 +1000,9 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> {
|
|||
|
||||
FormatElement::StaticText { 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::SourceCodeSlice { slice, .. } => {
|
||||
let text = slice.text(self.printer.source_code);
|
||||
return Ok(self.fits_text(text));
|
||||
}
|
||||
FormatElement::LineSuffixBoundary => {
|
||||
if self.state.has_line_suffix {
|
||||
|
@ -1256,6 +1263,7 @@ struct FitsState {
|
|||
mod tests {
|
||||
use crate::prelude::*;
|
||||
use crate::printer::{LineEnding, PrintWidth, Printer, PrinterOptions};
|
||||
use crate::source_code::SourceCode;
|
||||
use crate::{format_args, write, Document, FormatState, IndentStyle, Printed, VecBuffer};
|
||||
|
||||
fn format(root: &dyn Format<SimpleFormatContext>) -> Printed {
|
||||
|
@ -1274,7 +1282,7 @@ mod tests {
|
|||
) -> Printed {
|
||||
let formatted = crate::format!(SimpleFormatContext::default(), [root]).unwrap();
|
||||
|
||||
Printer::new(options)
|
||||
Printer::new(SourceCode::default(), options)
|
||||
.print(formatted.document())
|
||||
.expect("Document to be valid")
|
||||
}
|
||||
|
@ -1510,7 +1518,10 @@ two lines`,
|
|||
|
||||
let document = Document::from(buffer.into_vec());
|
||||
|
||||
let printed = Printer::new(PrinterOptions::default().with_print_width(PrintWidth::new(10)))
|
||||
let printed = Printer::new(
|
||||
SourceCode::default(),
|
||||
PrinterOptions::default().with_print_width(PrintWidth::new(10)),
|
||||
)
|
||||
.print(&document)
|
||||
.unwrap();
|
||||
|
||||
|
|
81
crates/ruff_formatter/src/source_code.rs
Normal file
81
crates/ruff_formatter/src/source_code.rs
Normal file
|
@ -0,0 +1,81 @@
|
|||
use ruff_text_size::TextRange;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
/// The source code of a document that gets formatted
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Default)]
|
||||
pub struct SourceCode<'a> {
|
||||
text: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> SourceCode<'a> {
|
||||
pub fn new(text: &'a str) -> Self {
|
||||
Self { text }
|
||||
}
|
||||
|
||||
pub fn slice(self, range: TextRange) -> SourceCodeSlice {
|
||||
assert!(
|
||||
usize::from(range.end()) <= self.text.len(),
|
||||
"Range end {:?} out of bounds {}.",
|
||||
range.end(),
|
||||
self.text.len()
|
||||
);
|
||||
|
||||
assert!(
|
||||
self.text.is_char_boundary(usize::from(range.start())),
|
||||
"The range start position {:?} is not a char boundary.",
|
||||
range.start()
|
||||
);
|
||||
|
||||
assert!(
|
||||
self.text.is_char_boundary(usize::from(range.end())),
|
||||
"The range end position {:?} is not a char boundary.",
|
||||
range.end()
|
||||
);
|
||||
|
||||
SourceCodeSlice {
|
||||
range,
|
||||
#[cfg(debug_assertions)]
|
||||
text: String::from(&self.text[range]).into_boxed_str(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for SourceCode<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("SourceCode").field(&self.text).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// A slice into the source text of a document.
|
||||
///
|
||||
/// It only stores the range in production builds for a more compact representation, but it
|
||||
/// keeps the original text in debug builds for better developer experience.
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
pub struct SourceCodeSlice {
|
||||
range: TextRange,
|
||||
#[cfg(debug_assertions)]
|
||||
text: Box<str>,
|
||||
}
|
||||
|
||||
impl SourceCodeSlice {
|
||||
/// Returns the slice's text.
|
||||
pub fn text<'a>(&self, code: SourceCode<'a>) -> &'a str {
|
||||
assert!(usize::from(self.range.end()) <= code.text.len(), "The range of this slice is out of bounds. Did you provide the correct source code for this slice?");
|
||||
&code.text[self.range]
|
||||
}
|
||||
|
||||
pub fn range(&self) -> TextRange {
|
||||
self.range
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for SourceCodeSlice {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let mut tuple = f.debug_tuple("SourceCodeSlice");
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
tuple.field(&self.text);
|
||||
|
||||
tuple.field(&self.range).finish()
|
||||
}
|
||||
}
|
|
@ -1,36 +1,34 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use ruff_formatter::{FormatContext, SimpleFormatOptions};
|
||||
use ruff_formatter::{FormatContext, SimpleFormatOptions, SourceCode};
|
||||
use ruff_python_ast::source_code::Locator;
|
||||
|
||||
pub struct ASTFormatContext {
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ASTFormatContext<'source> {
|
||||
options: SimpleFormatOptions,
|
||||
contents: Rc<str>,
|
||||
contents: &'source str,
|
||||
}
|
||||
|
||||
impl ASTFormatContext {
|
||||
pub fn new(options: SimpleFormatOptions, contents: &str) -> Self {
|
||||
Self {
|
||||
options,
|
||||
contents: Rc::from(contents),
|
||||
impl<'source> ASTFormatContext<'source> {
|
||||
pub fn new(options: SimpleFormatOptions, contents: &'source str) -> Self {
|
||||
Self { options, contents }
|
||||
}
|
||||
|
||||
pub fn contents(&self) -> &'source str {
|
||||
self.contents
|
||||
}
|
||||
|
||||
pub fn locator(&self) -> Locator<'source> {
|
||||
Locator::new(self.contents)
|
||||
}
|
||||
}
|
||||
|
||||
impl FormatContext for ASTFormatContext {
|
||||
impl FormatContext for ASTFormatContext<'_> {
|
||||
type Options = SimpleFormatOptions;
|
||||
|
||||
fn options(&self) -> &Self::Options {
|
||||
&self.options
|
||||
}
|
||||
}
|
||||
|
||||
impl ASTFormatContext {
|
||||
pub fn contents(&self) -> Rc<str> {
|
||||
self.contents.clone()
|
||||
}
|
||||
|
||||
pub fn locator(&self) -> Locator {
|
||||
Locator::new(&self.contents)
|
||||
fn source_code(&self) -> SourceCode {
|
||||
SourceCode::new(self.contents)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ pub struct FormatAlias<'a> {
|
|||
item: &'a Alias,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for Alias {
|
||||
impl AsFormat<ASTFormatContext<'_>> for Alias {
|
||||
type Format<'a> = FormatAlias<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -18,7 +18,7 @@ impl AsFormat<ASTFormatContext> for Alias {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatAlias<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatAlias<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let alias = self.item;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ pub struct FormatArg<'a> {
|
|||
item: &'a Arg,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for Arg {
|
||||
impl AsFormat<ASTFormatContext<'_>> for Arg {
|
||||
type Format<'a> = FormatArg<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -18,7 +18,7 @@ impl AsFormat<ASTFormatContext> for Arg {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatArg<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatArg<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let arg = self.item;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ pub struct FormatArguments<'a> {
|
|||
item: &'a Arguments,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for Arguments {
|
||||
impl AsFormat<ASTFormatContext<'_>> for Arguments {
|
||||
type Format<'a> = FormatArguments<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -17,7 +17,7 @@ impl AsFormat<ASTFormatContext> for Arguments {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatArguments<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatArguments<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let args = self.item;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ pub struct FormatBoolOp<'a> {
|
|||
item: &'a BoolOp,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for BoolOp {
|
||||
impl AsFormat<ASTFormatContext<'_>> for BoolOp {
|
||||
type Format<'a> = FormatBoolOp<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -18,7 +18,7 @@ impl AsFormat<ASTFormatContext> for BoolOp {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatBoolOp<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatBoolOp<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let bool_op = self.item;
|
||||
write!(f, [leading_comments(bool_op)])?;
|
||||
|
|
|
@ -12,7 +12,7 @@ pub(crate) struct Block<'a> {
|
|||
body: &'a Body,
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for Block<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for Block<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
for (i, stmt) in self.body.iter().enumerate() {
|
||||
if i > 0 {
|
||||
|
@ -28,7 +28,7 @@ impl Format<ASTFormatContext> for Block<'_> {
|
|||
write!(f, [empty_line()])?;
|
||||
}
|
||||
TriviaKind::OwnLineComment(range) => {
|
||||
write!(f, [literal(range), hard_line_break()])?;
|
||||
write!(f, [literal(range, ContainsNewlines::No), hard_line_break()])?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ pub(crate) struct Statements<'a> {
|
|||
suite: &'a [Stmt],
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for Statements<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for Statements<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
for (i, stmt) in self.suite.iter().enumerate() {
|
||||
if i > 0 {
|
||||
|
@ -70,20 +70,18 @@ pub(crate) struct Literal {
|
|||
range: TextRange,
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for Literal {
|
||||
impl Format<ASTFormatContext<'_>> for Literal {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let text = f.context().contents();
|
||||
|
||||
f.write_element(FormatElement::StaticTextSlice {
|
||||
text,
|
||||
range: self.range,
|
||||
})
|
||||
source_text_slice(self.range, ContainsNewlines::Detect).fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) const fn literal(range: TextRange) -> Literal {
|
||||
Literal { range }
|
||||
pub(crate) const fn literal(
|
||||
range: TextRange,
|
||||
newlines: ContainsNewlines,
|
||||
) -> SourceTextSliceBuilder {
|
||||
source_text_slice(range, newlines)
|
||||
}
|
||||
|
||||
pub(crate) const fn join_names(names: &[String]) -> JoinNames {
|
||||
|
|
|
@ -10,7 +10,7 @@ pub struct FormatCmpOp<'a> {
|
|||
item: &'a CmpOp,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for CmpOp {
|
||||
impl AsFormat<ASTFormatContext<'_>> for CmpOp {
|
||||
type Format<'a> = FormatCmpOp<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -18,7 +18,7 @@ impl AsFormat<ASTFormatContext> for CmpOp {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatCmpOp<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatCmpOp<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let cmp_op = self.item;
|
||||
write!(f, [leading_comments(cmp_op)])?;
|
||||
|
|
|
@ -11,7 +11,7 @@ pub(crate) struct LeadingComments<'a, T> {
|
|||
item: &'a Attributed<T>,
|
||||
}
|
||||
|
||||
impl<T> Format<ASTFormatContext> for LeadingComments<'_, T> {
|
||||
impl<T> Format<ASTFormatContext<'_>> for LeadingComments<'_, T> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
for trivia in &self.item.trivia {
|
||||
if trivia.relationship.is_leading() {
|
||||
|
@ -20,7 +20,7 @@ impl<T> Format<ASTFormatContext> for LeadingComments<'_, T> {
|
|||
write!(f, [empty_line()])?;
|
||||
}
|
||||
TriviaKind::OwnLineComment(range) => {
|
||||
write!(f, [literal(range), hard_line_break()])?;
|
||||
write!(f, [literal(range, ContainsNewlines::No), hard_line_break()])?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ pub(crate) struct TrailingComments<'a, T> {
|
|||
item: &'a Attributed<T>,
|
||||
}
|
||||
|
||||
impl<T> Format<ASTFormatContext> for TrailingComments<'_, T> {
|
||||
impl<T> Format<ASTFormatContext<'_>> for TrailingComments<'_, T> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
for trivia in &self.item.trivia {
|
||||
if trivia.relationship.is_trailing() {
|
||||
|
@ -49,7 +49,7 @@ impl<T> Format<ASTFormatContext> for TrailingComments<'_, T> {
|
|||
write!(f, [empty_line()])?;
|
||||
}
|
||||
TriviaKind::OwnLineComment(range) => {
|
||||
write!(f, [literal(range), hard_line_break()])?;
|
||||
write!(f, [literal(range, ContainsNewlines::No), hard_line_break()])?;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ pub(crate) struct EndOfLineComments<'a, T> {
|
|||
item: &'a Attributed<T>,
|
||||
}
|
||||
|
||||
impl<T> Format<ASTFormatContext> for EndOfLineComments<'_, T> {
|
||||
impl<T> Format<ASTFormatContext<'_>> for EndOfLineComments<'_, T> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let mut first = true;
|
||||
for range in self
|
||||
|
@ -81,7 +81,7 @@ impl<T> Format<ASTFormatContext> for EndOfLineComments<'_, T> {
|
|||
if std::mem::take(&mut first) {
|
||||
write!(f, [line_suffix(&text(" "))])?;
|
||||
}
|
||||
write!(f, [line_suffix(&literal(range))])?;
|
||||
write!(f, [line_suffix(&literal(range, ContainsNewlines::No))])?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -97,13 +97,13 @@ pub(crate) struct DanglingComments<'a, T> {
|
|||
item: &'a Attributed<T>,
|
||||
}
|
||||
|
||||
impl<T> Format<ASTFormatContext> for DanglingComments<'_, T> {
|
||||
impl<T> Format<ASTFormatContext<'_>> for DanglingComments<'_, T> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
for trivia in &self.item.trivia {
|
||||
if trivia.relationship.is_dangling() {
|
||||
if let TriviaKind::OwnLineComment(range) = trivia.kind {
|
||||
write!(f, [hard_line_break()])?;
|
||||
write!(f, [literal(range)])?;
|
||||
write!(f, [literal(range, ContainsNewlines::No)])?;
|
||||
write!(f, [hard_line_break()])?;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ pub struct FormatComprehension<'a> {
|
|||
item: &'a Comprehension,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for Comprehension {
|
||||
impl AsFormat<ASTFormatContext<'_>> for Comprehension {
|
||||
type Format<'a> = FormatComprehension<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -17,7 +17,7 @@ impl AsFormat<ASTFormatContext> for Comprehension {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatComprehension<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatComprehension<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let comprehension = self.item;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ pub struct FormatExcepthandler<'a> {
|
|||
item: &'a Excepthandler,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for Excepthandler {
|
||||
impl AsFormat<ASTFormatContext<'_>> for Excepthandler {
|
||||
type Format<'a> = FormatExcepthandler<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -19,7 +19,7 @@ impl AsFormat<ASTFormatContext> for Excepthandler {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatExcepthandler<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatExcepthandler<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let excepthandler = self.item;
|
||||
let ExcepthandlerKind::ExceptHandler { type_, name, body } = &excepthandler.node;
|
||||
|
|
|
@ -33,7 +33,7 @@ fn format_starred(
|
|||
}
|
||||
|
||||
fn format_name(f: &mut Formatter<ASTFormatContext>, expr: &Expr, _id: &str) -> FormatResult<()> {
|
||||
write!(f, [literal(expr.range())])?;
|
||||
write!(f, [literal(expr.range(), ContainsNewlines::No)])?;
|
||||
write!(f, [end_of_line_comments(expr)])?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ fn format_subscript(
|
|||
if let TriviaKind::OwnLineComment(range) = trivia.kind {
|
||||
write!(f, [expand_parent()])?;
|
||||
write!(f, [hard_line_break()])?;
|
||||
write!(f, [literal(range)])?;
|
||||
write!(f, [literal(range, ContainsNewlines::No)])?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -573,7 +573,7 @@ fn format_joined_str(
|
|||
expr: &Expr,
|
||||
_values: &[Expr],
|
||||
) -> FormatResult<()> {
|
||||
write!(f, [literal(expr.range())])?;
|
||||
write!(f, [literal(expr.range(), ContainsNewlines::Detect)])?;
|
||||
write!(f, [end_of_line_comments(expr)])?;
|
||||
Ok(())
|
||||
}
|
||||
|
@ -800,7 +800,7 @@ fn format_if_exp(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatExpr<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatExpr<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
if self.item.parentheses.is_always() {
|
||||
write!(f, [text("(")])?;
|
||||
|
@ -871,7 +871,7 @@ impl Format<ASTFormatContext> for FormatExpr<'_> {
|
|||
if trivia.relationship.is_trailing() {
|
||||
if let TriviaKind::OwnLineComment(range) = trivia.kind {
|
||||
write!(f, [expand_parent()])?;
|
||||
write!(f, [literal(range)])?;
|
||||
write!(f, [literal(range, ContainsNewlines::No)])?;
|
||||
write!(f, [hard_line_break()])?;
|
||||
}
|
||||
}
|
||||
|
@ -885,7 +885,7 @@ impl Format<ASTFormatContext> for FormatExpr<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for Expr {
|
||||
impl AsFormat<ASTFormatContext<'_>> for Expr {
|
||||
type Format<'a> = FormatExpr<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
|
|
@ -10,7 +10,7 @@ pub struct FormatKeyword<'a> {
|
|||
item: &'a Keyword,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for Keyword {
|
||||
impl AsFormat<ASTFormatContext<'_>> for Keyword {
|
||||
type Format<'a> = FormatKeyword<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -18,7 +18,7 @@ impl AsFormat<ASTFormatContext> for Keyword {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatKeyword<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatKeyword<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let keyword = self.item;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ pub struct FormatMatchCase<'a> {
|
|||
item: &'a MatchCase,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for MatchCase {
|
||||
impl AsFormat<ASTFormatContext<'_>> for MatchCase {
|
||||
type Format<'a> = FormatMatchCase<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -19,7 +19,7 @@ impl AsFormat<ASTFormatContext> for MatchCase {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatMatchCase<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatMatchCase<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let MatchCase {
|
||||
pattern,
|
||||
|
|
|
@ -12,7 +12,7 @@ struct FloatAtom {
|
|||
range: TextRange,
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FloatAtom {
|
||||
impl Format<ASTFormatContext<'_>> for FloatAtom {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let contents = f.context().contents();
|
||||
|
||||
|
@ -26,12 +26,15 @@ impl Format<ASTFormatContext> for FloatAtom {
|
|||
} else {
|
||||
write!(
|
||||
f,
|
||||
[literal(TextRange::new(
|
||||
[literal(
|
||||
TextRange::new(
|
||||
self.range.start(),
|
||||
self.range
|
||||
.start()
|
||||
.add(TextSize::try_from(dot_index).unwrap())
|
||||
))]
|
||||
),
|
||||
ContainsNewlines::No
|
||||
)]
|
||||
)?;
|
||||
}
|
||||
|
||||
|
@ -42,16 +45,19 @@ impl Format<ASTFormatContext> for FloatAtom {
|
|||
} else {
|
||||
write!(
|
||||
f,
|
||||
[literal(TextRange::new(
|
||||
[literal(
|
||||
TextRange::new(
|
||||
self.range
|
||||
.start()
|
||||
.add(TextSize::try_from(dot_index + 1).unwrap()),
|
||||
self.range.end()
|
||||
))]
|
||||
),
|
||||
ContainsNewlines::No
|
||||
)]
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
write!(f, [literal(self.range)])?;
|
||||
write!(f, [literal(self.range, ContainsNewlines::No)])?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -68,7 +74,7 @@ pub(crate) struct FloatLiteral {
|
|||
range: TextRange,
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FloatLiteral {
|
||||
impl Format<ASTFormatContext<'_>> for FloatLiteral {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let contents = f.context().contents();
|
||||
|
||||
|
@ -93,12 +99,15 @@ impl Format<ASTFormatContext> for FloatLiteral {
|
|||
let plus = content[exponent_index + 1..].starts_with('+');
|
||||
write!(
|
||||
f,
|
||||
[literal(TextRange::new(
|
||||
self.range
|
||||
.start()
|
||||
.add(TextSize::try_from(exponent_index + 1 + usize::from(plus)).unwrap()),
|
||||
[literal(
|
||||
TextRange::new(
|
||||
self.range.start().add(
|
||||
TextSize::try_from(exponent_index + 1 + usize::from(plus)).unwrap()
|
||||
),
|
||||
self.range.end()
|
||||
))]
|
||||
),
|
||||
ContainsNewlines::No
|
||||
)]
|
||||
)?;
|
||||
} else {
|
||||
write!(f, [float_atom(self.range)])?;
|
||||
|
@ -118,7 +127,7 @@ pub(crate) struct IntLiteral {
|
|||
range: TextRange,
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for IntLiteral {
|
||||
impl Format<ASTFormatContext<'_>> for IntLiteral {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let contents = f.context().contents();
|
||||
|
||||
|
@ -142,14 +151,14 @@ impl Format<ASTFormatContext> for IntLiteral {
|
|||
)?;
|
||||
} else {
|
||||
// Use the existing source.
|
||||
write!(f, [literal(self.range)])?;
|
||||
write!(f, [literal(self.range, ContainsNewlines::No)])?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
write!(f, [literal(self.range)])?;
|
||||
write!(f, [literal(self.range, ContainsNewlines::No)])?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -165,20 +174,20 @@ pub(crate) struct ComplexLiteral {
|
|||
range: TextRange,
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for ComplexLiteral {
|
||||
impl Format<ASTFormatContext<'_>> for ComplexLiteral {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let contents = f.context().contents();
|
||||
let content = &contents[self.range];
|
||||
|
||||
if content.ends_with('j') {
|
||||
write!(f, [literal(self.range)])?;
|
||||
write!(f, [literal(self.range, ContainsNewlines::No)])?;
|
||||
} else if content.ends_with('J') {
|
||||
write!(
|
||||
f,
|
||||
[literal(TextRange::new(
|
||||
self.range.start(),
|
||||
self.range.end().sub(TextSize::from(1))
|
||||
))]
|
||||
[literal(
|
||||
TextRange::new(self.range.start(), self.range.end().sub(TextSize::from(1))),
|
||||
ContainsNewlines::No
|
||||
)]
|
||||
)?;
|
||||
write!(f, [text("j")])?;
|
||||
} else {
|
||||
|
|
|
@ -10,7 +10,7 @@ pub struct FormatOperator<'a> {
|
|||
item: &'a Operator,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for Operator {
|
||||
impl AsFormat<ASTFormatContext<'_>> for Operator {
|
||||
type Format<'a> = FormatOperator<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -18,7 +18,7 @@ impl AsFormat<ASTFormatContext> for Operator {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatOperator<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatOperator<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let operator = self.item;
|
||||
write!(f, [leading_comments(operator)])?;
|
||||
|
|
|
@ -11,7 +11,7 @@ pub struct FormatPattern<'a> {
|
|||
item: &'a Pattern,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for Pattern {
|
||||
impl AsFormat<ASTFormatContext<'_>> for Pattern {
|
||||
type Format<'a> = FormatPattern<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -19,7 +19,7 @@ impl AsFormat<ASTFormatContext> for Pattern {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatPattern<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatPattern<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let pattern = self.item;
|
||||
|
||||
|
|
|
@ -756,7 +756,7 @@ pub struct FormatStmt<'a> {
|
|||
item: &'a Stmt,
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatStmt<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatStmt<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
write!(f, [leading_comments(self.item)])?;
|
||||
|
||||
|
@ -939,7 +939,7 @@ impl Format<ASTFormatContext> for FormatStmt<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for Stmt {
|
||||
impl AsFormat<ASTFormatContext<'_>> for Stmt {
|
||||
type Format<'a> = FormatStmt<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
|
|
@ -13,7 +13,7 @@ pub(crate) struct StringLiteralPart {
|
|||
range: TextRange,
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for StringLiteralPart {
|
||||
impl Format<ASTFormatContext<'_>> for StringLiteralPart {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let contents = f.context().contents();
|
||||
|
||||
|
@ -115,7 +115,7 @@ pub(crate) struct StringLiteral<'a> {
|
|||
expr: &'a Expr,
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for StringLiteral<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for StringLiteral<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let expr = self.expr;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ pub struct FormatUnaryOp<'a> {
|
|||
item: &'a UnaryOp,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for UnaryOp {
|
||||
impl AsFormat<ASTFormatContext<'_>> for UnaryOp {
|
||||
type Format<'a> = FormatUnaryOp<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -17,7 +17,7 @@ impl AsFormat<ASTFormatContext> for UnaryOp {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatUnaryOp<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatUnaryOp<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let unary_op = self.item;
|
||||
write!(
|
||||
|
|
|
@ -9,7 +9,7 @@ pub struct FormatWithitem<'a> {
|
|||
item: &'a Withitem,
|
||||
}
|
||||
|
||||
impl AsFormat<ASTFormatContext> for Withitem {
|
||||
impl AsFormat<ASTFormatContext<'_>> for Withitem {
|
||||
type Format<'a> = FormatWithitem<'a>;
|
||||
|
||||
fn format(&self) -> Self::Format<'_> {
|
||||
|
@ -17,7 +17,7 @@ impl AsFormat<ASTFormatContext> for Withitem {
|
|||
}
|
||||
}
|
||||
|
||||
impl Format<ASTFormatContext> for FormatWithitem<'_> {
|
||||
impl Format<ASTFormatContext<'_>> for FormatWithitem<'_> {
|
||||
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
|
||||
let withitem = self.item;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue