From 660d618f8b0df318d636cd780e547890d0248c0c Mon Sep 17 00:00:00 2001 From: _ov4 Date: Thu, 22 Oct 2026 01:45:15 +0000 Subject: feat(bundle): color compiler diagnostics in Output The runner now passes -fdiagnostics-color=always, since auto only sees a pipe. src/ansi.js turns stderr's SGR sequences into bold and colored runs, keeping style and cut-off sequences across chunks and dropping other sequences such as gcc's erase-line. Program stdout stays verbatim. Colors come from --vscode-terminal-ansi* variables. 2026 Dark leaves them unset, so vendor/vscode/terminal-colors.json pins VS Code's dark terminal defaults from the same upstream commit as the themes; a theme value still wins. Co-Authored-By: Claude Opus 5.5 --- bundle/src/ansi.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 bundle/src/ansi.js (limited to 'bundle/src/ansi.js') diff --git a/bundle/src/ansi.js b/bundle/src/ansi.js new file mode 100644 index 0000000..66173ea --- /dev/null +++ b/bundle/src/ansi.js @@ -0,0 +1,36 @@ +// Splits terminal text into runs styled by SGR escape sequences, keeping the +// style and any sequence cut off at a chunk boundary for the next chunk. +// Handles reset, bold and the 16 foreground colors; drops other sequences. +const names = ['Black', 'Red', 'Green', 'Yellow', 'Blue', 'Magenta', 'Cyan', 'White']; +const sequence = /\x1b\[([0-?]*)[ -/]*([@-~])/g; +const unfinished = /\x1b(\[[0-?]*[ -/]*)?$/; + +export function createAnsiParser() { + let bold = false; + let color = null; + let rest = ''; + return text => { + text = rest + text; + const cut = text.match(unfinished); + rest = cut ? cut[0] : ''; + if (cut) text = text.slice(0, cut.index); + const runs = []; + let start = 0; + for (const match of text.matchAll(sequence)) { + if (match.index > start) runs.push({ text: text.slice(start, match.index), bold, color }); + start = match.index + match[0].length; + if (match[2] !== 'm') continue; + for (const parameter of match[1].split(';')) { + const code = Number(parameter || 0); + if (code === 0) { bold = false; color = null; } + else if (code === 1) bold = true; + else if (code === 22) bold = false; + else if (code === 39) color = null; + else if (code >= 30 && code <= 37) color = `terminal.ansi${names[code - 30]}`; + else if (code >= 90 && code <= 97) color = `terminal.ansiBright${names[code - 90]}`; + } + } + if (start < text.length) runs.push({ text: text.slice(start), bold, color }); + return runs; + }; +} -- cgit v1.3.1-4-g156e