Skip to content

Commit 3f286a4

Browse files
Add inline summaries in --write-changes mode (codespell-project#3836)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 09c0976 commit 3f286a4

File tree

2 files changed

+72
-10
lines changed

2 files changed

+72
-10
lines changed

codespell_lib/_codespell.py

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,32 @@ def apply_uri_ignore_words(
883883
return check_matches
884884

885885

886+
def _format_colored_output(
887+
filename: str,
888+
colors: TermColors,
889+
line_num: int,
890+
wrong: str,
891+
right: str,
892+
) -> tuple[str, str, str, str]:
893+
"""Format colored strings for output.
894+
895+
Args:
896+
filename: The filename being processed.
897+
colors: TermColors instance for color formatting.
898+
line_num: Line number (1-based) where the misspelling was found.
899+
wrong: The misspelled word.
900+
right: The correct word.
901+
902+
Returns:
903+
Tuple of (filename, line_num, wrong_word, right_word) with color codes.
904+
"""
905+
cfilename = f"{colors.FILE}{filename}{colors.DISABLE}"
906+
cline = f"{colors.FILE}{line_num}{colors.DISABLE}"
907+
cwrongword = f"{colors.WWORD}{wrong}{colors.DISABLE}"
908+
crightword = f"{colors.FWORD}{right}{colors.DISABLE}"
909+
return cfilename, cline, cwrongword, crightword
910+
911+
886912
def parse_lines(
887913
fragment: tuple[bool, int, list[str]],
888914
filename: str,
@@ -897,9 +923,10 @@ def parse_lines(
897923
uri_ignore_words: set[str],
898924
context: Optional[tuple[int, int]],
899925
options: argparse.Namespace,
900-
) -> tuple[int, bool]:
926+
) -> tuple[int, bool, list[tuple[int, str, str]]]:
901927
bad_count = 0
902928
changed = False
929+
changes_made: list[tuple[int, str, str]] = []
903930

904931
_, fragment_line_number, lines = fragment
905932

@@ -985,6 +1012,7 @@ def parse_lines(
9851012
changed = True
9861013
lines[i] = re.sub(rf"\b{word}\b", fixword, lines[i])
9871014
fixed_words.add(word)
1015+
changes_made.append((line_number + 1, word, fixword))
9881016
continue
9891017

9901018
# otherwise warning was explicitly set by interactive mode
@@ -995,10 +1023,9 @@ def parse_lines(
9951023
):
9961024
continue
9971025

998-
cfilename = f"{colors.FILE}{filename}{colors.DISABLE}"
999-
cline = f"{colors.FILE}{line_number + 1}{colors.DISABLE}"
1000-
cwrongword = f"{colors.WWORD}{word}{colors.DISABLE}"
1001-
crightword = f"{colors.FWORD}{fixword}{colors.DISABLE}"
1026+
cfilename, cline, cwrongword, crightword = _format_colored_output(
1027+
filename, colors, line_number + 1, word, fixword
1028+
)
10021029

10031030
reason = misspellings[lword].reason
10041031
if reason:
@@ -1028,7 +1055,7 @@ def parse_lines(
10281055
f"==> {crightword}{creason}"
10291056
)
10301057

1031-
return bad_count, changed
1058+
return bad_count, changed, changes_made
10321059

10331060

10341061
def parse_file(
@@ -1068,9 +1095,9 @@ def parse_file(
10681095
if summary and fix:
10691096
summary.update(lword)
10701097

1071-
cfilename = f"{colors.FILE}{filename}{colors.DISABLE}"
1072-
cwrongword = f"{colors.WWORD}{word}{colors.DISABLE}"
1073-
crightword = f"{colors.FWORD}{fixword}{colors.DISABLE}"
1098+
cfilename, _, cwrongword, crightword = _format_colored_output(
1099+
filename, colors, 0, word, fixword
1100+
)
10741101

10751102
reason = misspellings[lword].reason
10761103
if reason:
@@ -1109,12 +1136,13 @@ def parse_file(
11091136

11101137
# Parse lines.
11111138
changed = False
1139+
changes_made: list[tuple[int, str, str]] = []
11121140
for fragment in fragments:
11131141
ignore, _, _ = fragment
11141142
if ignore:
11151143
continue
11161144

1117-
bad_count_update, changed_update = parse_lines(
1145+
bad_count_update, changed_update, changes_made_update = parse_lines(
11181146
fragment,
11191147
filename,
11201148
colors,
@@ -1131,6 +1159,7 @@ def parse_file(
11311159
)
11321160
bad_count += bad_count_update
11331161
changed = changed or changed_update
1162+
changes_made.extend(changes_made_update)
11341163

11351164
# Write out lines, if changed.
11361165
if changed:
@@ -1145,6 +1174,14 @@ def parse_file(
11451174
f"{colors.FWORD}FIXED:{colors.DISABLE} {filename}",
11461175
file=sys.stderr,
11471176
)
1177+
for line_num, wrong, right in changes_made:
1178+
cfilename, cline, cwrongword, crightword = _format_colored_output(
1179+
filename, colors, line_num, wrong, right
1180+
)
1181+
print(
1182+
f" {cfilename}:{cline}: {cwrongword} ==> {crightword}",
1183+
file=sys.stderr,
1184+
)
11481185
with open(filename, "w", encoding=encoding, newline="") as f:
11491186
for _, _, lines in fragments:
11501187
f.writelines(lines)

codespell_lib/tests/test_basic.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,31 @@ def test_basic(
169169
assert cs.main(tmp_path) == 0
170170

171171

172+
def test_write_changes_lists_changes(
173+
tmp_path: Path,
174+
capsys: pytest.CaptureFixture[str],
175+
) -> None:
176+
"""Test that -w flag shows list of changes made to file."""
177+
178+
fname = tmp_path / "misspelled.txt"
179+
fname.write_text("This is abandonned\nAnd this is occured\nAlso teh typo\n")
180+
181+
result = cs.main("-w", fname, std=True)
182+
assert isinstance(result, tuple)
183+
code, _, stderr = result
184+
assert code == 0
185+
186+
assert "FIXED:" in stderr
187+
188+
# Check that changes are listed with format: filename:line: wrong ==> right
189+
assert "misspelled.txt:1: abandonned ==> abandoned" in stderr
190+
assert "misspelled.txt:2: occured ==> occurred" in stderr
191+
assert "misspelled.txt:3: teh ==> the" in stderr
192+
193+
corrected = fname.read_text()
194+
assert corrected == "This is abandoned\nAnd this is occurred\nAlso the typo\n"
195+
196+
172197
def test_default_word_parsing(
173198
tmp_path: Path,
174199
capsys: pytest.CaptureFixture[str],

0 commit comments

Comments
 (0)