diff --git a/crates/ruff/resources/test/fixtures/pycodestyle/E501.py b/crates/ruff/resources/test/fixtures/pycodestyle/E501.py index 9126b341ab7307..274cf369c201d4 100644 --- a/crates/ruff/resources/test/fixtures/pycodestyle/E501.py +++ b/crates/ruff/resources/test/fixtures/pycodestyle/E501.py @@ -56,7 +56,27 @@ def caller(string: str) -> None: # OK # https://loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong.url.com -# Not OK +# OK _ = """ Source: https://github.com/PyCQA/pycodestyle/pull/258/files#diff-841c622497a8033d10152bfdfb15b20b92437ecdea21a260944ea86b77b51533 """ + +# OK +_ = """ +[this-is-ok](https://github.com/PyCQA/pycodestyle/pull/258/files#diff-841c622497a8033d10152bfdfb15b20b92437ecdea21a260944ea86b77b51533) +[this is ok](https://github.com/PyCQA/pycodestyle/pull/258/files#diff-841c622497a8033d10152bfdfb15b20b92437ecdea21a260944ea86b77b51533) +""" + + +# OK +class Foo: + """ + @see https://looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong.url.com + """ + + +# Error +class Bar: + """ + This is a long sentence that ends with a shortened URL and, therefore, could easily be broken across multiple lines ([source](https://ruff.rs)) + """ diff --git a/crates/ruff/src/rules/pycodestyle/helpers.rs b/crates/ruff/src/rules/pycodestyle/helpers.rs index aaae17b643cf50..ea9593fb8f2af7 100644 --- a/crates/ruff/src/rules/pycodestyle/helpers.rs +++ b/crates/ruff/src/rules/pycodestyle/helpers.rs @@ -1,7 +1,6 @@ -use once_cell::sync::Lazy; -use regex::Regex; use rustpython_parser::ast::{Cmpop, Expr, ExprKind}; use rustpython_parser::Tok; +use unicode_width::UnicodeWidthStr; use ruff_python_ast::helpers::{create_expr, unparse_expr}; use ruff_python_ast::source_code::Stylist; @@ -21,8 +20,6 @@ pub fn compare(left: &Expr, ops: &[Cmpop], comparators: &[Expr], stylist: &Styli ) } -static URL_REGEX: Lazy = Lazy::new(|| Regex::new(r"^https?://\S+$").unwrap()); - pub fn is_overlong( line: &str, line_width: usize, @@ -35,22 +32,25 @@ pub fn is_overlong( } let mut chunks = line.split_whitespace(); - let (Some(first), Some(second)) = (chunks.next(), chunks.next()) else { + let (Some(first_chunk), Some(second_chunk)) = (chunks.next(), chunks.next()) else { // Single word / no printable chars - no way to make the line shorter return false; }; - if first == "#" { + if first_chunk == "#" { if ignore_overlong_task_comments { - let second = second.trim_end_matches(':'); - if task_tags.iter().any(|tag| tag == second) { + let second = second_chunk.trim_end_matches(':'); + if task_tags.iter().any(|task_tag| task_tag == second) { return false; } } + } - // Do not enforce the line length for commented lines that end with a URL - // or contain only a single word. - if chunks.last().map_or(true, |c| URL_REGEX.is_match(c)) { + // Do not enforce the line length for lines that end with a URL, as long as the URL + // begins before the limit. + let last_chunk = chunks.last().unwrap_or(second_chunk); + if last_chunk.contains("://") { + if line_width - last_chunk.width() <= limit { return false; } } diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E501_E501.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E501_E501.py.snap index 4819b25ff36c32..5200cd0e8e39bf 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E501_E501.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E501_E501.py.snap @@ -69,15 +69,15 @@ expression: diagnostics parent: ~ - kind: name: LineTooLong - body: Line too long (129 > 88 characters) + body: Line too long (147 > 88 characters) suggestion: ~ fixable: false location: - row: 61 + row: 81 column: 88 end_location: - row: 61 - column: 129 + row: 81 + column: 147 fix: ~ parent: ~