2323import re
2424import sys
2525import 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
2929from ._version import __version__ as VERSION
@@ -680,18 +680,26 @@ def fix_case(word: str, fixword: str) -> str:
680680
681681def 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+
746763def 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
756779def 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
772800def 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