forked from defunkt/toes
Move styles array outside the parse loop in ansiToHtml so styles accumulate across sequences, and use stripAnsi when filtering live logs so search matches visible text.
72 lines
1.7 KiB
TypeScript
72 lines
1.7 KiB
TypeScript
const ESC = /\x1b\[([0-9;]*)m/g
|
|
|
|
const STYLES: Record<number, string> = {
|
|
1: 'font-weight:bold',
|
|
2: 'opacity:0.7',
|
|
30: 'color:#666',
|
|
31: 'color:#f87171',
|
|
32: 'color:#4ade80',
|
|
33: 'color:#facc15',
|
|
34: 'color:#60a5fa',
|
|
35: 'color:#c084fc',
|
|
36: 'color:#22d3ee',
|
|
37: 'color:#e5e5e5',
|
|
90: 'color:#999',
|
|
91: 'color:#fca5a5',
|
|
92: 'color:#86efac',
|
|
93: 'color:#fde047',
|
|
94: 'color:#93c5fd',
|
|
95: 'color:#d8b4fe',
|
|
96: 'color:#67e8f9',
|
|
97: 'color:#fff',
|
|
}
|
|
|
|
const escape = (s: string) =>
|
|
s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
|
|
export const stripAnsi = (s: string) =>
|
|
s.replace(/\x1b\[[0-9;]*m/g, '')
|
|
|
|
export function ansiToHtml(text: string): string {
|
|
if (!text.includes('\x1b')) return escape(text)
|
|
|
|
ESC.lastIndex = 0
|
|
let result = ''
|
|
let last = 0
|
|
let open = false
|
|
const styles: string[] = []
|
|
let match: RegExpExecArray | null
|
|
|
|
while ((match = ESC.exec(text)) !== null) {
|
|
result += escape(text.slice(last, match.index))
|
|
last = match.index + match[0].length
|
|
|
|
const codes = match[1] ? match[1].split(';').map(Number) : [0]
|
|
|
|
for (const code of codes) {
|
|
if (code === 0) {
|
|
styles.length = 0
|
|
if (open) { result += '</span>'; open = false }
|
|
} else if (code === 39) {
|
|
const filtered = styles.filter(s => !s.startsWith('color:'))
|
|
styles.length = 0
|
|
styles.push(...filtered)
|
|
if (open) { result += '</span>'; open = false }
|
|
} else if (STYLES[code]) {
|
|
styles.push(STYLES[code])
|
|
}
|
|
}
|
|
|
|
if (styles.length) {
|
|
if (open) result += '</span>'
|
|
result += `<span style="${styles.join(';')}">`
|
|
open = true
|
|
}
|
|
}
|
|
|
|
result += escape(text.slice(last))
|
|
if (open) result += '</span>'
|
|
|
|
return result
|
|
}
|