diff options
Diffstat (limited to 'src/utils/grid.ts')
| -rw-r--r-- | src/utils/grid.ts | 83 |
1 files changed, 82 insertions, 1 deletions
diff --git a/src/utils/grid.ts b/src/utils/grid.ts index 71370da..1a2aa29 100644 --- a/src/utils/grid.ts +++ b/src/utils/grid.ts @@ -1,7 +1,88 @@ import type { AnsiTermColor, Grid } from '@/types/grid'; -import { getAnsiColorEscape, getAnsiEscapeCodeFromDiff } from './ansi'; +import { getAnsiColorEscape, getAnsiEscapeCodeFromDiff, parseAnsiColorCode } from './ansi'; const defaultColor: AnsiTermColor = { foreground: null, background: null }; + +export const gridFromAnsi = (ansiText: string): Grid => { + const lines = ansiText.split('\n'); + const grid: Grid = []; + + for (let y = 0; y < lines.length; y++) { + const line = lines[y]; + const row: Grid[0] = []; + let x = 0; + let currentColor: AnsiTermColor = { ...defaultColor }; + + // Regex to match ANSI escape codes + const ansiRegex = /\x1b\[([0-9;]+)m/g; + let lastIndex = 0; + let match; + + while ((match = ansiRegex.exec(line)) !== null) { + // Add characters before this escape code + const text = line.slice(lastIndex, match.index); + for (const char of text) { + row.push({ char, color: { ...currentColor }, x: x++, y }); + } + + // Parse escape code + const codes = match[1].split(';').map(Number); + let i = 0; + while (i < codes.length) { + const code = codes[i]; + + if (code === 38 && codes[i + 1] === 5) { + // Foreground color: ESC[38;5;{code}m + const colorCode = codes[i + 2]; + currentColor.foreground = parseAnsiColorCode(colorCode); + i += 3; + } else if (code === 48 && codes[i + 1] === 5) { + // Background color: ESC[48;5;{code}m + const colorCode = codes[i + 2]; + currentColor.background = parseAnsiColorCode(colorCode); + i += 3; + } else if (code === 39) { + // Reset foreground + currentColor.foreground = null; + i++; + } else if (code === 49) { + // Reset background + currentColor.background = null; + i++; + } else { + i++; + } + } + + lastIndex = ansiRegex.lastIndex; + } + + // Add remaining characters + const remainingText = line.slice(lastIndex); + for (const char of remainingText) { + row.push({ char, color: { ...currentColor }, x: x++, y }); + } + + grid.push(row); + } + + // Normalize grid width + const maxWidth = Math.max(...grid.map(row => row.length)); + for (let y = 0; y < grid.length; y++) { + while (grid[y].length < maxWidth) { + const x = grid[y].length; + grid[y].push({ + char: ' ', + color: { ...defaultColor }, + x, + y, + }); + } + } + + return grid; +}; + export const gridFromAscii = ( ascii: string, color: AnsiTermColor = defaultColor, |
