diff --git a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D.py b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D.py index 724490934ffaf..617231c5c81a9 100644 --- a/crates/ruff_linter/resources/test/fixtures/pydocstyle/D.py +++ b/crates/ruff_linter/resources/test/fixtures/pydocstyle/D.py @@ -713,5 +713,12 @@ def retain_extra_whitespace_not_overindented(): This is not overindented This is overindented, but since one line is not overindented this should not raise - And so is this, but it we should preserve the extra space on this line relative + And so is this, but it we should preserve the extra space on this line relative + """ + + +def inconsistent_indent_byte_size(): + """There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). + +     Returns: """ diff --git a/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs b/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs index 1c2ced8bd1b0d..c91565837f9ad 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs +++ b/crates/ruff_linter/src/rules/pydocstyle/rules/indent.rs @@ -254,14 +254,26 @@ pub(crate) fn indent(checker: &mut Checker, docstring: &Docstring) { Edit::range_deletion(TextRange::at(line.start(), line_indent.text_len())) } else { // Convert the character count to an offset within the source. + // Example, where `[]` is a 2 byte non-breaking space: + // ``` + // def f(): + // """ Docstring header + // ^^^^ Real indentation is 4 chars + // docstring body, over-indented + // ^^^^^^ Over-indentation is 6 - 4 = 2 chars due to this line + // [] [] docstring body 2, further indented + // ^^^^^ We take these 4 chars/5 bytes to match the docstring ... + // ^^^ ... and these 2 chars/3 bytes to remove the `over_indented_size` ... + // ^^ ... but preserve this real indent + // ``` let offset = checker .locator() - .after(line.start() + indent.text_len()) + .after(line.start()) .chars() - .take(over_indented_size) + .take(docstring.indentation.chars().count() + over_indented_size) .map(TextLen::text_len) .sum::(); - let range = TextRange::at(line.start(), indent.text_len() + offset); + let range = TextRange::at(line.start(), offset); Edit::range_replacement(indent, range) }; diagnostic.set_fix(Fix::safe_edit(edit)); diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D.py.snap index caa57c1faa72d..5048d030c7dcd 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D.py.snap +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D208_D.py.snap @@ -411,4 +411,22 @@ D.py:707:1: D208 [*] Docstring is over-indented 709 709 | 710 710 | +D.py:723:1: D208 [*] Docstring is over-indented + | +721 | """There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). +722 | +723 |     Returns: + | D208 +724 | """ + | + = help: Remove over-indentation + +ℹ Safe fix +720 720 | def inconsistent_indent_byte_size(): +721 721 | """There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). +722 722 | +723 |-     Returns: + 723 |+ Returns: +724 724 | """ + diff --git a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D213_D.py.snap b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D213_D.py.snap index e0f3516e76c32..0253bc44cd427 100644 --- a/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D213_D.py.snap +++ b/crates/ruff_linter/src/rules/pydocstyle/snapshots/ruff_linter__rules__pydocstyle__tests__D213_D.py.snap @@ -662,7 +662,7 @@ D.py:712:5: D213 [*] Multi-line docstring summary should start at the second lin 713 | | 714 | | This is not overindented 715 | | This is overindented, but since one line is not overindented this should not raise -716 | | And so is this, but it we should preserve the extra space on this line relative +716 | | And so is this, but it we should preserve the extra space on this line relative 717 | | """ | |_______^ D213 | @@ -679,4 +679,27 @@ D.py:712:5: D213 [*] Multi-line docstring summary should start at the second lin 714 715 | This is not overindented 715 716 | This is overindented, but since one line is not overindented this should not raise +D.py:721:5: D213 [*] Multi-line docstring summary should start at the second line + | +720 | def inconsistent_indent_byte_size(): +721 | """There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). + | _____^ +722 | | +723 | |     Returns: +724 | | """ + | |_______^ D213 + | + = help: Insert line break and indentation after opening quotes + +ℹ Safe fix +718 718 | +719 719 | +720 720 | def inconsistent_indent_byte_size(): +721 |- """There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). + 721 |+ """ + 722 |+ There's a non-breaking space (2-bytes) after 3 spaces (https://github.com/astral-sh/ruff/issues/9080). +722 723 | +723 724 |     Returns: +724 725 | """ +