remove old parser

This commit is contained in:
LenAnderson
2024-04-20 09:00:36 -04:00
parent 45cde8b5f1
commit ba0c896eef

View File

@ -37,7 +37,7 @@ import {
system_message_types, system_message_types,
this_chid, this_chid,
} from '../script.js'; } from '../script.js';
import { SlashCommandParser as NewSlashCommandParser } from './slash-commands/SlashCommandParser.js'; import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
import { SlashCommandParserError } from './slash-commands/SlashCommandParserError.js'; import { SlashCommandParserError } from './slash-commands/SlashCommandParserError.js';
import { SlashCommandExecutor } from './slash-commands/SlashCommandExecutor.js'; import { SlashCommandExecutor } from './slash-commands/SlashCommandExecutor.js';
import { getMessageTimeStamp } from './RossAscends-mods.js'; import { getMessageTimeStamp } from './RossAscends-mods.js';
@ -62,179 +62,7 @@ export {
executeSlashCommands, getSlashCommandsHelp, registerSlashCommand, executeSlashCommands, getSlashCommandsHelp, registerSlashCommand,
}; };
class SlashCommandParser { export const parser = new SlashCommandParser();
static COMMENT_KEYWORDS = ['#', '/'];
static RESERVED_KEYWORDS = [
...this.COMMENT_KEYWORDS,
];
constructor() {
/**
* @type {Record<string, SlashCommand>} - Slash commands registered in the parser
*/
this.commands = {};
/**
* @type {Record<string, string>} - Help strings for each command
*/
this.helpStrings = {};
}
/**
* Adds a slash command to the parser.
* @param {string} command - The command name
* @param {function} callback - The callback function to execute
* @param {string[]} aliases - The command aliases
* @param {string} helpString - The help string for the command
* @param {boolean} [interruptsGeneration] - Whether the command interrupts message generation
* @param {boolean} [purgeFromMessage] - Whether the command should be purged from the message
* @returns {void}
*/
addCommand(command, callback, aliases, helpString = '', interruptsGeneration = false, purgeFromMessage = true) {
const fnObj = { callback, helpString, interruptsGeneration, purgeFromMessage };
if ([command, ...aliases].some(x => SlashCommandParser.RESERVED_KEYWORDS.includes(x))) {
console.error('ERROR: Reserved slash command keyword used!');
return;
}
if ([command, ...aliases].some(x => Object.hasOwn(this.commands, x))) {
console.trace('WARN: Duplicate slash command registered!');
}
this.commands[command] = fnObj;
if (Array.isArray(aliases)) {
aliases.forEach((alias) => {
this.commands[alias] = fnObj;
});
}
let stringBuilder = `<span class="monospace">/${command}</span> ${helpString} `;
if (Array.isArray(aliases) && aliases.length) {
let aliasesString = `(alias: ${aliases.map(x => `<span class="monospace">/${x}</span>`).join(', ')})`;
stringBuilder += aliasesString;
}
this.helpStrings[command] = stringBuilder;
}
/**
* Parses a slash command to extract the command name, the (named) arguments and the remaining text
* @param {string} text - Slash command text
* @returns {{command: SlashCommand, args: object, value: string, commandName: string}} - The parsed command, its arguments and the remaining text
*/
parse(text) {
// Parses a command even when spaces are present in arguments
// /buttons labels=["OK","I do not accept"] some text
// /fuzzy list=[ "red pink" , "yellow" ] threshold=" 0.6 " he yelled when the color was reddish and not pink | /echo
const excludedFromRegex = ['sendas'];
let command = '';
const argObj = {};
let unnamedArg = '';
// extract the command " /fuzzy " => "fuzzy"
text = text.trim();
let remainingText = '';
const commandArgPattern = /^\/([^\s]+)\s*(.*)$/s;
let match = commandArgPattern.exec(text);
if (match !== null && match[1].length > 0) {
command = match[1];
remainingText = match[2];
console.debug('command:' + command);
}
if (SlashCommandParser.COMMENT_KEYWORDS.includes(command)) {
return {
commandName: command,
command: {
callback: () => {},
helpString: '',
interruptsGeneration: false,
purgeFromMessage: true,
},
args: {},
value: '',
};
}
// parse the rest of the string to extract named arguments, the remainder is the "unnamedArg" which is usually text, like the prompt to send
while (remainingText.length > 0) {
// does the remaining text is like nameArg=[value] or nameArg=[value,value] or nameArg=[ value , value , value]
// where value can be a string like " this is some text " , note previously it was not possible to have have spaces
// where value can be a scalar like AScalar
// where value can be a number like +9 -1005.44
// where value can be a macro like {{getvar::name}}
const namedArrayArgPattern = /^(\w+)=\[\s*(((?<quote>["'])[^"]*(\k<quote>)|{{[^}]*}}|[+-]?\d*\.?\d+|\w*)\s*,?\s*)+\]/s;
match = namedArrayArgPattern.exec(remainingText);
if (match !== null && match[0].length > 0) {
//console.log(`matching: ${match[0]}`);
const posFirstEqual = match[0].indexOf('=');
const key = match[0].substring(0, posFirstEqual).trim();
const value = match[0].substring(posFirstEqual + 1).trim();
// Remove the quotes around the value, if any
argObj[key] = value.replace(/(^")|("$)/g, '');
remainingText = remainingText.slice(match[0].length + 1).trim();
continue;
}
// does the remaining text is like nameArg=value
// where value can be a string like " this is some text " , note previously it was not possible to have have spaces
// where value can be a scalar like AScalar
// where value can be a number like +9 -1005.44
// where value can be a macro like {{getvar::name}}
const namedScalarArgPattern = /^(\w+)=(((?<quote>["'])[^"]*(\k<quote>)|{{[^}]*}}|[+-]?\d*\.?\d+|\w*))/s;
match = namedScalarArgPattern.exec(remainingText);
if (match !== null && match[0].length > 0) {
//console.log(`matching: ${match[0]}`);
const posFirstEqual = match[0].indexOf('=');
const key = match[0].substring(0, posFirstEqual).trim();
const value = match[0].substring(posFirstEqual + 1).trim();
// Remove the quotes around the value, if any
argObj[key] = value.replace(/(^")|("$)/g, '');
remainingText = remainingText.slice(match[0].length + 1).trim();
continue;
}
// the remainder that matches no named argument is the "unamedArg" previously mentioned
unnamedArg = remainingText.trim();
remainingText = '';
}
// Excluded commands format in their own function
if (!excludedFromRegex.includes(command)) {
console.debug(`parse: !excludedFromRegex.includes(${command}`);
console.debug(` parse: unnamedArg before: ${unnamedArg}`);
unnamedArg = getRegexedString(
unnamedArg,
regex_placement.SLASH_COMMAND,
);
console.debug(` parse: unnamedArg after: ${unnamedArg}`);
}
// your weird complex command is now transformed into a juicy tiny text or something useful :)
if (this.commands[command]) {
return { command: this.commands[command], args: argObj, value: unnamedArg, commandName: command };
}
return null;
}
getHelpString() {
const listItems = Object
.entries(this.helpStrings)
.sort((a, b) => a[0].localeCompare(b[0]))
.map(x => x[1])
.map(x => `<li>${x}</li>`)
.join('\n');
return `<p>Slash commands:</p><ol>${listItems}</ol>
<small>Slash commands can be batched into a single input by adding a pipe character | at the end, and then writing a new slash command.</small>
<ul><li><small>Example:</small><code>/cut 1 | /sys Hello, | /continue</code></li>
<li>This will remove the first message in chat, send a system message that starts with 'Hello,', and then ask the AI to continue the message.</li></ul>`;
}
}
export const parser = new NewSlashCommandParser();
const registerSlashCommand = parser.addCommand.bind(parser); const registerSlashCommand = parser.addCommand.bind(parser);
const getSlashCommandsHelp = parser.getHelpString.bind(parser); const getSlashCommandsHelp = parser.getHelpString.bind(parser);