From f8b36a6942e8c7fd419c8297f1f62e08d1255533 Mon Sep 17 00:00:00 2001 From: konstin Date: Fri, 25 Aug 2023 13:37:08 +0200 Subject: [PATCH] Unify line size settings between ruff and the formatter **Summary** Previuosly, there had been `LineLength` in ruff and `LineWidth` in the formatter. `LineLength` was a lenient usize wrapper, while `LineWidth` was a strict u16. With the formatter moving into the ruff cli, we need to unify the two types. This PR makes both crates share a new `LineLength` type based on the previous ruff formatter type. It currently lives in `ruff_python_trivia` but i'm happy to move it wherever. This is technically a breaking change because the line limit afterwards has a limit of 320 that it didn't have before. **Test Plan** No functional changes. --- Cargo.lock | 5 + crates/ruff/Cargo.toml | 2 +- crates/ruff/src/checkers/physical_lines.rs | 4 +- crates/ruff/src/flake8_to_ruff/black.rs | 3 +- crates/ruff/src/flake8_to_ruff/converter.rs | 17 ++- crates/ruff/src/line_width.rs | 29 ++--- crates/ruff/src/message/text.rs | 4 +- .../src/rules/flake8_simplify/rules/ast_if.rs | 8 +- .../rules/flake8_simplify/rules/ast_with.rs | 4 +- .../rules/reimplemented_builtin.rs | 6 +- crates/ruff/src/rules/isort/format.rs | 9 +- crates/ruff/src/rules/isort/mod.rs | 7 +- .../src/rules/isort/rules/organize_imports.rs | 4 +- crates/ruff/src/rules/pycodestyle/helpers.rs | 11 +- crates/ruff/src/rules/pycodestyle/mod.rs | 8 +- .../pycodestyle/rules/doc_line_too_long.rs | 2 +- .../rules/pycodestyle/rules/line_too_long.rs | 7 +- crates/ruff/src/rules/pycodestyle/settings.rs | 3 +- .../src/rules/pyupgrade/rules/f_strings.rs | 4 +- crates/ruff/src/settings/configuration.rs | 3 +- crates/ruff/src/settings/defaults.rs | 3 +- crates/ruff/src/settings/mod.rs | 3 +- crates/ruff/src/settings/options.rs | 3 +- crates/ruff/src/settings/pyproject.rs | 6 +- crates/ruff_cli/src/args.rs | 8 +- crates/ruff_cli/src/commands/format.rs | 10 +- crates/ruff_dev/src/format_dev.rs | 12 +- crates/ruff_formatter/Cargo.toml | 1 + crates/ruff_formatter/src/builders.rs | 74 ++++++++----- .../src/format_element/document.rs | 16 +-- crates/ruff_formatter/src/lib.rs | 100 +---------------- crates/ruff_formatter/src/macros.rs | 6 +- .../src/printer/printer_options/mod.rs | 8 +- crates/ruff_python_formatter/Cargo.toml | 2 +- crates/ruff_python_formatter/src/options.rs | 13 ++- crates/ruff_python_trivia/Cargo.toml | 9 +- crates/ruff_python_trivia/src/lib.rs | 2 + crates/ruff_python_trivia/src/line_width.rs | 103 ++++++++++++++++++ crates/ruff_text_size/Cargo.toml | 6 +- crates/ruff_wasm/Cargo.toml | 1 + crates/ruff_wasm/src/lib.rs | 3 +- ruff.schema.json | 4 +- 42 files changed, 297 insertions(+), 236 deletions(-) create mode 100644 crates/ruff_python_trivia/src/line_width.rs diff --git a/Cargo.lock b/Cargo.lock index 07b6c43c4fc2a4..12e925bbcd5a0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2275,6 +2275,7 @@ version = "0.0.0" dependencies = [ "drop_bomb", "insta", + "ruff_python_trivia", "ruff_text_size", "rustc-hash", "schemars", @@ -2450,10 +2451,13 @@ version = "0.0.0" dependencies = [ "insta", "memchr", + "ruff_cache", "ruff_python_ast", "ruff_python_parser", "ruff_source_file", "ruff_text_size", + "schemars", + "serde", "smallvec", "unic-ucd-ident", ] @@ -2510,6 +2514,7 @@ dependencies = [ "ruff_python_formatter", "ruff_python_index", "ruff_python_parser", + "ruff_python_trivia", "ruff_source_file", "serde", "serde-wasm-bindgen", diff --git a/crates/ruff/Cargo.toml b/crates/ruff/Cargo.toml index e5164a61695adf..2409b654caa286 100644 --- a/crates/ruff/Cargo.toml +++ b/crates/ruff/Cargo.toml @@ -25,7 +25,7 @@ ruff_python_index = { path = "../ruff_python_index" } ruff_python_literal = { path = "../ruff_python_literal" } ruff_python_semantic = { path = "../ruff_python_semantic" } ruff_python_stdlib = { path = "../ruff_python_stdlib" } -ruff_python_trivia = { path = "../ruff_python_trivia" } +ruff_python_trivia = { path = "../ruff_python_trivia", features = ["schemars"] } ruff_python_parser = { path = "../ruff_python_parser" } ruff_source_file = { path = "../ruff_source_file", features = ["serde"] } ruff_text_size = { path = "../ruff_text_size" } diff --git a/crates/ruff/src/checkers/physical_lines.rs b/crates/ruff/src/checkers/physical_lines.rs index cf4479a4113251..e3d46d541e2a27 100644 --- a/crates/ruff/src/checkers/physical_lines.rs +++ b/crates/ruff/src/checkers/physical_lines.rs @@ -104,9 +104,9 @@ mod tests { use ruff_python_codegen::Stylist; use ruff_python_index::Indexer; + use ruff_python_trivia::LineLength; use ruff_source_file::Locator; - use crate::line_width::LineLength; use crate::registry::Rule; use crate::settings::Settings; @@ -132,7 +132,7 @@ mod tests { }, ) }; - let line_length = LineLength::from(8); + let line_length = LineLength::try_from(8).unwrap(); assert_eq!(check_with_max_line_length(line_length), vec![]); assert_eq!(check_with_max_line_length(line_length), vec![]); } diff --git a/crates/ruff/src/flake8_to_ruff/black.rs b/crates/ruff/src/flake8_to_ruff/black.rs index b1e2e5e601cf7e..da6ef9a5e8f6b9 100644 --- a/crates/ruff/src/flake8_to_ruff/black.rs +++ b/crates/ruff/src/flake8_to_ruff/black.rs @@ -1,5 +1,6 @@ //! Extract Black configuration settings from a pyproject.toml. +use ruff_python_trivia::LineLength; use serde::{Deserialize, Serialize}; use crate::settings::types::PythonVersion; @@ -7,7 +8,7 @@ use crate::settings::types::PythonVersion; #[derive(Debug, PartialEq, Eq, Serialize, Deserialize, Default)] pub struct Black { #[serde(alias = "line-length", alias = "line_length")] - pub line_length: Option, + pub line_length: Option, #[serde(alias = "target-version", alias = "target_version")] pub target_version: Option>, } diff --git a/crates/ruff/src/flake8_to_ruff/converter.rs b/crates/ruff/src/flake8_to_ruff/converter.rs index 5bccf6369199d0..b9fa1f7eff4555 100644 --- a/crates/ruff/src/flake8_to_ruff/converter.rs +++ b/crates/ruff/src/flake8_to_ruff/converter.rs @@ -1,9 +1,10 @@ use std::collections::{HashMap, HashSet}; +use std::str::FromStr; use anyhow::Result; use itertools::Itertools; +use ruff_python_trivia::LineLength; -use crate::line_width::LineLength; use crate::registry::Linter; use crate::rule_selector::RuleSelector; use crate::rules::flake8_pytest_style::types::{ @@ -120,10 +121,8 @@ pub fn convert( "builtins" => { options.builtins = Some(parser::parse_strings(value.as_ref())); } - "max-line-length" | "max_line_length" => match value.parse::() { - Ok(line_length) => { - options.line_length = Some(LineLength::from(line_length)); - } + "max-line-length" | "max_line_length" => match LineLength::from_str(value) { + Ok(line_length) => options.line_length = Some(line_length), Err(e) => { warn_user!("Unable to parse '{key}' property: {e}"); } @@ -406,7 +405,7 @@ pub fn convert( // Extract any settings from the existing `pyproject.toml`. if let Some(black) = &external_config.black { if let Some(line_length) = &black.line_length { - options.line_length = Some(LineLength::from(*line_length)); + options.line_length = Some(*line_length); } if let Some(target_version) = &black.target_version { @@ -459,11 +458,11 @@ mod tests { use itertools::Itertools; use pep440_rs::VersionSpecifiers; use pretty_assertions::assert_eq; + use ruff_python_trivia::LineLength; use crate::flake8_to_ruff::converter::DEFAULT_SELECTORS; use crate::flake8_to_ruff::pep621::Project; use crate::flake8_to_ruff::ExternalConfig; - use crate::line_width::LineLength; use crate::registry::Linter; use crate::rule_selector::RuleSelector; use crate::rules::pydocstyle::settings::Convention; @@ -514,7 +513,7 @@ mod tests { Some(vec![]), )?; let expected = Pyproject::new(Options { - line_length: Some(LineLength::from(100)), + line_length: Some(LineLength::try_from(100).unwrap()), ..default_options([]) }); assert_eq!(actual, expected); @@ -533,7 +532,7 @@ mod tests { Some(vec![]), )?; let expected = Pyproject::new(Options { - line_length: Some(LineLength::from(100)), + line_length: Some(LineLength::try_from(100).unwrap()), ..default_options([]) }); assert_eq!(actual, expected); diff --git a/crates/ruff/src/line_width.rs b/crates/ruff/src/line_width.rs index ee8e4f6bc9561a..69cf653c441444 100644 --- a/crates/ruff/src/line_width.rs +++ b/crates/ruff/src/line_width.rs @@ -3,7 +3,9 @@ use std::num::NonZeroU8; use unicode_width::UnicodeWidthChar; use ruff_macros::CacheKey; +use ruff_python_trivia::LineLength; +/* /// The length of a line of text that is considered too long. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, CacheKey)] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] @@ -27,13 +29,14 @@ impl From for LineLength { Self(value) } } +*/ /// A measure of the width of a line of text. /// /// This is used to determine if a line is too long. /// It should be compared to a [`LineLength`]. #[derive(Clone, Copy, Debug)] -pub struct LineWidth { +pub struct LineWidthBuilder { /// The width of the line. width: usize, /// The column of the line. @@ -43,40 +46,40 @@ pub struct LineWidth { tab_size: TabSize, } -impl Default for LineWidth { +impl Default for LineWidthBuilder { fn default() -> Self { Self::new(TabSize::default()) } } -impl PartialEq for LineWidth { +impl PartialEq for LineWidthBuilder { fn eq(&self, other: &Self) -> bool { self.width == other.width } } -impl Eq for LineWidth {} +impl Eq for LineWidthBuilder {} -impl PartialOrd for LineWidth { +impl PartialOrd for LineWidthBuilder { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for LineWidth { +impl Ord for LineWidthBuilder { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.width.cmp(&other.width) } } -impl LineWidth { +impl LineWidthBuilder { pub fn get(&self) -> usize { self.width } /// Creates a new `LineWidth` with the given tab size. pub fn new(tab_size: TabSize) -> Self { - LineWidth { + LineWidthBuilder { width: 0, column: 0, tab_size, @@ -119,7 +122,7 @@ impl LineWidth { /// Adds the given width to the line width. /// Also adds the given width to the column. - /// It is generally better to use [`LineWidth::add_str`] or [`LineWidth::add_char`]. + /// It is generally better to use [`LineWidthBuilder::add_str`] or [`LineWidthBuilder::add_char`]. /// The width and column should be the same for the corresponding text. /// Currently, this is only used to add spaces. #[must_use] @@ -130,15 +133,15 @@ impl LineWidth { } } -impl PartialEq for LineWidth { +impl PartialEq for LineWidthBuilder { fn eq(&self, other: &LineLength) -> bool { - self.width == other.0 + self.width == (other.value() as usize) } } -impl PartialOrd for LineWidth { +impl PartialOrd for LineWidthBuilder { fn partial_cmp(&self, other: &LineLength) -> Option { - self.width.partial_cmp(&other.0) + self.width.partial_cmp(&(other.value() as usize)) } } diff --git a/crates/ruff/src/message/text.rs b/crates/ruff/src/message/text.rs index f0f0df6f169cf8..23cfd8c5644ad5 100644 --- a/crates/ruff/src/message/text.rs +++ b/crates/ruff/src/message/text.rs @@ -12,7 +12,7 @@ use ruff_text_size::{TextRange, TextSize}; use crate::fs::relativize_path; use crate::jupyter::{Notebook, NotebookIndex}; -use crate::line_width::{LineWidth, TabSize}; +use crate::line_width::{LineWidthBuilder, TabSize}; use crate::message::diff::Diff; use crate::message::{Emitter, EmitterContext, Message}; use crate::registry::AsRule; @@ -292,7 +292,7 @@ fn replace_whitespace(source: &str, annotation_range: TextRange) -> SourceCode { let mut result = String::new(); let mut last_end = 0; let mut range = annotation_range; - let mut line_width = LineWidth::new(TabSize::default()); + let mut line_width = LineWidthBuilder::new(TabSize::default()); for (index, c) in source.char_indices() { let old_width = line_width.get(); diff --git a/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs b/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs index 27d1b551421c8b..403b173150aa0d 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs @@ -16,7 +16,7 @@ use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer}; use ruff_source_file::{Locator, UniversalNewlines}; use crate::checkers::ast::Checker; -use crate::line_width::LineWidth; +use crate::line_width::LineWidthBuilder; use crate::registry::AsRule; use crate::rules::flake8_simplify::rules::fix_if; @@ -415,7 +415,7 @@ pub(crate) fn nested_if_statements( .unwrap_or_default() .universal_newlines() .all(|line| { - LineWidth::new(checker.settings.tab_size).add_str(&line) + LineWidthBuilder::new(checker.settings.tab_size).add_str(&line) <= checker.settings.line_length }) { @@ -661,7 +661,7 @@ pub(crate) fn use_ternary_operator(checker: &mut Checker, stmt: &Stmt) { // Don't flag if the resulting expression would exceed the maximum line length. let line_start = checker.locator().line_start(stmt.start()); - if LineWidth::new(checker.settings.tab_size) + if LineWidthBuilder::new(checker.settings.tab_size) .add_str(&checker.locator().contents()[TextRange::new(line_start, stmt.start())]) .add_str(&contents) > checker.settings.line_length @@ -965,7 +965,7 @@ pub(crate) fn use_dict_get_with_default(checker: &mut Checker, stmt_if: &ast::St // Don't flag if the resulting expression would exceed the maximum line length. let line_start = checker.locator().line_start(stmt_if.start()); - if LineWidth::new(checker.settings.tab_size) + if LineWidthBuilder::new(checker.settings.tab_size) .add_str(&checker.locator().contents()[TextRange::new(line_start, stmt_if.start())]) .add_str(&contents) > checker.settings.line_length diff --git a/crates/ruff/src/rules/flake8_simplify/rules/ast_with.rs b/crates/ruff/src/rules/flake8_simplify/rules/ast_with.rs index 95fe3d66bebef0..8b5f148f91bc97 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_with.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_with.rs @@ -9,7 +9,7 @@ use ruff_source_file::UniversalNewlines; use ruff_text_size::TextRange; use crate::checkers::ast::Checker; -use crate::line_width::LineWidth; +use crate::line_width::LineWidthBuilder; use crate::registry::AsRule; use super::fix_with; @@ -142,7 +142,7 @@ pub(crate) fn multiple_with_statements( .unwrap_or_default() .universal_newlines() .all(|line| { - LineWidth::new(checker.settings.tab_size).add_str(&line) + LineWidthBuilder::new(checker.settings.tab_size).add_str(&line) <= checker.settings.line_length }) { diff --git a/crates/ruff/src/rules/flake8_simplify/rules/reimplemented_builtin.rs b/crates/ruff/src/rules/flake8_simplify/rules/reimplemented_builtin.rs index 6246da0da370ac..1d0758c5dfe232 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/reimplemented_builtin.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/reimplemented_builtin.rs @@ -11,7 +11,7 @@ use ruff_python_ast::traversal; use ruff_python_codegen::Generator; use crate::checkers::ast::Checker; -use crate::line_width::LineWidth; +use crate::line_width::LineWidthBuilder; use crate::registry::AsRule; /// ## What it does @@ -99,7 +99,7 @@ pub(crate) fn convert_for_loop_to_any_all(checker: &mut Checker, stmt: &Stmt) { // Don't flag if the resulting expression would exceed the maximum line length. let line_start = checker.locator().line_start(stmt.start()); - if LineWidth::new(checker.settings.tab_size) + if LineWidthBuilder::new(checker.settings.tab_size) .add_str(&checker.locator().contents()[TextRange::new(line_start, stmt.start())]) .add_str(&contents) > checker.settings.line_length @@ -181,7 +181,7 @@ pub(crate) fn convert_for_loop_to_any_all(checker: &mut Checker, stmt: &Stmt) { // Don't flag if the resulting expression would exceed the maximum line length. let line_start = checker.locator().line_start(stmt.start()); - if LineWidth::new(checker.settings.tab_size) + if LineWidthBuilder::new(checker.settings.tab_size) .add_str(&checker.locator().contents()[TextRange::new(line_start, stmt.start())]) .add_str(&contents) > checker.settings.line_length diff --git a/crates/ruff/src/rules/isort/format.rs b/crates/ruff/src/rules/isort/format.rs index cfabdb5364b907..a13d7a11c3940d 100644 --- a/crates/ruff/src/rules/isort/format.rs +++ b/crates/ruff/src/rules/isort/format.rs @@ -1,6 +1,7 @@ use ruff_python_codegen::Stylist; +use ruff_python_trivia::LineLength; -use crate::line_width::{LineLength, LineWidth}; +use crate::line_width::LineWidthBuilder; use super::types::{AliasData, CommentSet, ImportFromData, Importable}; @@ -46,7 +47,7 @@ pub(crate) fn format_import_from( comments: &CommentSet, aliases: &[(AliasData, CommentSet)], line_length: LineLength, - indentation_width: LineWidth, + indentation_width: LineWidthBuilder, stylist: &Stylist, force_wrap_aliases: bool, is_first: bool, @@ -103,8 +104,8 @@ fn format_single_line( aliases: &[(AliasData, CommentSet)], is_first: bool, stylist: &Stylist, - indentation_width: LineWidth, -) -> (String, LineWidth) { + indentation_width: LineWidthBuilder, +) -> (String, LineWidthBuilder) { let mut output = String::with_capacity(CAPACITY); let mut line_width = indentation_width; diff --git a/crates/ruff/src/rules/isort/mod.rs b/crates/ruff/src/rules/isort/mod.rs index 074f59be1530e2..9b8b18cf27620c 100644 --- a/crates/ruff/src/rules/isort/mod.rs +++ b/crates/ruff/src/rules/isort/mod.rs @@ -13,13 +13,14 @@ use normalize::normalize_imports; use order::order_imports; use ruff_python_ast::PySourceType; use ruff_python_codegen::Stylist; +use ruff_python_trivia::LineLength; use ruff_source_file::Locator; use settings::RelativeImportsOrder; use sorting::cmp_either_import; use types::EitherImport::{Import, ImportFrom}; use types::{AliasData, EitherImport, TrailingComma}; -use crate::line_width::{LineLength, LineWidth}; +use crate::line_width::LineWidthBuilder; use crate::rules::isort::categorize::KnownModules; use crate::rules::isort::types::ImportBlock; use crate::settings::types::PythonVersion; @@ -69,7 +70,7 @@ pub(crate) fn format_imports( comments: Vec, locator: &Locator, line_length: LineLength, - indentation_width: LineWidth, + indentation_width: LineWidthBuilder, stylist: &Stylist, src: &[PathBuf], package: Option<&Path>, @@ -179,7 +180,7 @@ pub(crate) fn format_imports( fn format_import_block( block: ImportBlock, line_length: LineLength, - indentation_width: LineWidth, + indentation_width: LineWidthBuilder, stylist: &Stylist, src: &[PathBuf], package: Option<&Path>, diff --git a/crates/ruff/src/rules/isort/rules/organize_imports.rs b/crates/ruff/src/rules/isort/rules/organize_imports.rs index 3681ba1af61ff9..c5cd5d0d9da179 100644 --- a/crates/ruff/src/rules/isort/rules/organize_imports.rs +++ b/crates/ruff/src/rules/isort/rules/organize_imports.rs @@ -12,7 +12,7 @@ use ruff_python_trivia::{leading_indentation, textwrap::indent, PythonWhitespace use ruff_source_file::{Locator, UniversalNewlines}; use ruff_text_size::TextRange; -use crate::line_width::LineWidth; +use crate::line_width::LineWidthBuilder; use crate::registry::AsRule; use crate::settings::Settings; @@ -121,7 +121,7 @@ pub(crate) fn organize_imports( comments, locator, settings.line_length, - LineWidth::new(settings.tab_size).add_str(indentation), + LineWidthBuilder::new(settings.tab_size).add_str(indentation), stylist, &settings.src, package, diff --git a/crates/ruff/src/rules/pycodestyle/helpers.rs b/crates/ruff/src/rules/pycodestyle/helpers.rs index 46b728b2245338..37a1b17d49523a 100644 --- a/crates/ruff/src/rules/pycodestyle/helpers.rs +++ b/crates/ruff/src/rules/pycodestyle/helpers.rs @@ -3,10 +3,11 @@ use unicode_width::UnicodeWidthStr; use ruff_python_ast::node::AnyNodeRef; use ruff_python_ast::parenthesize::parenthesized_range; use ruff_python_ast::{CmpOp, Expr, Ranged}; +use ruff_python_trivia::LineLength; use ruff_source_file::{Line, Locator}; use ruff_text_size::{TextLen, TextRange}; -use crate::line_width::{LineLength, LineWidth, TabSize}; +use crate::line_width::{LineWidthBuilder, TabSize}; pub(super) fn is_ambiguous_name(name: &str) -> bool { name == "l" || name == "I" || name == "O" @@ -66,11 +67,11 @@ pub(super) fn is_overlong( // worst-case scenario is that the line is all tabs). If the maximum width is less than the // limit, then the line is not overlong. let max_width = line.len() * tab_size.as_usize(); - if max_width < limit.get() { + if max_width < limit.value() as usize { return None; } - let mut width = LineWidth::new(tab_size); + let mut width = LineWidthBuilder::new(tab_size); width = width.add_str(line.as_str()); if width <= limit { return None; @@ -95,14 +96,14 @@ pub(super) fn is_overlong( // begins before the limit. let last_chunk = chunks.last().unwrap_or(second_chunk); if last_chunk.contains("://") { - if width.get() - last_chunk.width() <= limit.get() { + if width.get() - last_chunk.width() <= limit.value() as usize { return None; } } // Obtain the start offset of the part of the line that exceeds the limit let mut start_offset = line.start(); - let mut start_width = LineWidth::new(tab_size); + let mut start_width = LineWidthBuilder::new(tab_size); for c in line.chars() { if start_width < limit { start_offset += c.text_len(); diff --git a/crates/ruff/src/rules/pycodestyle/mod.rs b/crates/ruff/src/rules/pycodestyle/mod.rs index 95495cbae70a93..b7f50848ab4f48 100644 --- a/crates/ruff/src/rules/pycodestyle/mod.rs +++ b/crates/ruff/src/rules/pycodestyle/mod.rs @@ -10,9 +10,9 @@ mod tests { use std::path::Path; use anyhow::Result; + use ruff_python_trivia::LineLength; use test_case::test_case; - use crate::line_width::LineLength; use crate::registry::Rule; use crate::test::test_path; use crate::{assert_messages, settings}; @@ -170,7 +170,7 @@ mod tests { Path::new("pycodestyle/W505.py"), &settings::Settings { pycodestyle: Settings { - max_doc_length: Some(LineLength::from(50)), + max_doc_length: Some(LineLength::try_from(50).unwrap()), ..Settings::default() }, ..settings::Settings::for_rule(Rule::DocLineTooLong) @@ -186,7 +186,7 @@ mod tests { Path::new("pycodestyle/W505_utf_8.py"), &settings::Settings { pycodestyle: Settings { - max_doc_length: Some(LineLength::from(50)), + max_doc_length: Some(LineLength::try_from(50).unwrap()), ..Settings::default() }, ..settings::Settings::for_rule(Rule::DocLineTooLong) @@ -206,7 +206,7 @@ mod tests { Path::new("pycodestyle/E501_2.py"), &settings::Settings { tab_size: NonZeroU8::new(tab_size).unwrap().into(), - line_length: LineLength::from(6), + line_length: LineLength::try_from(6).unwrap(), ..settings::Settings::for_rule(Rule::LineTooLong) }, )?; diff --git a/crates/ruff/src/rules/pycodestyle/rules/doc_line_too_long.rs b/crates/ruff/src/rules/pycodestyle/rules/doc_line_too_long.rs index caaaa2032c0abd..0faa662370d358 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/doc_line_too_long.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/doc_line_too_long.rs @@ -78,7 +78,7 @@ pub(crate) fn doc_line_too_long(line: &Line, settings: &Settings) -> Option Option offset = 0 // ``` let offset = if idx == 0 { col_offset.to_usize() } else { 0 }; - offset + line.chars().count() > line_length.get() + offset + line.chars().count() > line_length.value() as usize }) { return; } diff --git a/crates/ruff/src/settings/configuration.rs b/crates/ruff/src/settings/configuration.rs index d673fdd1109d34..6c4797d5028214 100644 --- a/crates/ruff/src/settings/configuration.rs +++ b/crates/ruff/src/settings/configuration.rs @@ -9,11 +9,12 @@ use std::path::{Path, PathBuf}; use anyhow::{anyhow, Result}; use glob::{glob, GlobError, Paths, PatternError}; use regex::Regex; +use ruff_python_trivia::LineLength; use shellexpand; use shellexpand::LookupError; use crate::fs; -use crate::line_width::{LineLength, TabSize}; +use crate::line_width::TabSize; use crate::rule_selector::RuleSelector; use crate::rules::{ flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_comprehensions, diff --git a/crates/ruff/src/settings/defaults.rs b/crates/ruff/src/settings/defaults.rs index a7ef3d3b88e672..91846e7270a763 100644 --- a/crates/ruff/src/settings/defaults.rs +++ b/crates/ruff/src/settings/defaults.rs @@ -1,13 +1,14 @@ use once_cell::sync::Lazy; use path_absolutize::path_dedot; use regex::Regex; +use ruff_python_trivia::LineLength; use rustc_hash::FxHashSet; use std::collections::HashSet; use super::types::{FilePattern, PythonVersion}; use super::Settings; use crate::codes::{self, RuleCodePrefix}; -use crate::line_width::{LineLength, TabSize}; +use crate::line_width::TabSize; use crate::registry::Linter; use crate::rule_selector::{prefix_to_selector, RuleSelector}; use crate::rules::{ diff --git a/crates/ruff/src/settings/mod.rs b/crates/ruff/src/settings/mod.rs index 12bbd983347bcd..7af84bf2e8557f 100644 --- a/crates/ruff/src/settings/mod.rs +++ b/crates/ruff/src/settings/mod.rs @@ -12,6 +12,7 @@ use strum::IntoEnumIterator; use ruff_cache::cache_dir; use ruff_macros::CacheKey; +use ruff_python_trivia::LineLength; use crate::registry::{Rule, RuleNamespace, RuleSet, INCOMPATIBLE_CODES}; use crate::rule_selector::{RuleSelector, Specificity}; @@ -27,7 +28,7 @@ use crate::settings::types::{FilePatternSet, PerFileIgnore, PythonVersion, Seria use crate::warn_user_once_by_id; use self::rule_table::RuleTable; -use super::line_width::{LineLength, TabSize}; +use super::line_width::TabSize; pub mod configuration; pub mod defaults; diff --git a/crates/ruff/src/settings/options.rs b/crates/ruff/src/settings/options.rs index d7e6c67edfb8ea..7d1b3ebf4fa660 100644 --- a/crates/ruff/src/settings/options.rs +++ b/crates/ruff/src/settings/options.rs @@ -4,8 +4,9 @@ use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use ruff_macros::ConfigurationOptions; +use ruff_python_trivia::LineLength; -use crate::line_width::{LineLength, TabSize}; +use crate::line_width::TabSize; use crate::rule_selector::RuleSelector; use crate::rules::{ flake8_annotations, flake8_bandit, flake8_bugbear, flake8_builtins, flake8_comprehensions, diff --git a/crates/ruff/src/settings/pyproject.rs b/crates/ruff/src/settings/pyproject.rs index 6c6df45ed7399e..d017e645d942c1 100644 --- a/crates/ruff/src/settings/pyproject.rs +++ b/crates/ruff/src/settings/pyproject.rs @@ -148,10 +148,10 @@ mod tests { use std::str::FromStr; use anyhow::Result; + use ruff_python_trivia::LineLength; use rustc_hash::FxHashMap; use crate::codes::{self, RuleCodePrefix}; - use crate::line_width::LineLength; use crate::settings::pyproject::{ find_settings_toml, parse_pyproject_toml, Options, Pyproject, Tools, }; @@ -194,7 +194,7 @@ line-length = 79 pyproject.tool, Some(Tools { ruff: Some(Options { - line_length: Some(LineLength::from(79)), + line_length: Some(LineLength::try_from(79).unwrap()), ..Options::default() }) }) @@ -294,7 +294,7 @@ other-attribute = 1 assert_eq!( config, Options { - line_length: Some(LineLength::from(88)), + line_length: Some(LineLength::try_from(88).unwrap()), extend_exclude: Some(vec![ "excluded_file.py".to_string(), "migrations".to_string(), diff --git a/crates/ruff_cli/src/args.rs b/crates/ruff_cli/src/args.rs index aa299cad602c6d..fb36ff0ea2251e 100644 --- a/crates/ruff_cli/src/args.rs +++ b/crates/ruff_cli/src/args.rs @@ -5,7 +5,6 @@ use clap::{command, Parser}; use regex::Regex; use rustc_hash::FxHashMap; -use ruff::line_width::LineLength; use ruff::logging::LogLevel; use ruff::registry::Rule; use ruff::resolver::ConfigProcessor; @@ -14,6 +13,7 @@ use ruff::settings::types::{ FilePattern, PatternPrefixPair, PerFileIgnore, PythonVersion, SerializationFormat, }; use ruff::RuleSelector; +use ruff_python_trivia::LineLength; #[derive(Debug, Parser)] #[command( @@ -256,7 +256,7 @@ pub struct CheckArgs { /// Set the line-length for length-associated rules and automatic /// formatting. #[arg(long, help_heading = "Rule configuration", hide = true)] - pub line_length: Option, + pub line_length: Option, /// Regular expression matching the name of dummy variables. #[arg(long, help_heading = "Rule configuration", hide = true)] pub dummy_variable_rgx: Option, @@ -497,7 +497,7 @@ pub struct Overrides { pub extend_unfixable: Option>, pub fixable: Option>, pub ignore: Option>, - pub line_length: Option, + pub line_length: Option, pub per_file_ignores: Option>, pub respect_gitignore: Option, pub select: Option>, @@ -560,7 +560,7 @@ impl ConfigProcessor for &Overrides { config.force_exclude = Some(*force_exclude); } if let Some(line_length) = &self.line_length { - config.line_length = Some(LineLength::from(*line_length)); + config.line_length = Some(*line_length); } if let Some(per_file_ignores) = &self.per_file_ignores { config.per_file_ignores = Some(collect_per_file_ignores(per_file_ignores.clone())); diff --git a/crates/ruff_cli/src/commands/format.rs b/crates/ruff_cli/src/commands/format.rs index c6a02f7ceabca3..34727dad8b1c7e 100644 --- a/crates/ruff_cli/src/commands/format.rs +++ b/crates/ruff_cli/src/commands/format.rs @@ -7,7 +7,6 @@ use anyhow::bail; use colored::Colorize; use rayon::iter::{IntoParallelIterator, ParallelIterator}; use ruff::resolver::python_files_in_path; -use ruff_formatter::LineWidth; use ruff_python_ast::PySourceType; use ruff_python_formatter::{format_module, FormatModuleError, PyFormatOptions}; use std::io; @@ -55,13 +54,8 @@ pub(crate) fn format(cli: &Arguments, overrides: &Overrides) -> anyhow::Result PyFormatOptions { PyFormatOptions::from_extension(file) .with_line_width( - LineWidth::try_from(self.line_length).expect("Invalid line length limit"), + LineLength::try_from(self.line_length).expect("Invalid line length limit"), ) .with_magic_trailing_comma(if self.skip_magic_trailing_comma { MagicTrailingComma::Ignore @@ -910,8 +911,9 @@ mod tests { use indoc::indoc; - use ruff_formatter::{FormatOptions, LineWidth}; + use ruff_formatter::FormatOptions; use ruff_python_formatter::MagicTrailingComma; + use ruff_python_trivia::LineLength; use crate::format_dev::BlackOptions; @@ -925,7 +927,7 @@ mod tests { let options = BlackOptions::from_toml(toml, Path::new("pyproject.toml")) .unwrap() .to_py_format_options(Path::new("code_inline.py")); - assert_eq!(options.line_width(), LineWidth::try_from(119).unwrap()); + assert_eq!(options.line_width(), LineLength::try_from(119).unwrap()); assert!(matches!( options.magic_trailing_comma(), MagicTrailingComma::Respect @@ -944,7 +946,7 @@ mod tests { let options = BlackOptions::from_toml(toml, Path::new("pyproject.toml")) .unwrap() .to_py_format_options(Path::new("code_inline.py")); - assert_eq!(options.line_width(), LineWidth::try_from(130).unwrap()); + assert_eq!(options.line_width(), LineLength::try_from(130).unwrap()); assert!(matches!( options.magic_trailing_comma(), MagicTrailingComma::Ignore diff --git a/crates/ruff_formatter/Cargo.toml b/crates/ruff_formatter/Cargo.toml index a4cf1781966fd0..a4e0c88863a7d6 100644 --- a/crates/ruff_formatter/Cargo.toml +++ b/crates/ruff_formatter/Cargo.toml @@ -11,6 +11,7 @@ repository = { workspace = true } license = { workspace = true } [dependencies] +ruff_python_trivia = { path = "../ruff_python_trivia" } ruff_text_size = { path = "../ruff_text_size" } drop_bomb = { version = "0.1.5" } diff --git a/crates/ruff_formatter/src/builders.rs b/crates/ruff_formatter/src/builders.rs index 881a80e557cd6a..de103d069dccd8 100644 --- a/crates/ruff_formatter/src/builders.rs +++ b/crates/ruff_formatter/src/builders.rs @@ -40,12 +40,13 @@ use Tag::*; /// /// Soft line breaks are emitted if the enclosing `Group` doesn't fit on a single line /// ``` -/// use ruff_formatter::{format, format_args, LineWidth, SimpleFormatOptions}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{format, format_args, SimpleFormatOptions}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { /// let context = SimpleFormatContext::new(SimpleFormatOptions { -/// line_width: LineWidth::try_from(10).unwrap(), +/// line_width: LineLength::try_from(10).unwrap(), /// ..SimpleFormatOptions::default() /// }); /// @@ -161,12 +162,13 @@ pub const fn empty_line() -> Line { /// /// The printer breaks the lines if the enclosing `Group` doesn't fit on a single line: /// ``` -/// use ruff_formatter::{format_args, format, LineWidth, SimpleFormatOptions}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{format_args, format, SimpleFormatOptions}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { /// let context = SimpleFormatContext::new(SimpleFormatOptions { -/// line_width: LineWidth::try_from(10).unwrap(), +/// line_width: LineLength::try_from(10).unwrap(), /// ..SimpleFormatOptions::default() /// }); /// @@ -537,8 +539,9 @@ impl Format for LineSuffixBoundary { /// ## Examples /// /// ```rust +/// use ruff_python_trivia::LineLength; /// use ruff_formatter::prelude::*; -/// use ruff_formatter::{format, write, LineWidth}; +/// use ruff_formatter::{format, write}; /// /// #[derive(Debug, Copy, Clone)] /// enum MyLabels { @@ -1038,12 +1041,13 @@ pub fn block_indent(content: &impl Format) -> BlockIndent FormatResult<()> { /// let context = SimpleFormatContext::new(SimpleFormatOptions { -/// line_width: LineWidth::try_from(10).unwrap(), +/// line_width: LineLength::try_from(10).unwrap(), /// ..SimpleFormatOptions::default() /// }); /// @@ -1112,12 +1116,13 @@ pub fn soft_block_indent(content: &impl Format) -> BlockIndent /// fit on a single line. Otherwise, just inserts a space. /// /// ``` -/// use ruff_formatter::{format, format_args, LineWidth, SimpleFormatOptions}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{format, format_args, SimpleFormatOptions}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { /// let context = SimpleFormatContext::new(SimpleFormatOptions { -/// line_width: LineWidth::try_from(10).unwrap(), +/// line_width: LineLength::try_from(10).unwrap(), /// ..SimpleFormatOptions::default() /// }); /// @@ -1244,12 +1249,13 @@ impl std::fmt::Debug for BlockIndent<'_, Context> { /// Adds line breaks and indents the content if the enclosing group doesn't fit on the line. /// /// ``` -/// use ruff_formatter::{format, format_args, LineWidth, SimpleFormatOptions}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{format, format_args, SimpleFormatOptions}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { /// let context = SimpleFormatContext::new(SimpleFormatOptions { -/// line_width: LineWidth::try_from(10).unwrap(), +/// line_width: LineLength::try_from(10).unwrap(), /// ..SimpleFormatOptions::default() /// }); /// @@ -1349,12 +1355,13 @@ pub fn soft_space_or_block_indent(content: &impl Format) -> Bl /// /// The printer breaks the `Group` over multiple lines if its content doesn't fit on a single line /// ``` -/// use ruff_formatter::{format, format_args, LineWidth, SimpleFormatOptions}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{format, format_args, SimpleFormatOptions}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { /// let context = SimpleFormatContext::new(SimpleFormatOptions { -/// line_width: LineWidth::try_from(20).unwrap(), +/// line_width: LineLength::try_from(20).unwrap(), /// ..SimpleFormatOptions::default() /// }); /// @@ -1454,7 +1461,8 @@ impl std::fmt::Debug for Group<'_, Context> { /// /// ``` /// # use ruff_formatter::prelude::*; -/// # use ruff_formatter::{format, format_args, LineWidth, SimpleFormatOptions}; +/// use ruff_python_trivia::LineLength; +/// # use ruff_formatter::{format, format_args, SimpleFormatOptions}; /// /// # fn main() -> FormatResult<()> { /// use ruff_formatter::Formatted; @@ -1502,7 +1510,7 @@ impl std::fmt::Debug for Group<'_, Context> { /// /// // All content fits /// let all_fits = Formatted::new(document.clone(), SimpleFormatContext::new(SimpleFormatOptions { -/// line_width: LineWidth::try_from(65).unwrap(), +/// line_width: LineLength::try_from(65).unwrap(), /// ..SimpleFormatOptions::default() /// })); /// @@ -1513,7 +1521,7 @@ impl std::fmt::Debug for Group<'_, Context> { /// /// // The parentheses group fits, because it can expand the list, /// let list_expanded = Formatted::new(document.clone(), SimpleFormatContext::new(SimpleFormatOptions { -/// line_width: LineWidth::try_from(21).unwrap(), +/// line_width: LineLength::try_from(21).unwrap(), /// ..SimpleFormatOptions::default() /// })); /// @@ -1524,7 +1532,7 @@ impl std::fmt::Debug for Group<'_, Context> { /// /// // It is necessary to split all groups to fit the content /// let all_expanded = Formatted::new(document, SimpleFormatContext::new(SimpleFormatOptions { -/// line_width: LineWidth::try_from(11).unwrap(), +/// line_width: LineLength::try_from(11).unwrap(), /// ..SimpleFormatOptions::default() /// })); /// @@ -1583,7 +1591,8 @@ impl std::fmt::Debug for ConditionalGroup<'_, Context> { /// ## Examples /// /// ``` -/// use ruff_formatter::{format, format_args, LineWidth}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{format, format_args}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { @@ -1668,13 +1677,14 @@ impl Format for ExpandParent { /// /// Prints the trailing comma for the last array element if the `Group` doesn't fit on a single line /// ``` -/// use ruff_formatter::{format_args, format, LineWidth, SimpleFormatOptions}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{format_args, format, SimpleFormatOptions}; /// use ruff_formatter::prelude::*; /// use ruff_formatter::printer::PrintWidth; /// /// fn main() -> FormatResult<()> { /// let context = SimpleFormatContext::new(SimpleFormatOptions { -/// line_width: LineWidth::try_from(20).unwrap(), +/// line_width: LineLength::try_from(20).unwrap(), /// ..SimpleFormatOptions::default() /// }); /// @@ -1750,12 +1760,13 @@ where /// /// Omits the trailing comma for the last array element if the `Group` doesn't fit on a single line /// ``` -/// use ruff_formatter::{format, format_args, LineWidth, SimpleFormatOptions}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{format, format_args, SimpleFormatOptions}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { /// let context = SimpleFormatContext::new(SimpleFormatOptions { -/// line_width: LineWidth::try_from(20).unwrap(), +/// line_width: LineLength::try_from(20).unwrap(), /// ..SimpleFormatOptions::default() /// }); /// @@ -1812,12 +1823,13 @@ impl IfGroupBreaks<'_, Context> { /// The item `[4]` in this example fits on a single line but the trailing comma should still be printed /// /// ``` - /// use ruff_formatter::{format, format_args, write, LineWidth, SimpleFormatOptions}; + /// use ruff_python_trivia::LineLength; + /// use ruff_formatter::{format, format_args, write, SimpleFormatOptions}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { /// let context = SimpleFormatContext::new(SimpleFormatOptions { - /// line_width: LineWidth::try_from(20).unwrap(), + /// line_width: LineLength::try_from(20).unwrap(), /// ..SimpleFormatOptions::default() /// }); /// @@ -1915,7 +1927,8 @@ impl std::fmt::Debug for IfGroupBreaks<'_, Context> { /// /// Indent the body of an arrow function if the group wrapping the signature breaks: /// ``` -/// use ruff_formatter::{format, format_args, LineWidth, SimpleFormatOptions, write}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{format, format_args, SimpleFormatOptions, write}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { @@ -1929,7 +1942,7 @@ impl std::fmt::Debug for IfGroupBreaks<'_, Context> { /// }); /// /// let context = SimpleFormatContext::new(SimpleFormatOptions { -/// line_width: LineWidth::try_from(20).unwrap(), +/// line_width: LineLength::try_from(20).unwrap(), /// ..SimpleFormatOptions::default() /// }); /// @@ -1945,7 +1958,8 @@ impl std::fmt::Debug for IfGroupBreaks<'_, Context> { /// /// It doesn't add an indent if the group wrapping the signature doesn't break: /// ``` -/// use ruff_formatter::{format, format_args, LineWidth, SimpleFormatOptions, write}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{format, format_args, SimpleFormatOptions, write}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { @@ -2017,7 +2031,8 @@ impl std::fmt::Debug for IndentIfGroupBreaks<'_, Context> { /// that spans multiple lines. /// /// ``` -/// # use ruff_formatter::{format, format_args, LineWidth, SimpleFormatOptions, write}; +/// use ruff_python_trivia::LineLength; +/// # use ruff_formatter::{format, format_args, SimpleFormatOptions, write}; /// # use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { @@ -2432,7 +2447,8 @@ impl<'a, Context> BestFitting<'a, Context> { /// ### All Lines /// /// ``` - /// use ruff_formatter::{Formatted, LineWidth, format, format_args, SimpleFormatOptions}; + /// use ruff_python_trivia::LineLength; + /// use ruff_formatter::{Formatted, format, format_args, SimpleFormatOptions}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { diff --git a/crates/ruff_formatter/src/format_element/document.rs b/crates/ruff_formatter/src/format_element/document.rs index 42bc2b1f39961f..8efa835a260975 100644 --- a/crates/ruff_formatter/src/format_element/document.rs +++ b/crates/ruff_formatter/src/format_element/document.rs @@ -7,7 +7,7 @@ use crate::source_code::SourceCode; use crate::{format, write}; use crate::{ BufferExtensions, Format, FormatContext, FormatElement, FormatOptions, FormatResult, Formatter, - IndentStyle, LineWidth, PrinterOptions, + IndentStyle, LineLength, PrinterOptions, }; use rustc_hash::FxHashMap; use std::collections::HashMap; @@ -215,8 +215,8 @@ impl FormatOptions for IrFormatOptions { IndentStyle::Space(2) } - fn line_width(&self) -> LineWidth { - LineWidth(80) + fn line_width(&self) -> LineLength { + LineLength::default() } fn as_print_options(&self) -> PrinterOptions { @@ -794,7 +794,7 @@ mod tests { soft_block_indent(&format_args![ text("Some longer content"), space(), - text("That should ultimately break"), + text("That should ultimately break for its length"), ]) ])] ) @@ -811,7 +811,7 @@ mod tests { "(", indent([ soft_line_break, - "Some longer content That should ultimately break" + "Some longer content That should ultimately break for its length" ]), soft_line_break ]) @@ -837,7 +837,7 @@ mod tests { #[test] fn display_elements_with_source_text_slice() { - let source_code = "Some longer content\nThat should ultimately break"; + let source_code = "Some longer content\nThat should ultimately break for its length"; let formatted = format!( SimpleFormatContext::default().with_source_code(source_code), [format_with(|f| { @@ -852,7 +852,7 @@ mod tests { ), space(), source_text_slice( - TextRange::at(TextSize::new(20), TextSize::new(28)), + TextRange::at(TextSize::new(20), TextSize::new(43)), ContainsNewlines::No ), ]) @@ -871,7 +871,7 @@ mod tests { "(", indent([ soft_line_break, - "Some longer content That should ultimately break" + "Some longer content That should ultimately break for its length" ]), soft_line_break ]) diff --git a/crates/ruff_formatter/src/lib.rs b/crates/ruff_formatter/src/lib.rs index 4f9f83827091a3..b333466a7183af 100644 --- a/crates/ruff_formatter/src/lib.rs +++ b/crates/ruff_formatter/src/lib.rs @@ -50,8 +50,8 @@ pub use source_code::{SourceCode, SourceCodeSlice}; pub use crate::diagnostics::{ActualStart, FormatError, InvalidDocumentError, PrintError}; pub use format_element::{normalize_newlines, FormatElement, LINE_TERMINATORS}; pub use group_id::GroupId; +use ruff_python_trivia::LineLength; use ruff_text_size::{TextRange, TextSize}; -use std::num::ParseIntError; use std::str::FromStr; #[derive(Debug, Eq, PartialEq, Clone, Copy, Hash)] @@ -108,95 +108,6 @@ impl std::fmt::Display for IndentStyle { } } -/// Validated value for the `line_width` formatter options -/// -/// The allowed range of values is 1..=320 -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -pub struct LineWidth(u16); - -impl LineWidth { - /// Maximum allowed value for a valid [`LineWidth`] - pub const MAX: u16 = 320; - - /// Return the numeric value for this [`LineWidth`] - pub fn value(&self) -> u16 { - self.0 - } -} - -impl Default for LineWidth { - fn default() -> Self { - Self(80) - } -} - -/// Error type returned when parsing a [`LineWidth`] from a string fails -pub enum ParseLineWidthError { - /// The string could not be parsed as a valid [u16] - ParseError(ParseIntError), - /// The [u16] value of the string is not a valid [LineWidth] - TryFromIntError(LineWidthFromIntError), -} - -impl Debug for ParseLineWidthError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(self, f) - } -} - -impl std::fmt::Display for ParseLineWidthError { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ParseLineWidthError::ParseError(err) => std::fmt::Display::fmt(err, fmt), - ParseLineWidthError::TryFromIntError(err) => std::fmt::Display::fmt(err, fmt), - } - } -} - -impl FromStr for LineWidth { - type Err = ParseLineWidthError; - - fn from_str(s: &str) -> Result { - let value = u16::from_str(s).map_err(ParseLineWidthError::ParseError)?; - let value = Self::try_from(value).map_err(ParseLineWidthError::TryFromIntError)?; - Ok(value) - } -} - -/// Error type returned when converting a u16 to a [`LineWidth`] fails -#[derive(Clone, Copy, Debug)] -pub struct LineWidthFromIntError(pub u16); - -impl TryFrom for LineWidth { - type Error = LineWidthFromIntError; - - fn try_from(value: u16) -> Result { - if value > 0 && value <= Self::MAX { - Ok(Self(value)) - } else { - Err(LineWidthFromIntError(value)) - } - } -} - -impl std::fmt::Display for LineWidthFromIntError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - writeln!( - f, - "The line width exceeds the maximum value ({})", - LineWidth::MAX - ) - } -} - -impl From for u16 { - fn from(value: LineWidth) -> Self { - value.0 - } -} - /// Context object storing data relevant when formatting an object. pub trait FormatContext { type Options: FormatOptions; @@ -214,7 +125,7 @@ pub trait FormatOptions { fn indent_style(&self) -> IndentStyle; /// What's the max width of a line. Defaults to 80. - fn line_width(&self) -> LineWidth; + fn line_width(&self) -> LineLength; /// Derives the print options from the these format options fn as_print_options(&self) -> PrinterOptions; @@ -256,7 +167,7 @@ impl FormatContext for SimpleFormatContext { #[derive(Debug, Default, Eq, PartialEq, Clone)] pub struct SimpleFormatOptions { pub indent_style: IndentStyle, - pub line_width: LineWidth, + pub line_width: LineLength, } impl FormatOptions for SimpleFormatOptions { @@ -264,7 +175,7 @@ impl FormatOptions for SimpleFormatOptions { self.indent_style } - fn line_width(&self) -> LineWidth { + fn line_width(&self) -> LineLength { self.line_width } @@ -444,7 +355,8 @@ pub type FormatResult = Result; /// Implementing `Format` for a custom struct /// /// ``` -/// use ruff_formatter::{format, write, IndentStyle, LineWidth}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{format, write, IndentStyle}; /// use ruff_formatter::prelude::*; /// use ruff_text_size::TextSize; /// diff --git a/crates/ruff_formatter/src/macros.rs b/crates/ruff_formatter/src/macros.rs index 2e6b28bf235452..20c82e9595f4f1 100644 --- a/crates/ruff_formatter/src/macros.rs +++ b/crates/ruff_formatter/src/macros.rs @@ -153,7 +153,8 @@ macro_rules! format { /// ## Examples /// /// ``` -/// use ruff_formatter::{Formatted, LineWidth, format, format_args, SimpleFormatOptions}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{Formatted, format, format_args, SimpleFormatOptions}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { @@ -241,7 +242,8 @@ macro_rules! format { /// ### Enclosing group with `should_expand: true` /// /// ``` -/// use ruff_formatter::{Formatted, LineWidth, format, format_args, SimpleFormatOptions}; +/// use ruff_python_trivia::LineLength; +/// use ruff_formatter::{Formatted, format, format_args, SimpleFormatOptions}; /// use ruff_formatter::prelude::*; /// /// # fn main() -> FormatResult<()> { diff --git a/crates/ruff_formatter/src/printer/printer_options/mod.rs b/crates/ruff_formatter/src/printer/printer_options/mod.rs index d68f60ef2ed3f2..d2f8efea17b806 100644 --- a/crates/ruff_formatter/src/printer/printer_options/mod.rs +++ b/crates/ruff_formatter/src/printer/printer_options/mod.rs @@ -1,4 +1,4 @@ -use crate::{FormatOptions, IndentStyle, LineWidth}; +use crate::{FormatOptions, IndentStyle, LineLength}; /// Options that affect how the [`crate::Printer`] prints the format tokens #[derive(Clone, Debug, Eq, PartialEq)] @@ -27,12 +27,12 @@ impl PrintWidth { impl Default for PrintWidth { fn default() -> Self { - LineWidth::default().into() + LineLength::default().into() } } -impl From for PrintWidth { - fn from(width: LineWidth) -> Self { +impl From for PrintWidth { + fn from(width: LineLength) -> Self { Self(u32::from(u16::from(width))) } } diff --git a/crates/ruff_python_formatter/Cargo.toml b/crates/ruff_python_formatter/Cargo.toml index e63bbeb8720b75..55ea7c763fa4ba 100644 --- a/crates/ruff_python_formatter/Cargo.toml +++ b/crates/ruff_python_formatter/Cargo.toml @@ -48,5 +48,5 @@ test = true required-features = ["serde"] [features] -serde = ["dep:serde", "ruff_formatter/serde", "ruff_source_file/serde", "ruff_python_ast/serde"] +serde = ["dep:serde", "ruff_formatter/serde", "ruff_source_file/serde", "ruff_python_ast/serde", "ruff_python_trivia/serde"] default = ["serde"] diff --git a/crates/ruff_python_formatter/src/options.rs b/crates/ruff_python_formatter/src/options.rs index ee427fd3128290..6b772d30ed4457 100644 --- a/crates/ruff_python_formatter/src/options.rs +++ b/crates/ruff_python_formatter/src/options.rs @@ -1,6 +1,7 @@ use ruff_formatter::printer::{LineEnding, PrinterOptions}; -use ruff_formatter::{FormatOptions, IndentStyle, LineWidth}; +use ruff_formatter::{FormatOptions, IndentStyle}; use ruff_python_ast::PySourceType; +use ruff_python_trivia::LineLength; use std::path::Path; use std::str::FromStr; @@ -22,7 +23,7 @@ pub struct PyFormatOptions { /// The preferred line width at which the formatter should wrap lines. #[cfg_attr(feature = "serde", serde(default = "default_line_width"))] - line_width: LineWidth, + line_width: LineLength, /// The preferred quote style to use (single vs double quotes). quote_style: QuoteStyle, @@ -31,8 +32,8 @@ pub struct PyFormatOptions { magic_trailing_comma: MagicTrailingComma, } -fn default_line_width() -> LineWidth { - LineWidth::try_from(88).unwrap() +fn default_line_width() -> LineLength { + LineLength::try_from(88).unwrap() } fn default_indent_style() -> IndentStyle { @@ -95,7 +96,7 @@ impl PyFormatOptions { } #[must_use] - pub fn with_line_width(mut self, line_width: LineWidth) -> Self { + pub fn with_line_width(mut self, line_width: LineLength) -> Self { self.line_width = line_width; self } @@ -106,7 +107,7 @@ impl FormatOptions for PyFormatOptions { self.indent_style } - fn line_width(&self) -> LineWidth { + fn line_width(&self) -> LineLength { self.line_width } diff --git a/crates/ruff_python_trivia/Cargo.toml b/crates/ruff_python_trivia/Cargo.toml index f0f9861e5ade3e..7ff1c2302a8af9 100644 --- a/crates/ruff_python_trivia/Cargo.toml +++ b/crates/ruff_python_trivia/Cargo.toml @@ -13,13 +13,20 @@ license = { workspace = true } [lib] [dependencies] -ruff_text_size = { path = "../ruff_text_size" } +ruff_cache = { path = "../ruff_cache" } ruff_source_file = { path = "../ruff_source_file" } +ruff_text_size = { path = "../ruff_text_size" } memchr = { workspace = true } +schemars = { workspace = true, optional = true } +serde = { workspace = true, optional = true } smallvec = { workspace = true } unic-ucd-ident = "0.9.0" +[features] +schemars = ["dep:schemars"] +serde = ["dep:serde"] + [dev-dependencies] insta = { workspace = true } ruff_python_ast = { path = "../ruff_python_ast" } diff --git a/crates/ruff_python_trivia/src/lib.rs b/crates/ruff_python_trivia/src/lib.rs index bef83ac26a079e..62f39b939c6111 100644 --- a/crates/ruff_python_trivia/src/lib.rs +++ b/crates/ruff_python_trivia/src/lib.rs @@ -1,8 +1,10 @@ mod cursor; +mod line_width; pub mod textwrap; mod tokenizer; mod whitespace; pub use cursor::*; +pub use line_width::LineLength; pub use tokenizer::*; pub use whitespace::*; diff --git a/crates/ruff_python_trivia/src/line_width.rs b/crates/ruff_python_trivia/src/line_width.rs new file mode 100644 index 00000000000000..8fc4ce740e38b2 --- /dev/null +++ b/crates/ruff_python_trivia/src/line_width.rs @@ -0,0 +1,103 @@ +use ruff_cache::{CacheKey, CacheKeyHasher}; +use std::error::Error; +use std::fmt::Debug; +use std::hash::Hasher; +use std::num::ParseIntError; +use std::str::FromStr; + +/// The length of a line of text that is considered too long. +/// +/// The allowed range of values is 1..=320 +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +pub struct LineLength(u16); + +impl LineLength { + /// Maximum allowed value for a valid [`LineLength`] + pub const MAX: u16 = 320; + + /// Return the numeric value for this [`LineLength`] + pub fn value(&self) -> u16 { + self.0 + } +} + +impl Default for LineLength { + fn default() -> Self { + Self(88) + } +} + +impl CacheKey for LineLength { + fn cache_key(&self, state: &mut CacheKeyHasher) { + state.write_u16(self.0); + } +} + +/// Error type returned when parsing a [`LineLength`] from a string fails +pub enum ParseLineWidthError { + /// The string could not be parsed as a valid [u16] + ParseError(ParseIntError), + /// The [u16] value of the string is not a valid [LineLength] + TryFromIntError(LineWidthFromIntError), +} + +impl Debug for ParseLineWidthError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} + +impl std::fmt::Display for ParseLineWidthError { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ParseLineWidthError::ParseError(err) => std::fmt::Display::fmt(err, fmt), + ParseLineWidthError::TryFromIntError(err) => std::fmt::Display::fmt(err, fmt), + } + } +} + +impl Error for ParseLineWidthError {} + +impl FromStr for LineLength { + type Err = ParseLineWidthError; + + fn from_str(s: &str) -> Result { + let value = u16::from_str(s).map_err(ParseLineWidthError::ParseError)?; + let value = Self::try_from(value).map_err(ParseLineWidthError::TryFromIntError)?; + Ok(value) + } +} + +/// Error type returned when converting a u16 to a [`LineLength`] fails +#[derive(Clone, Copy, Debug)] +pub struct LineWidthFromIntError(pub u16); + +impl TryFrom for LineLength { + type Error = LineWidthFromIntError; + + fn try_from(value: u16) -> Result { + if value > 0 && value <= Self::MAX { + Ok(Self(value)) + } else { + Err(LineWidthFromIntError(value)) + } + } +} + +impl std::fmt::Display for LineWidthFromIntError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!( + f, + "The line width exceeds the maximum value ({})", + LineLength::MAX + ) + } +} + +impl From for u16 { + fn from(value: LineLength) -> Self { + value.0 + } +} diff --git a/crates/ruff_text_size/Cargo.toml b/crates/ruff_text_size/Cargo.toml index d3ce1851678498..7878d5e16b5177 100644 --- a/crates/ruff_text_size/Cargo.toml +++ b/crates/ruff_text_size/Cargo.toml @@ -6,8 +6,8 @@ edition = "2021" rust-version = "1.67.1" [dependencies] -serde = { version="1.0.152", optional = true, default_features = false } -schemars = { version = "0.8.12", optional = true } +serde = { workspace = true, optional = true } +schemars = { workspace = true, optional = true } [dev-dependencies] serde_test = { version = "1.0.152" } @@ -19,4 +19,4 @@ serde = ["dep:serde"] [[test]] name = "serde" path = "tests/serde.rs" -required-features = ["serde"] \ No newline at end of file +required-features = ["serde"] diff --git a/crates/ruff_wasm/Cargo.toml b/crates/ruff_wasm/Cargo.toml index f3707a7362e2d4..8193bfbe72300e 100644 --- a/crates/ruff_wasm/Cargo.toml +++ b/crates/ruff_wasm/Cargo.toml @@ -25,6 +25,7 @@ ruff_python_codegen = { path = "../ruff_python_codegen" } ruff_python_formatter = { path = "../ruff_python_formatter" } ruff_python_index = { path = "../ruff_python_index" } ruff_python_parser = { path = "../ruff_python_parser" } +ruff_python_trivia = { path = "../ruff_python_trivia" } ruff_source_file = { path = "../ruff_source_file" } console_error_panic_hook = { version = "0.1.7", optional = true } diff --git a/crates/ruff_wasm/src/lib.rs b/crates/ruff_wasm/src/lib.rs index 602b18f552a216..7cb6de631225e3 100644 --- a/crates/ruff_wasm/src/lib.rs +++ b/crates/ruff_wasm/src/lib.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::*; use ruff::directives; -use ruff::line_width::{LineLength, TabSize}; +use ruff::line_width::TabSize; use ruff::linter::{check_path, LinterResult}; use ruff::registry::AsRule; use ruff::rules::{ @@ -27,6 +27,7 @@ use ruff_python_codegen::Stylist; use ruff_python_formatter::{format_module, format_node, PyFormatOptions}; use ruff_python_index::{CommentRangesBuilder, Indexer}; use ruff_python_parser::AsMode; +use ruff_python_trivia::LineLength; use ruff_source_file::{Locator, SourceLocation}; #[wasm_bindgen(typescript_custom_section)] diff --git a/ruff.schema.json b/ruff.schema.json index beb32b04ede191..9b97ac374b62b6 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -1386,9 +1386,9 @@ "additionalProperties": false }, "LineLength": { - "description": "The length of a line of text that is considered too long.", + "description": "The length of a line of text that is considered too long.\n\nThe allowed range of values is 1..=320", "type": "integer", - "format": "uint", + "format": "uint16", "minimum": 0.0 }, "McCabeOptions": {