From 451d494129a6733eba66d705c7b174a2bad2804e Mon Sep 17 00:00:00 2001 From: Jonathan Plasse <13716151+JonathanPlasse@users.noreply.github.com> Date: Mon, 22 May 2023 21:05:50 +0200 Subject: [PATCH] Separate LineWidth and LineLength implementation --- crates/ruff/src/message/text.rs | 9 +- .../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 | 8 +- crates/ruff/src/rules/isort/mod.rs | 6 +- .../src/rules/isort/rules/organize_imports.rs | 4 +- crates/ruff/src/rules/pycodestyle/helpers.rs | 8 +- .../pycodestyle/rules/doc_line_too_long.rs | 2 +- .../rules/pycodestyle/rules/line_too_long.rs | 7 +- crates/ruff/src/settings/line_width.rs | 168 ++++++------------ crates/ruff_wasm/src/lib.rs | 4 +- ruff.schema.json | 27 +-- 13 files changed, 93 insertions(+), 168 deletions(-) diff --git a/crates/ruff/src/message/text.rs b/crates/ruff/src/message/text.rs index f6fa00373fc164..f6ee1707c0bc3e 100644 --- a/crates/ruff/src/message/text.rs +++ b/crates/ruff/src/message/text.rs @@ -14,7 +14,7 @@ use crate::fs::relativize_path; use crate::message::diff::Diff; use crate::message::{Emitter, EmitterContext, Message}; use crate::registry::AsRule; -use crate::settings::line_width::{TabSize, Width}; +use crate::settings::line_width::{LineWidth, TabSize}; bitflags! { #[derive(Default)] @@ -243,15 +243,16 @@ 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 = Width::new(TAB_SIZE); + let mut line_width = LineWidth::new(TAB_SIZE); for (index, c) in source.char_indices() { - let old_width = line_width.width(); + let old_width = line_width.get(); line_width = line_width.add_char(c); if matches!(c, '\t') { + // SAFETY: The difference is a value in the range [1..TAB_SIZE] which is guaranteed to be less than `u32`. #[allow(clippy::cast_possible_truncation)] - let tab_width = (line_width.width() - old_width) as u32; + let tab_width = (line_width.get() - old_width) as u32; if index < usize::from(annotation_range.start()) { range += TextSize::new(tab_width - 1); 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 ca89c957dabbd6..264fa901441205 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_if.rs @@ -15,7 +15,7 @@ use ruff_python_semantic::model::SemanticModel; use crate::checkers::ast::Checker; use crate::registry::AsRule; use crate::rules::flake8_simplify::rules::fix_if; -use crate::settings::line_width::Width; +use crate::settings::line_width::LineWidth; fn compare_expr(expr1: &ComparableExpr, expr2: &ComparableExpr) -> bool { expr1.eq(expr2) @@ -289,7 +289,7 @@ pub(crate) fn nested_if_statements( .unwrap_or_default() .universal_newlines() .all(|line| { - Width::new(checker.settings.tab_size).add_str(&line) + LineWidth::new(checker.settings.tab_size).add_str(&line) <= checker.settings.line_length }) { @@ -511,7 +511,7 @@ pub(crate) fn use_ternary_operator(checker: &mut Checker, stmt: &Stmt, parent: O // Don't flag if the resulting expression would exceed the maximum line length. let line_start = checker.locator.line_start(stmt.start()); - if Width::new(checker.settings.tab_size) + if LineWidth::new(checker.settings.tab_size) .add_str(&checker.locator.contents()[TextRange::new(line_start, stmt.start())]) .add_str(&contents) > checker.settings.line_length @@ -867,7 +867,7 @@ pub(crate) fn use_dict_get_with_default( // Don't flag if the resulting expression would exceed the maximum line length. let line_start = checker.locator.line_start(stmt.start()); - if Width::new(checker.settings.tab_size) + if LineWidth::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/flake8_simplify/rules/ast_with.rs b/crates/ruff/src/rules/flake8_simplify/rules/ast_with.rs index 363e34e9dba583..3ca36f5acad96d 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/ast_with.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/ast_with.rs @@ -10,7 +10,7 @@ use ruff_python_ast::newlines::StrExt; use crate::checkers::ast::Checker; use crate::registry::AsRule; -use crate::settings::line_width::Width; +use crate::settings::line_width::LineWidth; use super::fix_with; @@ -112,7 +112,7 @@ pub(crate) fn multiple_with_statements( .unwrap_or_default() .universal_newlines() .all(|line| { - Width::new(checker.settings.tab_size).add_str(&line) + LineWidth::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 6b30bc4a58057b..1dc48cc3c42fd4 100644 --- a/crates/ruff/src/rules/flake8_simplify/rules/reimplemented_builtin.rs +++ b/crates/ruff/src/rules/flake8_simplify/rules/reimplemented_builtin.rs @@ -9,7 +9,7 @@ use ruff_python_ast::source_code::Generator; use crate::checkers::ast::Checker; use crate::registry::{AsRule, Rule}; -use crate::settings::line_width::Width; +use crate::settings::line_width::LineWidth; #[violation] pub struct ReimplementedBuiltin { @@ -224,7 +224,7 @@ pub(crate) fn convert_for_loop_to_any_all( // Don't flag if the resulting expression would exceed the maximum line length. let line_start = checker.locator.line_start(stmt.start()); - if Width::new(checker.settings.tab_size) + if LineWidth::new(checker.settings.tab_size) .add_str(&checker.locator.contents()[TextRange::new(line_start, stmt.start())]) .add_str(&contents) > checker.settings.line_length @@ -317,7 +317,7 @@ pub(crate) fn convert_for_loop_to_any_all( // Don't flag if the resulting expression would exceed the maximum line length. let line_start = checker.locator.line_start(stmt.start()); - if Width::new(checker.settings.tab_size) + if LineWidth::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 56f5fcec59323b..77c42190f6937f 100644 --- a/crates/ruff/src/rules/isort/format.rs +++ b/crates/ruff/src/rules/isort/format.rs @@ -1,6 +1,6 @@ use ruff_python_ast::source_code::Stylist; -use crate::settings::line_width::{LineLength, Width}; +use crate::settings::line_width::{LineLength, LineWidth}; use super::types::{AliasData, CommentSet, ImportFromData, Importable}; @@ -46,7 +46,7 @@ pub(crate) fn format_import_from( comments: &CommentSet, aliases: &[(AliasData, CommentSet)], line_length: LineLength, - indentation_width: Width, + indentation_width: LineWidth, stylist: &Stylist, force_wrap_aliases: bool, is_first: bool, @@ -103,8 +103,8 @@ fn format_single_line( aliases: &[(AliasData, CommentSet)], is_first: bool, stylist: &Stylist, - indentation_width: Width, -) -> (String, Width) { + indentation_width: LineWidth, +) -> (String, LineWidth) { 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 cba2e700f5ad9f..add62564486b7e 100644 --- a/crates/ruff/src/rules/isort/mod.rs +++ b/crates/ruff/src/rules/isort/mod.rs @@ -19,7 +19,7 @@ use types::{AliasData, EitherImport, TrailingComma}; use crate::rules::isort::categorize::KnownModules; use crate::rules::isort::types::ImportBlock; -use crate::settings::line_width::{LineLength, Width}; +use crate::settings::line_width::{LineLength, LineWidth}; use crate::settings::types::PythonVersion; mod annotate; @@ -67,7 +67,7 @@ pub(crate) fn format_imports( comments: Vec, locator: &Locator, line_length: LineLength, - indentation_width: Width, + indentation_width: LineWidth, stylist: &Stylist, src: &[PathBuf], package: Option<&Path>, @@ -166,7 +166,7 @@ pub(crate) fn format_imports( fn format_import_block( block: ImportBlock, line_length: LineLength, - indentation_width: Width, + indentation_width: LineWidth, 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 a677aed7bf918f..6d81c353f50b4d 100644 --- a/crates/ruff/src/rules/isort/rules/organize_imports.rs +++ b/crates/ruff/src/rules/isort/rules/organize_imports.rs @@ -14,7 +14,7 @@ use ruff_python_ast::source_code::{Indexer, Locator, Stylist}; use ruff_python_ast::whitespace::leading_space; use crate::registry::AsRule; -use crate::settings::line_width::Width; +use crate::settings::line_width::LineWidth; use crate::settings::Settings; use super::super::block::Block; @@ -118,7 +118,7 @@ pub(crate) fn organize_imports( comments, locator, settings.line_length, - Width::new(settings.tab_size).add_str(indentation), + LineWidth::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 063d3a62db68c8..9db4a18e16f863 100644 --- a/crates/ruff/src/rules/pycodestyle/helpers.rs +++ b/crates/ruff/src/rules/pycodestyle/helpers.rs @@ -5,7 +5,7 @@ use unicode_width::UnicodeWidthStr; use ruff_python_ast::newlines::Line; use ruff_python_ast::source_code::Generator; -use crate::settings::line_width::{LineLength, TabSize, Width}; +use crate::settings::line_width::{LineLength, LineWidth, TabSize}; pub(crate) fn is_ambiguous_name(name: &str) -> bool { name == "l" || name == "I" || name == "O" @@ -34,7 +34,7 @@ pub(super) fn is_overlong( tab_size: TabSize, ) -> Option { let mut start_offset = line.start(); - let mut width = Width::new(tab_size); + let mut width = LineWidth::new(tab_size); for c in line.chars() { if width < limit { @@ -66,14 +66,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.width() - last_chunk.width() <= limit.width() { + if width.get() - last_chunk.width() <= limit.get() { return None; } } Some(Overlong { range: TextRange::new(start_offset, line.end()), - width: width.width(), + width: width.get(), }) } 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 28928cacfedb50..74e94801631d74 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 @@ -52,7 +52,7 @@ pub(crate) fn doc_line_too_long(line: &Line, settings: &Settings) -> Option Option Self { - Self + Self(88) } } -#[derive(Clone, Copy, Default, CacheKey)] -pub struct TabInfos { - column: usize, - tab_size: TabSize, +impl LineLength { + pub const fn get(&self) -> usize { + self.0 + } } -impl LineWidthState for Length {} -impl LineWidthState for TabInfos {} +impl From for LineLength { + fn from(value: usize) -> Self { + Self(value) + } +} -#[derive(Clone, Copy, Debug, CacheKey)] -#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] -pub struct LineWidth { +#[derive(Clone, Copy, Debug)] +pub struct LineWidth { + /// The current width of the line. width: usize, - extra: S, + /// The current column of the line. + column: usize, + /// The tab width. + tab_size: TabSize, } -impl Default for LineWidth { +impl Default for LineWidth { fn default() -> Self { - Self { - width: 88, - extra: Length, - } + Self::new(TabSize::default()) } } -impl Default for LineWidth { - fn default() -> Self { - Self::new(TabSize::default()) +impl PartialEq for LineWidth { + fn eq(&self, other: &Self) -> bool { + self.width == other.width } } -impl LineWidth -where - S: LineWidthState, -{ - pub const fn width(&self) -> usize { - self.width +impl Eq for LineWidth {} + +impl PartialOrd for LineWidth { + fn partial_cmp(&self, other: &Self) -> Option { + self.width.partial_cmp(&other.width) + } +} + +impl Ord for LineWidth { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.width.cmp(&other.width) } } -impl LineWidth { +impl LineWidth { + pub fn get(&self) -> usize { + self.width + } + pub fn new(tab_size: TabSize) -> Self { LineWidth { width: 0, - extra: TabInfos { - column: 0, - tab_size, - }, + column: 0, + tab_size, } } fn update(mut self, chars: impl Iterator) -> Self { - let tab_size: usize = self.extra.tab_size.into(); + let tab_size: usize = self.tab_size.into(); for c in chars { match c { '\t' => { - let tab_offset = tab_size - (self.extra.column % tab_size); + let tab_offset = tab_size - (self.column % tab_size); self.width += tab_offset; - self.extra.column += tab_offset; + self.column += tab_offset; } '\n' | '\r' => { self.width = 0; - self.extra.column = 0; + self.column = 0; } _ => { self.width += c.width().unwrap_or(0); - self.extra.column += 1; + self.column += 1; } } } @@ -102,80 +109,20 @@ impl LineWidth { #[must_use] pub fn add_width(mut self, width: usize) -> Self { self.width += width; - self.extra.column += width; + self.column += width; self } } -impl PartialOrd> for LineWidth -where - S: LineWidthState, -{ - fn partial_cmp(&self, other: &LineWidth) -> Option { - self.width.partial_cmp(&other.width) - } -} - -impl PartialOrd> for LineWidth { - fn partial_cmp(&self, other: &LineWidth) -> Option { - self.width.partial_cmp(&other.width) +impl PartialEq for LineWidth { + fn eq(&self, other: &LineLength) -> bool { + self.width == other.0 } } -impl Ord for LineWidth -where - S: LineWidthState, -{ - fn cmp(&self, other: &LineWidth) -> std::cmp::Ordering { - self.width.cmp(&other.width) - } -} - -impl PartialEq> for LineWidth -where - S: LineWidthState, -{ - fn eq(&self, other: &LineWidth) -> bool { - self.width == other.width - } -} - -impl PartialEq> for LineWidth { - fn eq(&self, other: &LineWidth) -> bool { - self.width == other.width - } -} - -impl Eq for LineWidth where S: LineWidthState {} - -impl From for LineWidth { - fn from(width: usize) -> Self { - Self { - width, - ..Default::default() - } - } -} - -impl<'de> Deserialize<'de> for LineWidth { - fn deserialize(deserializer: D) -> Result, D::Error> - where - D: Deserializer<'de>, - { - let width = usize::deserialize(deserializer)?; - Ok(LineWidth { - width, - ..Default::default() - }) - } -} - -impl Serialize for LineWidth { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - usize::serialize(&self.width, serializer) +impl PartialOrd for LineWidth { + fn partial_cmp(&self, other: &LineLength) -> Option { + self.width.partial_cmp(&other.0) } } @@ -200,6 +147,3 @@ impl From for usize { tab_size.0 as usize } } - -pub type LineLength = LineWidth; -pub type Width = LineWidth; diff --git a/crates/ruff_wasm/src/lib.rs b/crates/ruff_wasm/src/lib.rs index 4af53442b126e1..e059008fda90fe 100644 --- a/crates/ruff_wasm/src/lib.rs +++ b/crates/ruff_wasm/src/lib.rs @@ -14,7 +14,7 @@ use ruff::rules::{ flake8_unused_arguments, isort, mccabe, pep8_naming, pycodestyle, pydocstyle, pylint, }; use ruff::settings::configuration::Configuration; -use ruff::settings::line_width::{LineWidth, TabSize}; +use ruff::settings::line_width::{LineLength, TabSize}; use ruff::settings::options::Options; use ruff::settings::{defaults, flags, Settings}; use ruff_diagnostics::Edit; @@ -103,7 +103,7 @@ pub fn defaultSettings() -> Result { extend_unfixable: Some(Vec::default()), external: Some(Vec::default()), ignore: Some(Vec::default()), - line_length: Some(LineWidth::default()), + line_length: Some(LineLength::default()), tab_size: Some(TabSize::default()), select: Some(defaults::PREFIXES.to_vec()), target_version: Some(defaults::TARGET_VERSION), diff --git a/ruff.schema.json b/ruff.schema.json index a55b96d48f0a27..1f98128279a0ac 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -368,7 +368,7 @@ "description": "The line length to use when enforcing long-lines violations (like `E501`).", "anyOf": [ { - "$ref": "#/definitions/LineWidth_for_Length" + "$ref": "#/definitions/LineLength" }, { "type": "null" @@ -1289,25 +1289,10 @@ }, "additionalProperties": false }, - "Length": { - "type": "null" - }, - "LineWidth_for_Length": { - "type": "object", - "required": [ - "extra", - "width" - ], - "properties": { - "extra": { - "$ref": "#/definitions/Length" - }, - "width": { - "type": "integer", - "format": "uint", - "minimum": 0.0 - } - } + "LineLength": { + "type": "integer", + "format": "uint", + "minimum": 0.0 }, "McCabeOptions": { "type": "object", @@ -1396,7 +1381,7 @@ "description": "The maximum line length to allow for line-length violations within documentation (`W505`), including standalone comments.", "anyOf": [ { - "$ref": "#/definitions/LineWidth_for_Length" + "$ref": "#/definitions/LineLength" }, { "type": "null"