@@ -656,18 +656,29 @@ def output_line(lineno):
656656 line = result [- 1 ]
657657 colorized_line_parts = []
658658 colorized_carets_parts = []
659-
660- for color , group in itertools .groupby (itertools .zip_longest (line , carets , fillvalue = "" ), key = lambda x : x [1 ]):
661- caret_group = list (group )
662- if color == "^" :
663- colorized_line_parts .append (ANSIColors .BOLD_RED + "" .join (char for char , _ in caret_group ) + ANSIColors .RESET )
664- colorized_carets_parts .append (ANSIColors .BOLD_RED + "" .join (caret for _ , caret in caret_group ) + ANSIColors .RESET )
665- elif color == "~" :
666- colorized_line_parts .append (ANSIColors .RED + "" .join (char for char , _ in caret_group ) + ANSIColors .RESET )
667- colorized_carets_parts .append (ANSIColors .RED + "" .join (caret for _ , caret in caret_group ) + ANSIColors .RESET )
659+ line_part_col = 0
660+ for char , group in itertools .groupby (carets ):
661+ carets_part = "" .join (group )
662+ width = len (carets_part )
663+ if char == "^" :
664+ color = ANSIColors .BOLD_RED
665+ elif char == "~" :
666+ color = ANSIColors .RED
668667 else :
669- colorized_line_parts .append ("" .join (char for char , _ in caret_group ))
670- colorized_carets_parts .append ("" .join (caret for _ , caret in caret_group ))
668+ colorized_carets_parts .append (carets_part )
669+ line_part_col , line_part = _offset_at_width (line , width , start = line_part_col )
670+ colorized_line_parts .append (line_part )
671+ continue
672+
673+ colorized_carets_parts .append (color )
674+ colorized_carets_parts .append (carets_part )
675+ colorized_carets_parts .append (ANSIColors .RESET )
676+
677+ colorized_line_parts .append (color )
678+ line_part_col , line_part = _offset_at_width (line , width , start = line_part_col )
679+ colorized_line_parts .append (line_part )
680+ colorized_line_parts .append (ANSIColors .RESET )
681+ colorized_line_parts .append (line [line_part_col :])
671682
672683 colorized_line = "" .join (colorized_line_parts )
673684 colorized_carets = "" .join (colorized_carets_parts )
@@ -965,6 +976,19 @@ def _display_width(line, offset=None):
965976 for char in line [:offset ]
966977 )
967978
979+ def _offset_at_width (line , width , start = 0 ):
980+ col = start + width
981+ part = line [start :col ]
982+ if part .isascii ():
983+ return col , part
984+
985+ from unicodedata import east_asian_width
986+
987+ for i in range (start , len (line )):
988+ if width <= 0 :
989+ return i , line [start :i ]
990+ width -= 2 if east_asian_width (line [i ]) in _WIDE_CHAR_SPECIFIERS else 1
991+ return len (line ), line [start :]
968992
969993
970994class _ExceptionPrintContext :
0 commit comments