121 lines
5.2 KiB
JavaScript
121 lines
5.2 KiB
JavaScript
import { MessageFlags } from 'discord-api-types/v10';
|
||
import { SlashCommandBuilder, PermissionFlagsBits } from 'discord.js';
|
||
|
||
import { CODES } from '../_src/ansiColors.js';
|
||
|
||
/**
|
||
* Combined ANSI utilities module
|
||
* - /ansi: preview nested [tag]…[/] ANSI coloring
|
||
* - /ansitheme: display full BG×FG theme chart
|
||
* Both commands are Admin-only.
|
||
*/
|
||
export const commands = [
|
||
// Preview arbitrary ANSI tags
|
||
{
|
||
data: new SlashCommandBuilder()
|
||
.setName('ansi')
|
||
.setDescription('Preview an ANSI-colored code block')
|
||
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
|
||
.setDMPermission(false)
|
||
.addStringOption(opt =>
|
||
opt
|
||
.setName('text')
|
||
.setDescription('Use [red]…[/], [bold,blue]…[/], escape \\[/]')
|
||
.setRequired(true)
|
||
)
|
||
.addBooleanOption(opt =>
|
||
opt
|
||
.setName('ephemeral')
|
||
.setDescription('Reply ephemerally?')
|
||
.setRequired(false)
|
||
),
|
||
async execute(interaction, client) {
|
||
const raw = interaction.options.getString('text', true);
|
||
const ephemeral = interaction.options.getBoolean('ephemeral') ?? true;
|
||
const colored = client.ansi`${raw}`;
|
||
const block = client.wrapAnsi(colored);
|
||
const opts = { content: block };
|
||
if (ephemeral) opts.flags = MessageFlags.Ephemeral;
|
||
await interaction.reply(opts);
|
||
}
|
||
},
|
||
|
||
// Show complete ANSI theme chart
|
||
{
|
||
data: new SlashCommandBuilder()
|
||
.setName('ansitheme')
|
||
.setDescription('Show ANSI color theme chart')
|
||
.setDefaultMemberPermissions(PermissionFlagsBits.Administrator)
|
||
.setDMPermission(false)
|
||
.addBooleanOption(opt =>
|
||
opt
|
||
.setName('ephemeral')
|
||
.setDescription('Reply ephemerally?')
|
||
.setRequired(false)
|
||
),
|
||
async execute(interaction, client) {
|
||
const fgs = ['gray', 'red', 'green', 'yellow', 'blue', 'pink', 'cyan', 'white'];
|
||
const bgs = ['bgGray', 'bgOrange', 'bgBlue', 'bgTurquoise', 'bgFirefly', 'bgIndigo', 'bgLightGray', 'bgWhite'];
|
||
const pad = 8;
|
||
// Column header with padded labels (no colors) - shifted right by 1
|
||
const header = ' ' + fgs.map(f => f.padEnd(pad, ' ')).join('');
|
||
// Sample row with no background (padded cells)
|
||
let defaultRow = '';
|
||
for (const fg of fgs) {
|
||
const fgCode = CODES[fg];
|
||
const openNormal = `\u001b[${fgCode}m`;
|
||
const openBold = `\u001b[${fgCode};${CODES.bold}m`;
|
||
const openUnder = `\u001b[${fgCode};${CODES.underline}m`;
|
||
const cell = `${openNormal}sa\u001b[0m${openBold}mp\u001b[0m${openUnder}le\u001b[0m`;
|
||
defaultRow += ' ' + cell + ' ';
|
||
}
|
||
// Append default row label after one pad
|
||
defaultRow += 'default';
|
||
// Colored rows per background
|
||
const rows = [];
|
||
for (const bg of bgs) {
|
||
let row = '';
|
||
const bgCode = CODES[bg];
|
||
for (const fg of fgs) {
|
||
const fgCode = CODES[fg];
|
||
const openNormal = `\u001b[${bgCode};${fgCode}m`;
|
||
const openBold = `\u001b[${bgCode};${fgCode};${CODES.bold}m`;
|
||
const openUnder = `\u001b[${bgCode};${fgCode};${CODES.underline}m`;
|
||
const cell = `${openNormal}sa\u001b[0m${openBold}mp\u001b[0m${openUnder}le\u001b[0m`;
|
||
row += ' ' + cell + ' ';
|
||
}
|
||
// Append uncolored row label immediately after cell padding
|
||
row += bg;
|
||
rows.push(row);
|
||
}
|
||
// Determine ephemeral setting
|
||
const ephemeral = interaction.options.getBoolean('ephemeral') ?? true;
|
||
// Initial sample table (header + default row)
|
||
const sampleContent = [header, defaultRow].join('\n');
|
||
const optsSample = { content: client.wrapAnsi(sampleContent) };
|
||
if (ephemeral) optsSample.flags = MessageFlags.Ephemeral;
|
||
await interaction.reply(optsSample);
|
||
// Split colored rows into two tables
|
||
const half = Math.ceil(rows.length / 2);
|
||
const firstRows = rows.slice(0, half);
|
||
const secondRows = rows.slice(half);
|
||
// First colored table
|
||
const table1 = [header, ...firstRows].join('\n');
|
||
const opts1 = { content: client.wrapAnsi(table1) };
|
||
if (ephemeral) opts1.flags = MessageFlags.Ephemeral;
|
||
await interaction.followUp(opts1);
|
||
// Second colored table
|
||
if (secondRows.length > 0) {
|
||
const table2 = [header, ...secondRows].join('\n');
|
||
const opts2 = { content: client.wrapAnsi(table2) };
|
||
if (ephemeral) opts2.flags = MessageFlags.Ephemeral;
|
||
await interaction.followUp(opts2);
|
||
}
|
||
}
|
||
}
|
||
];
|
||
|
||
export async function init(client) {
|
||
client.logger.info('[module:ansi] Loaded ANSI utilities');
|
||
}
|