Skip to content

Commit 892922e

Browse files
authored
ENH: Color matching wrong word in the interactive session (#2771)
1 parent 3601c9a commit 892922e

File tree

1 file changed

+49
-17
lines changed

1 file changed

+49
-17
lines changed

codespell_lib/_codespell.py

+49-17
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import re
2424
import sys
2525
import textwrap
26-
from typing import Dict, List, Optional, Pattern, Sequence, Set, Tuple
26+
from typing import Dict, List, Match, Optional, Pattern, Sequence, Set, Tuple
2727

2828
# autogenerated by setuptools_scm
2929
from ._version import __version__ as VERSION
@@ -680,18 +680,26 @@ def fix_case(word: str, fixword: str) -> str:
680680

681681
def ask_for_word_fix(
682682
line: str,
683-
wrongword: str,
683+
match: Match[str],
684684
misspelling: Misspelling,
685685
interactivity: int,
686+
colors: TermColors,
686687
) -> Tuple[bool, str]:
688+
wrongword = match.group()
687689
if interactivity <= 0:
688690
return misspelling.fix, fix_case(wrongword, misspelling.data)
689691

692+
line_ui = (
693+
f"{line[:match.start()]}"
694+
f"{colors.WWORD}{wrongword}{colors.DISABLE}"
695+
f"{line[match.end():]}"
696+
)
697+
690698
if misspelling.fix and interactivity & 1:
691699
r = ""
692700
fixword = fix_case(wrongword, misspelling.data)
693701
while not r:
694-
print(f"{line}\t{wrongword} ==> {fixword} (Y/n) ", end="", flush=True)
702+
print(f"{line_ui}\t{wrongword} ==> {fixword} (Y/n) ", end="", flush=True)
695703
r = sys.stdin.readline().strip().upper()
696704
if not r:
697705
r = "Y"
@@ -709,7 +717,7 @@ def ask_for_word_fix(
709717
r = ""
710718
opt = [w.strip() for w in misspelling.data.split(",")]
711719
while not r:
712-
print(f"{line} Choose an option (blank for none): ", end="")
720+
print(f"{line_ui} Choose an option (blank for none): ", end="")
713721
for i, o in enumerate(opt):
714722
fixword = fix_case(wrongword, o)
715723
print(f" {i}) {fixword}", end="")
@@ -743,30 +751,50 @@ def print_context(
743751
print("{} {}".format(">" if i == index else ":", lines[i].rstrip()))
744752

745753

754+
def _ignore_word_sub(
755+
text: str,
756+
ignore_word_regex: Optional[Pattern[str]],
757+
) -> str:
758+
if ignore_word_regex:
759+
text = ignore_word_regex.sub(" ", text)
760+
return text
761+
762+
746763
def extract_words(
747764
text: str,
748765
word_regex: Pattern[str],
749766
ignore_word_regex: Optional[Pattern[str]],
750767
) -> List[str]:
751-
if ignore_word_regex:
752-
text = ignore_word_regex.sub(" ", text)
753-
return word_regex.findall(text)
768+
return word_regex.findall(_ignore_word_sub(text, ignore_word_regex))
769+
770+
771+
def extract_words_iter(
772+
text: str,
773+
word_regex: Pattern[str],
774+
ignore_word_regex: Optional[Pattern[str]],
775+
) -> List[Match[str]]:
776+
return list(word_regex.finditer(_ignore_word_sub(text, ignore_word_regex)))
754777

755778

756779
def apply_uri_ignore_words(
757-
check_words: List[str],
780+
check_matches: List[Match[str]],
758781
line: str,
759782
word_regex: Pattern[str],
760783
ignore_word_regex: Optional[Pattern[str]],
761784
uri_regex: Pattern[str],
762785
uri_ignore_words: Set[str],
763-
) -> None:
786+
) -> List[Match[str]]:
764787
if not uri_ignore_words:
765-
return
788+
return check_matches
766789
for uri in re.findall(uri_regex, line):
767790
for uri_word in extract_words(uri, word_regex, ignore_word_regex):
768791
if uri_word in uri_ignore_words:
769-
check_words.remove(uri_word)
792+
# determine/remove only the first among matches
793+
for i, match in enumerate(check_matches):
794+
if match.group() == uri_word:
795+
check_matches = check_matches[:i] + check_matches[i + 1 :]
796+
break
797+
return check_matches
770798

771799

772800
def parse_file(
@@ -855,18 +883,18 @@ def parse_file(
855883
# outside, it will still be a spelling error.
856884
if "*" in uri_ignore_words:
857885
line = uri_regex.sub(" ", line)
858-
check_words = extract_words(line, word_regex, ignore_word_regex)
886+
check_matches = extract_words_iter(line, word_regex, ignore_word_regex)
859887
if "*" not in uri_ignore_words:
860-
apply_uri_ignore_words(
861-
check_words,
888+
check_matches = apply_uri_ignore_words(
889+
check_matches,
862890
line,
863891
word_regex,
864892
ignore_word_regex,
865893
uri_regex,
866894
uri_ignore_words,
867895
)
868-
869-
for word in check_words:
896+
for match in check_matches:
897+
word = match.group()
870898
lword = word.lower()
871899
if lword in misspellings:
872900
context_shown = False
@@ -878,7 +906,11 @@ def parse_file(
878906
context_shown = True
879907
print_context(lines, i, context)
880908
fix, fixword = ask_for_word_fix(
881-
lines[i], word, misspellings[lword], options.interactive
909+
lines[i],
910+
match,
911+
misspellings[lword],
912+
options.interactive,
913+
colors=colors,
882914
)
883915
asked_for.add(lword)
884916

0 commit comments

Comments
 (0)