108 lines
3.7 KiB
TypeScript
108 lines
3.7 KiB
TypeScript
/*
|
|
Copyright (c) Microsoft Corporation.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
export function ansi2html(text: string): string {
|
|
const regex = /(\x1b\[(\d+(;\d+)*)m)|([^\x1b]+)/g;
|
|
const tokens: string[] = [];
|
|
let match;
|
|
let style: any = {};
|
|
while ((match = regex.exec(text)) !== null) {
|
|
const [, , codeStr, , text] = match;
|
|
if (codeStr) {
|
|
const code = +codeStr;
|
|
switch (code) {
|
|
case 0: style = {}; break;
|
|
case 1: style['font-weight'] = 'bold'; break;
|
|
case 3: style['font-style'] = 'italic'; break;
|
|
case 4: style['text-decoration'] = 'underline'; break;
|
|
case 8: style.display = 'none'; break;
|
|
case 9: style['text-decoration'] = 'line-through'; break;
|
|
case 22: style = { ...style, 'font-weight': undefined, 'font-style': undefined, 'text-decoration': undefined }; break;
|
|
case 23: style = { ...style, 'font-weight': undefined, 'font-style': undefined }; break;
|
|
case 24: style = { ...style, 'text-decoration': undefined }; break;
|
|
case 30:
|
|
case 31:
|
|
case 32:
|
|
case 33:
|
|
case 34:
|
|
case 35:
|
|
case 36:
|
|
case 37: style.color = ansiColors[code - 30]; break;
|
|
case 39: style = { ...style, color: undefined }; break;
|
|
case 40:
|
|
case 41:
|
|
case 42:
|
|
case 43:
|
|
case 44:
|
|
case 45:
|
|
case 46:
|
|
case 47: style['background-color'] = ansiColors[code - 40]; break;
|
|
case 49: style = { ...style, 'background-color': undefined }; break;
|
|
case 53: style['text-decoration'] = 'overline'; break;
|
|
case 90:
|
|
case 91:
|
|
case 92:
|
|
case 93:
|
|
case 94:
|
|
case 95:
|
|
case 96:
|
|
case 97: style.color = brightAnsiColors[code - 90]; break;
|
|
case 100:
|
|
case 101:
|
|
case 102:
|
|
case 103:
|
|
case 104:
|
|
case 105:
|
|
case 106:
|
|
case 107: style['background-color'] = brightAnsiColors[code - 100]; break;
|
|
}
|
|
} else if (text) {
|
|
tokens.push(`<span style="${styleBody(style)}">${escapeHTML(text)}</span>`);
|
|
}
|
|
}
|
|
return tokens.join('');
|
|
}
|
|
|
|
const ansiColors: Record<number, string> = {
|
|
0: 'var(--vscode-terminal-ansiBlack)',
|
|
1: 'var(--vscode-terminal-ansiRed)',
|
|
2: 'var(--vscode-terminal-ansiGreen)',
|
|
3: 'var(--vscode-terminal-ansiYellow)',
|
|
4: 'var(--vscode-terminal-ansiBlue)',
|
|
5: 'var(--vscode-terminal-ansiMagenta)',
|
|
6: 'var(--vscode-terminal-ansiCyan)',
|
|
7: 'var(--vscode-terminal-ansiWhite)',
|
|
};
|
|
|
|
const brightAnsiColors: Record<number, string> = {
|
|
0: 'var(--vscode-terminal-ansiBrightBlack)',
|
|
1: 'var(--vscode-terminal-ansiBrightRed)',
|
|
2: 'var(--vscode-terminal-ansiBrightGreen)',
|
|
3: 'var(--vscode-terminal-ansiBrightYellow)',
|
|
4: 'var(--vscode-terminal-ansiBrightBlue)',
|
|
5: 'var(--vscode-terminal-ansiBrightMagenta)',
|
|
6: 'var(--vscode-terminal-ansiBrightCyan)',
|
|
7: 'var(--vscode-terminal-ansiBrightWhite)',
|
|
};
|
|
|
|
function escapeHTML(text: string): string {
|
|
return text.replace(/[&"<>]/g, c => ({ '&': '&', '"': '"', '<': '<', '>': '>' }[c]!));
|
|
}
|
|
|
|
function styleBody(style: any): string {
|
|
return Object.entries(style).map(([name, value]) => `${name}: ${value}`).join('; ');
|
|
}
|