Files
shahondin1624 31300cc2a2 Include shared/ dir in repo (gitignore allowlist)
The previous commit referenced shared/ansi.ts, shared/format.ts, and
shared/ctx.ts but those files were filtered by the default-deny
.gitignore. Adding !/shared/ to the allowlist so the imports actually
resolve in a fresh clone.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 00:05:38 +02:00

48 lines
1.6 KiB
TypeScript

/**
* ANSI escape-sequence helpers shared across extensions.
*
* Kept free of relative imports so Node's --experimental-strip-types can load
* this directly in tests.
*/
export const ANSI_RESET_FG = "\x1b[39m";
export const ANSI_RESET_ALL = "\x1b[0m";
/**
* Convert `#rrggbb` (or `#rgb`) to [r, g, b] bytes. Throws on malformed input
* rather than silently producing NaN — previously the callers built broken
* ANSI codes out of `\x1b[38;2;NaN;NaN;NaNm` which some terminals render as
* bright cyan, giving mysterious color bugs.
*/
export function hexToRgb(hex: string): [number, number, number] {
const m = hex.trim().replace(/^#/, "");
const expanded =
m.length === 3 ? m.split("").map((c) => c + c).join("") : m;
if (!/^[0-9a-fA-F]{6}$/.test(expanded)) {
throw new Error(`Invalid hex color: ${hex}`);
}
const n = parseInt(expanded, 16);
return [(n >> 16) & 0xff, (n >> 8) & 0xff, n & 0xff];
}
/** Build a 24-bit foreground ANSI escape for an `#rrggbb` hex color. */
export function fgFromHex(hex: string): string {
const [r, g, b] = hexToRgb(hex);
return `\x1b[38;2;${r};${g};${b}m`;
}
/**
* Strip every ANSI CSI escape sequence from a string. Useful when the
* renderer needs to know the visible width of a line that contains color
* codes.
*/
export function stripAnsi(s: string): string {
// biome-ignore lint/suspicious/noControlCharactersInRegex: CSI stripping is the point
return s.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "");
}
/** Count visible grapheme-less characters. Mirrors pi-tui's visibleWidth. */
export function visibleWidth(s: string): number {
return stripAnsi(s).length;
}