import { addOneMessage, chat, chat_metadata, saveChatConditional, sendSystemMessage, system_avatar, system_message_types } from "../script.js"; import { humanizedDateTime } from "./RossAscends-mods.js"; export { executeSlashCommands, registerSlashCommand, getSlashCommandsHelp, } class SlashCommandParser { constructor() { this.commands = {}; this.helpStrings = []; } addCommand(command, callback, aliases, helpString = '', interruptsGeneration = false, purgeFromMessage = true) { const fnObj = { callback, helpString, interruptsGeneration, purgeFromMessage }; this.commands[command] = fnObj; if (Array.isArray(aliases)) { aliases.forEach((alias) => { this.commands[alias] = fnObj; }); } let stringBuilder = `/${command} ${helpString} `; if (Array.isArray(aliases) && aliases.length) { let aliasesString = `(aliases: ${aliases.map(x => `/${x}`).join(', ')})`; stringBuilder += aliasesString; } this.helpStrings.push(stringBuilder); } parse(text) { const firstSpace = text.indexOf(' '); const command = firstSpace !== -1 ? text.substring(1, firstSpace) : text.substring(1); const args = firstSpace !== -1 ? text.substring(firstSpace + 1) : ''; const argObj = {}; let unnamedArg; if (args.length > 0) { const argsArray = args.split(' '); for (let arg of argsArray) { const equalsIndex = arg.indexOf('='); if (equalsIndex !== -1) { const key = arg.substring(0, equalsIndex); const value = arg.substring(equalsIndex + 1); argObj[key] = value; } else { break; } } unnamedArg = argsArray.slice(Object.keys(argObj).length).join(' '); } if (this.commands[command]) { return { command: this.commands[command], args: argObj, value: unnamedArg }; } return false; } getHelpString() { const listItems = this.helpStrings.map(x => `
  • ${x}
  • `).join('\n'); return `

    Slash commands:

      ${listItems}
    `; } } const parser = new SlashCommandParser(); const registerSlashCommand = parser.addCommand.bind(parser); const getSlashCommandsHelp = parser.getHelpString.bind(parser); parser.addCommand('help', helpCommandCallback, ['?'], ' – displays this help message', true, true); parser.addCommand('bg', setBackgroundCallback, ['background'], '(filename) – sets a background according to filename, partial names allowed, will set the first one alphebetically if multiple files begin with the provided argument string', false, true); parser.addCommand('sys', sendNarratorMessage, [], ' – sends message as a system narrator', false, true); parser.addCommand('sysname', setNarratorName, [], '(name) – sets a name for future system narrator messages in this chat (display only). Default: System. Leave empty to reset.', true, true); const NARRATOR_NAME_KEY = 'narrator_name'; const NARRATOR_NAME_DEFAULT = 'System'; function setNarratorName(_, text) { chat_metadata[NARRATOR_NAME_KEY] = text || NARRATOR_NAME_DEFAULT; saveChatConditional(); } function sendNarratorMessage(_, text) { if (!text) { return; } const name = chat_metadata[NARRATOR_NAME_KEY] || NARRATOR_NAME_DEFAULT; const message = { name: name, is_user: false, is_name: false, is_system: false, send_date: humanizedDateTime(), mes: text.trim(), force_avatar: system_avatar, extra: { type: system_message_types.NARRATOR, }, }; chat.push(message); addOneMessage(message); } function helpCommandCallback() { sendSystemMessage(system_message_types.HELP); } function setBackgroundCallback(_, bg) { if (!bg) { return; } console.log('Set background to ' + bg); const bgElement = $(`.bg_example[bgfile^="${bg.trim()}"`); if (bgElement.length) { bgElement.get(0).click(); } } function executeSlashCommands(text) { if (!text) { return false; } // Hack to allow multi-line slash commands // All slash command messages should begin with a slash const lines = [text]; const linesToRemove = []; let interrupt = false; for (let index = 0; index < lines.length; index++) { const trimmedLine = lines[index].trim(); if (!trimmedLine.startsWith('/')) { continue; } const result = parser.parse(trimmedLine); if (!result) { continue; } result.command.callback(result.args, result.value); if (result.command.interruptsGeneration) { interrupt = true; } if (result.command.purgeFromMessage) { linesToRemove.push(lines[index]); } } const newText = lines.filter(x => linesToRemove.indexOf(x) === -1).join('\n'); return { interrupt, newText }; }