mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-02 19:07:40 +01:00
Parser followup (#2377)
* set pipe to empty string on empty closure * fix missing parser flags and scope * add closure serializing * add enum provider function to slash command arguments * add enum providers for /bg, /ask, and /go * fix index out of bounds returning undefined * keep whitespace as is in mixed unnamed args (string+closure) * add _hasUnnamedArgument to named arguments dictionary * allow /var key=x retrieval * add enum provider to /tag-add * fix typo (case) * add option to make enum matching optional * add executor to enum provider * change /tag-add enum provider to only show tags not already assigned * add enum provider to /tag-remove * fix name enum provider excluding groups * remove void from slash command callback return types * Lint undefined and null pipes * enable pointer events in chat autocomplete * fix type hint --------- Co-authored-by: LenAnderson <Anderson.Len@outlook.com> Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
This commit is contained in:
parent
cef65a17f9
commit
5cb319771d
@ -4673,7 +4673,7 @@ function addChatsSeparator(mesSendString) {
|
|||||||
async function DupeChar() {
|
async function DupeChar() {
|
||||||
if (!this_chid) {
|
if (!this_chid) {
|
||||||
toastr.warning('You must first select a character to duplicate!');
|
toastr.warning('You must first select a character to duplicate!');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmMessage = `
|
const confirmMessage = `
|
||||||
@ -4684,7 +4684,7 @@ async function DupeChar() {
|
|||||||
|
|
||||||
if (!confirm) {
|
if (!confirm) {
|
||||||
console.log('User cancelled duplication');
|
console.log('User cancelled duplication');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const body = { avatar_url: characters[this_chid].avatar };
|
const body = { avatar_url: characters[this_chid].avatar };
|
||||||
@ -4699,6 +4699,8 @@ async function DupeChar() {
|
|||||||
await eventSource.emit(event_types.CHARACTER_DUPLICATED, { oldAvatar: body.avatar_url, newAvatar: data.path });
|
await eventSource.emit(event_types.CHARACTER_DUPLICATED, { oldAvatar: body.avatar_url, newAvatar: data.path });
|
||||||
getCharacters();
|
getCharacters();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function itemizedParams(itemizedPrompts, thisPromptSet) {
|
export async function itemizedParams(itemizedPrompts, thisPromptSet) {
|
||||||
@ -8261,10 +8263,12 @@ async function selectInstructCallback(_, name) {
|
|||||||
|
|
||||||
async function enableInstructCallback() {
|
async function enableInstructCallback() {
|
||||||
$('#instruct_enabled').prop('checked', true).trigger('change');
|
$('#instruct_enabled').prop('checked', true).trigger('change');
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function disableInstructCallback() {
|
async function disableInstructCallback() {
|
||||||
$('#instruct_enabled').prop('checked', false).trigger('change');
|
$('#instruct_enabled').prop('checked', false).trigger('change');
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8470,23 +8474,25 @@ async function doDeleteChat() {
|
|||||||
$(currentChatDeleteButton).trigger('click');
|
$(currentChatDeleteButton).trigger('click');
|
||||||
await delay(1);
|
await delay(1);
|
||||||
$('#dialogue_popup_ok').trigger('click', { fromSlashCommand: true });
|
$('#dialogue_popup_ok').trigger('click', { fromSlashCommand: true });
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function doRenameChat(_, chatName) {
|
async function doRenameChat(_, chatName) {
|
||||||
if (!chatName) {
|
if (!chatName) {
|
||||||
toastr.warning('Name must be provided as an argument to rename this chat.');
|
toastr.warning('Name must be provided as an argument to rename this chat.');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentChatName = getCurrentChatId();
|
const currentChatName = getCurrentChatId();
|
||||||
if (!currentChatName) {
|
if (!currentChatName) {
|
||||||
toastr.warning('No chat selected that can be renamed.');
|
toastr.warning('No chat selected that can be renamed.');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
await renameChat(currentChatName, chatName);
|
await renameChat(currentChatName, chatName);
|
||||||
|
|
||||||
toastr.success(`Successfully renamed chat to: ${chatName}`);
|
toastr.success(`Successfully renamed chat to: ${chatName}`);
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8560,6 +8566,7 @@ function doCharListDisplaySwitch() {
|
|||||||
|
|
||||||
function doCloseChat() {
|
function doCloseChat() {
|
||||||
$('#option_close_chat').trigger('click');
|
$('#option_close_chat').trigger('click');
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -8655,6 +8662,7 @@ async function removeCharacterFromUI(name, avatar, reloadCharacters = true) {
|
|||||||
|
|
||||||
function doTogglePanels() {
|
function doTogglePanels() {
|
||||||
$('#option_settings').trigger('click');
|
$('#option_settings').trigger('click');
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function addDebugFunctions() {
|
function addDebugFunctions() {
|
||||||
@ -8742,6 +8750,7 @@ jQuery(async function () {
|
|||||||
await saveSettings();
|
await saveSettings();
|
||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
toastr.success('Chat and settings saved.');
|
toastr.success('Chat and settings saved.');
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
@ -8893,7 +8902,10 @@ jQuery(async function () {
|
|||||||
}));
|
}));
|
||||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
name: 'chat-manager',
|
name: 'chat-manager',
|
||||||
callback: () => $('#option_select_chat').trigger('click'),
|
callback: () => {
|
||||||
|
$('#option_select_chat').trigger('click');
|
||||||
|
return '';
|
||||||
|
},
|
||||||
aliases: ['chat-history', 'manage-chats'],
|
aliases: ['chat-history', 'manage-chats'],
|
||||||
helpString: 'Opens the chat manager for the current character/group.',
|
helpString: 'Opens the chat manager for the current character/group.',
|
||||||
}));
|
}));
|
||||||
|
@ -386,11 +386,15 @@ export class AutoComplete {
|
|||||||
// no result and no input? hide autocomplete
|
// no result and no input? hide autocomplete
|
||||||
return this.hide();
|
return this.hide();
|
||||||
}
|
}
|
||||||
|
if (this.effectiveParserResult instanceof AutoCompleteSecondaryNameResult && !this.effectiveParserResult.forceMatch) {
|
||||||
|
// no result and matching is no forced? hide autocomplete
|
||||||
|
return this.hide();
|
||||||
|
}
|
||||||
// otherwise add "no match" notice
|
// otherwise add "no match" notice
|
||||||
const option = new BlankAutoCompleteOption(
|
const option = new BlankAutoCompleteOption(
|
||||||
this.name.length ?
|
this.name.length ?
|
||||||
this.effectiveParserResult.makeNoMatchText()
|
this.effectiveParserResult.makeNoMatchText()
|
||||||
: this.effectiveParserResult.makeNoOptionstext()
|
: this.effectiveParserResult.makeNoOptionsText()
|
||||||
,
|
,
|
||||||
);
|
);
|
||||||
this.result.push(option);
|
this.result.push(option);
|
||||||
|
@ -10,7 +10,7 @@ export class AutoCompleteNameResult {
|
|||||||
/**@type {AutoCompleteOption[]} */ optionList = [];
|
/**@type {AutoCompleteOption[]} */ optionList = [];
|
||||||
/**@type {boolean} */ canBeQuoted = false;
|
/**@type {boolean} */ canBeQuoted = false;
|
||||||
/**@type {()=>string} */ makeNoMatchText = ()=>`No matches found for "${this.name}"`;
|
/**@type {()=>string} */ makeNoMatchText = ()=>`No matches found for "${this.name}"`;
|
||||||
/**@type {()=>string} */ makeNoOptionstext = ()=>'No options';
|
/**@type {()=>string} */ makeNoOptionsText = ()=>'No options';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,7 +27,7 @@ export class AutoCompleteNameResult {
|
|||||||
this.optionList = optionList;
|
this.optionList = optionList;
|
||||||
this.canBeQuoted = canBeQuoted;
|
this.canBeQuoted = canBeQuoted;
|
||||||
this.noMatchText = makeNoMatchText ?? this.makeNoMatchText;
|
this.noMatchText = makeNoMatchText ?? this.makeNoMatchText;
|
||||||
this.noOptionstext = makeNoOptionsText ?? this.makeNoOptionstext;
|
this.noOptionstext = makeNoOptionsText ?? this.makeNoOptionsText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import { AutoCompleteFuzzyScore } from './AutoCompleteFuzzyScore.js';
|
|||||||
export class AutoCompleteOption {
|
export class AutoCompleteOption {
|
||||||
/**@type {string}*/ name;
|
/**@type {string}*/ name;
|
||||||
/**@type {string}*/ typeIcon;
|
/**@type {string}*/ typeIcon;
|
||||||
|
/**@type {string}*/ type;
|
||||||
/**@type {number}*/ nameOffset = 0;
|
/**@type {number}*/ nameOffset = 0;
|
||||||
/**@type {AutoCompleteFuzzyScore}*/ score;
|
/**@type {AutoCompleteFuzzyScore}*/ score;
|
||||||
/**@type {string}*/ replacer;
|
/**@type {string}*/ replacer;
|
||||||
@ -24,9 +25,10 @@ export class AutoCompleteOption {
|
|||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
*/
|
*/
|
||||||
constructor(name, typeIcon = ' ') {
|
constructor(name, typeIcon = ' ', type = '') {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.typeIcon = typeIcon;
|
this.typeIcon = typeIcon;
|
||||||
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -181,6 +183,7 @@ export class AutoCompleteOption {
|
|||||||
let li;
|
let li;
|
||||||
li = this.makeItem(this.name, this.typeIcon, true);
|
li = this.makeItem(this.name, this.typeIcon, true);
|
||||||
li.setAttribute('data-name', this.name);
|
li.setAttribute('data-name', this.name);
|
||||||
|
li.setAttribute('data-option-type', this.type);
|
||||||
return li;
|
return li;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,4 +2,5 @@ import { AutoCompleteNameResult } from './AutoCompleteNameResult.js';
|
|||||||
|
|
||||||
export class AutoCompleteSecondaryNameResult extends AutoCompleteNameResult {
|
export class AutoCompleteSecondaryNameResult extends AutoCompleteNameResult {
|
||||||
/**@type {boolean}*/ isRequired = false;
|
/**@type {boolean}*/ isRequired = false;
|
||||||
|
/**@type {boolean}*/ forceMatch = true;
|
||||||
}
|
}
|
||||||
|
@ -56,13 +56,12 @@ import { background_settings } from './backgrounds.js';
|
|||||||
import { SlashCommandScope } from './slash-commands/SlashCommandScope.js';
|
import { SlashCommandScope } from './slash-commands/SlashCommandScope.js';
|
||||||
import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
|
import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
|
||||||
import { SlashCommandClosureResult } from './slash-commands/SlashCommandClosureResult.js';
|
import { SlashCommandClosureResult } from './slash-commands/SlashCommandClosureResult.js';
|
||||||
import { AutoCompleteNameResult } from './autocomplete/AutoCompleteNameResult.js';
|
|
||||||
import { AutoCompleteOption } from './autocomplete/AutoCompleteOption.js';
|
|
||||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
||||||
import { AutoComplete } from './autocomplete/AutoComplete.js';
|
import { AutoComplete } from './autocomplete/AutoComplete.js';
|
||||||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||||
import { SlashCommandAbortController } from './slash-commands/SlashCommandAbortController.js';
|
import { SlashCommandAbortController } from './slash-commands/SlashCommandAbortController.js';
|
||||||
import { SlashCommandNamedArgumentAssignment } from './slash-commands/SlashCommandNamedArgumentAssignment.js';
|
import { SlashCommandNamedArgumentAssignment } from './slash-commands/SlashCommandNamedArgumentAssignment.js';
|
||||||
|
import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
|
||||||
export {
|
export {
|
||||||
executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand,
|
executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand,
|
||||||
};
|
};
|
||||||
@ -117,9 +116,14 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|||||||
aliases: ['background'],
|
aliases: ['background'],
|
||||||
returns: 'the current background',
|
returns: 'the current background',
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
new SlashCommandArgument(
|
SlashCommandArgument.fromProps({ description: 'filename',
|
||||||
'filename', [ARGUMENT_TYPE.STRING], true,
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
),
|
isRequired: true,
|
||||||
|
enumProvider: ()=>[...document.querySelectorAll('.bg_example')]
|
||||||
|
.map((it)=>new SlashCommandEnumValue(it.getAttribute('bgfile')))
|
||||||
|
.filter(it=>it.value?.length)
|
||||||
|
,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
helpString: `
|
helpString: `
|
||||||
<div>
|
<div>
|
||||||
@ -323,9 +327,14 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|||||||
name: 'go',
|
name: 'go',
|
||||||
callback: goToCharacterCallback,
|
callback: goToCharacterCallback,
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
new SlashCommandArgument(
|
SlashCommandArgument.fromProps({ description: 'name',
|
||||||
'name', [ARGUMENT_TYPE.STRING], true,
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
),
|
isRequired: true,
|
||||||
|
enumProvider: ()=>[
|
||||||
|
...characters.map(it=>new SlashCommandEnumValue(it.name, null, 'qr', 'C')),
|
||||||
|
...groups.map(it=>new SlashCommandEnumValue(it.name, null, 'variable', 'G')),
|
||||||
|
],
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
helpString: 'Opens up a chat with the character or group by its name',
|
helpString: 'Opens up a chat with the character or group by its name',
|
||||||
aliases: ['char'],
|
aliases: ['char'],
|
||||||
@ -367,9 +376,12 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
|||||||
name: 'ask',
|
name: 'ask',
|
||||||
callback: askCharacter,
|
callback: askCharacter,
|
||||||
namedArgumentList: [
|
namedArgumentList: [
|
||||||
new SlashCommandNamedArgument(
|
SlashCommandNamedArgument.fromProps({ name: 'name',
|
||||||
'name', 'character name', [ARGUMENT_TYPE.STRING], true, false, '',
|
description: 'character name',
|
||||||
),
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
isRequired: true,
|
||||||
|
enumProvider: ()=>characters.map(it=>new SlashCommandEnumValue(it.name, null, 'qr', 'C')),
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
new SlashCommandArgument(
|
new SlashCommandArgument(
|
||||||
@ -1572,7 +1584,7 @@ function abortCallback({ _abortController, quiet }, reason) {
|
|||||||
async function delayCallback(_, amount) {
|
async function delayCallback(_, amount) {
|
||||||
if (!amount) {
|
if (!amount) {
|
||||||
console.warn('WARN: No amount provided for /delay command');
|
console.warn('WARN: No amount provided for /delay command');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
amount = Number(amount);
|
amount = Number(amount);
|
||||||
@ -1581,6 +1593,7 @@ async function delayCallback(_, amount) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await delay(amount);
|
await delay(amount);
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function inputCallback(args, prompt) {
|
async function inputCallback(args, prompt) {
|
||||||
@ -1767,27 +1780,27 @@ async function addSwipeCallback(_, arg) {
|
|||||||
|
|
||||||
if (!lastMessage) {
|
if (!lastMessage) {
|
||||||
toastr.warning('No messages to add swipes to.');
|
toastr.warning('No messages to add swipes to.');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
console.warn('WARN: No argument provided for /addswipe command');
|
console.warn('WARN: No argument provided for /addswipe command');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastMessage.is_user) {
|
if (lastMessage.is_user) {
|
||||||
toastr.warning('Can\'t add swipes to user messages.');
|
toastr.warning('Can\'t add swipes to user messages.');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastMessage.is_system) {
|
if (lastMessage.is_system) {
|
||||||
toastr.warning('Can\'t add swipes to system messages.');
|
toastr.warning('Can\'t add swipes to system messages.');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastMessage.extra?.image) {
|
if (lastMessage.extra?.image) {
|
||||||
toastr.warning('Can\'t add swipes to message containing an image.');
|
toastr.warning('Can\'t add swipes to message containing an image.');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Array.isArray(lastMessage.swipes)) {
|
if (!Array.isArray(lastMessage.swipes)) {
|
||||||
@ -1811,6 +1824,8 @@ async function addSwipeCallback(_, arg) {
|
|||||||
|
|
||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
await reloadCurrentChat();
|
await reloadCurrentChat();
|
||||||
|
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteSwipeCallback(_, arg) {
|
async function deleteSwipeCallback(_, arg) {
|
||||||
@ -1818,19 +1833,19 @@ async function deleteSwipeCallback(_, arg) {
|
|||||||
|
|
||||||
if (!lastMessage || !Array.isArray(lastMessage.swipes) || !lastMessage.swipes.length) {
|
if (!lastMessage || !Array.isArray(lastMessage.swipes) || !lastMessage.swipes.length) {
|
||||||
toastr.warning('No messages to delete swipes from.');
|
toastr.warning('No messages to delete swipes from.');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lastMessage.swipes.length <= 1) {
|
if (lastMessage.swipes.length <= 1) {
|
||||||
toastr.warning('Can\'t delete the last swipe.');
|
toastr.warning('Can\'t delete the last swipe.');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const swipeId = arg && !isNaN(Number(arg)) ? (Number(arg) - 1) : lastMessage.swipe_id;
|
const swipeId = arg && !isNaN(Number(arg)) ? (Number(arg) - 1) : lastMessage.swipe_id;
|
||||||
|
|
||||||
if (swipeId < 0 || swipeId >= lastMessage.swipes.length) {
|
if (swipeId < 0 || swipeId >= lastMessage.swipes.length) {
|
||||||
toastr.warning(`Invalid swipe ID: ${swipeId + 1}`);
|
toastr.warning(`Invalid swipe ID: ${swipeId + 1}`);
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
lastMessage.swipes.splice(swipeId, 1);
|
lastMessage.swipes.splice(swipeId, 1);
|
||||||
@ -1845,6 +1860,8 @@ async function deleteSwipeCallback(_, arg) {
|
|||||||
|
|
||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
await reloadCurrentChat();
|
await reloadCurrentChat();
|
||||||
|
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function askCharacter(args, text) {
|
async function askCharacter(args, text) {
|
||||||
@ -1855,13 +1872,13 @@ async function askCharacter(args, text) {
|
|||||||
// TODO: Maybe support group chats?
|
// TODO: Maybe support group chats?
|
||||||
if (selected_group) {
|
if (selected_group) {
|
||||||
toastr.error('Cannot run this command in a group chat!');
|
toastr.error('Cannot run this command in a group chat!');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!text) {
|
if (!text) {
|
||||||
console.warn('WARN: No text provided for /ask command');
|
console.warn('WARN: No text provided for /ask command');
|
||||||
toastr.warning('No text provided for /ask command');
|
toastr.warning('No text provided for /ask command');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let name = '';
|
let name = '';
|
||||||
@ -1873,7 +1890,7 @@ async function askCharacter(args, text) {
|
|||||||
|
|
||||||
if (!name && !mesText) {
|
if (!name && !mesText) {
|
||||||
toastr.warning('You must specify a name and text to ask.');
|
toastr.warning('You must specify a name and text to ask.');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1885,7 +1902,7 @@ async function askCharacter(args, text) {
|
|||||||
const chId = characters.findIndex((e) => e.name === name);
|
const chId = characters.findIndex((e) => e.name === name);
|
||||||
if (!characters[chId] || chId === -1) {
|
if (!characters[chId] || chId === -1) {
|
||||||
toastr.error('Character not found.');
|
toastr.error('Character not found.');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override character and send a user message
|
// Override character and send a user message
|
||||||
@ -1935,22 +1952,24 @@ async function askCharacter(args, text) {
|
|||||||
// Restore previous character once message renders
|
// Restore previous character once message renders
|
||||||
// Hack for generate
|
// Hack for generate
|
||||||
eventSource.on(event_types.CHARACTER_MESSAGE_RENDERED, restoreCharacter);
|
eventSource.on(event_types.CHARACTER_MESSAGE_RENDERED, restoreCharacter);
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function hideMessageCallback(_, arg) {
|
async function hideMessageCallback(_, arg) {
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
console.warn('WARN: No argument provided for /hide command');
|
console.warn('WARN: No argument provided for /hide command');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const range = stringToRange(arg, 0, chat.length - 1);
|
const range = stringToRange(arg, 0, chat.length - 1);
|
||||||
|
|
||||||
if (!range) {
|
if (!range) {
|
||||||
console.warn(`WARN: Invalid range provided for /hide command: ${arg}`);
|
console.warn(`WARN: Invalid range provided for /hide command: ${arg}`);
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
await hideChatMessageRange(range.start, range.end, false);
|
await hideChatMessageRange(range.start, range.end, false);
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function unhideMessageCallback(_, arg) {
|
async function unhideMessageCallback(_, arg) {
|
||||||
@ -2347,7 +2366,7 @@ export async function generateSystemMessage(_, prompt) {
|
|||||||
if (!prompt) {
|
if (!prompt) {
|
||||||
console.warn('WARN: No prompt provided for /sysgen command');
|
console.warn('WARN: No prompt provided for /sysgen command');
|
||||||
toastr.warning('You must provide a prompt for the system message');
|
toastr.warning('You must provide a prompt for the system message');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate and regex the output if applicable
|
// Generate and regex the output if applicable
|
||||||
@ -2356,43 +2375,49 @@ export async function generateSystemMessage(_, prompt) {
|
|||||||
message = getRegexedString(message, regex_placement.SLASH_COMMAND);
|
message = getRegexedString(message, regex_placement.SLASH_COMMAND);
|
||||||
|
|
||||||
sendNarratorMessage(_, message);
|
sendNarratorMessage(_, message);
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function syncCallback() {
|
function syncCallback() {
|
||||||
$('#sync_name_button').trigger('click');
|
$('#sync_name_button').trigger('click');
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function bindCallback() {
|
function bindCallback() {
|
||||||
$('#lock_user_name').trigger('click');
|
$('#lock_user_name').trigger('click');
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function setStoryModeCallback() {
|
function setStoryModeCallback() {
|
||||||
$('#chat_display').val(chat_styles.DOCUMENT).trigger('change');
|
$('#chat_display').val(chat_styles.DOCUMENT).trigger('change');
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function setBubbleModeCallback() {
|
function setBubbleModeCallback() {
|
||||||
$('#chat_display').val(chat_styles.BUBBLES).trigger('change');
|
$('#chat_display').val(chat_styles.BUBBLES).trigger('change');
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
function setFlatModeCallback() {
|
function setFlatModeCallback() {
|
||||||
$('#chat_display').val(chat_styles.DEFAULT).trigger('change');
|
$('#chat_display').val(chat_styles.DEFAULT).trigger('change');
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a persona name and optionally an avatar.
|
* Sets a persona name and optionally an avatar.
|
||||||
* @param {{mode: 'lookup' | 'temp' | 'all'}} namedArgs Named arguments
|
* @param {{mode: 'lookup' | 'temp' | 'all'}} namedArgs Named arguments
|
||||||
* @param {string} name Name to set
|
* @param {string} name Name to set
|
||||||
* @returns {void}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function setNameCallback({ mode = 'all' }, name) {
|
function setNameCallback({ mode = 'all' }, name) {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
toastr.warning('You must specify a name to change to');
|
toastr.warning('You must specify a name to change to');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!['lookup', 'temp', 'all'].includes(mode)) {
|
if (!['lookup', 'temp', 'all'].includes(mode)) {
|
||||||
toastr.warning('Mode must be one of "lookup", "temp" or "all"');
|
toastr.warning('Mode must be one of "lookup", "temp" or "all"');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
name = name.trim();
|
name = name.trim();
|
||||||
@ -2404,10 +2429,10 @@ function setNameCallback({ mode = 'all' }, name) {
|
|||||||
if (persona) {
|
if (persona) {
|
||||||
autoSelectPersona(persona);
|
autoSelectPersona(persona);
|
||||||
retriggerFirstMessageOnEmptyChat();
|
retriggerFirstMessageOnEmptyChat();
|
||||||
return;
|
return '';
|
||||||
} else if (mode === 'lookup') {
|
} else if (mode === 'lookup') {
|
||||||
toastr.warning(`Persona ${name} not found`);
|
toastr.warning(`Persona ${name} not found`);
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2416,6 +2441,8 @@ function setNameCallback({ mode = 'all' }, name) {
|
|||||||
setUserName(name); //this prevented quickReply usage
|
setUserName(name); //this prevented quickReply usage
|
||||||
retriggerFirstMessageOnEmptyChat();
|
retriggerFirstMessageOnEmptyChat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setNarratorName(_, text) {
|
async function setNarratorName(_, text) {
|
||||||
@ -2423,11 +2450,12 @@ async function setNarratorName(_, text) {
|
|||||||
chat_metadata[NARRATOR_NAME_KEY] = name;
|
chat_metadata[NARRATOR_NAME_KEY] = name;
|
||||||
toastr.info(`System narrator name set to ${name}`);
|
toastr.info(`System narrator name set to ${name}`);
|
||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sendMessageAs(args, text) {
|
export async function sendMessageAs(args, text) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let name;
|
let name;
|
||||||
@ -2439,7 +2467,7 @@ export async function sendMessageAs(args, text) {
|
|||||||
|
|
||||||
if (!name && !text) {
|
if (!name && !text) {
|
||||||
toastr.warning('You must specify a name and text to send as');
|
toastr.warning('You must specify a name and text to send as');
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const namelessWarningKey = 'sendAsNamelessWarningShown';
|
const namelessWarningKey = 'sendAsNamelessWarningShown';
|
||||||
@ -2500,11 +2528,13 @@ export async function sendMessageAs(args, text) {
|
|||||||
await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, (chat.length - 1));
|
await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, (chat.length - 1));
|
||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sendNarratorMessage(args, text) {
|
export async function sendNarratorMessage(args, text) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = chat_metadata[NARRATOR_NAME_KEY] || NARRATOR_NAME_DEFAULT;
|
const name = chat_metadata[NARRATOR_NAME_KEY] || NARRATOR_NAME_DEFAULT;
|
||||||
@ -2543,6 +2573,8 @@ export async function sendNarratorMessage(args, text) {
|
|||||||
await eventSource.emit(event_types.USER_MESSAGE_RENDERED, (chat.length - 1));
|
await eventSource.emit(event_types.USER_MESSAGE_RENDERED, (chat.length - 1));
|
||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function promptQuietForLoudResponse(who, text) {
|
export async function promptQuietForLoudResponse(who, text) {
|
||||||
@ -2586,7 +2618,7 @@ export async function promptQuietForLoudResponse(who, text) {
|
|||||||
|
|
||||||
async function sendCommentMessage(args, text) {
|
async function sendCommentMessage(args, text) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const compact = isTrueBoolean(args?.compact);
|
const compact = isTrueBoolean(args?.compact);
|
||||||
@ -2619,6 +2651,8 @@ async function sendCommentMessage(args, text) {
|
|||||||
await eventSource.emit(event_types.USER_MESSAGE_RENDERED, (chat.length - 1));
|
await eventSource.emit(event_types.USER_MESSAGE_RENDERED, (chat.length - 1));
|
||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2656,6 +2690,8 @@ function helpCommandCallback(_, type) {
|
|||||||
sendSystemMessage(system_message_types.HELP);
|
sendSystemMessage(system_message_types.HELP);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
$(document).on('click', '[data-displayHelp]', function (e) {
|
$(document).on('click', '[data-displayHelp]', function (e) {
|
||||||
@ -2680,7 +2716,7 @@ function setBackgroundCallback(_, bg) {
|
|||||||
|
|
||||||
if (!result.length) {
|
if (!result.length) {
|
||||||
toastr.error(`No background found with name "${bg}"`);
|
toastr.error(`No background found with name "${bg}"`);
|
||||||
return;
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
const bgElement = result[0].item.element;
|
const bgElement = result[0].item.element;
|
||||||
@ -2688,6 +2724,8 @@ function setBackgroundCallback(_, bg) {
|
|||||||
if (bgElement instanceof HTMLElement) {
|
if (bgElement instanceof HTMLElement) {
|
||||||
bgElement.click();
|
bgElement.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2910,6 +2948,8 @@ export async function executeSlashCommandsOnChatInput(text, options = {}) {
|
|||||||
result = await executeSlashCommandsWithOptions(text, {
|
result = await executeSlashCommandsWithOptions(text, {
|
||||||
abortController: commandsFromChatInputAbortController,
|
abortController: commandsFromChatInputAbortController,
|
||||||
onProgress: (done, total) => ta.style.setProperty('--prog', `${done / total * 100}%`),
|
onProgress: (done, total) => ta.style.setProperty('--prog', `${done / total * 100}%`),
|
||||||
|
parserFlags: options.parserFlags,
|
||||||
|
scope: options.scope,
|
||||||
});
|
});
|
||||||
if (commandsFromChatInputAbortController.signal.aborted) {
|
if (commandsFromChatInputAbortController.signal.aborted) {
|
||||||
document.querySelector('#form_sheld').classList.add('script_aborted');
|
document.querySelector('#form_sheld').classList.add('script_aborted');
|
||||||
@ -3006,7 +3046,7 @@ async function executeSlashCommandsWithOptions(text, options = {}) {
|
|||||||
* @param {boolean} handleParserErrors Whether to handle parser errors (show toast on error) or throw
|
* @param {boolean} handleParserErrors Whether to handle parser errors (show toast on error) or throw
|
||||||
* @param {SlashCommandScope} scope The scope to be used when executing the commands.
|
* @param {SlashCommandScope} scope The scope to be used when executing the commands.
|
||||||
* @param {boolean} handleExecutionErrors Whether to handle execution errors (show toast on error) or throw
|
* @param {boolean} handleExecutionErrors Whether to handle execution errors (show toast on error) or throw
|
||||||
* @param {PARSER_FLAG[]} parserFlags Parser flags to apply
|
* @param {{[id:PARSER_FLAG]:boolean}} parserFlags Parser flags to apply
|
||||||
* @param {SlashCommandAbortController} abortController Controller used to abort or pause command execution
|
* @param {SlashCommandAbortController} abortController Controller used to abort or pause command execution
|
||||||
* @param {(done:number, total:number)=>void} onProgress Callback to handle progress events
|
* @param {(done:number, total:number)=>void} onProgress Callback to handle progress events
|
||||||
* @returns {Promise<SlashCommandClosureResult>}
|
* @returns {Promise<SlashCommandClosureResult>}
|
||||||
|
@ -9,10 +9,10 @@ import { SlashCommandScope } from './SlashCommandScope.js';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef {{
|
* @typedef {{
|
||||||
* _pipe:string|SlashCommandClosure,
|
|
||||||
* _scope:SlashCommandScope,
|
* _scope:SlashCommandScope,
|
||||||
* _parserFlags:{[id:PARSER_FLAG]:boolean},
|
* _parserFlags:{[id:PARSER_FLAG]:boolean},
|
||||||
* _abortController:SlashCommandAbortController,
|
* _abortController:SlashCommandAbortController,
|
||||||
|
* _hasUnnamedArgument:boolean,
|
||||||
* [id:string]:string|SlashCommandClosure,
|
* [id:string]:string|SlashCommandClosure,
|
||||||
* }} NamedArguments
|
* }} NamedArguments
|
||||||
*/
|
*/
|
||||||
@ -33,7 +33,7 @@ export class SlashCommand {
|
|||||||
* Creates a SlashCommand from a properties object.
|
* Creates a SlashCommand from a properties object.
|
||||||
* @param {Object} props
|
* @param {Object} props
|
||||||
* @param {string} [props.name]
|
* @param {string} [props.name]
|
||||||
* @param {(namedArguments:NamedArguments|NamedArgumentsCapture, unnamedArguments:string|SlashCommandClosure|(string|SlashCommandClosure)[])=>string|SlashCommandClosure|void|Promise<string|SlashCommandClosure|void>} [props.callback]
|
* @param {(namedArguments:NamedArguments|NamedArgumentsCapture, unnamedArguments:string|SlashCommandClosure|(string|SlashCommandClosure)[])=>string|SlashCommandClosure|Promise<string|SlashCommandClosure>} [props.callback]
|
||||||
* @param {string} [props.helpString]
|
* @param {string} [props.helpString]
|
||||||
* @param {boolean} [props.splitUnnamedArgument]
|
* @param {boolean} [props.splitUnnamedArgument]
|
||||||
* @param {string[]} [props.aliases]
|
* @param {string[]} [props.aliases]
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { SlashCommandClosure } from './SlashCommandClosure.js';
|
import { SlashCommandClosure } from './SlashCommandClosure.js';
|
||||||
import { SlashCommandEnumValue } from './SlashCommandEnumValue.js';
|
import { SlashCommandEnumValue } from './SlashCommandEnumValue.js';
|
||||||
|
import { SlashCommandExecutor } from './SlashCommandExecutor.js';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -29,6 +30,8 @@ export class SlashCommandArgument {
|
|||||||
* @param {boolean} [props.acceptsMultiple] default: false - whether argument accepts multiple values
|
* @param {boolean} [props.acceptsMultiple] default: false - whether argument accepts multiple values
|
||||||
* @param {string|SlashCommandClosure} [props.defaultValue] default value if no value is provided
|
* @param {string|SlashCommandClosure} [props.defaultValue] default value if no value is provided
|
||||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [props.enumList] list of accepted values
|
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [props.enumList] list of accepted values
|
||||||
|
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} [props.enumProvider] function that returns auto complete options
|
||||||
|
* @param {boolean} [props.forceEnum] default: true - whether the input must match one of the enum values
|
||||||
*/
|
*/
|
||||||
static fromProps(props) {
|
static fromProps(props) {
|
||||||
return new SlashCommandArgument(
|
return new SlashCommandArgument(
|
||||||
@ -38,6 +41,8 @@ export class SlashCommandArgument {
|
|||||||
props.acceptsMultiple ?? false,
|
props.acceptsMultiple ?? false,
|
||||||
props.defaultValue ?? null,
|
props.defaultValue ?? null,
|
||||||
props.enumList ?? [],
|
props.enumList ?? [],
|
||||||
|
props.enumProvider ?? null,
|
||||||
|
props.forceEnum ?? true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,6 +55,8 @@ export class SlashCommandArgument {
|
|||||||
/**@type {boolean}*/ acceptsMultiple = false;
|
/**@type {boolean}*/ acceptsMultiple = false;
|
||||||
/**@type {string|SlashCommandClosure}*/ defaultValue;
|
/**@type {string|SlashCommandClosure}*/ defaultValue;
|
||||||
/**@type {SlashCommandEnumValue[]}*/ enumList = [];
|
/**@type {SlashCommandEnumValue[]}*/ enumList = [];
|
||||||
|
/**@type {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]}*/ enumProvider = null;
|
||||||
|
/**@type {boolean}*/ forceEnum = true;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,8 +64,9 @@ export class SlashCommandArgument {
|
|||||||
* @param {ARGUMENT_TYPE|ARGUMENT_TYPE[]} types
|
* @param {ARGUMENT_TYPE|ARGUMENT_TYPE[]} types
|
||||||
* @param {string|SlashCommandClosure} defaultValue
|
* @param {string|SlashCommandClosure} defaultValue
|
||||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} enums
|
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} enums
|
||||||
|
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} enumProvider function that returns auto complete options
|
||||||
*/
|
*/
|
||||||
constructor(description, types, isRequired = false, acceptsMultiple = false, defaultValue = null, enums = []) {
|
constructor(description, types, isRequired = false, acceptsMultiple = false, defaultValue = null, enums = [], enumProvider = null, forceEnum = true) {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.typeList = types ? Array.isArray(types) ? types : [types] : [];
|
this.typeList = types ? Array.isArray(types) ? types : [types] : [];
|
||||||
this.isRequired = isRequired ?? false;
|
this.isRequired = isRequired ?? false;
|
||||||
@ -68,6 +76,8 @@ export class SlashCommandArgument {
|
|||||||
if (it instanceof SlashCommandEnumValue) return it;
|
if (it instanceof SlashCommandEnumValue) return it;
|
||||||
return new SlashCommandEnumValue(it);
|
return new SlashCommandEnumValue(it);
|
||||||
});
|
});
|
||||||
|
this.enumProvider = enumProvider;
|
||||||
|
this.forceEnum = forceEnum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +95,8 @@ export class SlashCommandNamedArgument extends SlashCommandArgument {
|
|||||||
* @param {boolean} [props.acceptsMultiple] default: false - whether argument accepts multiple values
|
* @param {boolean} [props.acceptsMultiple] default: false - whether argument accepts multiple values
|
||||||
* @param {string|SlashCommandClosure} [props.defaultValue] default value if no value is provided
|
* @param {string|SlashCommandClosure} [props.defaultValue] default value if no value is provided
|
||||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [props.enumList] list of accepted values
|
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} [props.enumList] list of accepted values
|
||||||
|
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} [props.enumProvider] function that returns auto complete options
|
||||||
|
* @param {boolean} [props.forceEnum] default: true - whether the input must match one of the enum values
|
||||||
*/
|
*/
|
||||||
static fromProps(props) {
|
static fromProps(props) {
|
||||||
return new SlashCommandNamedArgument(
|
return new SlashCommandNamedArgument(
|
||||||
@ -96,6 +108,8 @@ export class SlashCommandNamedArgument extends SlashCommandArgument {
|
|||||||
props.defaultValue ?? null,
|
props.defaultValue ?? null,
|
||||||
props.enumList ?? [],
|
props.enumList ?? [],
|
||||||
props.aliasList ?? [],
|
props.aliasList ?? [],
|
||||||
|
props.enumProvider ?? null,
|
||||||
|
props.forceEnum ?? true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,9 +126,11 @@ export class SlashCommandNamedArgument extends SlashCommandArgument {
|
|||||||
* @param {ARGUMENT_TYPE|ARGUMENT_TYPE[]} types
|
* @param {ARGUMENT_TYPE|ARGUMENT_TYPE[]} types
|
||||||
* @param {string|SlashCommandClosure} defaultValue
|
* @param {string|SlashCommandClosure} defaultValue
|
||||||
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} enums
|
* @param {string|SlashCommandEnumValue|(string|SlashCommandEnumValue)[]} enums
|
||||||
|
* @param {(executor:SlashCommandExecutor)=>SlashCommandEnumValue[]} enumProvider function that returns auto complete options
|
||||||
|
* @param {boolean} forceEnum
|
||||||
*/
|
*/
|
||||||
constructor(name, description, types, isRequired = false, acceptsMultiple = false, defaultValue = null, enums = [], aliases = []) {
|
constructor(name, description, types, isRequired = false, acceptsMultiple = false, defaultValue = null, enums = [], aliases = [], enumProvider = null, forceEnum = true) {
|
||||||
super(description, types, isRequired, acceptsMultiple, defaultValue, enums);
|
super(description, types, isRequired, acceptsMultiple, defaultValue, enums, enumProvider, forceEnum);
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.aliasList = aliases ? Array.isArray(aliases) ? aliases : [aliases] : [];
|
this.aliasList = aliases ? Array.isArray(aliases) ? aliases : [aliases] : [];
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
|
|||||||
[...namedResult.optionList, ...unnamedResult.optionList],
|
[...namedResult.optionList, ...unnamedResult.optionList],
|
||||||
);
|
);
|
||||||
combinedResult.isRequired = namedResult.isRequired || unnamedResult.isRequired;
|
combinedResult.isRequired = namedResult.isRequired || unnamedResult.isRequired;
|
||||||
|
combinedResult.forceMatch = namedResult.forceMatch && unnamedResult.forceMatch;
|
||||||
return combinedResult;
|
return combinedResult;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,18 +103,19 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
|
|||||||
|
|
||||||
if (name.includes('=') && cmdArg) {
|
if (name.includes('=') && cmdArg) {
|
||||||
// if cursor is already behind "=" check for enums
|
// if cursor is already behind "=" check for enums
|
||||||
/**@type {SlashCommandNamedArgument} */
|
const enumList = cmdArg?.enumProvider?.(this.executor) ?? cmdArg?.enumList;
|
||||||
if (cmdArg && cmdArg.enumList?.length) {
|
if (cmdArg && enumList?.length) {
|
||||||
if (isSelect && cmdArg.enumList.includes(value) && argAssign && argAssign.end == index) {
|
if (isSelect && enumList.find(it=>it.value == value) && argAssign && argAssign.end == index) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const result = new AutoCompleteSecondaryNameResult(
|
const result = new AutoCompleteSecondaryNameResult(
|
||||||
value,
|
value,
|
||||||
start + name.length,
|
start + name.length,
|
||||||
cmdArg.enumList.map(it=>new SlashCommandEnumAutoCompleteOption(this.executor.command, it)),
|
enumList.map(it=>new SlashCommandEnumAutoCompleteOption(this.executor.command, it)),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
result.isRequired = true;
|
result.isRequired = true;
|
||||||
|
result.forceMatch = cmdArg.forceEnum;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,7 +150,8 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
|
|||||||
if (idx > -1) {
|
if (idx > -1) {
|
||||||
argAssign = this.executor.unnamedArgumentList[idx];
|
argAssign = this.executor.unnamedArgumentList[idx];
|
||||||
cmdArg = this.executor.command.unnamedArgumentList[idx];
|
cmdArg = this.executor.command.unnamedArgumentList[idx];
|
||||||
if (cmdArg && cmdArg.enumList.length > 0) {
|
const enumList = cmdArg?.enumProvider?.(this.executor) ?? cmdArg?.enumList;
|
||||||
|
if (cmdArg && enumList.length > 0) {
|
||||||
value = argAssign.value.toString().slice(0, index - argAssign.start);
|
value = argAssign.value.toString().slice(0, index - argAssign.start);
|
||||||
start = argAssign.start;
|
start = argAssign.start;
|
||||||
} else {
|
} else {
|
||||||
@ -163,17 +166,19 @@ export class SlashCommandAutoCompleteNameResult extends AutoCompleteNameResult {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cmdArg == null || cmdArg.enumList.length == 0) return null;
|
const enumList = cmdArg?.enumProvider?.(this.executor) ?? cmdArg?.enumList;
|
||||||
|
if (cmdArg == null || enumList.length == 0) return null;
|
||||||
|
|
||||||
const result = new AutoCompleteSecondaryNameResult(
|
const result = new AutoCompleteSecondaryNameResult(
|
||||||
value,
|
value,
|
||||||
start,
|
start,
|
||||||
cmdArg.enumList.map(it=>new SlashCommandEnumAutoCompleteOption(this.executor.command, it)),
|
enumList.map(it=>new SlashCommandEnumAutoCompleteOption(this.executor.command, it)),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
const isCompleteValue = cmdArg.enumList.find(it=>it.value == value);
|
const isCompleteValue = enumList.find(it=>it.value == value);
|
||||||
const isSelectedValue = isSelect && isCompleteValue;
|
const isSelectedValue = isSelect && isCompleteValue;
|
||||||
result.isRequired = cmdArg.isRequired && !isSelectedValue && !isCompleteValue;
|
result.isRequired = cmdArg.isRequired && !isSelectedValue && !isCompleteValue;
|
||||||
|
result.forceMatch = cmdArg.forceEnum;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { substituteParams } from '../../script.js';
|
import { substituteParams } from '../../script.js';
|
||||||
import { delay, escapeRegex } from '../utils.js';
|
import { delay, escapeRegex } from '../utils.js';
|
||||||
|
import { SlashCommand } from './SlashCommand.js';
|
||||||
import { SlashCommandAbortController } from './SlashCommandAbortController.js';
|
import { SlashCommandAbortController } from './SlashCommandAbortController.js';
|
||||||
import { SlashCommandClosureExecutor } from './SlashCommandClosureExecutor.js';
|
import { SlashCommandClosureExecutor } from './SlashCommandClosureExecutor.js';
|
||||||
import { SlashCommandClosureResult } from './SlashCommandClosureResult.js';
|
import { SlashCommandClosureResult } from './SlashCommandClosureResult.js';
|
||||||
@ -17,6 +18,7 @@ export class SlashCommandClosure {
|
|||||||
/**@type {SlashCommandExecutor[]}*/ executorList = [];
|
/**@type {SlashCommandExecutor[]}*/ executorList = [];
|
||||||
/**@type {SlashCommandAbortController}*/ abortController;
|
/**@type {SlashCommandAbortController}*/ abortController;
|
||||||
/**@type {(done:number, total:number)=>void}*/ onProgress;
|
/**@type {(done:number, total:number)=>void}*/ onProgress;
|
||||||
|
/**@type {string}*/ rawText;
|
||||||
|
|
||||||
/**@type {number}*/
|
/**@type {number}*/
|
||||||
get commandCount() {
|
get commandCount() {
|
||||||
@ -148,6 +150,9 @@ export class SlashCommandClosure {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let done = 0;
|
let done = 0;
|
||||||
|
if (this.executorList.length == 0) {
|
||||||
|
this.scope.pipe = '';
|
||||||
|
}
|
||||||
for (const executor of this.executorList) {
|
for (const executor of this.executorList) {
|
||||||
this.onProgress?.(done, this.commandCount);
|
this.onProgress?.(done, this.commandCount);
|
||||||
if (executor instanceof SlashCommandClosureExecutor) {
|
if (executor instanceof SlashCommandClosureExecutor) {
|
||||||
@ -158,10 +163,12 @@ export class SlashCommandClosure {
|
|||||||
const result = await closure.execute();
|
const result = await closure.execute();
|
||||||
this.scope.pipe = result.pipe;
|
this.scope.pipe = result.pipe;
|
||||||
} else {
|
} else {
|
||||||
|
/**@type {import('./SlashCommand.js').NamedArguments} */
|
||||||
let args = {
|
let args = {
|
||||||
_scope: this.scope,
|
_scope: this.scope,
|
||||||
_parserFlags: executor.parserFlags,
|
_parserFlags: executor.parserFlags,
|
||||||
_abortController: this.abortController,
|
_abortController: this.abortController,
|
||||||
|
_hasUnnamedArgument: executor.unnamedArgumentList.length > 0,
|
||||||
};
|
};
|
||||||
let value;
|
let value;
|
||||||
// substitute named arguments
|
// substitute named arguments
|
||||||
@ -191,6 +198,7 @@ export class SlashCommandClosure {
|
|||||||
if (executor.unnamedArgumentList.length == 0) {
|
if (executor.unnamedArgumentList.length == 0) {
|
||||||
if (executor.injectPipe) {
|
if (executor.injectPipe) {
|
||||||
value = this.scope.pipe;
|
value = this.scope.pipe;
|
||||||
|
args._hasUnnamedArgument = this.scope.pipe !== null && this.scope.pipe !== undefined;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
value = [];
|
value = [];
|
||||||
@ -214,7 +222,7 @@ export class SlashCommandClosure {
|
|||||||
if (value.length == 1) {
|
if (value.length == 1) {
|
||||||
value = value[0];
|
value = value[0];
|
||||||
} else if (!value.find(it=>it instanceof SlashCommandClosure)) {
|
} else if (!value.find(it=>it instanceof SlashCommandClosure)) {
|
||||||
value = value.join(' ');
|
value = value.join('');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,6 +249,7 @@ export class SlashCommandClosure {
|
|||||||
}
|
}
|
||||||
executor.onProgress = (subDone, subTotal)=>this.onProgress?.(done + subDone, this.commandCount);
|
executor.onProgress = (subDone, subTotal)=>this.onProgress?.(done + subDone, this.commandCount);
|
||||||
this.scope.pipe = await executor.command.callback(args, value ?? '');
|
this.scope.pipe = await executor.command.callback(args, value ?? '');
|
||||||
|
this.#lintPipe(executor.command);
|
||||||
done += executor.commandCount;
|
done += executor.commandCount;
|
||||||
this.onProgress?.(done, this.commandCount);
|
this.onProgress?.(done, this.commandCount);
|
||||||
abortResult = await this.testAbortController();
|
abortResult = await this.testAbortController();
|
||||||
@ -269,4 +278,15 @@ export class SlashCommandClosure {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-fixes the pipe if it is not a valid result for STscript.
|
||||||
|
* @param {SlashCommand} command Command being executed
|
||||||
|
*/
|
||||||
|
#lintPipe(command) {
|
||||||
|
if (this.scope.pipe === undefined || this.scope.pipe === null) {
|
||||||
|
console.warn(`${command.name} returned undefined or null. Auto-fixing to empty string.`);
|
||||||
|
this.scope.pipe = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ export class SlashCommandEnumAutoCompleteOption extends AutoCompleteOption {
|
|||||||
* @param {SlashCommandEnumValue} enumValue
|
* @param {SlashCommandEnumValue} enumValue
|
||||||
*/
|
*/
|
||||||
constructor(cmd, enumValue) {
|
constructor(cmd, enumValue) {
|
||||||
super(enumValue.value, '◊');
|
super(enumValue.value, enumValue.typeIcon, enumValue.type);
|
||||||
this.cmd = cmd;
|
this.cmd = cmd;
|
||||||
this.enumValue = enumValue;
|
this.enumValue = enumValue;
|
||||||
}
|
}
|
||||||
@ -21,9 +21,9 @@ export class SlashCommandEnumAutoCompleteOption extends AutoCompleteOption {
|
|||||||
|
|
||||||
renderItem() {
|
renderItem() {
|
||||||
let li;
|
let li;
|
||||||
li = this.makeItem(this.name, '◊', true, [], [], null, this.enumValue.description);
|
li = this.makeItem(this.name, this.typeIcon, true, [], [], null, this.enumValue.description);
|
||||||
li.setAttribute('data-name', this.name);
|
li.setAttribute('data-name', this.name);
|
||||||
li.setAttribute('data-option-type', 'enum');
|
li.setAttribute('data-option-type', this.type);
|
||||||
return li;
|
return li;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
export class SlashCommandEnumValue {
|
export class SlashCommandEnumValue {
|
||||||
/**@type {string}*/ value;
|
/**@type {string}*/ value;
|
||||||
/**@type {string}*/ description;
|
/**@type {string}*/ description;
|
||||||
|
/**@type {string}*/ type = 'enum';
|
||||||
|
/**@type {string}*/ typeIcon = '◊';
|
||||||
|
|
||||||
constructor(value, description = null) {
|
constructor(value, description = null, type = 'enum', typeIcon = '◊') {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
this.type = type;
|
||||||
|
this.typeIcon = typeIcon;
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
|
@ -598,6 +598,7 @@ export class SlashCommandParser {
|
|||||||
this.closureIndex.push(closureIndexEntry);
|
this.closureIndex.push(closureIndexEntry);
|
||||||
let injectPipe = true;
|
let injectPipe = true;
|
||||||
if (!isRoot) this.take(2); // discard opening {:
|
if (!isRoot) this.take(2); // discard opening {:
|
||||||
|
const textStart = this.index;
|
||||||
let closure = new SlashCommandClosure(this.scope);
|
let closure = new SlashCommandClosure(this.scope);
|
||||||
closure.abortController = this.abortController;
|
closure.abortController = this.abortController;
|
||||||
this.scope = closure.scope;
|
this.scope = closure.scope;
|
||||||
@ -638,13 +639,13 @@ export class SlashCommandParser {
|
|||||||
}
|
}
|
||||||
this.discardWhitespace(); // discard further whitespace
|
this.discardWhitespace(); // discard further whitespace
|
||||||
}
|
}
|
||||||
|
closure.rawText = this.text.slice(textStart, this.index);
|
||||||
if (!isRoot) this.take(2); // discard closing :}
|
if (!isRoot) this.take(2); // discard closing :}
|
||||||
if (this.testSymbol('()')) {
|
if (this.testSymbol('()')) {
|
||||||
this.take(2); // discard ()
|
this.take(2); // discard ()
|
||||||
closure.executeNow = true;
|
closure.executeNow = true;
|
||||||
}
|
}
|
||||||
closureIndexEntry.end = this.index - 1;
|
closureIndexEntry.end = this.index - 1;
|
||||||
this.discardWhitespace(); // discard trailing whitespace
|
|
||||||
this.scope = closure.scope.parent;
|
this.scope = closure.scope.parent;
|
||||||
return closure;
|
return closure;
|
||||||
}
|
}
|
||||||
@ -820,9 +821,8 @@ export class SlashCommandParser {
|
|||||||
if (this.testClosure()) {
|
if (this.testClosure()) {
|
||||||
isList = true;
|
isList = true;
|
||||||
if (value.length > 0) {
|
if (value.length > 0) {
|
||||||
assignment.end = assignment.end - (value.length - value.trim().length);
|
|
||||||
this.indexMacros(this.index - value.length, value);
|
this.indexMacros(this.index - value.length, value);
|
||||||
assignment.value = value.trim();
|
assignment.value = value;
|
||||||
listValues.push(assignment);
|
listValues.push(assignment);
|
||||||
assignment = new SlashCommandUnnamedArgumentAssignment();
|
assignment = new SlashCommandUnnamedArgumentAssignment();
|
||||||
assignment.start = this.index;
|
assignment.start = this.index;
|
||||||
@ -834,6 +834,7 @@ export class SlashCommandParser {
|
|||||||
listValues.push(assignment);
|
listValues.push(assignment);
|
||||||
assignment = new SlashCommandUnnamedArgumentAssignment();
|
assignment = new SlashCommandUnnamedArgumentAssignment();
|
||||||
assignment.start = this.index;
|
assignment.start = this.index;
|
||||||
|
if (split) this.discardWhitespace();
|
||||||
} else if (split) {
|
} else if (split) {
|
||||||
if (this.testQuotedValue()) {
|
if (this.testQuotedValue()) {
|
||||||
assignment.start = this.index;
|
assignment.start = this.index;
|
||||||
@ -862,8 +863,8 @@ export class SlashCommandParser {
|
|||||||
assignment.end = this.index;
|
assignment.end = this.index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isList && value.trim().length > 0) {
|
if (isList && value.length > 0) {
|
||||||
assignment.value = value.trim();
|
assignment.value = value;
|
||||||
listValues.push(assignment);
|
listValues.push(assignment);
|
||||||
}
|
}
|
||||||
if (isList) {
|
if (isList) {
|
||||||
|
@ -92,7 +92,7 @@ export class SlashCommandScope {
|
|||||||
v = v[numIndex];
|
v = v[numIndex];
|
||||||
}
|
}
|
||||||
if (typeof v == 'object') return JSON.stringify(v);
|
if (typeof v == 'object') return JSON.stringify(v);
|
||||||
return v;
|
return v ?? '';
|
||||||
} else {
|
} else {
|
||||||
const value = this.variables[key];
|
const value = this.variables[key];
|
||||||
return (value === '' || isNaN(Number(value))) ? (value || '') : Number(value);
|
return (value === '' || isNaN(Number(value))) ? (value || '') : Number(value);
|
||||||
|
@ -20,6 +20,8 @@ import { power_user } from './power-user.js';
|
|||||||
import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
||||||
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
import { SlashCommand } from './slash-commands/SlashCommand.js';
|
||||||
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js';
|
||||||
|
import { SlashCommandEnumValue } from './slash-commands/SlashCommandEnumValue.js';
|
||||||
|
import { SlashCommandExecutor } from './slash-commands/SlashCommandExecutor.js';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
TAG_FOLDER_TYPES,
|
TAG_FOLDER_TYPES,
|
||||||
@ -1607,10 +1609,28 @@ function registerTagsSlashCommands() {
|
|||||||
return String(result);
|
return String(result);
|
||||||
},
|
},
|
||||||
namedArgumentList: [
|
namedArgumentList: [
|
||||||
new SlashCommandNamedArgument('name', 'Character name', [ARGUMENT_TYPE.STRING], false, false, '{{char}}'),
|
SlashCommandNamedArgument.fromProps({ name: 'name',
|
||||||
|
description: 'Character name',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
defaultValue: '{{char}}',
|
||||||
|
enumProvider: ()=>[
|
||||||
|
...characters.map(it=>new SlashCommandEnumValue(it.name, null, 'qr', 'C')),
|
||||||
|
...groups.map(it=>new SlashCommandEnumValue(it.name, null, 'variable', 'G')),
|
||||||
|
],
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
new SlashCommandArgument('tag name', [ARGUMENT_TYPE.STRING], true),
|
SlashCommandArgument.fromProps({ description: 'tag name',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
isRequired: true,
|
||||||
|
enumProvider: (executor)=>{
|
||||||
|
const key = paraGetCharKey(/**@type {string}*/(executor.namedArgumentList.find(it=>it.name == 'name')?.value));
|
||||||
|
if (!key) return tags.map(it=>new SlashCommandEnumValue(it.name, it.title));
|
||||||
|
const assigned = getTagsList(key);
|
||||||
|
return tags.filter(it=>!assigned.includes(it)).map(it=>new SlashCommandEnumValue(it.name, it.title));
|
||||||
|
},
|
||||||
|
forceEnum: false,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
helpString: `
|
helpString: `
|
||||||
<div>
|
<div>
|
||||||
@ -1642,10 +1662,27 @@ function registerTagsSlashCommands() {
|
|||||||
return String(result);
|
return String(result);
|
||||||
},
|
},
|
||||||
namedArgumentList: [
|
namedArgumentList: [
|
||||||
new SlashCommandNamedArgument('name', 'Character name', [ARGUMENT_TYPE.STRING], false, false, '{{char}}'),
|
SlashCommandNamedArgument.fromProps({ name: 'name',
|
||||||
|
description: 'Character name',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
defaultValue: '{{char}}',
|
||||||
|
enumProvider: ()=>[
|
||||||
|
...characters.map(it=>new SlashCommandEnumValue(it.name, null, 'qr', 'C')),
|
||||||
|
...groups.map(it=>new SlashCommandEnumValue(it.name, null, 'variable', 'G')),
|
||||||
|
],
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
new SlashCommandArgument('tag name', [ARGUMENT_TYPE.STRING], true),
|
SlashCommandArgument.fromProps({ description: 'tag name',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
isRequired: true,
|
||||||
|
/**@param {SlashCommandExecutor} executor */
|
||||||
|
enumProvider: (executor)=>{
|
||||||
|
const key = paraGetCharKey(/**@type {string}*/(executor.namedArgumentList.find(it=>it.name == 'name')?.value));
|
||||||
|
if (!key) return tags.map(it=>new SlashCommandEnumValue(it.name, it.title));
|
||||||
|
return getTagsList(key).map(it=>new SlashCommandEnumValue(it.name, it.title));
|
||||||
|
},
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
helpString: `
|
helpString: `
|
||||||
<div>
|
<div>
|
||||||
|
@ -795,7 +795,7 @@ function letCallback(args, value) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Set or retrieve a variable in the current scope or nearest ancestor scope.
|
* Set or retrieve a variable in the current scope or nearest ancestor scope.
|
||||||
* @param {{_scope:SlashCommandScope, key?:string, index?:string|number}} args Named arguments.
|
* @param {{_hasUnnamedArgument:boolean, _scope:SlashCommandScope, key?:string, index?:string|number}} args Named arguments.
|
||||||
* @param {string|SlashCommandClosure|(string|SlashCommandClosure)[]} value Name and optional value for the variable.
|
* @param {string|SlashCommandClosure|(string|SlashCommandClosure)[]} value Name and optional value for the variable.
|
||||||
* @returns The variable's value
|
* @returns The variable's value
|
||||||
*/
|
*/
|
||||||
@ -803,9 +803,13 @@ function varCallback(args, value) {
|
|||||||
if (!Array.isArray(value)) value = [value];
|
if (!Array.isArray(value)) value = [value];
|
||||||
if (args.key !== undefined) {
|
if (args.key !== undefined) {
|
||||||
const key = args.key;
|
const key = args.key;
|
||||||
|
if (args._hasUnnamedArgument) {
|
||||||
const val = value.join(' ');
|
const val = value.join(' ');
|
||||||
args._scope.setVariable(key, val, args.index);
|
args._scope.setVariable(key, val, args.index);
|
||||||
return val;
|
return val;
|
||||||
|
} else {
|
||||||
|
return args._scope.getVariable(key, args.index);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const key = value.shift();
|
const key = value.shift();
|
||||||
if (value.length > 0) {
|
if (value.length > 0) {
|
||||||
@ -817,6 +821,30 @@ function varCallback(args, value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('./slash-commands/SlashCommand.js').NamedArguments} args
|
||||||
|
* @param {SlashCommandClosure} value
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function closureSerializeCallback(args, value) {
|
||||||
|
if (!(value instanceof SlashCommandClosure)) {
|
||||||
|
throw new Error('unnamed argument must be a closure');
|
||||||
|
}
|
||||||
|
return value.rawText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {import('./slash-commands/SlashCommand.js').NamedArguments} args
|
||||||
|
* @param {import('./slash-commands/SlashCommand.js').UnnamedArguments} value
|
||||||
|
* @returns {SlashCommandClosure}
|
||||||
|
*/
|
||||||
|
function closureDeserializeCallback(args, value) {
|
||||||
|
const parser = new SlashCommandParser();
|
||||||
|
const closure = parser.parse(value, true, args._parserFlags, args._abortController);
|
||||||
|
closure.scope.parent = args._scope;
|
||||||
|
return closure;
|
||||||
|
}
|
||||||
|
|
||||||
export function registerVariableCommands() {
|
export function registerVariableCommands() {
|
||||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'listvar',
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'listvar',
|
||||||
callback: listVariablesCallback,
|
callback: listVariablesCallback,
|
||||||
@ -1811,4 +1839,61 @@ export function registerVariableCommands() {
|
|||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
}));
|
}));
|
||||||
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'closure-serialize',
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {import('./slash-commands/SlashCommand.js').NamedArguments} args
|
||||||
|
* @param {SlashCommandClosure} value
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
callback: (args, value)=>closureSerializeCallback(args, value),
|
||||||
|
unnamedArgumentList: [
|
||||||
|
SlashCommandArgument.fromProps({ description: 'the closure to serialize',
|
||||||
|
typeList: [ARGUMENT_TYPE.CLOSURE],
|
||||||
|
isRequired: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
returns: 'serialized closure as string',
|
||||||
|
helpString: `
|
||||||
|
<div>
|
||||||
|
Serialize a closure as text that can be stored in global and chat variables.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Examples:</strong>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<pre><code class="language-stscript">/closure-serialize {: x=1 /echo x is {{var::x}} and y is {{var::y}} :} |\n/setvar key=myClosure</code></pre>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}));
|
||||||
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'closure-deserialize',
|
||||||
|
/**
|
||||||
|
* @param {import('./slash-commands/SlashCommand.js').NamedArguments} args
|
||||||
|
* @param {import('./slash-commands/SlashCommand.js').UnnamedArguments} value
|
||||||
|
* @returns {SlashCommandClosure}
|
||||||
|
*/
|
||||||
|
callback: (args, value)=>closureDeserializeCallback(args, value),
|
||||||
|
unnamedArgumentList: [
|
||||||
|
SlashCommandArgument.fromProps({ description: 'serialized closure',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
isRequired: true,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
returns: 'deserialized closure',
|
||||||
|
helpString: `
|
||||||
|
<div>
|
||||||
|
Deserialize a closure from text.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<strong>Examples:</strong>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<pre><code class="language-stscript">/closure-deserialize {{getvar::myClosure}} |\n/let myClosure {{pipe}} |\n/let y bar |\n/:myClosure x=foo</code></pre>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
@ -645,7 +645,7 @@ function registerWorldInfoSlashCommands() {
|
|||||||
await saveWorldInfo(file, data, true);
|
await saveWorldInfo(file, data, true);
|
||||||
reloadEditor(file);
|
reloadEditor(file);
|
||||||
|
|
||||||
return entry.uid;
|
return String(entry.uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setEntryFieldCallback(args, value) {
|
async function setEntryFieldCallback(args, value) {
|
||||||
@ -3541,6 +3541,7 @@ function onWorldInfoChange(args, text) {
|
|||||||
|
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
eventSource.emit(event_types.WORLDINFO_SETTINGS_UPDATED);
|
eventSource.emit(event_types.WORLDINFO_SETTINGS_UPDATED);
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function importWorldInfo(file) {
|
export async function importWorldInfo(file) {
|
||||||
|
@ -1230,6 +1230,10 @@ select {
|
|||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
|
.autoComplete {
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
&.isFloating {
|
&.isFloating {
|
||||||
--direction: row;
|
--direction: row;
|
||||||
@ -1246,7 +1250,6 @@ select {
|
|||||||
.autoComplete {
|
.autoComplete {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
width: 50vw;
|
width: 50vw;
|
||||||
pointer-events: all;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
&:after {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user