diff --git a/src/ansi.ts b/src/ansi.ts index 56b4b86..6ee2b3d 100644 --- a/src/ansi.ts +++ b/src/ansi.ts @@ -55,40 +55,17 @@ interface ExtendedColorResult { // Trim trailing whitespace from each line to prevent background color bleeding. // Terminal buffers often pad lines with spaces. Preserve trailing ANSI resets. -// ESC character code -const ESC = "\x1b"; - export function trimLineEndPreserveAnsi(line: string): string { - // Peel off any ANSI sequences at the end of the line let end = line.length; let ansiSuffix = ""; while (end > 0) { - // Check for ANSI escape sequence at end: ESC [ params letter - const suffix = line.slice(0, end); - if (!suffix.endsWith("]")) { - // Look for the closing letter (A-Z, a-z) - const lastChar = suffix[suffix.length - 1]; - if (!lastChar || !/[A-Za-z]/.test(lastChar)) break; - - // Walk back to find ESC [ - let seqStart = suffix.length - 2; - while (seqStart >= 0 && /[0-9;?]/.test(suffix[seqStart] || "")) { - seqStart--; - } - if (seqStart < 0 || suffix[seqStart] !== "[") break; - seqStart--; - if (seqStart < 0 || suffix[seqStart] !== ESC) break; - - // Found a valid ANSI sequence - const seq = suffix.slice(seqStart); - ansiSuffix = seq + ansiSuffix; - end = seqStart; - } else { - break; - } + // biome-ignore lint/suspicious/noControlCharactersInRegex: ESC character is intentional for ANSI sequences + const match = line.slice(0, end).match(/\u001b\[[0-9;?]*[A-Za-z]$/); + if (!match) break; + ansiSuffix = match[0] + ansiSuffix; + end -= match[0].length; } - const trimmed = line.slice(0, end).trimEnd(); - return trimmed + ansiSuffix; + return line.slice(0, end).trimEnd() + ansiSuffix; } // Parse extended color: 38;2;R;G;B (24-bit) or 38;5;N (256-color)