ClientX/_src/ansiColors.js

91 lines
2.5 KiB
JavaScript
Raw Normal View History

// ANSI Colors helper - provides nested [tag]…[/] parsing and code-block wrapping.
// ANSI color/style codes
const CODES = {
2025-05-08 01:52:12 +00:00
// 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) {
2025-05-08 01:52:12 +00:00
return str
.replace(/\\\[/g, '__ESC_LB__')
.replace(/\\\]/g, '__ESC_RB__');
}
/** Restore any escaped brackets after formatting. */
export function restoreBrackets(str) {
2025-05-08 01:52:12 +00:00
return str
.replace(/__ESC_LB__/g, '[')
.replace(/__ESC_RB__/g, ']');
}
/**
* Parse nested [tag1,tag2][/] patterns into ANSI codes (stack-based).
*/
export function formatAnsi(input) {
2025-05-08 01:52:12 +00:00
const stack = [];
let output = '';
const pattern = /\[\/\]|\[([^\]]+)\]/g;
let lastIndex = 0;
let match;
2025-05-08 01:52:12 +00:00
while ((match = pattern.exec(input)) !== null) {
output += input.slice(lastIndex, match.index);
2025-05-08 01:52:12 +00:00
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`;
}
}
2025-05-08 01:52:12 +00:00
lastIndex = pattern.lastIndex;
}
2025-05-08 01:52:12 +00:00
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) {
2025-05-08 01:52:12 +00:00
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) {
2025-05-08 01:52:12 +00:00
return '```ansi\n' + text + '\n```';
}
// Export raw codes for advanced use (e.g., ansitheme module)
2025-05-08 01:52:12 +00:00
export { CODES };