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() {
227227 }));
228228 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
229229 name: 'sendas',
230+ rawQuotes: true,
230231 callback: sendMessageAs,
231232 returns: 'Optionally the text of the sent message, if specified in the "return" argument',
232233 namedArgumentList: [
@@ -293,6 +294,7 @@ export function initDefaultSlashCommands() {
293294 }));
294295 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
295296 name: 'sys',
297+ rawQuotes: true,
296298 callback: sendNarratorMessage,
297299 aliases: ['nar'],
298300 returns: 'Optionally the text of the sent message, if specified in the "return" argument',
@@ -357,6 +359,7 @@ export function initDefaultSlashCommands() {
357359 }));
358360 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
359361 name: 'comment',
362+ rawQuotes: true,
360363 callback: sendCommentMessage,
361364 returns: 'Optionally the text of the sent message, if specified in the "return" argument',
362365 namedArgumentList: [
@@ -574,6 +577,7 @@ export function initDefaultSlashCommands() {
574577 }));
575578 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
576579 name: 'send',
580+ rawQuotes: true,
577581 callback: sendUserMessageCallback,
578582 returns: 'Optionally the text of the sent message, if specified in the "return" argument',
579583 namedArgumentList: [
@@ -936,6 +940,7 @@ export function initDefaultSlashCommands() {
936940 }));
937941 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
938942 name: 'echo',
943+ rawQuotes: true,
939944 callback: echoCallback,
940945 returns: 'the text',
941946 namedArgumentList: [
public/scripts/slash-commands/SlashCommand.js+12 -0
@@ -1,4 +1,5 @@
11import { hljs } from '../../lib.js';
2+import { t } from '../i18n.js';
23import { SlashCommandAbortController } from './SlashCommandAbortController.js';
34import { SlashCommandArgument, SlashCommandNamedArgument } from './SlashCommandArgument.js';
45import { SlashCommandClosure } from './SlashCommandClosure.js';
@@ -36,6 +37,7 @@ export class SlashCommand {
3637 * @param {string} [props.helpString]
3738 * @param {boolean} [props.splitUnnamedArgument]
3839 * @param {Number} [props.splitUnnamedArgumentCount]
40+ * @param {boolean} [props.rawQuotes] If set to true, does not remove wrapping quotes from the unnamed argument.
3941 * @param {string[]} [props.aliases]
4042 * @param {string} [props.returns]
4143 * @param {SlashCommandNamedArgument[]} [props.namedArgumentList]
@@ -54,6 +56,7 @@ export class SlashCommand {
5456 /**@type {string}*/ helpString;
5557 /**@type {boolean}*/ splitUnnamedArgument = false;
5658 /**@type {Number}*/ splitUnnamedArgumentCount;
59+ /** @type {boolean} */ rawQuotes = false;
5760 /**@type {string[]}*/ aliases = [];
5861 /**@type {string}*/ returns;
5962 /**@type {SlashCommandNamedArgument[]}*/ namedArgumentList = [];
@@ -258,6 +261,15 @@ export class SlashCommand {
258261 ].filter(it=>it).join('\n');
259262 head.append(src);
260263 }
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+ }
261273 specs.append(head);
262274 }
263275 const body = document.createElement('div'); {
public/scripts/slash-commands/SlashCommandParser.js+3 -3
@@ -975,7 +975,7 @@ export class SlashCommandParser {
975975 cmd.startUnnamedArgs = this.index - (/\s(\s*)$/s.exec(this.behind)?.[1]?.length ?? 0);
976976 cmd.endUnnamedArgs = this.index;
977977 if (this.testUnnamedArgument()) {
978978 cmd.unnamedArgumentList = this.parseUnnamedArgument(cmd.command?.unnamedArgumentList?.length && cmd?.command?.splitUnnamedArgument, cmd?.command?.splitUnnamedArgumentCount, cmd?.command?.rawQuotes);
979979 cmd.endUnnamedArgs = this.index;
980980 if (cmd.name == 'let') {
981981 const keyArg = cmd.namedArgumentList.find(it=>it.name == 'key');
@@ -1035,7 +1035,7 @@ export class SlashCommandParser {
10351035 testUnnamedArgumentEnd() {
10361036 return this.testCommandEnd();
10371037 }
10381038 parseUnnamedArgument(split, splitCount = null, rawQuotes = false) {
10391039 const wasSplit = split;
10401040 /**@type {SlashCommandClosure|String}*/
10411041 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 {
10451045 /**@type {SlashCommandUnnamedArgumentAssignment}*/
10461046 let assignment = new SlashCommandUnnamedArgumentAssignment();
10471047 assignment.start = this.index;
10481048 if (!split && !rawQuotes && this.testQuotedValue()) {
10491049 // if the next bit is a quoted value, take the whole value and gather contents as a list
10501050 assignment.value = this.parseQuotedValue();
10511051 assignment.end = this.index;
public/style.css+9 -0
@@ -2086,6 +2086,15 @@ body[data-stscript-style] .hljs.language-stscript {
20862086 }
20872087 }
20882088
2089+ >.head>.rawQuotes {
2090+ padding: 0 0.5em;
2091+ cursor: help;
2092+
2093+ &:hover {
2094+ text-decoration: 1px dotted underline;
2095+ }
2096+ }
2097+
20892098 >.head>.source {
20902099 padding: 0 0.5em;
20912100 cursor: help;