forked from defunkt/toes
Refactor ANSI parser to support SGR reset (code 39) and bold/dim styles
Merge color and style maps into a unified STYLES table, hoist the regex to module scope, export stripAnsi for use in log parsing, and handle SGR 39 (default foreground) by removing only color styles instead of clearing all styles. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
33d91747af
commit
a824d62058
|
|
@ -1,26 +1,36 @@
|
|||
const COLORS: Record<number, string> = {
|
||||
30: '#666', // black (brightened for dark bg)
|
||||
31: '#f87171', // red
|
||||
32: '#4ade80', // green
|
||||
33: '#facc15', // yellow
|
||||
34: '#60a5fa', // blue
|
||||
35: '#c084fc', // magenta
|
||||
36: '#22d3ee', // cyan
|
||||
37: '#e5e5e5', // white
|
||||
90: '#999', // bright black
|
||||
91: '#fca5a5', // bright red
|
||||
92: '#86efac', // bright green
|
||||
93: '#fde047', // bright yellow
|
||||
94: '#93c5fd', // bright blue
|
||||
95: '#d8b4fe', // bright magenta
|
||||
96: '#67e8f9', // bright cyan
|
||||
97: '#fff', // bright white
|
||||
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)
|
||||
|
||||
const ESC = /\x1b\[([0-9;]*)m/g
|
||||
ESC.lastIndex = 0
|
||||
let result = ''
|
||||
let last = 0
|
||||
let open = false
|
||||
|
|
@ -34,15 +44,16 @@ export function ansiToHtml(text: string): string {
|
|||
const styles: string[] = []
|
||||
|
||||
for (const code of codes) {
|
||||
if (code === 0 || code === 39) {
|
||||
if (code === 0) {
|
||||
styles.length = 0
|
||||
if (open) { result += '</span>'; open = false }
|
||||
} else if (COLORS[code]) {
|
||||
styles.push(`color:${COLORS[code]}`)
|
||||
} else if (code === 1) {
|
||||
styles.push('font-weight:bold')
|
||||
} else if (code === 2) {
|
||||
styles.push('opacity:0.7')
|
||||
} 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])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +69,3 @@ export function ansiToHtml(text: string): string {
|
|||
|
||||
return result
|
||||
}
|
||||
|
||||
const escape = (s: string) =>
|
||||
s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ansiToHtml } from '../ansi'
|
||||
import { ansiToHtml, stripAnsi } from '../ansi'
|
||||
import { isNarrow } from '../state'
|
||||
import {
|
||||
LogApp,
|
||||
|
|
@ -59,7 +59,7 @@ function parseLogText(text: string): { method?: string, path?: string, status?:
|
|||
}
|
||||
|
||||
function LogLineEntry({ log }: { log: UnifiedLogLine }) {
|
||||
const parsed = parseLogText(log.text)
|
||||
const parsed = parseLogText(stripAnsi(log.text))
|
||||
const statusColor = getStatusColor(parsed.status)
|
||||
const narrow = isNarrow || undefined
|
||||
return (
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user