Fix carriage return handling to emulate line overwrite
This commit is contained in:
parent
350c352989
commit
21b8caeb67
2 changed files with 62 additions and 16 deletions
|
|
@ -285,14 +285,35 @@ test("multiple newlines with styling", () => {
|
|||
);
|
||||
});
|
||||
|
||||
test("carriage return is stripped", () => {
|
||||
test("carriage return in \\r\\n is treated as line ending", () => {
|
||||
const result = ansiToHtml("line1\r\nline2");
|
||||
expect(result).toBe("line1\nline2");
|
||||
});
|
||||
|
||||
test("standalone carriage return is stripped", () => {
|
||||
test("standalone carriage return overwrites from line start", () => {
|
||||
const result = ansiToHtml("text\rmore");
|
||||
expect(result).toBe("textmore");
|
||||
expect(result).toBe("more");
|
||||
});
|
||||
|
||||
test("multiple carriage returns overwrite progressively", () => {
|
||||
const result = ansiToHtml("loading...\rloading...\rdone ");
|
||||
// Note: trailing spaces are trimmed by trimLineEndPreserveAnsi
|
||||
expect(result).toBe("done");
|
||||
});
|
||||
|
||||
test("carriage return with newlines preserves lines", () => {
|
||||
const result = ansiToHtml("line1\nloading...\rdone\nline3");
|
||||
expect(result).toBe("line1\ndone\nline3");
|
||||
});
|
||||
|
||||
test("carriage return with styling preserves style", () => {
|
||||
const result = ansiToHtml("\x1b[31mloading...\rdone\x1b[0m");
|
||||
expect(result).toBe('<span style="color:#f85149">done</span>');
|
||||
});
|
||||
|
||||
test("carriage return at start of line", () => {
|
||||
const result = ansiToHtml("\rtext");
|
||||
expect(result).toBe("text");
|
||||
});
|
||||
|
||||
// 9. trimLineEndPreserveAnsi tests
|
||||
|
|
|
|||
31
src/ansi.ts
31
src/ansi.ts
|
|
@ -274,8 +274,7 @@ export function ansiToHtml(text: string): string {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Track newlines in the content
|
||||
if (text[i] === "\n" || text[i] === "\r") {
|
||||
// Track newlines and carriage returns
|
||||
if (text[i] === "\n") {
|
||||
// Close span before newline to prevent background color bleeding
|
||||
if (inSpan) {
|
||||
|
|
@ -286,8 +285,34 @@ export function ansiToHtml(text: string): string {
|
|||
if (inSpan) {
|
||||
result += `<span style="${currentStyle}">`;
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
// Skip carriage return - we only care about line feeds
|
||||
|
||||
// Carriage return: overwrite from start of current line
|
||||
if (text[i] === "\r") {
|
||||
// Check if this is \r\n - if so, just skip the \r
|
||||
if (text[i + 1] === "\n") {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Standalone \r: truncate back to last newline (or start)
|
||||
// Need to handle open spans carefully
|
||||
const lastNewline = result.lastIndexOf("\n");
|
||||
if (lastNewline >= 0) {
|
||||
// Truncate after the last newline
|
||||
result = result.substring(0, lastNewline + 1);
|
||||
} else {
|
||||
// No newline found, truncate everything
|
||||
result = "";
|
||||
}
|
||||
|
||||
// If we had a span open, we need to reopen it after truncation
|
||||
if (inSpan) {
|
||||
result += `<span style="${currentStyle}">`;
|
||||
}
|
||||
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue