Skip to content

Report real line numbers after an --ignore-multiline-regex region#3981

Open
chuenchen309 wants to merge 1 commit into
codespell-project:mainfrom
chuenchen309:fix/ignore-multiline-regex-line-numbers
Open

Report real line numbers after an --ignore-multiline-regex region#3981
chuenchen309 wants to merge 1 commit into
codespell-project:mainfrom
chuenchen309:fix/ignore-multiline-regex-line-numbers

Conversation

@chuenchen309

Copy link
Copy Markdown

Misspellings that appear after an --ignore-multiline-regex region are reported with the wrong line number — including with the exact example given in --help.

Reproducer

ml.txt:

1  line one is fine
2  # codespell:ignore-begin
3  abandonned inside the ignored region
4  # codespell:ignore-end
5  line five is fine
6  here is the abandonned typo we care about

The typo is really on line 6, and plain codespell ml.txt agrees (it reports lines 3 and 6). With the option, the surviving typo moves:

invocation reported correct
codespell ml.txt ml.txt:3, ml.txt:6
--ignore-multiline-regex '# codespell:ignore-begin *\n.*# codespell:ignore-end *\n'the example from --help ml.txt:5 ml.txt:6
--ignore-multiline-regex 'codespell:ignore-begin.*codespell:ignore-end' — the form the test suite uses ml.txt:7 ml.txt:6

Both directions of error are reachable. The region itself is ignored correctly in both cases, and --write-changes still edits the right bytes; only the reported line number (and the FIXED: output) is off.

Cause

get_lines tracks the line number by accumulating len(lines) per fragment and then subtracting one for the ignored match:

line_number += len(lines)      # text before the match
...
line_number += len(lines) - 1  # the match itself

Splitting a slice tells you how many lines it touches, not how many line breaks it crosses. The - 1 is a correction for the case where the match begins at column 0 and does not end on a line boundary — the leading partial line and the trailing partial line are each counted once too often, and the two errors cancel. Change either property and the cancellation breaks:

  • the --help example ends with \n, so there is no trailing partial line and the - 1 over-subtracts → one line too low;
  • codespell:ignore-begin.* starts mid-line (after # ), so the preceding fragment's "# " remainder is counted as a whole line → one line too high.

Fix

Take each fragment's line number from its own start offset, which is the definition of the thing being computed:

text.count("\n", 0, pos)

No fragment content changes — only the line number attached to it — so detection and --write-changes behaviour are untouched.

Tests

test_ignore_multiline_regex_line_numbers asserts the reported line number for both regex forms above. There was no existing coverage for this: the current --ignore-multiline-regex tests assert error counts and post-fix file contents, never line numbers, which is why the bug survived.

Full suite is unchanged otherwise: 124 passed vs. 123 on main (the one extra is this new test), with the same pre-existing failures on my sandbox in both runs. ruff check / ruff format clean; both of CI's codespell self-checks still behave as expected.

Disclosure

AI-assisted, and I'd rather say so plainly. The reproducer above, the main-vs-branch baseline comparison, and the --help-example finding are all things I ran and read myself; the root-cause reasoning about the two cancelling off-by-ones is likewise checked against the actual behaviour rather than asserted. Happy to adjust scope or naming if you'd prefer something narrower.

get_lines derived each fragment's line number by accumulating
len(splitlines()) and subtracting one for the ignored match. That only
holds when the match starts at column 0 and does not end on a line
boundary, so misspellings after an ignored region were reported one line
off in either direction -- including with the example from --help.

Take each fragment's line number from its own offset instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant