Skip to content

Commit fbe6e8e

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 fbe6e8e

File tree

5 files changed

+67
-1
lines changed

5 files changed

+67
-1
lines changed

llvm/utils/lit/lit/TestRunner.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1005,6 +1005,44 @@ 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+
1045+
10081046
def formatOutput(title, data, limit=None):
10091047
if not data.strip():
10101048
return ""
@@ -1016,7 +1054,7 @@ def formatOutput(title, data, limit=None):
10161054
ndashes = 30
10171055
# fmt: off
10181056
out = f"# .---{title}{'-' * (ndashes - 4 - len(title))}\n"
1019-
out += f"# | " + "\n# | ".join(data.splitlines()) + "\n"
1057+
out += formatLines(data.splitlines())
10201058
out += f"# `---{msg}{'-' * (ndashes - 4 - len(msg))}\n"
10211059
# fmt: on
10221060
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)