Formatter: Detect line endings (#7054)

This commit is contained in:
Micha Reiser 2023-09-04 08:09:31 +02:00 committed by GitHub
parent 834566f34f
commit 93ca8ebbc0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 32 additions and 8 deletions

1
Cargo.lock generated
View file

@ -2369,6 +2369,7 @@ dependencies = [
"similar", "similar",
"smallvec", "smallvec",
"thiserror", "thiserror",
"tracing",
"unicode-width", "unicode-width",
] ]

View file

@ -12,7 +12,6 @@ use log::{debug, warn};
use rayon::iter::Either::{Left, Right}; use rayon::iter::Either::{Left, Right};
use rayon::iter::{IntoParallelIterator, ParallelIterator}; use rayon::iter::{IntoParallelIterator, ParallelIterator};
use thiserror::Error; use thiserror::Error;
use tracing::{span, Level};
use ruff::fs; use ruff::fs;
use ruff::logging::LogLevel; use ruff::logging::LogLevel;
@ -20,6 +19,7 @@ use ruff::warn_user_once;
use ruff_formatter::LineWidth; use ruff_formatter::LineWidth;
use ruff_python_ast::{PySourceType, SourceType}; use ruff_python_ast::{PySourceType, SourceType};
use ruff_python_formatter::{format_module, FormatModuleError, PyFormatOptions}; use ruff_python_formatter::{format_module, FormatModuleError, PyFormatOptions};
use ruff_source_file::{find_newline, LineEnding};
use ruff_workspace::resolver::python_files_in_path; use ruff_workspace::resolver::python_files_in_path;
use crate::args::{FormatArguments, Overrides}; use crate::args::{FormatArguments, Overrides};
@ -140,12 +140,18 @@ fn format_path(
) -> Result<FormatCommandResult, FormatCommandError> { ) -> Result<FormatCommandResult, FormatCommandError> {
let unformatted = std::fs::read_to_string(path) let unformatted = std::fs::read_to_string(path)
.map_err(|err| FormatCommandError::Read(Some(path.to_path_buf()), err))?; .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 line_ending = match find_newline(&unformatted) {
let _enter = span.enter(); Some((_, LineEnding::Lf)) | None => ruff_formatter::printer::LineEnding::LineFeed,
format_module(&unformatted, options) Some((_, LineEnding::Cr)) => ruff_formatter::printer::LineEnding::CarriageReturn,
.map_err(|err| FormatCommandError::FormatModule(Some(path.to_path_buf()), err))? 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(); let formatted = formatted.as_code();
if formatted.len() == unformatted.len() && formatted == unformatted { if formatted.len() == unformatted.len() && formatted == unformatted {
Ok(FormatCommandResult::Unchanged) Ok(FormatCommandResult::Unchanged)

View file

@ -124,7 +124,8 @@ impl SourceMapGeneration {
} }
#[allow(dead_code)] #[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 { pub enum LineEnding {
/// Line Feed only (\n), common on Linux and macOS as well as inside git repos /// Line Feed only (\n), common on Linux and macOS as well as inside git repos
#[default] #[default]

View file

@ -31,6 +31,7 @@ rustc-hash = { workspace = true }
serde = { workspace = true, optional = true } serde = { workspace = true, optional = true }
smallvec = { workspace = true } smallvec = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
tracing = { workspace = true }
unicode-width = { workspace = true } unicode-width = { workspace = true }
[dev-dependencies] [dev-dependencies]

View file

@ -1,4 +1,5 @@
use thiserror::Error; use thiserror::Error;
use tracing::Level;
use ruff_formatter::prelude::*; use ruff_formatter::prelude::*;
use ruff_formatter::{format, FormatError, Formatted, PrintError, Printed, SourceCode}; use ruff_formatter::{format, FormatError, Formatted, PrintError, Printed, SourceCode};
@ -119,6 +120,7 @@ impl From<ParseError> for FormatModuleError {
} }
} }
#[tracing::instrument(level=Level::TRACE, skip_all, err)]
pub fn format_module( pub fn format_module(
contents: &str, contents: &str,
options: PyFormatOptions, options: PyFormatOptions,

View file

@ -28,6 +28,8 @@ pub struct PyFormatOptions {
#[cfg_attr(feature = "serde", serde(default = "default_tab_width"))] #[cfg_attr(feature = "serde", serde(default = "default_tab_width"))]
tab_width: TabWidth, tab_width: TabWidth,
line_ending: LineEnding,
/// The preferred quote style to use (single vs double quotes). /// The preferred quote style to use (single vs double quotes).
quote_style: QuoteStyle, quote_style: QuoteStyle,
@ -59,6 +61,7 @@ impl Default for PyFormatOptions {
line_width: default_line_width(), line_width: default_line_width(),
tab_width: default_tab_width(), tab_width: default_tab_width(),
quote_style: QuoteStyle::default(), quote_style: QuoteStyle::default(),
line_ending: LineEnding::default(),
magic_trailing_comma: MagicTrailingComma::default(), magic_trailing_comma: MagicTrailingComma::default(),
source_map_generation: SourceMapGeneration::default(), source_map_generation: SourceMapGeneration::default(),
} }
@ -94,6 +97,10 @@ impl PyFormatOptions {
self.source_map_generation self.source_map_generation
} }
pub fn line_ending(&self) -> LineEnding {
self.line_ending
}
#[must_use] #[must_use]
pub fn with_tab_width(mut self, tab_width: TabWidth) -> Self { pub fn with_tab_width(mut self, tab_width: TabWidth) -> Self {
self.tab_width = tab_width; self.tab_width = tab_width;
@ -123,6 +130,12 @@ impl PyFormatOptions {
self.line_width = line_width; self.line_width = line_width;
self self
} }
#[must_use]
pub fn with_line_ending(mut self, line_ending: LineEnding) -> Self {
self.line_ending = line_ending;
self
}
} }
impl FormatOptions for PyFormatOptions { impl FormatOptions for PyFormatOptions {
@ -142,7 +155,7 @@ impl FormatOptions for PyFormatOptions {
PrinterOptions { PrinterOptions {
tab_width: self.tab_width, tab_width: self.tab_width,
line_width: self.line_width, line_width: self.line_width,
line_ending: LineEnding::LineFeed, line_ending: self.line_ending,
indent_style: self.indent_style, indent_style: self.indent_style,
source_map_generation: self.source_map_generation, source_map_generation: self.source_map_generation,
} }