// ANSI Colors helper - provides nested [tag]…[/] parsing and code-block wrapping. // ANSI color/style codes const CODES = { // text colors gray: 30, red: 31, green: 32, yellow: 33, blue: 34, pink: 35, cyan: 36, white: 37, // background colors bgGray: 40, bgOrange: 41, bgBlue: 42, bgTurquoise: 43, bgFirefly: 44, bgIndigo: 45, bgLightGray: 46, bgWhite: 47, // styles bold: 1, underline: 4, // reset reset: 0 }; /** * Escape literal brackets so users can write \[ and \] without triggering tags. */ export function escapeBrackets(str) { return str .replace(/\\\[/g, '__ESC_LB__') .replace(/\\\]/g, '__ESC_RB__'); } /** Restore any escaped brackets after formatting. */ export function restoreBrackets(str) { return str .replace(/__ESC_LB__/g, '[') .replace(/__ESC_RB__/g, ']'); } /** * Parse nested [tag1,tag2]…[/] patterns into ANSI codes (stack-based). */ export function formatAnsi(input) { const stack = []; let output = ''; const pattern = /\[\/\]|\[([^\]]+)\]/g; let lastIndex = 0; let match; while ((match = pattern.exec(input)) !== null) { output += input.slice(lastIndex, match.index); if (match[0] === '[/]') { if (stack.length) stack.pop(); output += `\u001b[${CODES.reset}m`; for (const tag of stack) { const code = CODES[tag] ?? CODES.gray; output += `\u001b[${code}m`; } } else { const tags = match[1].split(/[,;\s]+/).filter(Boolean); for (const tag of tags) { stack.push(tag); const code = CODES[tag] ?? CODES.gray; output += `\u001b[${code}m`; } } lastIndex = pattern.lastIndex; } output += input.slice(lastIndex); if (stack.length) output += `\u001b[${CODES.reset}m`; return output; } /** * Template-tag: ansi`[red]…[/] text` * Escapes brackets, parses ANSI, and restores literals. */ export function ansi(strings, ...values) { let built = ''; for (let i = 0; i < strings.length; i++) { built += strings[i]; if (i < values.length) built += values[i]; } return restoreBrackets(formatAnsi(escapeBrackets(built))); } /** Wrap text in a ```ansi code block for Discord. */ export function wrapAnsi(text) { return '```ansi\n' + text + '\n```'; } // Export raw codes for advanced use (e.g., ansitheme module) export { CODES };