Optional source map generation (#6894)

This commit is contained in:
Micha Reiser 2023-08-26 18:00:43 +02:00 committed by GitHub
parent 15b73bdb8a
commit eae59cf088
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 117 additions and 73 deletions

View file

@ -1,16 +1,17 @@
use std::cell::Cell;
use std::marker::PhantomData;
use std::num::NonZeroU8;
use ruff_text_size::TextRange;
#[allow(clippy::enum_glob_use)]
use Tag::*;
use crate::format_element::tag::{Condition, Tag}; use crate::format_element::tag::{Condition, Tag};
use crate::prelude::tag::{DedentMode, GroupMode, LabelId}; use crate::prelude::tag::{DedentMode, GroupMode, LabelId};
use crate::prelude::*; use crate::prelude::*;
use crate::{format_element, write, Argument, Arguments, FormatContext, GroupId, TextSize}; use crate::{format_element, write, Argument, Arguments, FormatContext, GroupId, TextSize};
use crate::{Buffer, VecBuffer}; use crate::{Buffer, VecBuffer};
use ruff_text_size::TextRange;
use std::cell::Cell;
use std::marker::PhantomData;
use std::num::NonZeroU8;
#[allow(clippy::enum_glob_use)]
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.
/// It's omitted if the enclosing `Group` fits on a single line. /// It's omitted if the enclosing `Group` fits on a single line.
/// A soft line break is identical to a hard line break when not enclosed inside of a `Group`. /// A soft line break is identical to a hard line break when not enclosed inside of a `Group`.
@ -283,7 +284,6 @@ impl std::fmt::Debug for StaticText {
/// ## Examples /// ## Examples
/// ///
/// ``` /// ```
/// /// ```
/// use ruff_formatter::format; /// use ruff_formatter::format;
/// use ruff_formatter::prelude::*; /// use ruff_formatter::prelude::*;
/// ///
@ -329,6 +329,7 @@ pub struct SourcePosition(TextSize);
impl<Context> Format<Context> for SourcePosition { impl<Context> Format<Context> for SourcePosition {
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> { fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
f.write_element(FormatElement::SourcePosition(self.0)); f.write_element(FormatElement::SourcePosition(self.0));
Ok(()) Ok(())
} }
} }

View file

@ -1,17 +1,19 @@
use super::tag::Tag; use std::collections::HashMap;
use std::ops::Deref;
use rustc_hash::FxHashMap;
use crate::format_element::tag::{Condition, DedentMode}; use crate::format_element::tag::{Condition, DedentMode};
use crate::prelude::tag::GroupMode; use crate::prelude::tag::GroupMode;
use crate::prelude::*; use crate::prelude::*;
use crate::printer::LineEnding;
use crate::source_code::SourceCode; use crate::source_code::SourceCode;
use crate::{format, write, TabWidth}; use crate::{format, write, TabWidth};
use crate::{ use crate::{
BufferExtensions, Format, FormatContext, FormatElement, FormatOptions, FormatResult, Formatter, BufferExtensions, Format, FormatContext, FormatElement, FormatOptions, FormatResult, Formatter,
IndentStyle, LineWidth, PrinterOptions, IndentStyle, LineWidth, PrinterOptions,
}; };
use rustc_hash::FxHashMap;
use std::collections::HashMap; use super::tag::Tag;
use std::ops::Deref;
/// A formatted document. /// A formatted document.
#[derive(Debug, Clone, Eq, PartialEq, Default)] #[derive(Debug, Clone, Eq, PartialEq, Default)]
@ -225,10 +227,9 @@ impl FormatOptions for IrFormatOptions {
fn as_print_options(&self) -> PrinterOptions { fn as_print_options(&self) -> PrinterOptions {
PrinterOptions { PrinterOptions {
tab_width: TabWidth::default(),
print_width: self.line_width().into(), print_width: self.line_width().into(),
line_ending: LineEnding::LineFeed,
indent_style: IndentStyle::Space(2), indent_style: IndentStyle::Space(2),
..PrinterOptions::default()
} }
} }
} }
@ -781,10 +782,11 @@ impl Format<IrFormatContext<'_>> for Condition {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use ruff_text_size::{TextRange, TextSize};
use crate::prelude::*; use crate::prelude::*;
use crate::{format, format_args, write}; use crate::{format, format_args, write};
use crate::{SimpleFormatContext, SourceCode}; use crate::{SimpleFormatContext, SourceCode};
use ruff_text_size::{TextRange, TextSize};
#[test] #[test]
fn display_elements() { fn display_elements() {

View file

@ -39,7 +39,7 @@ use std::fmt::{Debug, Display};
use std::marker::PhantomData; use std::marker::PhantomData;
use crate::format_element::document::Document; use crate::format_element::document::Document;
use crate::printer::{Printer, PrinterOptions}; use crate::printer::{Printer, PrinterOptions, SourceMapGeneration};
pub use arguments::{Argument, Arguments}; pub use arguments::{Argument, Arguments};
pub use buffer::{ pub use buffer::{
Buffer, BufferExtensions, BufferSnapshot, Inspect, RemoveSoftLinesBuffer, VecBuffer, Buffer, BufferExtensions, BufferSnapshot, Inspect, RemoveSoftLinesBuffer, VecBuffer,
@ -311,10 +311,12 @@ impl FormatOptions for SimpleFormatOptions {
} }
fn as_print_options(&self) -> PrinterOptions { fn as_print_options(&self) -> PrinterOptions {
PrinterOptions::default() PrinterOptions {
.with_indent(self.indent_style) print_width: self.line_width.into(),
.with_tab_width(self.tab_width()) indent_style: self.indent_style,
.with_print_width(self.line_width.into()) source_map_generation: SourceMapGeneration::Enabled,
..PrinterOptions::default()
}
} }
} }

View file

@ -396,6 +396,10 @@ impl<'a> Printer<'a> {
} }
fn push_marker(&mut self) { fn push_marker(&mut self) {
if self.options.source_map_generation.is_disabled() {
return;
}
let marker = SourceMarker { let marker = SourceMarker {
source: self.state.source_position, source: self.state.source_position,
dest: self.state.buffer.text_len(), dest: self.state.buffer.text_len(),

View file

@ -14,39 +14,10 @@ pub struct PrinterOptions {
/// Whether the printer should use tabs or spaces to indent code and if spaces, by how many. /// Whether the printer should use tabs or spaces to indent code and if spaces, by how many.
pub indent_style: IndentStyle, pub indent_style: IndentStyle,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)] /// Whether the printer should build a source map that allows mapping positions in the source document
pub struct PrintWidth(u32); /// to positions in the formatted document.
pub source_map_generation: SourceMapGeneration,
impl PrintWidth {
pub fn new(width: u32) -> Self {
Self(width)
}
}
impl Default for PrintWidth {
fn default() -> Self {
LineWidth::default().into()
}
}
impl From<LineWidth> for PrintWidth {
fn from(width: LineWidth) -> Self {
Self(u32::from(u16::from(width)))
}
}
impl From<PrintWidth> for usize {
fn from(width: PrintWidth) -> Self {
width.0 as usize
}
}
impl From<PrintWidth> for u32 {
fn from(width: PrintWidth) -> Self {
width.0
}
} }
impl<'a, O> From<&'a O> for PrinterOptions impl<'a, O> From<&'a O> for PrinterOptions
@ -94,6 +65,64 @@ impl PrinterOptions {
} }
} }
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct PrintWidth(u32);
impl PrintWidth {
pub fn new(width: u32) -> Self {
Self(width)
}
}
impl Default for PrintWidth {
fn default() -> Self {
LineWidth::default().into()
}
}
impl From<LineWidth> for PrintWidth {
fn from(width: LineWidth) -> Self {
Self(u32::from(u16::from(width)))
}
}
impl From<PrintWidth> for usize {
fn from(width: PrintWidth) -> Self {
width.0 as usize
}
}
impl From<PrintWidth> for u32 {
fn from(width: PrintWidth) -> Self {
width.0
}
}
/// Configures whether the formatter and printer generate 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 formatter generates no source map.
#[default]
Disabled,
/// The formatter 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, SourceMapGeneration::Enabled)
}
pub const fn is_disabled(self) -> bool {
matches!(self, SourceMapGeneration::Disabled)
}
}
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Clone, Debug, Eq, PartialEq, Default)] #[derive(Clone, Debug, Eq, PartialEq, Default)]
pub enum LineEnding { pub enum LineEnding {

View file

@ -1,11 +1,8 @@
use thiserror::Error; use thiserror::Error;
use ruff_formatter::format_element::tag; use ruff_formatter::format_element::tag;
use ruff_formatter::prelude::{source_position, text, Formatter, Tag}; use ruff_formatter::prelude::*;
use ruff_formatter::{ use ruff_formatter::{format, FormatError, Formatted, PrintError, Printed, SourceCode};
format, write, Buffer, Format, FormatElement, FormatError, FormatResult, PrintError,
};
use ruff_formatter::{Formatted, Printed, SourceCode};
use ruff_python_ast::node::{AnyNodeRef, AstNode}; use ruff_python_ast::node::{AnyNodeRef, AstNode};
use ruff_python_ast::Mod; use ruff_python_ast::Mod;
use ruff_python_index::{CommentRanges, CommentRangesBuilder}; use ruff_python_index::{CommentRanges, CommentRangesBuilder};
@ -54,23 +51,22 @@ where
if self.is_suppressed(node_comments.trailing, f.context()) { if self.is_suppressed(node_comments.trailing, f.context()) {
suppressed_node(node.as_any_node_ref()).fmt(f) suppressed_node(node.as_any_node_ref()).fmt(f)
} else { } else {
write!( leading_comments(node_comments.leading).fmt(f)?;
f,
[ let is_source_map_enabled = f.options().source_map_generation().is_enabled();
leading_comments(node_comments.leading),
source_position(node.start()) if is_source_map_enabled {
] source_position(node.start()).fmt(f)?;
)?; }
self.fmt_fields(node, f)?; self.fmt_fields(node, f)?;
self.fmt_dangling_comments(node_comments.dangling, f)?; self.fmt_dangling_comments(node_comments.dangling, f)?;
write!( if is_source_map_enabled {
f, source_position(node.end()).fmt(f)?;
[ }
source_position(node.end()),
trailing_comments(node_comments.trailing) trailing_comments(node_comments.trailing).fmt(f)
]
)
} }
} }

View file

@ -1,4 +1,4 @@
use ruff_formatter::printer::{LineEnding, PrinterOptions}; use ruff_formatter::printer::{LineEnding, PrinterOptions, SourceMapGeneration};
use ruff_formatter::{FormatOptions, IndentStyle, LineWidth, TabWidth}; use ruff_formatter::{FormatOptions, IndentStyle, LineWidth, TabWidth};
use ruff_python_ast::PySourceType; use ruff_python_ast::PySourceType;
use std::path::Path; use std::path::Path;
@ -33,6 +33,10 @@ pub struct PyFormatOptions {
/// Whether to expand lists or elements if they have a trailing comma such as `(a, b,)`. /// Whether to expand lists or elements if they have a trailing comma such as `(a, b,)`.
magic_trailing_comma: MagicTrailingComma, magic_trailing_comma: MagicTrailingComma,
/// Should the formatter generate a source map that allows mapping source positions to positions
/// in the formatted document.
source_map_generation: SourceMapGeneration,
} }
fn default_line_width() -> LineWidth { fn default_line_width() -> LineWidth {
@ -56,6 +60,7 @@ impl Default for PyFormatOptions {
tab_width: default_tab_width(), tab_width: default_tab_width(),
quote_style: QuoteStyle::default(), quote_style: QuoteStyle::default(),
magic_trailing_comma: MagicTrailingComma::default(), magic_trailing_comma: MagicTrailingComma::default(),
source_map_generation: SourceMapGeneration::default(),
} }
} }
} }
@ -85,6 +90,10 @@ impl PyFormatOptions {
self.source_type self.source_type
} }
pub fn source_map_generation(&self) -> SourceMapGeneration {
self.source_map_generation
}
#[must_use] #[must_use]
pub fn with_quote_style(mut self, style: QuoteStyle) -> Self { pub fn with_quote_style(mut self, style: QuoteStyle) -> Self {
self.quote_style = style; self.quote_style = style;
@ -129,6 +138,7 @@ impl FormatOptions for PyFormatOptions {
print_width: self.line_width.into(), print_width: self.line_width.into(),
line_ending: LineEnding::LineFeed, line_ending: LineEnding::LineFeed,
indent_style: self.indent_style, indent_style: self.indent_style,
source_map_generation: self.source_map_generation,
} }
} }
} }