Handle ANSI color codes in console.log
Categories
(DevTools :: Console, enhancement, P3)
Tracking
(Not tracked)
People
(Reporter: fvsch, Unassigned)
Details
Attachments
(2 files)
I’m working on StackBlitz (stackblitz.com) which recently launched support for running npm packages using Node.js APIs in the browser, using the browser's JavaScript VM. This enables running web servers such as express, and build tools such as webpack, directly in the browser.
Some of those tools use popular npm packages such as chalk (one of the very top npm packages, accounting to 0,3% of all package downloads in my calculations) and colors to log colorized text to stdout. When running in Firefox, this results in text looking like this in the Console:
[31mthis is an error[39m
[33mthis is a warning[39m
and extreme cases can be completely unreadable:
[31mA[39m[37mm[39m[34me[39m[31mr[39m[37mi[39m[34mc[39m[31ma[39m[37m,[39m [31mH[39m[37me[39m[34mc[39m[31mk[39m [34mY[39m[31me[39m[37ma[39m[34mh[39m[31m![39m
It could be great if console.log input could either support ANSI color codes (which Chrome DevTools does), or alternatively strip them to show the raw text in a readable fashion.
I haven't seen other websites using ANSI color codes with console.log yet, so I can't say it's widespread.
| Reporter | ||
Comment 1•4 years ago
|
||
For comparison, here's the result in Chrome DevTools.
| Reporter | ||
Comment 2•4 years ago
|
||
Limited test case:
console.log(`
\u001B[31mThis is an error\u001B[39m
\u001B[33mThis is a warning\u001B[39m
`)
Works in Chrome, not in Firefox.
I have a more complex test case, shown above, which uses the chalk and colors npm pages.
https://stackblitz.com/edit/node-colors-test?file=README.md
It's a bit complex because it runs in StackBlitz WebContainer which doesn't officially support Firefox yet.
You can get it to run in Firefox (at least in Nightly) with:
- In about:config, set
dom.postMessage.sharedArrayBuffer.bypassCOOP_COEP.insecure.enabledtotrue. - You probably need to set Enhanced Tracking Protection to “Standard” if it’s set to “Strict”.
- In the browser console, run
localStorage.webcontainer_any_ua = 'true'. - Reload the page.
Comment 3•4 years ago
|
||
thanks for filing Florens!
For what it's worth, Safari doesn't support this either, and I couldn't find anything about this in the spec (https://console.spec.whatwg.org/)
Chrome seems to treat it as a "style block" (%c), as console.log(%cHello \u001B[31mRED, "background-color: yellow") won't apply the background color (or any other property, say font-size) to "RED".
Comment 4•4 years ago
|
||
I filed an issue in the console spec repo: https://github.com/whatwg/console/issues/197
Comment 5•4 years ago
|
||
I'm currently working on improving support for ANSI color codes in Chromium DevTools. Relevant links:
| Reporter | ||
Comment 6•4 years ago
|
||
Improvements shipped in Chrome DevTools: https://developer.chrome.com/blog/new-in-devtools-99/#console
Chrome supports ANSI color since 2018.
https://stackoverflow.com/a/52733695/11468937
Any plans about it in Firefox?
Comment 8•3 years ago
|
||
It would also be useful to have this when viewing content served as text/plain. CI logs tend to be served as such and can also contain color codes. Now one has to download the file and open it using less -R or a similar tool.
Comment 9•3 years ago
|
||
This add-on provides this functionality already: https://addons.mozilla.org/en-US/firefox/addon/retrotxt/
Comment 10•2 years ago
|
||
Still doesnt have colors in console?
Comment 11•10 months ago
|
||
It would be nice to have this feature.
Updated•8 months ago
|
Comment 12•7 months ago
|
||
Comment 13•7 months ago
|
||
(In reply to steve02081504 from comment #12)
its quiet easy to impl
https://cdn.jsdelivr.net/npm/ansi-up
https://github.com/steve02081504/virtual-console/blob/master/util.mjs
would you want to give this a try?
We should probably handle the ANSI color escape codes where we process args in the C++ (https://searchfox.org/firefox-main/rev/813224374ca2d9aa44770230bc40bd351bcbe6ea/dom/console/Console.cpp#1801-1819), to transform them into color/background-color into the styles string so we don't have to update the client
Comment 14•6 months ago
|
||
(In reply to Nicolas Chevobbe [:nchevobbe] from comment #13)
(In reply to steve02081504 from comment #12)
its quiet easy to impl
https://cdn.jsdelivr.net/npm/ansi-up
https://github.com/steve02081504/virtual-console/blob/master/util.mjswould you want to give this a try?
We should probably handle the ANSI color escape codes where we process args in the C++ (https://searchfox.org/firefox-main/rev/813224374ca2d9aa44770230bc40bd351bcbe6ea/dom/console/Console.cpp#1801-1819), to transform them intocolor/background-colorinto the styles string so we don't have to update the client
yeah ofcorce I can help for test but I dono how to PR or build for firefox...
Comment 15•6 months ago
|
||
// 新函数:解析字符串中的 ANSI,转为多个文本片段 + 样式。
// 如果无 ANSI,直接追加原字符串作为单个元素。
static bool ProcessStringWithANSI(JSContext* aCx, const nsString& input,
Sequence<JS::Value>& aSequence,
Sequence<nsString>& aStyles) {
if (input.IsEmpty() || input.FindChar('\x1B') == kNotFound) {
// 无 ANSI,直接追加为 JS 字符串。
JS::Rooted<JSString*> jsStr(aCx, JS_NewUCStringCopyN(aCx, input.get(), input.Length()));
if (NS_WARN_IF(!jsStr)) {
return false;
}
JS::Value val = JS::StringValue(jsStr);
if (NS_WARN_IF(!aSequence.AppendElement(val, fallible))) {
return false;
}
// 填充空样式。
if (NS_WARN_IF(!aStyles.AppendElement(VoidString(), fallible))) {
return false;
}
return true;
}
// 有 ANSI:使用状态机解析。
nsString currentText; // 当前文本片段。
nsString currentStyle; // 当前 CSS 样式字符串。
bool bold = false, italic = false, underline = false;
nsString fgColor, bgColor; // 为空表示默认。
// 颜色映射(基本 16 色;可扩展到 256 色)。
static const nsString kFgColors[8] = {u"black", u"red", u"green", u"yellow", u"blue", u"magenta", u"cyan", u"white"};
static const nsString kBrightFgColors[8] = {u"gray", u"lightred", u"lightgreen", u"lightyellow", u"lightblue", u"lightmagenta", u"lightcyan", u"white"}; // 近似。
nsString::const_iterator iter = input.begin();
nsString::const_iterator end = input.end();
auto FlushSegment = [&]() -> bool {
if (!currentText.IsEmpty()) {
JS::Rooted<JSString*> jsStr(aCx, JS_NewUCStringCopyN(aCx, currentText.get(), currentText.Length()));
if (NS_WARN_IF(!jsStr)) {
return false;
}
JS::Value val = JS::StringValue(jsStr);
if (NS_WARN_IF(!aSequence.AppendElement(val, fallible))) {
return false;
}
if (NS_WARN_IF(!aStyles.AppendElement(currentStyle, fallible))) {
return false;
}
currentText.Truncate();
}
return true;
};
while (iter != end) {
if (*iter == '\x1B' && iter + 1 != end && *(iter + 1) == '[') { // ESC [
// 刷新当前片段(如果有)。
if (NS_WARN_IF(!FlushSegment())) {
return false;
}
// 跳过 ESC [,解析参数。
iter += 2;
nsString params;
while (iter != end && *iter != 'm') {
params.Append(*iter);
++iter;
}
if (iter != end) ++iter; // 跳过 'm'。
// 解析参数(多个用 ; 分隔)。
nsTArray<int32_t> codes;
nsString paramStr = params;
nsStringTokenizer tokenizer(paramStr, ';');
while (tokenizer.HasMoreTokens()) {
nsString token = tokenizer.NextToken();
int32_t code = token.ToInteger(nullptr); // 忽略错误。
codes.AppendElement(code);
}
// 更新状态。
for (int32_t code : codes) {
switch (code) {
case 0: // 重置。
bold = italic = underline = false;
fgColor.Truncate();
bgColor.Truncate();
break;
case 1: bold = true; break;
case 3: italic = true; break;
case 4: underline = true; break;
case 30 ... 37: fgColor = kFgColors[code - 30]; break;
case 40 ... 47: bgColor = kFgColors[code - 40]; break;
case 90 ... 97: fgColor = kBrightFgColors[code - 90]; break;
case 100 ... 107: bgColor = kBrightFgColors[code - 100]; break;
// TODO: 支持 38/48 for 256/RGB (使用 rgb() ).
default: break; // 忽略未知。
}
}
// 构建新 CSS 样式。
currentStyle.Truncate();
if (!fgColor.IsEmpty()) {
currentStyle.AppendLiteral(u"color: ");
currentStyle.Append(fgColor);
currentStyle.AppendLiteral(u"; ");
}
if (!bgColor.IsEmpty()) {
currentStyle.AppendLiteral(u"background-color: ");
currentStyle.Append(bgColor);
currentStyle.AppendLiteral(u"; ");
}
if (bold) currentStyle.AppendLiteral(u"font-weight: bold; ");
if (italic) currentStyle.AppendLiteral(u"font-style: italic; ");
if (underline) currentStyle.AppendLiteral(u"text-decoration: underline; ");
continue;
}
// 普通字符,追加到当前文本。
currentText.Append(*iter);
++iter;
}
// 刷新最后片段。
if (NS_WARN_IF(!FlushSegment())) {
return false;
}
// 填充多余样式为空(如果需要对齐)。
while (aStyles.Length() < aSequence.Length()) {
if (NS_WARN_IF(!aStyles.AppendElement(VoidString(), fallible))) {
return false;
}
}
return true;
}
not sure is this right
Comment 16•6 months ago
|
||
(In reply to steve02081504 from comment #14)
yeah ofcorce I can help for test but I dono how to PR or build for firefox...
Great! You can go through https://firefox-source-docs.mozilla.org/devtools/index.html to check how to setup the environment and see how you can ask for review on your patch
Comment 17•6 months ago
|
||
(In reply to Nicolas Chevobbe [:nchevobbe] from comment #16)
Great! You can go through https://firefox-source-docs.mozilla.org/devtools/index.html to check how to setup the environment and see how you can ask for review on your patch
I may have notime for this unfamiliar complex contribution process so thnaks but no?
free to use my code anyway :D
Comment 18•14 days ago
|
||
Guys, 2026, FF still cannot make past era ansi codes output to be colored in browser console? Even node js have it is built in now
Description
•