diff --git a/.changeset/tough-buckets-write.md b/.changeset/tough-buckets-write.md new file mode 100644 index 000000000000..f50ba66703a3 --- /dev/null +++ b/.changeset/tough-buckets-write.md @@ -0,0 +1,5 @@ +--- +"@biomejs/biome": patch +--- + +Improved the performance of the Biome Formatter by enabling the internal source maps only when needed. diff --git a/crates/biome_css_semantic/src/format_semantic_model.rs b/crates/biome_css_semantic/src/format_semantic_model.rs index 00ebf37dd539..6b5902a67b59 100644 --- a/crates/biome_css_semantic/src/format_semantic_model.rs +++ b/crates/biome_css_semantic/src/format_semantic_model.rs @@ -3,7 +3,7 @@ use biome_formatter::prelude::*; use biome_formatter::write; use biome_formatter::{ FormatContext, FormatOptions, IndentStyle, IndentWidth, LineEnding, LineWidth, - TransformSourceMap, + SourceMapGeneration, TransformSourceMap, }; use biome_rowan::{AstNode, TextSize}; @@ -33,6 +33,7 @@ impl FormatOptions for FormatSemanticModelOptions { print_width: self.line_width().into(), line_ending: self.line_ending(), indent_style: self.indent_style(), + source_map_generation: SourceMapGeneration::default(), } } } diff --git a/crates/biome_formatter/src/format_element/document.rs b/crates/biome_formatter/src/format_element/document.rs index 82b6f7b1af0e..a9fa24f2784a 100644 --- a/crates/biome_formatter/src/format_element/document.rs +++ b/crates/biome_formatter/src/format_element/document.rs @@ -6,7 +6,8 @@ use crate::prelude::tag::GroupMode; use crate::prelude::*; use crate::{ BufferExtensions, Format, FormatContext, FormatElement, FormatOptions, FormatResult, Formatter, - IndentStyle, IndentWidth, LineEnding, LineWidth, PrinterOptions, TransformSourceMap, + IndentStyle, IndentWidth, LineEnding, LineWidth, PrinterOptions, SourceMapGeneration, + TransformSourceMap, }; use crate::{format, write}; use biome_rowan::TextSize; @@ -266,6 +267,7 @@ impl FormatOptions for IrFormatOptions { print_width: self.line_width().into(), line_ending: LineEnding::Lf, indent_style: IndentStyle::Space, + source_map_generation: SourceMapGeneration::default(), } } } diff --git a/crates/biome_formatter/src/lib.rs b/crates/biome_formatter/src/lib.rs index e9bb5df1315e..3815319d6bb3 100644 --- a/crates/biome_formatter/src/lib.rs +++ b/crates/biome_formatter/src/lib.rs @@ -74,6 +74,7 @@ pub use buffer::{ pub use builders::BestFitting; pub use format_element::{FormatElement, LINE_TERMINATORS, normalize_newlines}; pub use group_id::GroupId; +pub use printer::SourceMapGeneration; pub use source_map::{TransformSourceMap, TransformSourceMapBuilder}; use std::num::ParseIntError; use std::str::FromStr; @@ -1021,8 +1022,16 @@ where Ok(printed) } - pub fn print_with_indent(&self, indent: u16) -> PrintResult { - let print_options = self.context.options().as_print_options(); + pub fn print_with_indent( + &self, + indent: u16, + source_map: SourceMapGeneration, + ) -> PrintResult { + let print_options = self + .context + .options() + .as_print_options() + .with_source_map_generation(source_map); let printed = Printer::new(print_options).print_with_indent(&self.document, indent)?; let printed = match self.context.source_map() { @@ -2045,7 +2054,7 @@ pub fn format_sub_tree( }; let formatted = format_node(root, language, false)?; - let mut printed = formatted.print_with_indent(initial_indent)?; + let mut printed = formatted.print_with_indent(initial_indent, SourceMapGeneration::Enabled)?; let sourcemap = printed.take_sourcemap(); let verbatim_ranges = printed.take_verbatim_ranges(); diff --git a/crates/biome_formatter/src/printer/mod.rs b/crates/biome_formatter/src/printer/mod.rs index cf1edae4bb56..935e017804ed 100644 --- a/crates/biome_formatter/src/printer/mod.rs +++ b/crates/biome_formatter/src/printer/mod.rs @@ -394,6 +394,10 @@ impl<'a> Printer<'a> { } fn push_marker(&mut self, marker: SourceMarker) { + if self.options.source_map_generation().is_disabled() { + return; + } + if let Some(last) = self.state.source_markers.last() { if last != &marker { self.state.source_markers.push(marker) diff --git a/crates/biome_formatter/src/printer/printer_options/mod.rs b/crates/biome_formatter/src/printer/printer_options/mod.rs index a677f8b69366..ab5c210086de 100644 --- a/crates/biome_formatter/src/printer/printer_options/mod.rs +++ b/crates/biome_formatter/src/printer/printer_options/mod.rs @@ -15,6 +15,10 @@ pub struct PrinterOptions { /// Whether the printer should use tabs or spaces to indent code and if spaces, by how many. pub indent_style: IndentStyle, + + /// Should the printer generate a source map that allows mapping positions in the source document + /// to positions in the formatted document. + pub source_map_generation: SourceMapGeneration, } #[derive(Debug, Copy, Clone, Eq, PartialEq)] @@ -81,10 +85,20 @@ impl PrinterOptions { self } + pub fn with_source_map_generation(mut self, source_map: SourceMapGeneration) -> Self { + self.source_map_generation = source_map; + + self + } + pub(crate) fn indent_style(&self) -> IndentStyle { self.indent_style } + pub const fn source_map_generation(&self) -> SourceMapGeneration { + self.source_map_generation + } + /// Width of an indent in characters. pub(super) const fn indent_width(&self) -> IndentWidth { self.indent_width @@ -103,6 +117,32 @@ impl Default for PrinterOptions { print_width: PrintWidth::default(), indent_style: Default::default(), line_ending: LineEnding::Lf, + source_map_generation: SourceMapGeneration::default(), } } } + +/// Configures whether the printer generates a source map that allows mapping +/// positions in the source document to positions in the formatted code. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum SourceMapGeneration { + /// The printer generates no source map. + #[default] + Disabled, + + /// The printer generates a source map that allows mapping positions in the source document + /// to positions in the formatted document. The ability to map positions is useful for range formatting + /// or when trying to identify where to move the cursor so that it matches its position in the source document. + Enabled, +} + +impl SourceMapGeneration { + pub const fn is_enabled(self) -> bool { + matches!(self, Self::Enabled) + } + + pub const fn is_disabled(self) -> bool { + matches!(self, Self::Disabled) + } +} diff --git a/crates/biome_js_formatter/src/syntax_rewriter.rs b/crates/biome_js_formatter/src/syntax_rewriter.rs index ee6f96a3f831..1c25fc60a8c8 100644 --- a/crates/biome_js_formatter/src/syntax_rewriter.rs +++ b/crates/biome_js_formatter/src/syntax_rewriter.rs @@ -465,7 +465,7 @@ fn has_type_cast_comment_or_skipped(trivia: &JsSyntaxTrivia) -> bool { mod tests { use super::JsFormatSyntaxRewriter; use crate::{JsFormatOptions, TextRange, format_node}; - use biome_formatter::{SourceMarker, TransformSourceMap}; + use biome_formatter::{SourceMapGeneration, SourceMarker, TransformSourceMap}; use biome_js_parser::{JsParserOptions, parse, parse_module}; use biome_js_syntax::{ JsArrayExpression, JsBinaryExpression, JsExpressionStatement, JsFileSource, @@ -847,7 +847,9 @@ mod tests { let formatted = format_node(JsFormatOptions::new(JsFileSource::default()), &transformed).unwrap(); - let printed = formatted.print().unwrap(); + let printed = formatted + .print_with_indent(0, SourceMapGeneration::Enabled) + .unwrap(); assert_eq!(printed.as_code(), "(a * b * c) / 3;\n"); diff --git a/crates/biome_js_semantic/src/format_semantic_model.rs b/crates/biome_js_semantic/src/format_semantic_model.rs index 154c2ba4ddf6..3b179fdccce1 100644 --- a/crates/biome_js_semantic/src/format_semantic_model.rs +++ b/crates/biome_js_semantic/src/format_semantic_model.rs @@ -1,7 +1,7 @@ use biome_formatter::prelude::*; use biome_formatter::{ FormatContext, FormatOptions, IndentStyle, IndentWidth, LineEnding, LineWidth, - TransformSourceMap, + SourceMapGeneration, TransformSourceMap, }; use biome_formatter::{format_args, write}; use biome_js_syntax::TextSize; @@ -33,6 +33,7 @@ impl FormatOptions for FormatSemanticModelOptions { print_width: self.line_width().into(), line_ending: self.line_ending(), indent_style: self.indent_style(), + source_map_generation: SourceMapGeneration::default(), } } } diff --git a/crates/biome_js_type_info/src/format_type_info.rs b/crates/biome_js_type_info/src/format_type_info.rs index a7902c4c6ba3..9f110243d259 100644 --- a/crates/biome_js_type_info/src/format_type_info.rs +++ b/crates/biome_js_type_info/src/format_type_info.rs @@ -10,7 +10,7 @@ use crate::{ use biome_formatter::prelude::*; use biome_formatter::{ FormatContext, FormatOptions, IndentStyle, IndentWidth, LineEnding, LineWidth, - TransformSourceMap, + SourceMapGeneration, TransformSourceMap, }; use biome_formatter::{format_args, write}; use biome_js_syntax::TextSize; @@ -44,6 +44,7 @@ impl FormatOptions for FormatTypeOptions { print_width: self.line_width().into(), line_ending: self.line_ending(), indent_style: self.indent_style(), + source_map_generation: SourceMapGeneration::default(), } } } diff --git a/crates/biome_service/src/file_handlers/svelte.rs b/crates/biome_service/src/file_handlers/svelte.rs index 0c02eedf029b..5637dbc2f398 100644 --- a/crates/biome_service/src/file_handlers/svelte.rs +++ b/crates/biome_service/src/file_handlers/svelte.rs @@ -7,7 +7,7 @@ use crate::file_handlers::{ }; use crate::settings::Settings; use crate::workspace::{DocumentFileSource, FixFileResult, PullActionsResult}; -use biome_formatter::Printed; +use biome_formatter::{Printed, SourceMapGeneration}; use biome_fs::BiomePath; use biome_html_syntax::HtmlLanguage; use biome_js_formatter::format_node; @@ -157,7 +157,7 @@ fn format( }; let tree = parse.syntax(); let formatted = format_node(options, &tree)?; - match formatted.print_with_indent(indent_amount) { + match formatted.print_with_indent(indent_amount, SourceMapGeneration::Disabled) { Ok(printed) => Ok(printed), Err(error) => { error!("The file {} couldn't be formatted", biome_path.as_str()); diff --git a/crates/biome_service/src/file_handlers/vue.rs b/crates/biome_service/src/file_handlers/vue.rs index 3658d4311534..c2c36fd40b5a 100644 --- a/crates/biome_service/src/file_handlers/vue.rs +++ b/crates/biome_service/src/file_handlers/vue.rs @@ -7,7 +7,7 @@ use crate::file_handlers::{ }; use crate::settings::Settings; use crate::workspace::{DocumentFileSource, FixFileResult, PullActionsResult}; -use biome_formatter::Printed; +use biome_formatter::{Printed, SourceMapGeneration}; use biome_fs::BiomePath; use biome_html_syntax::HtmlLanguage; use biome_js_formatter::format_node; @@ -157,7 +157,7 @@ fn format( }; let tree = parse.syntax(); let formatted = format_node(options, &tree)?; - match formatted.print_with_indent(indent_amount) { + match formatted.print_with_indent(indent_amount, SourceMapGeneration::Disabled) { Ok(printed) => Ok(printed), Err(error) => { error!("The file {} couldn't be formatted", biome_path.as_str());