From 93ca8ebbc0caebe9c30c29bcc5941690cf24a8e8 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Mon, 4 Sep 2023 08:09:31 +0200 Subject: [PATCH] Formatter: Detect line endings (#7054) --- Cargo.lock | 1 + crates/ruff_cli/src/commands/format.rs | 18 ++++++++++++------ .../src/printer/printer_options/mod.rs | 3 ++- crates/ruff_python_formatter/Cargo.toml | 1 + crates/ruff_python_formatter/src/lib.rs | 2 ++ crates/ruff_python_formatter/src/options.rs | 15 ++++++++++++++- 6 files changed, 32 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6f5d3a93a9..ce777d5efb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2369,6 +2369,7 @@ dependencies = [ "similar", "smallvec", "thiserror", + "tracing", "unicode-width", ] diff --git a/crates/ruff_cli/src/commands/format.rs b/crates/ruff_cli/src/commands/format.rs index 79d9ce23e9..d2383f17ce 100644 --- a/crates/ruff_cli/src/commands/format.rs +++ b/crates/ruff_cli/src/commands/format.rs @@ -12,7 +12,6 @@ use log::{debug, warn}; use rayon::iter::Either::{Left, Right}; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use thiserror::Error; -use tracing::{span, Level}; use ruff::fs; use ruff::logging::LogLevel; @@ -20,6 +19,7 @@ use ruff::warn_user_once; use ruff_formatter::LineWidth; use ruff_python_ast::{PySourceType, SourceType}; use ruff_python_formatter::{format_module, FormatModuleError, PyFormatOptions}; +use ruff_source_file::{find_newline, LineEnding}; use ruff_workspace::resolver::python_files_in_path; use crate::args::{FormatArguments, Overrides}; @@ -140,12 +140,18 @@ fn format_path( ) -> Result { let unformatted = std::fs::read_to_string(path) .map_err(|err| FormatCommandError::Read(Some(path.to_path_buf()), err))?; - let formatted = { - let span = span!(Level::TRACE, "format_path_without_io", path = %path.display()); - let _enter = span.enter(); - format_module(&unformatted, options) - .map_err(|err| FormatCommandError::FormatModule(Some(path.to_path_buf()), err))? + + let line_ending = match find_newline(&unformatted) { + Some((_, LineEnding::Lf)) | None => ruff_formatter::printer::LineEnding::LineFeed, + Some((_, LineEnding::Cr)) => ruff_formatter::printer::LineEnding::CarriageReturn, + Some((_, LineEnding::CrLf)) => ruff_formatter::printer::LineEnding::CarriageReturnLineFeed, }; + + let options = options.with_line_ending(line_ending); + + let formatted = format_module(&unformatted, options) + .map_err(|err| FormatCommandError::FormatModule(Some(path.to_path_buf()), err))?; + let formatted = formatted.as_code(); if formatted.len() == unformatted.len() && formatted == unformatted { Ok(FormatCommandResult::Unchanged) diff --git a/crates/ruff_formatter/src/printer/printer_options/mod.rs b/crates/ruff_formatter/src/printer/printer_options/mod.rs index f4d058d34f..84048ce499 100644 --- a/crates/ruff_formatter/src/printer/printer_options/mod.rs +++ b/crates/ruff_formatter/src/printer/printer_options/mod.rs @@ -124,7 +124,8 @@ impl SourceMapGeneration { } #[allow(dead_code)] -#[derive(Clone, Debug, Eq, PartialEq, Default)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum LineEnding { /// Line Feed only (\n), common on Linux and macOS as well as inside git repos #[default] diff --git a/crates/ruff_python_formatter/Cargo.toml b/crates/ruff_python_formatter/Cargo.toml index e63bbeb872..c93f28a909 100644 --- a/crates/ruff_python_formatter/Cargo.toml +++ b/crates/ruff_python_formatter/Cargo.toml @@ -31,6 +31,7 @@ rustc-hash = { workspace = true } serde = { workspace = true, optional = true } smallvec = { workspace = true } thiserror = { workspace = true } +tracing = { workspace = true } unicode-width = { workspace = true } [dev-dependencies] diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index 98ab2a19d8..51ff0ed3ed 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -1,4 +1,5 @@ use thiserror::Error; +use tracing::Level; use ruff_formatter::prelude::*; use ruff_formatter::{format, FormatError, Formatted, PrintError, Printed, SourceCode}; @@ -119,6 +120,7 @@ impl From for FormatModuleError { } } +#[tracing::instrument(level=Level::TRACE, skip_all, err)] pub fn format_module( contents: &str, options: PyFormatOptions, diff --git a/crates/ruff_python_formatter/src/options.rs b/crates/ruff_python_formatter/src/options.rs index 14d9fea415..c089d3f6a2 100644 --- a/crates/ruff_python_formatter/src/options.rs +++ b/crates/ruff_python_formatter/src/options.rs @@ -28,6 +28,8 @@ pub struct PyFormatOptions { #[cfg_attr(feature = "serde", serde(default = "default_tab_width"))] tab_width: TabWidth, + line_ending: LineEnding, + /// The preferred quote style to use (single vs double quotes). quote_style: QuoteStyle, @@ -59,6 +61,7 @@ impl Default for PyFormatOptions { line_width: default_line_width(), tab_width: default_tab_width(), quote_style: QuoteStyle::default(), + line_ending: LineEnding::default(), magic_trailing_comma: MagicTrailingComma::default(), source_map_generation: SourceMapGeneration::default(), } @@ -94,6 +97,10 @@ impl PyFormatOptions { self.source_map_generation } + pub fn line_ending(&self) -> LineEnding { + self.line_ending + } + #[must_use] pub fn with_tab_width(mut self, tab_width: TabWidth) -> Self { self.tab_width = tab_width; @@ -123,6 +130,12 @@ impl PyFormatOptions { self.line_width = line_width; self } + + #[must_use] + pub fn with_line_ending(mut self, line_ending: LineEnding) -> Self { + self.line_ending = line_ending; + self + } } impl FormatOptions for PyFormatOptions { @@ -142,7 +155,7 @@ impl FormatOptions for PyFormatOptions { PrinterOptions { tab_width: self.tab_width, line_width: self.line_width, - line_ending: LineEnding::LineFeed, + line_ending: self.line_ending, indent_style: self.indent_style, source_map_generation: self.source_map_generation, }