Merge pull request #3776 from SillyTavern/fix/raw-quotes Add opt-in for rawQuotes in SlashCommand registration

2271d7a22082dc6fa9fa9bc4069c62e49d0ebece

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

Signed
4 files changed, +29 -3Ignore whitespace
public/scripts/slash-commands.js+5 -0
@@ -227,6 +227,7 @@ export function initDefaultSlashCommands() {
227 }));227 }));
228 SlashCommandParser.addCommandObject(SlashCommand.fromProps({228 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
229 name: 'sendas',229 name: 'sendas',
230 rawQuotes: true,
230 callback: sendMessageAs,231 callback: sendMessageAs,
231 returns: 'Optionally the text of the sent message, if specified in the "return" argument',232 returns: 'Optionally the text of the sent message, if specified in the "return" argument',
232 namedArgumentList: [233 namedArgumentList: [
@@ -293,6 +294,7 @@ export function initDefaultSlashCommands() {
293 }));294 }));
294 SlashCommandParser.addCommandObject(SlashCommand.fromProps({295 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
295 name: 'sys',296 name: 'sys',
297 rawQuotes: true,
296 callback: sendNarratorMessage,298 callback: sendNarratorMessage,
297 aliases: ['nar'],299 aliases: ['nar'],
298 returns: 'Optionally the text of the sent message, if specified in the "return" argument',300 returns: 'Optionally the text of the sent message, if specified in the "return" argument',
@@ -357,6 +359,7 @@ export function initDefaultSlashCommands() {
357 }));359 }));
358 SlashCommandParser.addCommandObject(SlashCommand.fromProps({360 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
359 name: 'comment',361 name: 'comment',
362 rawQuotes: true,
360 callback: sendCommentMessage,363 callback: sendCommentMessage,
361 returns: 'Optionally the text of the sent message, if specified in the "return" argument',364 returns: 'Optionally the text of the sent message, if specified in the "return" argument',
362 namedArgumentList: [365 namedArgumentList: [
@@ -574,6 +577,7 @@ export function initDefaultSlashCommands() {
574 }));577 }));
575 SlashCommandParser.addCommandObject(SlashCommand.fromProps({578 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
576 name: 'send',579 name: 'send',
580 rawQuotes: true,
577 callback: sendUserMessageCallback,581 callback: sendUserMessageCallback,
578 returns: 'Optionally the text of the sent message, if specified in the "return" argument',582 returns: 'Optionally the text of the sent message, if specified in the "return" argument',
579 namedArgumentList: [583 namedArgumentList: [
@@ -936,6 +940,7 @@ export function initDefaultSlashCommands() {
936 }));940 }));
937 SlashCommandParser.addCommandObject(SlashCommand.fromProps({941 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
938 name: 'echo',942 name: 'echo',
943 rawQuotes: true,
939 callback: echoCallback,944 callback: echoCallback,
940 returns: 'the text',945 returns: 'the text',
941 namedArgumentList: [946 namedArgumentList: [
public/scripts/slash-commands/SlashCommand.js+12 -0
@@ -1,4 +1,5 @@
1import { hljs } from '../../lib.js';1import { hljs } from '../../lib.js';
2import { t } from '../i18n.js';
2import { SlashCommandAbortController } from './SlashCommandAbortController.js';3import { SlashCommandAbortController } from './SlashCommandAbortController.js';
3import { SlashCommandArgument, SlashCommandNamedArgument } from './SlashCommandArgument.js';4import { SlashCommandArgument, SlashCommandNamedArgument } from './SlashCommandArgument.js';
4import { SlashCommandClosure } from './SlashCommandClosure.js';5import { SlashCommandClosure } from './SlashCommandClosure.js';
@@ -36,6 +37,7 @@ export class SlashCommand {
36 * @param {string} [props.helpString]37 * @param {string} [props.helpString]
37 * @param {boolean} [props.splitUnnamedArgument]38 * @param {boolean} [props.splitUnnamedArgument]
38 * @param {Number} [props.splitUnnamedArgumentCount]39 * @param {Number} [props.splitUnnamedArgumentCount]
40 * @param {boolean} [props.rawQuotes] If set to true, does not remove wrapping quotes from the unnamed argument.
39 * @param {string[]} [props.aliases]41 * @param {string[]} [props.aliases]
40 * @param {string} [props.returns]42 * @param {string} [props.returns]
41 * @param {SlashCommandNamedArgument[]} [props.namedArgumentList]43 * @param {SlashCommandNamedArgument[]} [props.namedArgumentList]
@@ -54,6 +56,7 @@ export class SlashCommand {
54 /**@type {string}*/ helpString;56 /**@type {string}*/ helpString;
55 /**@type {boolean}*/ splitUnnamedArgument = false;57 /**@type {boolean}*/ splitUnnamedArgument = false;
56 /**@type {Number}*/ splitUnnamedArgumentCount;58 /**@type {Number}*/ splitUnnamedArgumentCount;
59 /** @type {boolean} */ rawQuotes = false;
57 /**@type {string[]}*/ aliases = [];60 /**@type {string[]}*/ aliases = [];
58 /**@type {string}*/ returns;61 /**@type {string}*/ returns;
59 /**@type {SlashCommandNamedArgument[]}*/ namedArgumentList = [];62 /**@type {SlashCommandNamedArgument[]}*/ namedArgumentList = [];
@@ -258,6 +261,15 @@ export class SlashCommand {
258 ].filter(it=>it).join('\n');261 ].filter(it=>it).join('\n');
259 head.append(src);262 head.append(src);
260 }263 }
264 if (this.rawQuotes) {
265 const rawQuotes = document.createElement('div'); {
266 rawQuotes.classList.add('rawQuotes');
267 rawQuotes.classList.add('fa-solid');
268 rawQuotes.classList.add('fa-quote-left');
269 rawQuotes.title = t`Does not alter quoted literal unnamed arguments`;
270 head.append(rawQuotes);
271 }
272 }
261 specs.append(head);273 specs.append(head);
262 }274 }
263 const body = document.createElement('div'); {275 const body = document.createElement('div'); {
public/scripts/slash-commands/SlashCommandParser.js+3 -3
@@ -975,7 +975,7 @@ export class SlashCommandParser {
975 cmd.startUnnamedArgs = this.index - (/\s(\s*)$/s.exec(this.behind)?.[1]?.length ?? 0);975 cmd.startUnnamedArgs = this.index - (/\s(\s*)$/s.exec(this.behind)?.[1]?.length ?? 0);
976 cmd.endUnnamedArgs = this.index;976 cmd.endUnnamedArgs = this.index;
977 if (this.testUnnamedArgument()) {977 if (this.testUnnamedArgument()) {
978 cmd.unnamedArgumentList = this.parseUnnamedArgument(cmd.command?.unnamedArgumentList?.length && cmd?.command?.splitUnnamedArgument, cmd?.command?.splitUnnamedArgumentCount);978 cmd.unnamedArgumentList = this.parseUnnamedArgument(cmd.command?.unnamedArgumentList?.length && cmd?.command?.splitUnnamedArgument, cmd?.command?.splitUnnamedArgumentCount, cmd?.command?.rawQuotes);
979 cmd.endUnnamedArgs = this.index;979 cmd.endUnnamedArgs = this.index;
980 if (cmd.name == 'let') {980 if (cmd.name == 'let') {
981 const keyArg = cmd.namedArgumentList.find(it=>it.name == 'key');981 const keyArg = cmd.namedArgumentList.find(it=>it.name == 'key');
@@ -1035,7 +1035,7 @@ export class SlashCommandParser {
1035 testUnnamedArgumentEnd() {1035 testUnnamedArgumentEnd() {
1036 return this.testCommandEnd();1036 return this.testCommandEnd();
1037 }1037 }
1038 parseUnnamedArgument(split, splitCount = null) {1038 parseUnnamedArgument(split, splitCount = null, rawQuotes = false) {
1039 const wasSplit = split;1039 const wasSplit = split;
1040 /**@type {SlashCommandClosure|String}*/1040 /**@type {SlashCommandClosure|String}*/
1041 let value = this.jumpedEscapeSequence ? this.take() : ''; // take the first, already tested, char if it is an escaped one1041 let value = this.jumpedEscapeSequence ? this.take() : ''; // take the first, already tested, char if it is an escaped one
@@ -1045,7 +1045,7 @@ export class SlashCommandParser {
1045 /**@type {SlashCommandUnnamedArgumentAssignment}*/1045 /**@type {SlashCommandUnnamedArgumentAssignment}*/
1046 let assignment = new SlashCommandUnnamedArgumentAssignment();1046 let assignment = new SlashCommandUnnamedArgumentAssignment();
1047 assignment.start = this.index;1047 assignment.start = this.index;
1048 if (!split && this.testQuotedValue()) {1048 if (!split && !rawQuotes && this.testQuotedValue()) {
1049 // if the next bit is a quoted value, take the whole value and gather contents as a list1049 // if the next bit is a quoted value, take the whole value and gather contents as a list
1050 assignment.value = this.parseQuotedValue();1050 assignment.value = this.parseQuotedValue();
1051 assignment.end = this.index;1051 assignment.end = this.index;
public/style.css+9 -0
@@ -2086,6 +2086,15 @@ body[data-stscript-style] .hljs.language-stscript {
2086 }2086 }
2087 }2087 }
20882088
2089 >.head>.rawQuotes {
2090 padding: 0 0.5em;
2091 cursor: help;
2092
2093 &:hover {
2094 text-decoration: 1px dotted underline;
2095 }
2096 }
2097
2089 >.head>.source {2098 >.head>.source {
2090 padding: 0 0.5em;2099 padding: 0 0.5em;
2091 cursor: help;2100 cursor: help;