Combine ANSI style codes into a single span element
Multiple SGR parameters in one escape sequence (e.g. bold + color) were each opening a new span, losing earlier styles. Collect styles per sequence and emit one span with all of them.
This commit is contained in:
parent
33d21777d3
commit
33d91747af
|
|
@ -17,14 +17,10 @@ const COLORS: Record<number, string> = {
|
|||
97: '#fff', // bright white
|
||||
}
|
||||
|
||||
const ESC = /\x1b\[([0-9;]*)m/g
|
||||
|
||||
const escape = (s: string) =>
|
||||
s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
||||
|
||||
export function ansiToHtml(text: string): string {
|
||||
if (!text.includes('\x1b')) return escape(text)
|
||||
|
||||
const ESC = /\x1b\[([0-9;]*)m/g
|
||||
let result = ''
|
||||
let last = 0
|
||||
let open = false
|
||||
|
|
@ -35,24 +31,26 @@ export function ansiToHtml(text: string): string {
|
|||
last = match.index + match[0].length
|
||||
|
||||
const codes = match[1] ? match[1].split(';').map(Number) : [0]
|
||||
const styles: string[] = []
|
||||
|
||||
for (const code of codes) {
|
||||
if (code === 0 || code === 39) {
|
||||
styles.length = 0
|
||||
if (open) { result += '</span>'; open = false }
|
||||
} else if (COLORS[code]) {
|
||||
if (open) result += '</span>'
|
||||
result += `<span style="color:${COLORS[code]}">`
|
||||
open = true
|
||||
styles.push(`color:${COLORS[code]}`)
|
||||
} else if (code === 1) {
|
||||
if (open) result += '</span>'
|
||||
result += '<span style="font-weight:bold">'
|
||||
open = true
|
||||
styles.push('font-weight:bold')
|
||||
} else if (code === 2) {
|
||||
if (open) result += '</span>'
|
||||
result += '<span style="opacity:0.7">'
|
||||
open = true
|
||||
styles.push('opacity:0.7')
|
||||
}
|
||||
}
|
||||
|
||||
if (styles.length) {
|
||||
if (open) result += '</span>'
|
||||
result += `<span style="${styles.join(';')}">`
|
||||
open = true
|
||||
}
|
||||
}
|
||||
|
||||
result += escape(text.slice(last))
|
||||
|
|
@ -60,3 +58,6 @@ export function ansiToHtml(text: string): string {
|
|||
|
||||
return result
|
||||
}
|
||||
|
||||
const escape = (s: string) =>
|
||||
s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user