Skip to content

Commit efd61e8

Browse files
committed
Fix incorrectly colored error locations when wide unicode characters exist
1 parent 076300d commit efd61e8

File tree

1 file changed

+35
-11
lines changed

1 file changed

+35
-11
lines changed

Lib/traceback.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

970994
class _ExceptionPrintContext:

0 commit comments

Comments
 (0)