mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
fix(tui): close truncated OSC 8 links (#7657)
When truncateToWidth() cut through an OSC 8 hyperlink label, the retained prefix could leave the hyperlink open. Close an active hyperlink before the existing reset and ellipsis, preserving its BEL or ST terminator. Added a focused regression test for the reported BEL-terminated case.
This commit is contained in:
parent
6bfd50261d
commit
b780d20aa1
2 changed files with 29 additions and 2 deletions
|
|
@ -153,13 +153,14 @@ function finalizeTruncatedResult(
|
|||
pad: boolean,
|
||||
): string {
|
||||
const reset = "\x1b[0m";
|
||||
const hyperlinkClose = getActiveOsc8Close(prefix);
|
||||
const visibleWidth = prefixWidth + ellipsisWidth;
|
||||
let result: string;
|
||||
|
||||
if (ellipsis.length > 0) {
|
||||
result = `${prefix}${reset}${ellipsis}${reset}`;
|
||||
result = `${prefix}${hyperlinkClose}${reset}${ellipsis}${reset}`;
|
||||
} else {
|
||||
result = `${prefix}${reset}`;
|
||||
result = `${prefix}${hyperlinkClose}${reset}`;
|
||||
}
|
||||
|
||||
return pad ? result + " ".repeat(Math.max(0, maxWidth - visibleWidth)) : result;
|
||||
|
|
@ -478,6 +479,24 @@ function formatOsc8Close(terminator: Osc8Terminator): string {
|
|||
return `\x1b]8;;${terminator}`;
|
||||
}
|
||||
|
||||
function getActiveOsc8Close(prefix: string): string {
|
||||
let activeHyperlink: ActiveHyperlink | null = null;
|
||||
let i = 0;
|
||||
while (i < prefix.length) {
|
||||
const ansi = extractAnsiCode(prefix, i);
|
||||
if (ansi) {
|
||||
const hyperlink = parseOsc8Hyperlink(ansi.code);
|
||||
if (hyperlink !== undefined) {
|
||||
activeHyperlink = hyperlink;
|
||||
}
|
||||
i += ansi.length;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return activeHyperlink ? formatOsc8Close(activeHyperlink.terminator) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Track active ANSI SGR codes to preserve styling across line breaks.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -20,6 +20,14 @@ describe("truncateToWidth", () => {
|
|||
assert.strictEqual(truncated.endsWith("\x1b[0m…\x1b[0m"), true);
|
||||
});
|
||||
|
||||
it("closes a BEL-terminated OSC 8 link when truncating its label", () => {
|
||||
const open = "\x1b]8;;https://example.com\x07";
|
||||
const close = "\x1b]8;;\x07";
|
||||
const text = `${open}some-longer-label-here${close}`;
|
||||
|
||||
assert.strictEqual(truncateToWidth(text, 15), `${open}some-longer-${close}\x1b[0m...\x1b[0m`);
|
||||
});
|
||||
|
||||
it("handles malformed ANSI escape prefixes without hanging", () => {
|
||||
const text = `abc\x1bnot-ansi ${"🙂".repeat(1000)}`;
|
||||
const truncated = truncateToWidth(text, 20, "…");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue