Merge pull request #3682 from SillyTavern/feat-add-regex-toggle-command Add `/regex-toggle` slash command

c9e716d42f8c8ad80226746c94eb2d645865ebbc

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
1 files changed, +95 -9Showing whitespace changes
public/scripts/extensions/regex/index.js+95 -9
@@ -4,22 +4,16 @@ import { selected_group } from '../../group-chats.js';
4import { callGenericPopup, POPUP_TYPE } from '../../popup.js';4import { callGenericPopup, POPUP_TYPE } from '../../popup.js';
5import { SlashCommand } from '../../slash-commands/SlashCommand.js';5import { SlashCommand } from '../../slash-commands/SlashCommand.js';
6import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';6import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
7import { enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';7import { commonEnumProviders, enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
8import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';8import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
9import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';9import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
10import { download, getFileText, getSortableDelay, regexFromString, setInfoBlock, uuidv4 } from '../../utils.js';10import { download, equalsIgnoreCaseAndAccents, getFileText, getSortableDelay, isFalseBoolean, isTrueBoolean, regexFromString, setInfoBlock, uuidv4 } from '../../utils.js';
11import { regex_placement, runRegexScript, substitute_find_regex } from './engine.js';11import { regex_placement, runRegexScript, substitute_find_regex } from './engine.js';
12import { t } from '../../i18n.js';12import { t } from '../../i18n.js';
13import { accountStorage } from '../../util/AccountStorage.js';13import { accountStorage } from '../../util/AccountStorage.js';
1414
15/**15/**
16 * @typedef {object} RegexScript16 * @typedef {import('../../char-data.js').RegexScriptData} RegexScript
17 * @property {string} scriptName - The name of the script
18 * @property {boolean} disabled - Whether the script is disabled
19 * @property {string} replaceString - The replace string
20 * @property {string[]} trimStrings - The trim strings
21 * @property {string?} findRegex - The find regex
22 * @property {number?} substituteRegex - The substitute regex
23 */17 */
2418
25/**19/**
@@ -418,6 +412,53 @@ function runRegexCallback(args, value) {
418}412}
419413
420/**414/**
415 * /regex-toggle slash command callback
416 * @param {{state: string, quiet: string}} args Named arguments
417 * @param {string} scriptName The name of the script to toggle
418 * @returns {Promise<string>} The name of the script
419 */
420async function toggleRegexCallback(args, scriptName) {
421 if (typeof scriptName !== 'string') throw new Error('Script name must be a string.');
422
423 const quiet = isTrueBoolean(args?.quiet);
424 const action = isTrueBoolean(args?.state) ? 'enable' :
425 isFalseBoolean(args?.state) ? 'disable' :
426 'toggle';
427
428 const scripts = getRegexScripts();
429 const script = scripts.find(s => equalsIgnoreCaseAndAccents(s.scriptName, scriptName));
430
431 if (!script) {
432 toastr.warning(t`Regex script '${scriptName}' not found.`);
433 return '';
434 }
435
436 switch (action) {
437 case 'enable':
438 script.disabled = false;
439 break;
440 case 'disable':
441 script.disabled = true;
442 break;
443 default:
444 script.disabled = !script.disabled;
445 break;
446 }
447
448 const isScoped = characters[this_chid]?.data?.extensions?.regex_scripts?.some(s => s.id === script.id);
449 const index = isScoped ? characters[this_chid]?.data?.extensions?.regex_scripts?.indexOf(script) : scripts.indexOf(script);
450
451 await saveRegexScript(script, index, isScoped);
452 if (script.disabled) {
453 !quiet && toastr.success(t`Regex script '${scriptName}' has been disabled.`);
454 } else {
455 !quiet && toastr.success(t`Regex script '${scriptName}' has been enabled.`);
456 }
457
458 return script.scriptName || '';
459}
460
461/**
421 * Performs the import of the regex file.462 * Performs the import of the regex file.
422 * @param {File} file Input file463 * @param {File} file Input file
423 * @param {boolean} isScoped Is the script scoped to a character?464 * @param {boolean} isScoped Is the script scoped to a character?
@@ -639,6 +680,51 @@ jQuery(async () => {
639 ],680 ],
640 helpString: 'Runs a Regex extension script by name on the provided string. The script must be enabled.',681 helpString: 'Runs a Regex extension script by name on the provided string. The script must be enabled.',
641 }));682 }));
683 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
684 name: 'regex-toggle',
685 callback: toggleRegexCallback,
686 returns: 'The name of the script that was toggled',
687 namedArgumentList: [
688 SlashCommandNamedArgument.fromProps({
689 name: 'state',
690 description: 'Explicitly set the state of the script (\'on\' to enable, \'off\' to disable). If not provided, the state will be toggled to the opposite of the current state.',
691 typeList: [ARGUMENT_TYPE.BOOLEAN],
692 defaultValue: 'toggle',
693 enumList: commonEnumProviders.boolean('onOffToggle')(),
694 }),
695 SlashCommandNamedArgument.fromProps({
696 name: 'quiet',
697 description: 'Suppress the toast message script toggled',
698 typeList: [ARGUMENT_TYPE.BOOLEAN],
699 defaultValue: 'false',
700 enumList: commonEnumProviders.boolean('trueFalse')(),
701 }),
702 ],
703 unnamedArgumentList: [
704 SlashCommandArgument.fromProps({
705 description: 'script name',
706 typeList: [ARGUMENT_TYPE.STRING],
707 isRequired: true,
708 enumProvider: localEnumProviders.regexScripts,
709 }),
710 ],
711 helpString: `
712 <div>
713 Toggles the state of a specified regex script.
714 </div>
715 <div>
716 <strong>Example:</strong>
717 <ul>
718 <li>
719 <pre><code class="language-stscript">/regex-toggle MyScript</code></pre>
720 </li>
721 <li>
722 <pre><code class="language-stscript">/regex-toggle state=off Character-specific Script</code></pre>
723 </li>
724 </ul>
725 </div>
726 `,
727 }));
642728
643 eventSource.on(event_types.CHAT_CHANGED, checkEmbeddedRegexScripts);729 eventSource.on(event_types.CHAT_CHANGED, checkEmbeddedRegexScripts);
644 eventSource.on(event_types.CHARACTER_DELETED, purgeEmbeddedRegexScripts);730 eventSource.on(event_types.CHARACTER_DELETED, purgeEmbeddedRegexScripts);