// ANSI 颜色与样式工具 // 忠实移植 CCometixLine 的 apply_color / apply_style / apply_background_color 逻辑 import type { AnsiColor } from "./types.ts"; /** 16 色前景码 */ function fg16Code(c16: number): string { const code = c16 < 8 ? 30 + c16 : 90 + (c16 - 8); return `\x1b[${code}m`; } /** 16 色背景码 */ function bg16Code(c16: number): string { const code = c16 < 8 ? 40 + c16 : 100 + (c16 - 8); return `\x1b[${code}m`; } /** 颜色 → 前景 SGR 序列(不含文本与 reset) */ export function fgSeq(color: AnsiColor): string { if ("c16" in color) return fg16Code(color.c16); if ("c256" in color) return `\x1b[38;5;${color.c256}m`; return `\x1b[38;2;${color.r};${color.g};${color.b}m`; } /** 颜色 → 背景序列(不含文本与 reset) */ export function bgSeq(color: AnsiColor): string { if ("c16" in color) return bg16Code(color.c16); if ("c256" in color) return `\x1b[48;5;${color.c256}m`; return `\x1b[48;2;${color.r};${color.g};${color.b}m`; } /** 应用前景色 + 可选加粗,末尾追加 reset(对齐 CCometixLine apply_style) */ export function colorText(text: string, color?: AnsiColor, bold = false): string { const codes: string[] = []; if (bold) codes.push("1"); if (color) { if ("c16" in color) { codes.push(String(color.c16 < 8 ? 30 + color.c16 : 90 + (color.c16 - 8))); } else if ("c256" in color) { codes.push("38", "5", String(color.c256)); } else { codes.push("38", "2", String(color.r), String(color.g), String(color.b)); } } if (codes.length === 0) return text; return `\x1b[${codes.join(";")}m${text}\x1b[0m`; }