#![deny(rustdoc::broken_intra_doc_links)]
mod arguments;
mod buffer;
mod builders;
pub mod comments;
pub mod diagnostics;
pub mod format_element;
mod format_extensions;
pub mod formatter;
pub mod group_id;
pub mod macros;
pub mod prelude;
#[cfg(debug_assertions)]
pub mod printed_tokens;
pub mod printer;
pub mod separated;
mod source_map;
pub mod token;
pub mod trivia;
mod verbatim;
use crate::formatter::Formatter;
use crate::group_id::UniqueGroupIdBuilder;
use crate::prelude::TagKind;
use std::fmt::Debug;
use crate::format_element::document::Document;
#[cfg(debug_assertions)]
use crate::printed_tokens::PrintedTokens;
use crate::printer::{Printer, PrinterOptions};
pub use arguments::{Argument, Arguments};
pub use buffer::{
Buffer, BufferExtensions, BufferSnapshot, Inspect, PreambleBuffer, RemoveSoftLinesBuffer,
VecBuffer,
};
pub use builders::BestFitting;
use crate::builders::syntax_token_cow_slice;
use crate::comments::{CommentStyle, Comments, SourceComment};
pub use crate::diagnostics::{ActualStart, FormatError, InvalidDocumentError, PrintError};
use crate::trivia::{format_skipped_token_trivia, format_trimmed_token};
use biome_rowan::{
Language, NodeOrToken, SyntaxElement, SyntaxNode, SyntaxResult, SyntaxToken, SyntaxTriviaPiece,
TextLen, TextRange, TextSize, TokenAtOffset,
};
pub use format_element::{normalize_newlines, FormatElement, LINE_TERMINATORS};
pub use group_id::GroupId;
pub use source_map::{TransformSourceMap, TransformSourceMapBuilder};
use std::marker::PhantomData;
use std::num::ParseIntError;
use std::str::FromStr;
#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize, schemars::JsonSchema)
)]
#[derive(Default)]
pub enum IndentStyle {
#[default]
Tab,
Space,
}
impl IndentStyle {
pub const DEFAULT_SPACES: u8 = 2;
pub const fn is_tab(&self) -> bool {
matches!(self, IndentStyle::Tab)
}
pub const fn is_space(&self) -> bool {
matches!(self, IndentStyle::Space)
}
}
impl FromStr for IndentStyle {
type Err = &'static str;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"tab" | "Tabs" => Ok(Self::Tab),
"space" | "Spaces" => Ok(Self::Space),
_ => Err("Value not supported for IndentStyle"),
}
}
}
impl std::fmt::Display for IndentStyle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IndentStyle::Tab => std::write!(f, "Tab"),
IndentStyle::Space => std::write!(f, "Space"),
}
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize, schemars::JsonSchema),
serde(rename_all = "camelCase")
)]
pub struct IndentWidth(u8);
impl IndentWidth {
pub fn value(&self) -> u8 {
self.0
}
}
impl Default for IndentWidth {
fn default() -> Self {
Self(2)
}
}
impl From<u8> for IndentWidth {
fn from(value: u8) -> Self {
Self(value)
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize, schemars::JsonSchema),
serde(rename_all = "camelCase")
)]
pub struct LineWidth(u16);
impl LineWidth {
pub const MAX: u16 = 320;
pub fn value(&self) -> u16 {
self.0
}
}
impl Default for LineWidth {
fn default() -> Self {
Self(80)
}
}
pub enum ParseLineWidthError {
ParseError(ParseIntError),
TryFromIntError(LineWidthFromIntError),
}
impl Debug for ParseLineWidthError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self, f)
}
}
impl std::fmt::Display for ParseLineWidthError {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ParseLineWidthError::ParseError(err) => std::fmt::Display::fmt(err, fmt),
ParseLineWidthError::TryFromIntError(err) => std::fmt::Display::fmt(err, fmt),
}
}
}
impl FromStr for LineWidth {
type Err = ParseLineWidthError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let value = u16::from_str(s).map_err(ParseLineWidthError::ParseError)?;
let value = Self::try_from(value).map_err(ParseLineWidthError::TryFromIntError)?;
Ok(value)
}
}
#[derive(Clone, Copy, Debug)]
pub struct LineWidthFromIntError(pub u16);
impl TryFrom<u16> for LineWidth {
type Error = LineWidthFromIntError;
fn try_from(value: u16) -> Result<Self, Self::Error> {
if value > 0 && value <= Self::MAX {
Ok(Self(value))
} else {
Err(LineWidthFromIntError(value))
}
}
}
impl std::fmt::Display for LineWidthFromIntError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(
f,
"The line width exceeds the maximum value ({})",
LineWidth::MAX
)
}
}
impl From<LineWidth> for u16 {
fn from(value: LineWidth) -> Self {
value.0
}
}
pub trait FormatContext {
type Options: FormatOptions;
fn options(&self) -> &Self::Options;
fn source_map(&self) -> Option<&TransformSourceMap>;
}
pub trait FormatOptions {
fn indent_style(&self) -> IndentStyle;
fn indent_width(&self) -> IndentWidth;
fn line_width(&self) -> LineWidth;
fn as_print_options(&self) -> PrinterOptions;
}
pub trait CstFormatContext: FormatContext {
type Language: Language;
type Style: CommentStyle<Language = Self::Language>;
type CommentRule: FormatRule<SourceComment<Self::Language>, Context = Self> + Default;
fn comments(&self) -> &Comments<Self::Language>;
}
#[derive(Debug, Default, Eq, PartialEq)]
pub struct SimpleFormatContext {
options: SimpleFormatOptions,
}
impl SimpleFormatContext {
pub fn new(options: SimpleFormatOptions) -> Self {
Self { options }
}
}
impl FormatContext for SimpleFormatContext {
type Options = SimpleFormatOptions;
fn options(&self) -> &Self::Options {
&self.options
}
fn source_map(&self) -> Option<&TransformSourceMap> {
None
}
}
#[derive(Debug, Default, Eq, PartialEq)]
pub struct SimpleFormatOptions {
pub indent_style: IndentStyle,
pub indent_width: IndentWidth,
pub line_width: LineWidth,
}
impl FormatOptions for SimpleFormatOptions {
fn indent_style(&self) -> IndentStyle {
self.indent_style
}
fn indent_width(&self) -> IndentWidth {
self.indent_width
}
fn line_width(&self) -> LineWidth {
self.line_width
}
fn as_print_options(&self) -> PrinterOptions {
PrinterOptions::default()
.with_indent_style(self.indent_style)
.with_indent_width(self.indent_width)
.with_print_width(self.line_width.into())
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize, schemars::JsonSchema)
)]
pub struct SourceMarker {
pub source: TextSize,
pub dest: TextSize,
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Formatted<Context> {
document: Document,
context: Context,
}
impl<Context> Formatted<Context> {
pub fn new(document: Document, context: Context) -> Self {
Self { document, context }
}
pub fn context(&self) -> &Context {
&self.context
}
pub fn document(&self) -> &Document {
&self.document
}
pub fn into_document(self) -> Document {
self.document
}
}
impl<Context> Formatted<Context>
where
Context: FormatContext,
{
pub fn print(&self) -> PrintResult<Printed> {
let print_options = self.context.options().as_print_options();
let printed = Printer::new(print_options).print(&self.document)?;
let printed = match self.context.source_map() {
Some(source_map) => source_map.map_printed(printed),
None => printed,
};
Ok(printed)
}
pub fn print_with_indent(&self, indent: u16) -> PrintResult<Printed> {
let print_options = self.context.options().as_print_options();
let printed = Printer::new(print_options).print_with_indent(&self.document, indent)?;
let printed = match self.context.source_map() {
Some(source_map) => source_map.map_printed(printed),
None => printed,
};
Ok(printed)
}
}
pub type PrintResult<T> = Result<T, PrintError>;
#[derive(Debug, Clone, Eq, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize, schemars::JsonSchema)
)]
pub struct Printed {
code: String,
range: Option<TextRange>,
sourcemap: Vec<SourceMarker>,
verbatim_ranges: Vec<TextRange>,
}
impl Printed {
pub fn new(
code: String,
range: Option<TextRange>,
sourcemap: Vec<SourceMarker>,
verbatim_source: Vec<TextRange>,
) -> Self {
Self {
code,
range,
sourcemap,
verbatim_ranges: verbatim_source,
}
}
pub fn new_empty() -> Self {
Self {
code: String::new(),
range: None,
sourcemap: Vec::new(),
verbatim_ranges: Vec::new(),
}
}
pub fn range(&self) -> Option<TextRange> {
self.range
}
pub fn sourcemap(&self) -> &[SourceMarker] {
&self.sourcemap
}
pub fn into_sourcemap(self) -> Vec<SourceMarker> {
self.sourcemap
}
pub fn take_sourcemap(&mut self) -> Vec<SourceMarker> {
std::mem::take(&mut self.sourcemap)
}
pub fn as_code(&self) -> &str {
&self.code
}
pub fn into_code(self) -> String {
self.code
}
pub fn verbatim(&self) -> impl Iterator<Item = (TextRange, &str)> {
self.verbatim_ranges
.iter()
.map(|range| (*range, &self.code[*range]))
}
pub fn verbatim_ranges(&self) -> &[TextRange] {
&self.verbatim_ranges
}
pub fn take_verbatim_ranges(&mut self) -> Vec<TextRange> {
std::mem::take(&mut self.verbatim_ranges)
}
}
pub type FormatResult<F> = Result<F, FormatError>;
pub trait Format<Context> {
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()>;
}
impl<T, Context> Format<Context> for &T
where
T: ?Sized + Format<Context>,
{
#[inline(always)]
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
Format::fmt(&**self, f)
}
}
impl<T, Context> Format<Context> for &mut T
where
T: ?Sized + Format<Context>,
{
#[inline(always)]
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
Format::fmt(&**self, f)
}
}
impl<T, Context> Format<Context> for Option<T>
where
T: Format<Context>,
{
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
match self {
Some(value) => value.fmt(f),
None => Ok(()),
}
}
}
impl<T, Context> Format<Context> for SyntaxResult<T>
where
T: Format<Context>,
{
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
match self {
Ok(value) => value.fmt(f),
Err(err) => Err(err.into()),
}
}
}
impl<Context> Format<Context> for () {
#[inline]
fn fmt(&self, _: &mut Formatter<Context>) -> FormatResult<()> {
Ok(())
}
}
pub trait FormatRule<T> {
type Context;
fn fmt(&self, item: &T, f: &mut Formatter<Self::Context>) -> FormatResult<()>;
}
pub struct FormatToken<C> {
context: PhantomData<C>,
}
impl<C> Default for FormatToken<C> {
fn default() -> Self {
Self {
context: PhantomData,
}
}
}
impl<C> FormatRule<SyntaxToken<C::Language>> for FormatToken<C>
where
C: CstFormatContext,
C::Language: 'static,
{
type Context = C;
fn fmt(
&self,
token: &SyntaxToken<C::Language>,
f: &mut Formatter<Self::Context>,
) -> FormatResult<()> {
f.state_mut().track_token(token);
crate::write!(
f,
[
format_skipped_token_trivia(token),
format_trimmed_token(token),
]
)
}
}
pub trait FormatRuleWithOptions<T>: FormatRule<T> {
type Options;
fn with_options(self, options: Self::Options) -> Self;
}
pub trait FormatWithRule<Context>: Format<Context> {
type Item;
fn item(&self) -> &Self::Item;
}
#[derive(Debug, Copy, Clone)]
pub struct FormatRefWithRule<'a, T, R>
where
R: FormatRule<T>,
{
item: &'a T,
rule: R,
}
impl<'a, T, R> FormatRefWithRule<'a, T, R>
where
R: FormatRule<T>,
{
pub fn new(item: &'a T, rule: R) -> Self {
Self { item, rule }
}
}
impl<T, R, O> FormatRefWithRule<'_, T, R>
where
R: FormatRuleWithOptions<T, Options = O>,
{
pub fn with_options(mut self, options: O) -> Self {
self.rule = self.rule.with_options(options);
self
}
}
impl<T, R> FormatWithRule<R::Context> for FormatRefWithRule<'_, T, R>
where
R: FormatRule<T>,
{
type Item = T;
fn item(&self) -> &Self::Item {
self.item
}
}
impl<T, R> Format<R::Context> for FormatRefWithRule<'_, T, R>
where
R: FormatRule<T>,
{
#[inline(always)]
fn fmt(&self, f: &mut Formatter<R::Context>) -> FormatResult<()> {
self.rule.fmt(self.item, f)
}
}
#[derive(Debug, Clone)]
pub struct FormatOwnedWithRule<T, R>
where
R: FormatRule<T>,
{
item: T,
rule: R,
}
impl<T, R> FormatOwnedWithRule<T, R>
where
R: FormatRule<T>,
{
pub fn new(item: T, rule: R) -> Self {
Self { item, rule }
}
pub fn with_item(mut self, item: T) -> Self {
self.item = item;
self
}
pub fn into_item(self) -> T {
self.item
}
}
impl<T, R> Format<R::Context> for FormatOwnedWithRule<T, R>
where
R: FormatRule<T>,
{
#[inline(always)]
fn fmt(&self, f: &mut Formatter<R::Context>) -> FormatResult<()> {
self.rule.fmt(&self.item, f)
}
}
impl<T, R, O> FormatOwnedWithRule<T, R>
where
R: FormatRuleWithOptions<T, Options = O>,
{
pub fn with_options(mut self, options: O) -> Self {
self.rule = self.rule.with_options(options);
self
}
}
impl<T, R> FormatWithRule<R::Context> for FormatOwnedWithRule<T, R>
where
R: FormatRule<T>,
{
type Item = T;
fn item(&self) -> &Self::Item {
&self.item
}
}
#[inline(always)]
pub fn write<Context>(
output: &mut dyn Buffer<Context = Context>,
args: Arguments<Context>,
) -> FormatResult<()> {
let mut f = Formatter::new(output);
f.write_fmt(args)
}
pub fn format<Context>(
context: Context,
arguments: Arguments<Context>,
) -> FormatResult<Formatted<Context>>
where
Context: FormatContext,
{
let mut state = FormatState::new(context);
let mut buffer = VecBuffer::with_capacity(arguments.items().len(), &mut state);
buffer.write_fmt(arguments)?;
let mut document = Document::from(buffer.into_vec());
document.propagate_expand();
Ok(Formatted::new(document, state.into_context()))
}
pub trait FormatLanguage {
type SyntaxLanguage: Language;
type Context: CstFormatContext<Language = Self::SyntaxLanguage>;
type FormatRule: FormatRule<SyntaxNode<Self::SyntaxLanguage>, Context = Self::Context> + Default;
fn transform(
&self,
_root: &SyntaxNode<Self::SyntaxLanguage>,
) -> Option<(SyntaxNode<Self::SyntaxLanguage>, TransformSourceMap)> {
None
}
fn is_range_formatting_node(&self, _node: &SyntaxNode<Self::SyntaxLanguage>) -> bool {
true
}
fn options(&self) -> &<Self::Context as FormatContext>::Options;
fn create_context(
self,
root: &SyntaxNode<Self::SyntaxLanguage>,
source_map: Option<TransformSourceMap>,
) -> Self::Context;
}
pub fn format_node<L: FormatLanguage>(
root: &SyntaxNode<L::SyntaxLanguage>,
language: L,
) -> FormatResult<Formatted<L::Context>> {
tracing::trace_span!("format_node").in_scope(move || {
let (root, source_map) = match language.transform(&root.clone()) {
Some((transformed, source_map)) => {
if &transformed == root {
(transformed, Some(source_map))
} else {
match root
.ancestors()
.skip(1)
.last()
{
None => (transformed, Some(source_map)),
Some(top_root) => {
let transformed_range = transformed.text_range();
let root_range = root.text_range();
let transformed_root = top_root
.replace_child(root.clone().into(), transformed.into())
.unwrap();
let transformed = transformed_root.covering_element(TextRange::new(
root_range.start(),
root_range.start() + transformed_range.len(),
));
let node = match transformed {
NodeOrToken::Node(node) => node,
NodeOrToken::Token(token) => {
token.parent().unwrap_or(transformed_root)
}
};
(node, Some(source_map))
}
}
}
}
None => (root.clone(), None),
};
let context = language.create_context(&root, source_map);
let format_node = FormatRefWithRule::new(&root, L::FormatRule::default());
let mut state = FormatState::new(context);
let mut buffer = VecBuffer::new(&mut state);
write!(buffer, [format_node])?;
let mut document = Document::from(buffer.into_vec());
document.propagate_expand();
state.assert_formatted_all_tokens(&root);
let context = state.into_context();
let comments = context.comments();
comments.assert_checked_all_suppressions(&root);
comments.assert_formatted_all_comments();
Ok(Formatted::new(document, context))
})
}
fn text_non_whitespace_range<E, L>(elem: &E) -> TextRange
where
E: Into<SyntaxElement<L>> + Clone,
L: Language,
{
let elem: SyntaxElement<L> = elem.clone().into();
let start = elem
.leading_trivia()
.into_iter()
.flat_map(|trivia| trivia.pieces())
.find_map(|piece| {
if piece.is_whitespace() || piece.is_newline() {
None
} else {
Some(piece.text_range().start())
}
})
.unwrap_or_else(|| elem.text_trimmed_range().start());
let end = elem
.trailing_trivia()
.into_iter()
.flat_map(|trivia| trivia.pieces().rev())
.find_map(|piece| {
if piece.is_whitespace() || piece.is_newline() {
None
} else {
Some(piece.text_range().end())
}
})
.unwrap_or_else(|| elem.text_trimmed_range().end());
TextRange::new(start, end)
}
pub fn format_range<Language: FormatLanguage>(
root: &SyntaxNode<Language::SyntaxLanguage>,
mut range: TextRange,
language: Language,
) -> FormatResult<Printed> {
if range.is_empty() {
return Ok(Printed::new(
String::new(),
Some(range),
Vec::new(),
Vec::new(),
));
}
let root_range = root.text_range();
if range.start() < root_range.start() || range.end() > root_range.end() {
return Err(FormatError::RangeError {
input: range,
tree: root_range,
});
}
let start_token = root.token_at_offset(range.start());
let end_token = root.token_at_offset(range.end());
let mut start_token = match start_token {
TokenAtOffset::Between(_, token) => token,
TokenAtOffset::Single(token) => token,
TokenAtOffset::None => match root.first_token() {
Some(token) => token,
None => return Ok(Printed::new_empty()),
},
};
let mut end_token = match end_token {
TokenAtOffset::Between(token, _) => token,
TokenAtOffset::Single(token) => token,
TokenAtOffset::None => match root.last_token() {
Some(token) => token,
None => return Ok(Printed::new_empty()),
},
};
let mut trimmed_start = range.start();
let start_token_range = text_non_whitespace_range(&start_token);
let start_token_trimmed_start = start_token_range.start();
let start_token_trimmed_end = start_token_range.end();
if start_token_trimmed_start >= range.start() && start_token_trimmed_start <= range.end() {
trimmed_start = start_token_trimmed_start;
} else if start_token_trimmed_end <= range.start() {
if let Some(next_token) = start_token.next_token() {
let next_token_start = text_non_whitespace_range(&next_token).start();
if next_token_start <= range.end() {
trimmed_start = next_token_start;
start_token = next_token;
}
}
}
let end_token_range = text_non_whitespace_range(&end_token);
let end_token_trimmed_start = end_token_range.start();
if end_token_trimmed_start >= range.end() {
if let Some(next_token) = end_token.prev_token() {
let next_token_end = text_non_whitespace_range(&next_token).end();
if next_token_end >= trimmed_start {
end_token = next_token;
}
}
}
let start_node = start_token
.ancestors()
.find(|node| language.is_range_formatting_node(node))
.unwrap_or_else(|| root.clone());
let end_node = end_token
.ancestors()
.find(|node| language.is_range_formatting_node(node))
.unwrap_or_else(|| root.clone());
let common_root = if start_node == end_node {
range = text_non_whitespace_range(&start_node);
Some(start_node)
} else {
let start_node_start = start_node.text_range().start();
let end_node_end = end_node.text_range().end();
let result_end_node = end_node
.ancestors()
.take_while(|end_parent| end_parent.text_range().start() >= start_node_start)
.last()
.unwrap_or(end_node);
let result_start_node = start_node
.ancestors()
.take_while(|start_parent| start_parent.text_range().end() <= end_node_end)
.last()
.unwrap_or(start_node);
range = text_non_whitespace_range(&result_start_node)
.cover(text_non_whitespace_range(&result_end_node));
#[allow(clippy::needless_collect)]
let start_to_root: Vec<_> = result_start_node.ancestors().collect();
#[allow(clippy::needless_collect)]
let end_to_root: Vec<_> = result_end_node.ancestors().collect();
start_to_root
.into_iter()
.rev()
.zip(end_to_root.into_iter().rev())
.map_while(|(lhs, rhs)| if lhs == rhs { Some(lhs) } else { None })
.last()
};
let common_root = common_root.as_ref().unwrap_or(root);
let mut printed = format_sub_tree(common_root, language)?;
let mut range_start: Option<&SourceMarker> = None;
let mut range_end: Option<&SourceMarker> = None;
let sourcemap = printed.sourcemap();
for marker in sourcemap {
if marker.source <= range.start() {
range_start = match range_start {
Some(prev_marker) => {
if marker.source > prev_marker.source {
if prev_marker.dest == marker.dest {
Some(prev_marker)
} else {
Some(marker)
}
} else {
Some(prev_marker)
}
}
None => Some(marker),
}
}
if marker.source >= range.end() {
range_end = match range_end {
Some(prev_marker) => {
if marker.source <= prev_marker.source || marker.dest == prev_marker.dest {
Some(marker)
} else {
Some(prev_marker)
}
}
None => Some(marker),
}
}
}
let (start_source, start_dest) = match range_start {
Some(start_marker) => (start_marker.source, start_marker.dest),
None => (common_root.text_range().start(), TextSize::from(0)),
};
let (end_source, end_dest) = match range_end {
Some(end_marker) => (end_marker.source, end_marker.dest),
None => (
common_root.text_range().end(),
TextSize::try_from(printed.as_code().len()).expect("code length out of bounds"),
),
};
let input_range = TextRange::new(start_source, end_source);
let output_range = TextRange::new(start_dest, end_dest);
let sourcemap = printed.take_sourcemap();
let verbatim_ranges = printed.take_verbatim_ranges();
let code = &printed.into_code()[output_range];
Ok(Printed::new(
code.into(),
Some(input_range),
sourcemap,
verbatim_ranges,
))
}
pub fn format_sub_tree<L: FormatLanguage>(
root: &SyntaxNode<L::SyntaxLanguage>,
language: L,
) -> FormatResult<Printed> {
let mut tokens = std::iter::successors(root.first_token(), |token| token.prev_token());
let first_token = tokens.next();
let first_token_trivias = first_token
.into_iter()
.flat_map(|token| token.leading_trivia().pieces().rev());
let next_tokens_trivias = tokens.flat_map(|token| {
token
.trailing_trivia()
.pieces()
.rev()
.chain(token.leading_trivia().pieces().rev())
});
let trivias = first_token_trivias
.chain(next_tokens_trivias)
.filter(|piece| {
let is_newline = piece.is_newline();
let is_whitespace = piece.is_whitespace();
is_newline || is_whitespace
});
let last_whitespace = trivias.map_while(|piece| piece.as_whitespace()).last();
let initial_indent = match last_whitespace {
Some(trivia) => {
let length = trivia.text().len() as u16;
let width = language.options().indent_width().value();
match language.options().indent_style() {
IndentStyle::Tab => length,
IndentStyle::Space => length / u16::from(width),
}
}
None => 0,
};
let formatted = format_node(root, language)?;
let mut printed = formatted.print_with_indent(initial_indent)?;
let sourcemap = printed.take_sourcemap();
let verbatim_ranges = printed.take_verbatim_ranges();
Ok(Printed::new(
printed.into_code(),
Some(root.text_range()),
sourcemap,
verbatim_ranges,
))
}
impl<L: Language, Context> Format<Context> for SyntaxTriviaPiece<L> {
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
let range = self.text_range();
let trimmed = self.text().trim_start();
let trimmed_start = range.start() + (range.len() - trimmed.text_len());
let trimmed = trimmed.trim_end();
write!(
f,
[syntax_token_cow_slice(
normalize_newlines(trimmed, LINE_TERMINATORS),
&self.token(),
trimmed_start
)]
)
}
}
pub struct FormatState<Context> {
context: Context,
group_id_builder: UniqueGroupIdBuilder,
#[cfg(debug_assertions)]
pub printed_tokens: PrintedTokens,
}
impl<Context> std::fmt::Debug for FormatState<Context>
where
Context: std::fmt::Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
f.debug_struct("FormatState")
.field("context", &self.context)
.finish()
}
}
impl<Context> FormatState<Context> {
pub fn new(context: Context) -> Self {
Self {
context,
group_id_builder: Default::default(),
#[cfg(debug_assertions)]
printed_tokens: Default::default(),
}
}
pub fn into_context(self) -> Context {
self.context
}
pub fn context(&self) -> &Context {
&self.context
}
pub fn context_mut(&mut self) -> &mut Context {
&mut self.context
}
pub fn group_id(&self, debug_name: &'static str) -> GroupId {
self.group_id_builder.group_id(debug_name)
}
#[inline]
pub fn track_token<L: Language>(&mut self, #[allow(unused_variables)] token: &SyntaxToken<L>) {
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
self.printed_tokens.track_token(token);
}
}
}
#[cfg(not(debug_assertions))]
#[inline]
pub fn set_token_tracking_disabled(&mut self, _: bool) {}
#[cfg(debug_assertions)]
pub fn set_token_tracking_disabled(&mut self, enabled: bool) {
self.printed_tokens.set_disabled(enabled)
}
#[cfg(not(debug_assertions))]
#[inline]
pub fn is_token_tracking_disabled(&self) -> bool {
false
}
#[cfg(debug_assertions)]
pub fn is_token_tracking_disabled(&self) -> bool {
self.printed_tokens.is_disabled()
}
#[inline]
pub fn assert_formatted_all_tokens<L: Language>(
&self,
#[allow(unused_variables)] root: &SyntaxNode<L>,
) {
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
self.printed_tokens.assert_all_tracked(root);
}
}
}
}
impl<Context> FormatState<Context>
where
Context: FormatContext,
{
pub fn snapshot(&self) -> FormatStateSnapshot {
FormatStateSnapshot {
#[cfg(debug_assertions)]
printed_tokens: self.printed_tokens.snapshot(),
}
}
pub fn restore_snapshot(&mut self, snapshot: FormatStateSnapshot) {
let FormatStateSnapshot {
#[cfg(debug_assertions)]
printed_tokens,
} = snapshot;
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
self.printed_tokens.restore(printed_tokens);
}
}
}
}
pub struct FormatStateSnapshot {
#[cfg(debug_assertions)]
printed_tokens: printed_tokens::PrintedTokensSnapshot,
}