Skip to content

Commit 2d38f04

Browse files
committed
[llvm-lit] Process ANSI color codes in test output when formatting
Test output that carried color across newlines previously resulted in the formatting around the output also being colored. Detect the current ANSI color and reset it when printing formatting, and then reapply it. As an added bonus an unterminated color code is also detected, preventing it from leaking out into the rest of the terminal. Fixes #106633
1 parent 9e1f1cf commit 2d38f04

File tree

5 files changed

+66
-1
lines changed

5 files changed

+66
-1
lines changed

llvm/utils/lit/lit/TestRunner.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,43 @@ def _executeShCmd(cmd, shenv, results, timeoutHelper):
10051005
return exitCode
10061006

10071007

1008+
def reFindLast(r, s):
1009+
matches = r.findall(s)
1010+
if not matches:
1011+
return None
1012+
return matches[-1]
1013+
1014+
1015+
def findColor(s, curr_color):
1016+
m = reFindLast(color_re, s)
1017+
if not m:
1018+
return curr_color
1019+
# "\33[0m" means "reset all formatting". Sometimes the 0 is skipped.
1020+
if m == "\33[m" or m == "\33[0m":
1021+
return None
1022+
return m
1023+
1024+
1025+
def escapeColor(s, f):
1026+
if not f:
1027+
return s
1028+
return f"\33[0m{s}{f}"
1029+
1030+
1031+
color_re = re.compile("\33\\[[^m]*m")
1032+
1033+
1034+
def formatLines(lines):
1035+
curr_color = None
1036+
out = ""
1037+
for line in lines:
1038+
out += escapeColor("# | ", curr_color)
1039+
out += line + "\n"
1040+
curr_color = findColor(line, curr_color)
1041+
if curr_color:
1042+
out += "\33[0m" # prevent unterminated formatting from leaking
1043+
return out
1044+
10081045
def formatOutput(title, data, limit=None):
10091046
if not data.strip():
10101047
return ""
@@ -1016,7 +1053,7 @@ def formatOutput(title, data, limit=None):
10161053
ndashes = 30
10171054
# fmt: off
10181055
out = f"# .---{title}{'-' * (ndashes - 4 - len(title))}\n"
1019-
out += f"# | " + "\n# | ".join(data.splitlines()) + "\n"
1056+
out += formatLines(data.splitlines())
10201057
out += f"# `---{msg}{'-' * (ndashes - 4 - len(msg))}\n"
10211058
# fmt: on
10221059
return out
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# .---command stdout------------
2+
# | # RUN: cat %s
3+
# | red
4+
# | still red(B
5+
# | plain
6+
# | green
7+
# | still green (never terminated)
8+
# `-----------------------------
9+
10+
--
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# RUN: cat %s
2+
red
3+
still red(B
4+
plain
5+
green
6+
still green (never terminated)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import lit.formats
2+
3+
config.name = "escape-color"
4+
config.suffixes = [".txt"]
5+
config.test_format = lit.formats.ShTest()
6+
config.test_source_root = None
7+
config.test_exec_root = None
8+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# cut off the first 9 lines to avoid absolute file paths in the output
2+
# then keep only the next 10 lines to avoid test timing in the output
3+
# RUN: %{lit} %{inputs}/escape-color/color.txt -a | tail -n +10 | head -n 10 > %t
4+
# RUN: diff %{inputs}/escape-color/color-escaped.txt %t

0 commit comments

Comments
 (0)