@@ -166,12 +166,14 @@ def __init__(self) -> None:
166166 self .FILE = "\033 [33m"
167167 self .WWORD = "\033 [31m"
168168 self .FWORD = "\033 [32m"
169+ self .CARET = "\033 [1;36m"
169170 self .DISABLE = "\033 [0m"
170171
171172 def disable (self ) -> None :
172173 self .FILE = ""
173174 self .WWORD = ""
174175 self .FWORD = ""
176+ self .CARET = ""
175177 self .DISABLE = ""
176178
177179
@@ -540,6 +542,11 @@ def parse_options(
540542 action = "store_true" ,
541543 help = "output just a single line for each misspelling in stdin mode" ,
542544 )
545+ parser .add_argument (
546+ "--caret-diagnostic" ,
547+ action = "store_true" ,
548+ help = "use the diagnostic message format of modern compilers" ,
549+ )
543550 parser .add_argument ("--config" , type = str , help = "path to config file." )
544551 parser .add_argument ("--toml" , type = str , help = "path to a pyproject.toml file." )
545552 parser .add_argument ("files" , nargs = "*" , help = "files or directories to check" )
@@ -919,6 +926,7 @@ def parse_file(
919926 )
920927 for match in check_matches :
921928 word = match .group ()
929+ column = match .start ()
922930 lword = word .lower ()
923931 if lword in misspellings :
924932 # Sometimes we find a 'misspelling' which is actually a valid word
@@ -973,8 +981,10 @@ def parse_file(
973981
974982 cfilename = f"{ colors .FILE } { filename } { colors .DISABLE } "
975983 cline = f"{ colors .FILE } { i + 1 } { colors .DISABLE } "
984+ ccolumn = f"{ colors .FILE } { column + 1 } { colors .DISABLE } "
976985 cwrongword = f"{ colors .WWORD } { word } { colors .DISABLE } "
977986 crightword = f"{ colors .FWORD } { fixword } { colors .DISABLE } "
987+ ccaret = f"{ colors .CARET } ^{ colors .DISABLE } "
978988
979989 reason = misspellings [lword ].reason
980990 if reason :
@@ -993,10 +1003,22 @@ def parse_file(
9931003 if (not context_shown ) and (context is not None ):
9941004 print_context (lines , i , context )
9951005 if filename != "-" :
996- print (
997- f"{ cfilename } :{ cline } : { cwrongword } "
998- f"==> { crightword } { creason } "
999- )
1006+ if options .caret_diagnostic :
1007+ ntabs = line [:column ].count ("\t " )
1008+ if ntabs > 0 :
1009+ line = line .replace ("\t " , " " )
1010+ column = column + ntabs * 3
1011+ print (
1012+ f"{ cfilename } :{ cline } :{ ccolumn } : { cwrongword } "
1013+ f"==> { crightword } { creason } "
1014+ )
1015+ print (f"{ line } " , end = "" )
1016+ print ("{:>{width}}{}" .format ("" , ccaret , width = column ))
1017+ else :
1018+ print (
1019+ f"{ cfilename } :{ cline } : { cwrongword } "
1020+ f"==> { crightword } { creason } "
1021+ )
10001022 elif options .stdin_single_line :
10011023 print (f"{ cline } : { cwrongword } ==> { crightword } { creason } " )
10021024 else :
@@ -1139,6 +1161,18 @@ def main(*args: str) -> int:
11391161 summary = None
11401162
11411163 context = None
1164+ if options .caret_diagnostic and (
1165+ (options .context is not None )
1166+ or (options .before_context is not None )
1167+ or (options .after_context is not None )
1168+ ):
1169+ print (
1170+ "ERROR: --caret-diagnostic cannot be used together with "
1171+ "--context/-C --context-before/-B or --context-after/-A" ,
1172+ file = sys .stderr ,
1173+ )
1174+ parser .print_help ()
1175+ return EX_USAGE
11421176 if options .context is not None :
11431177 if (options .before_context is not None ) or (options .after_context is not None ):
11441178 print (
0 commit comments