Add 3-state find substitution select Fixes #3104

da42d0a47a1a2ca8206ebb95cf408596973fd421

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

4 files changed, +32 -11Showing whitespace changes
public/scripts/char-data.js+1 -1
@@ -89,7 +89,7 @@
89* @property {boolean} markdownOnly - Whether the script only applies to Markdown89* @property {boolean} markdownOnly - Whether the script only applies to Markdown
90* @property {boolean} promptOnly - Whether the script only applies to prompts90* @property {boolean} promptOnly - Whether the script only applies to prompts
91* @property {boolean} runOnEdit - Whether the script runs on edit91* @property {boolean} runOnEdit - Whether the script runs on edit
92* @property {boolean} substituteRegex - Whether the regex should be substituted92* @property {number} substituteRegex - Whether the regex should be substituted
93* @property {number} minDepth - The minimum depth93* @property {number} minDepth - The minimum depth
94* @property {number} maxDepth - The maximum depth94* @property {number} maxDepth - The maximum depth
95*/95*/
public/scripts/extensions/regex/editor.html+7 -3
@@ -121,12 +121,16 @@
121 <input type="checkbox" name="run_on_edit" />121 <input type="checkbox" name="run_on_edit" />
122 <span data-i18n="Run On Edit">Run On Edit</span>122 <span data-i18n="Run On Edit">Run On Edit</span>
123 </label>123 </label>
124 <label class="checkbox flex-container" data-i18n="[title]ext_regex_substitute_regex_desc" title="Substitute &lcub;&lcub;macros&rcub;&rcub; in Find Regex before running it">124 <label class="checkbox flex-container flexNoGap marginBot5" data-i18n="[title]ext_regex_substitute_regex_desc" title="Substitute &lcub;&lcub;macros&rcub;&rcub; in Find Regex before running it">
125 <input type="checkbox" name="substitute_regex" />
126 <span>125 <span>
127 <span data-i18n="Substitute Regex">Substitute Regex</span>126 <small data-i18n="Macro in Find Regex">Macros in Find Regex</small>
128 <span class="fa-solid fa-circle-question note-link-span"></span>127 <span class="fa-solid fa-circle-question note-link-span"></span>
129 </span>128 </span>
129 <select name="substitute_regex" class="text_pole textarea_compact margin0">
130 <option value="0" data-i18n="Don't substitute">Don't substitute</option>
131 <option value="1" data-i18n="Substitute (raw)">Substitute (raw)</option>
132 <option value="2" data-i18n="Substitute (escaped)">Substitute (escaped)</option>
133 </select>
130 </label>134 </label>
131 <span>135 <span>
132 <small data-i18n="ext_regex_other_options" data-i18n="Ephemerality">Ephemerality</small>136 <small data-i18n="ext_regex_other_options" data-i18n="Ephemerality">Ephemerality</small>
public/scripts/extensions/regex/engine.js+20 -3
@@ -22,6 +22,12 @@ const regex_placement = {
22 WORLD_INFO: 5,22 WORLD_INFO: 5,
23};23};
2424
25export const substitute_find_regex = {
26 NONE: 0,
27 RAW: 1,
28 ESCAPED: 2,
29};
30
25function sanitizeRegexMacro(x) {31function sanitizeRegexMacro(x) {
26 return (x && typeof x === 'string') ?32 return (x && typeof x === 'string') ?
27 x.replaceAll(/[\n\r\t\v\f\0.^$*+?{}[\]\\/|()]/gs, function (s) {33 x.replaceAll(/[\n\r\t\v\f\0.^$*+?{}[\]\\/|()]/gs, function (s) {
@@ -131,9 +137,20 @@ function runRegexScript(regexScript, rawString, { characterOverride } = {}) {
131 return newString;137 return newString;
132 }138 }
133139
134 const regexString = regexScript.substituteRegex140 const getRegexString = () => {
135 ? substituteParamsExtended(regexScript.findRegex, {}, sanitizeRegexMacro)141 switch(Number(regexScript.substituteRegex)) {
136 : regexScript.findRegex;142 case substitute_find_regex.NONE:
143 return regexScript.findRegex;
144 case substitute_find_regex.RAW:
145 return substituteParamsExtended(regexScript.findRegex);
146 case substitute_find_regex.ESCAPED:
147 return substituteParamsExtended(regexScript.findRegex, {}, sanitizeRegexMacro);
148 default:
149 console.warn(`runRegexScript: Unknown substituteRegex value ${regexScript.substituteRegex}. Using raw regex.`);
150 return regexScript.findRegex;
151 }
152 };
153 const regexString = getRegexString();
137 const findRegex = regexFromString(regexString);154 const findRegex = regexFromString(regexString);
138155
139 // The user skill issued. Return with nothing.156 // The user skill issued. Return with nothing.
public/scripts/extensions/regex/index.js+4 -4
@@ -8,7 +8,7 @@ import { enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.
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, uuidv4 } from '../../utils.js';10import { download, getFileText, getSortableDelay, uuidv4 } from '../../utils.js';
11import { regex_placement, runRegexScript } from './engine.js';11import { regex_placement, runRegexScript, substitute_find_regex } from './engine.js';
12import { t } from '../../i18n.js';12import { t } from '../../i18n.js';
1313
14/**14/**
@@ -227,7 +227,7 @@ async function onRegexEditorOpenClick(existingId, isScoped) {
227 editorHtml.find('input[name="only_format_display"]').prop('checked', existingScript.markdownOnly ?? false);227 editorHtml.find('input[name="only_format_display"]').prop('checked', existingScript.markdownOnly ?? false);
228 editorHtml.find('input[name="only_format_prompt"]').prop('checked', existingScript.promptOnly ?? false);228 editorHtml.find('input[name="only_format_prompt"]').prop('checked', existingScript.promptOnly ?? false);
229 editorHtml.find('input[name="run_on_edit"]').prop('checked', existingScript.runOnEdit ?? false);229 editorHtml.find('input[name="run_on_edit"]').prop('checked', existingScript.runOnEdit ?? false);
230 editorHtml.find('input[name="substitute_regex"]').prop('checked', existingScript.substituteRegex ?? false);230 editorHtml.find('select[name="substitute_regex"]').val(existingScript.substituteRegex ?? substitute_find_regex.NONE);
231 editorHtml.find('input[name="min_depth"]').val(existingScript.minDepth ?? '');231 editorHtml.find('input[name="min_depth"]').val(existingScript.minDepth ?? '');
232 editorHtml.find('input[name="max_depth"]').val(existingScript.maxDepth ?? '');232 editorHtml.find('input[name="max_depth"]').val(existingScript.maxDepth ?? '');
233233
@@ -267,7 +267,7 @@ async function onRegexEditorOpenClick(existingId, isScoped) {
267 findRegex: editorHtml.find('.find_regex').val(),267 findRegex: editorHtml.find('.find_regex').val(),
268 replaceString: editorHtml.find('.regex_replace_string').val(),268 replaceString: editorHtml.find('.regex_replace_string').val(),
269 trimStrings: String(editorHtml.find('.regex_trim_strings').val()).split('\n').filter((e) => e.length !== 0) || [],269 trimStrings: String(editorHtml.find('.regex_trim_strings').val()).split('\n').filter((e) => e.length !== 0) || [],
270 substituteRegex: editorHtml.find('input[name="substitute_regex"]').prop('checked'),270 substituteRegex: Number(editorHtml.find('select[name="substitute_regex"]').val()),
271 };271 };
272 const rawTestString = String(editorHtml.find('#regex_test_input').val());272 const rawTestString = String(editorHtml.find('#regex_test_input').val());
273 const result = runRegexScript(testScript, rawTestString);273 const result = runRegexScript(testScript, rawTestString);
@@ -295,7 +295,7 @@ async function onRegexEditorOpenClick(existingId, isScoped) {
295 markdownOnly: editorHtml.find('input[name="only_format_display"]').prop('checked'),295 markdownOnly: editorHtml.find('input[name="only_format_display"]').prop('checked'),
296 promptOnly: editorHtml.find('input[name="only_format_prompt"]').prop('checked'),296 promptOnly: editorHtml.find('input[name="only_format_prompt"]').prop('checked'),
297 runOnEdit: editorHtml.find('input[name="run_on_edit"]').prop('checked'),297 runOnEdit: editorHtml.find('input[name="run_on_edit"]').prop('checked'),
298 substituteRegex: editorHtml.find('input[name="substitute_regex"]').prop('checked'),298 substituteRegex: Number(editorHtml.find('select[name="substitute_regex"]').val()),
299 minDepth: parseInt(String(editorHtml.find('input[name="min_depth"]').val())),299 minDepth: parseInt(String(editorHtml.find('input[name="min_depth"]').val())),
300 maxDepth: parseInt(String(editorHtml.find('input[name="max_depth"]').val())),300 maxDepth: parseInt(String(editorHtml.find('input[name="max_depth"]').val())),
301 };301 };