Skip to content

Commit

Permalink
challenge(formatter): add lineEnding option (#786)
Browse files Browse the repository at this point in the history
  • Loading branch information
SuperchupuDev authored Nov 19, 2023
1 parent 55be4d4 commit fa7894d
Show file tree
Hide file tree
Showing 253 changed files with 866 additions and 60 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ Read our [guidelines for writing a good changelog entry](https://github.com/biom

### Formatter

#### New features

- Add a new option [`--line-ending`](https://biomejs.dev/reference/configuration/#formatterlineending). This option allows changing the type of line endings. Contributed by @SuperchupuDev

#### Bug fixes

- Fix [#301](https://github.com/biomejs/biome/issues/301), the formatter should not break before the `in` keyword. Contributed by @ematipico
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ The configuration that is contained inside the file `biome.json`
--indent-style=<tab|space> The indent style.
--indent-size=NUMBER The size of the indentation, 2 by default (deprecated, use `indent-width`)
--indent-width=NUMBER The size of the indentation, 2 by default
--line-ending=<lf|crlf|cr> The type of line ending.
--line-width=NUMBER What's the max width of a line. Defaults to 80.
--quote-style=<double|single> The type of quotes used in JavaScript code. Defaults to double.
--jsx-quote-style=<double|single> The type of quotes used in JSX. Defaults to double.
Expand All @@ -44,7 +45,9 @@ The configuration that is contained inside the file `biome.json`
(and its super languages) files. Default to 2.
--javascript-formatter-indent-width=NUMBER The size of the indentation applied to JavaScript
(and its super languages) files. Default to 2.
--javascript-formatter-line-width=NUMBER What's the max width of a line, applied to JavaScript
--javascript-formatter-line-ending=<lf|crlf|cr> The type of line ending applied to JavaScript
(and its super languages) files.
--javascript-formatter-line-width=NUMBER What's the max width of a line applied to JavaScript
(and its super languages) files. Defaults to 80.
--json-formatter-enabled=<true|false> Control the formatter for JSON (and its super languages)
files.
Expand All @@ -54,8 +57,10 @@ The configuration that is contained inside the file `biome.json`
languages) files. Default to 2.
--json-formatter-indent-size=NUMBER The size of the indentation applied to JSON (and its super
languages) files. Default to 2.
--json-formatter-line-width=NUMBER What's the max width of a line, applied to JSON (and its
super languages) files. Defaults to 80.
--json-formatter-line-ending=<lf|crlf|cr> The type of line ending applied to JSON (and its super
languages) files.
--json-formatter-line-width=NUMBER What's the max width of a line applied to JSON (and its super
languages) files. Defaults to 80.
Global options applied to all commands
--colors=<off|force> Set the formatting mode for markup: "off" prints everything as plain text,
Expand Down
11 changes: 8 additions & 3 deletions crates/biome_cli/tests/snapshots/main_commands_ci/ci_help.snap
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ The configuration that is contained inside the file `biome.json`
--indent-style=<tab|space> The indent style.
--indent-size=NUMBER The size of the indentation, 2 by default (deprecated, use `indent-width`)
--indent-width=NUMBER The size of the indentation, 2 by default
--line-ending=<lf|crlf|cr> The type of line ending.
--line-width=NUMBER What's the max width of a line. Defaults to 80.
--quote-style=<double|single> The type of quotes used in JavaScript code. Defaults to double.
--jsx-quote-style=<double|single> The type of quotes used in JSX. Defaults to double.
Expand All @@ -46,7 +47,9 @@ The configuration that is contained inside the file `biome.json`
(and its super languages) files. Default to 2.
--javascript-formatter-indent-width=NUMBER The size of the indentation applied to JavaScript
(and its super languages) files. Default to 2.
--javascript-formatter-line-width=NUMBER What's the max width of a line, applied to JavaScript
--javascript-formatter-line-ending=<lf|crlf|cr> The type of line ending applied to JavaScript
(and its super languages) files.
--javascript-formatter-line-width=NUMBER What's the max width of a line applied to JavaScript
(and its super languages) files. Defaults to 80.
--json-formatter-enabled=<true|false> Control the formatter for JSON (and its super languages)
files.
Expand All @@ -56,8 +59,10 @@ The configuration that is contained inside the file `biome.json`
languages) files. Default to 2.
--json-formatter-indent-size=NUMBER The size of the indentation applied to JSON (and its super
languages) files. Default to 2.
--json-formatter-line-width=NUMBER What's the max width of a line, applied to JSON (and its
super languages) files. Defaults to 80.
--json-formatter-line-ending=<lf|crlf|cr> The type of line ending applied to JSON (and its super
languages) files.
--json-formatter-line-width=NUMBER What's the max width of a line applied to JSON (and its super
languages) files. Defaults to 80.
Global options applied to all commands
--colors=<off|force> Set the formatting mode for markup: "off" prints everything as plain text,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Generic options applied to all files
--indent-style=<tab|space> The indent style.
--indent-size=NUMBER The size of the indentation, 2 by default (deprecated, use `indent-width`)
--indent-width=NUMBER The size of the indentation, 2 by default
--line-ending=<lf|crlf|cr> The type of line ending.
--line-width=NUMBER What's the max width of a line. Defaults to 80.
Formatting options specific to the JavaScript files
Expand All @@ -33,7 +34,9 @@ Formatting options specific to the JavaScript files
(and its super languages) files. Default to 2.
--javascript-formatter-indent-width=NUMBER The size of the indentation applied to JavaScript
(and its super languages) files. Default to 2.
--javascript-formatter-line-width=NUMBER What's the max width of a line, applied to JavaScript
--javascript-formatter-line-ending=<lf|crlf|cr> The type of line ending applied to JavaScript
(and its super languages) files.
--javascript-formatter-line-width=NUMBER What's the max width of a line applied to JavaScript
(and its super languages) files. Defaults to 80.
Set of properties to integrate Biome with a VCS software.
Expand Down Expand Up @@ -90,8 +93,10 @@ Available options:
languages) files. Default to 2.
--json-formatter-indent-size=NUMBER The size of the indentation applied to JSON (and its super
languages) files. Default to 2.
--json-formatter-line-width=NUMBER What's the max width of a line, applied to JSON (and its
super languages) files. Defaults to 80.
--json-formatter-line-ending=<lf|crlf|cr> The type of line ending applied to JSON (and its super
languages) files.
--json-formatter-line-width=NUMBER What's the max width of a line applied to JSON (and its super
languages) files. Defaults to 80.
--stdin-file-path=PATH Use this option when you want to format code piped from `stdin`, and
print the output to `stdout`.
The file doesn't need to exist on disk, what matters is the extension of
Expand Down
9 changes: 6 additions & 3 deletions crates/biome_formatter/src/format_element/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ use super::tag::Tag;
use crate::format_element::tag::DedentMode;
use crate::prelude::tag::GroupMode;
use crate::prelude::*;
use crate::printer::LineEnding;
use crate::{format, write};
use crate::{
BufferExtensions, Format, FormatContext, FormatElement, FormatOptions, FormatResult, Formatter,
IndentStyle, IndentWidth, LineWidth, PrinterOptions, TransformSourceMap,
IndentStyle, IndentWidth, LineEnding, LineWidth, PrinterOptions, TransformSourceMap,
};
use biome_rowan::TextSize;
use rustc_hash::FxHashMap;
Expand Down Expand Up @@ -163,11 +162,15 @@ impl FormatOptions for IrFormatOptions {
LineWidth::default()
}

fn line_ending(&self) -> LineEnding {
LineEnding::Lf
}

fn as_print_options(&self) -> PrinterOptions {
PrinterOptions {
indent_width: self.indent_width(),
print_width: self.line_width().into(),
line_ending: LineEnding::LineFeed,
line_ending: LineEnding::Lf,
indent_style: IndentStyle::Space,
}
}
Expand Down
101 changes: 100 additions & 1 deletion crates/biome_formatter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ use crate::printed_tokens::PrintedTokens;
use crate::printer::{Printer, PrinterOptions};
pub use arguments::{Argument, Arguments};
use biome_deserialize::{
Deserializable, DeserializableValue, DeserializationDiagnostic, TextNumber,
Deserializable, DeserializableValue, DeserializationDiagnostic, Text, TextNumber,
};
pub use buffer::{
Buffer, BufferExtensions, BufferSnapshot, Inspect, PreambleBuffer, RemoveSoftLinesBuffer,
Expand Down Expand Up @@ -125,6 +125,96 @@ impl std::fmt::Display for IndentStyle {
}
}

#[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize, schemars::JsonSchema),
serde(rename_all = "camelCase")
)]
#[derive(Default)]
pub enum LineEnding {
/// Line Feed only (\n), common on Linux and macOS as well as inside git repos
#[default]
Lf,

/// Carriage Return + Line Feed characters (\r\n), common on Windows
Crlf,

/// Carriage Return character only (\r), used very rarely
Cr,
}

impl LineEnding {
#[inline]
pub const fn as_str(&self) -> &'static str {
match self {
LineEnding::Lf => "\n",
LineEnding::Crlf => "\r\n",
LineEnding::Cr => "\r",
}
}

/// Returns `true` if this is a [LineEnding::Lf].
pub const fn is_line_feed(&self) -> bool {
matches!(self, LineEnding::Lf)
}

/// Returns `true` if this is a [LineEnding::Crlf].
pub const fn is_carriage_return_line_feed(&self) -> bool {
matches!(self, LineEnding::Crlf)
}

/// Returns `true` if this is a [LineEnding::Cr].
pub const fn is_carriage_return(&self) -> bool {
matches!(self, LineEnding::Cr)
}
}

impl FromStr for LineEnding {
type Err = &'static str;

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"lf" => Ok(Self::Lf),
"crlf" => Ok(Self::Crlf),
"cr" => Ok(Self::Cr),
// TODO: replace this error with a diagnostic
_ => Err("Value not supported for LineEnding"),
}
}
}

impl std::fmt::Display for LineEnding {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LineEnding::Lf => std::write!(f, "LF"),
LineEnding::Crlf => std::write!(f, "CRLF"),
LineEnding::Cr => std::write!(f, "CR"),
}
}
}

impl Deserializable for LineEnding {
fn deserialize(
value: &impl DeserializableValue,
name: &str,
diagnostics: &mut Vec<DeserializationDiagnostic>,
) -> Option<Self> {
let value_text = Text::deserialize(value, name, diagnostics)?;
if let Ok(value) = value_text.parse::<Self>() {
Some(value)
} else {
const ALLOWED_VARIANTS: &[&str] = &["lf", "crlf", "cr"];
diagnostics.push(DeserializationDiagnostic::new_unknown_value(
&value_text,
value.range(),
ALLOWED_VARIANTS,
));
None
}
}
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(
feature = "serde",
Expand Down Expand Up @@ -292,6 +382,9 @@ pub trait FormatOptions {
/// What's the max width of a line. Defaults to 80.
fn line_width(&self) -> LineWidth;

/// The type of line ending.
fn line_ending(&self) -> LineEnding;

/// Derives the print options from the these format options
fn as_print_options(&self) -> PrinterOptions;
}
Expand Down Expand Up @@ -339,6 +432,7 @@ pub struct SimpleFormatOptions {
pub indent_style: IndentStyle,
pub indent_width: IndentWidth,
pub line_width: LineWidth,
pub line_ending: LineEnding,
}

impl FormatOptions for SimpleFormatOptions {
Expand All @@ -354,11 +448,16 @@ impl FormatOptions for SimpleFormatOptions {
self.line_width
}

fn line_ending(&self) -> LineEnding {
self.line_ending
}

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())
.with_line_ending(self.line_ending)
}
}

Expand Down
6 changes: 4 additions & 2 deletions crates/biome_formatter/src/printer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1260,7 +1260,8 @@ struct FitsState {
#[cfg(test)]
mod tests {
use crate::prelude::*;
use crate::printer::{LineEnding, PrintWidth, Printer, PrinterOptions};
use crate::printer::{PrintWidth, Printer, PrinterOptions};
use crate::LineEnding;
use crate::{format_args, write, Document, FormatState, IndentStyle, Printed, VecBuffer};

fn format(root: &dyn Format<SimpleFormatContext>) -> Printed {
Expand All @@ -1269,6 +1270,7 @@ mod tests {
PrinterOptions {
indent_style: IndentStyle::Space,
indent_width: 2.into(),
line_ending: LineEnding::Lf,
..PrinterOptions::default()
},
)
Expand Down Expand Up @@ -1331,7 +1333,7 @@ a"#,
#[test]
fn it_converts_line_endings() {
let options = PrinterOptions {
line_ending: LineEnding::CarriageReturnLineFeed,
line_ending: LineEnding::Crlf,
..PrinterOptions::default()
};

Expand Down
36 changes: 12 additions & 24 deletions crates/biome_formatter/src/printer/printer_options/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::{FormatOptions, IndentStyle, IndentWidth, LineWidth};
use crate::{FormatOptions, IndentStyle, IndentWidth, LineEnding, LineWidth};

/// Options that affect how the [crate::Printer] prints the format tokens
#[derive(Clone, Debug, Eq, PartialEq)]
Expand Down Expand Up @@ -53,6 +53,7 @@ where
.with_indent_style(options.indent_style())
.with_indent_width(options.indent_width())
.with_print_width(options.line_width().into())
.with_line_ending(options.line_ending())
}
}

Expand All @@ -74,6 +75,12 @@ impl PrinterOptions {
self
}

pub fn with_line_ending(mut self, line_ending: LineEnding) -> Self {
self.line_ending = line_ending;

self
}

pub(crate) fn indent_style(&self) -> IndentStyle {
self.indent_style
}
Expand All @@ -82,29 +89,10 @@ impl PrinterOptions {
pub(super) const fn indent_width(&self) -> IndentWidth {
self.indent_width
}
}

#[allow(dead_code)]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LineEnding {
/// Line Feed only (\n), common on Linux and macOS as well as inside git repos
LineFeed,

/// Carriage Return + Line Feed characters (\r\n), common on Windows
CarriageReturnLineFeed,

/// Carriage Return character only (\r), used very rarely
CarriageReturn,
}

impl LineEnding {
#[inline]
pub const fn as_str(&self) -> &'static str {
match self {
LineEnding::LineFeed => "\n",
LineEnding::CarriageReturnLineFeed => "\r\n",
LineEnding::CarriageReturn => "\r",
}
#[allow(dead_code)]
pub(super) const fn line_ending(&self) -> LineEnding {
self.line_ending
}
}

Expand All @@ -114,7 +102,7 @@ impl Default for PrinterOptions {
indent_width: 2.into(),
print_width: PrintWidth::default(),
indent_style: Default::default(),
line_ending: LineEnding::LineFeed,
line_ending: LineEnding::Lf,
}
}
}
12 changes: 11 additions & 1 deletion crates/biome_formatter_test/src/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,10 +220,20 @@ where
.deserialize_format_options(options_path.get_buffer_from_file().as_str());

for (index, options) in test_options.into_iter().enumerate() {
let (output_code, printed) = self.formatted(&parsed, options.clone());
let (mut output_code, printed) = self.formatted(&parsed, options.clone());

let max_width = options.line_width().get() as usize;

// There are some logs that print different line endings, and we can't snapshot those
// otherwise we risk automatically having them replaced with LF by git.
//
// This is a workaround, and it might not work for all cases.
const CRLF_PATTERN: &str = "\r\n";
const CR_PATTERN: &str = "\r";
output_code = output_code
.replace(CRLF_PATTERN, "<CRLF>\n")
.replace(CR_PATTERN, "<CR>\n");

snapshot_builder = snapshot_builder
.with_output_and_options(
SnapshotOutput::new(&output_code).with_index(index + 2),
Expand Down
Loading

0 comments on commit fa7894d

Please sign in to comment.