diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 31cf55209..2a5066036 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -77,21 +77,22 @@ class SlashCommandParser { let unnamedArg; if (args.length > 0) { - const argsArray = args.split(' '); - for (let arg of argsArray) { - const equalsIndex = arg.indexOf('='); - if (equalsIndex !== -1) { - const key = arg.substring(0, equalsIndex); - const value = arg.substring(equalsIndex + 1); - // Replace "wrapping quotes" used for escaping spaces - argObj[key] = value.replace(/(^")|("$)/g, ''); - } - else { - break; - } + // Match named arguments + const namedArgPattern = /(\w+)=("(?:\\.|[^"\\])*"|\S+)/g; + let match; + while ((match = namedArgPattern.exec(args)) !== null) { + const key = match[1]; + const value = match[2]; + // Remove the quotes around the value, if any + argObj[key] = value.replace(/(^")|("$)/g, ''); } - unnamedArg = argsArray.slice(Object.keys(argObj).length).join(' '); + // Match unnamed argument + const unnamedArgPattern = /(?:\w+=(?:"(?:\\.|[^"\\])*"|\S+)\s*)*(.*)/s; + match = unnamedArgPattern.exec(args); + if (match !== null) { + unnamedArg = match[1].trim(); + } // Excluded commands format in their own function if (!excludedFromRegex.includes(command)) { @@ -132,7 +133,7 @@ parser.addCommand('name', setNameCallback, ['persona'], '(filename) – sets a background according to filename, partial names allowed', false, true); -parser.addCommand('sendas', sendMessageAs, [], ` – sends message as a specific character. Uses character avatar if it exists in the characters list. Example that will send "Hello, guys!" from "Chloe":
/sendas Chloe
Hello, guys!
`, true, true);
+parser.addCommand('sendas', sendMessageAs, [], ` – sends message as a specific character. Uses character avatar if it exists in the characters list. Example that will send "Hello, guys!" from "Chloe": /sendas name="Chloe" Hello, guys!
`, true, true);
parser.addCommand('sys', sendNarratorMessage, ['nar'], '(text) – sends message as a system narrator', false, true);
parser.addCommand('sysname', setNarratorName, [], '(name) – sets a name for future system narrator messages in this chat (display only). Default: System. Leave empty to reset.', true, true);
parser.addCommand('comment', sendCommentMessage, [], '(text) – adds a note/comment message not part of the chat', false, true);
@@ -499,19 +500,32 @@ async function setNarratorName(_, text) {
await saveChatConditional();
}
-export async function sendMessageAs(_, text) {
+export async function sendMessageAs(namedArgs, text) {
if (!text) {
return;
}
- const parts = text.split('\n');
- if (parts.length <= 1) {
- toastr.warning('Both character name and message are required. Separate them with a new line.');
- return;
- }
+ let name;
+ let mesText;
- const name = parts.shift().trim();
- let mesText = parts.join('\n').trim();
+ if (namedArgs.name) {
+ name = namedArgs.name.trim();
+ mesText = text.trim();
+
+ if (!name && !text) {
+ toastr.warning('You must specify a name and text to send as');
+ return;
+ }
+ } else {
+ const parts = text.split('\n');
+ if (parts.length <= 1) {
+ toastr.warning('Both character name and message are required. Separate them with a new line.');
+ return;
+ }
+
+ name = parts.shift().trim();
+ mesText = parts.join('\n').trim();
+ }
// Requires a regex check after the slash command is pushed to output
mesText = getRegexedString(mesText, regex_placement.SLASH_COMMAND, { characterOverride: name });
diff --git a/public/style.css b/public/style.css
index b46c1f8cb..2637870c6 100644
--- a/public/style.css
+++ b/public/style.css
@@ -218,7 +218,7 @@ table.responsiveTable {
color: var(--white50a);
}
-.mes[is_system="true"] .mes_text br {
+.mes[is_system="true"][ch_name="SillyTavern System"] .mes_text br {
display: none;
}