Merge pull request #2925 from SillyTavern/fix-math-commands

Fix and improve math slash commands
This commit is contained in:
Cohee 2024-09-30 23:56:15 +03:00 committed by GitHub
commit c42df886c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 106 additions and 58 deletions

View File

@ -152,6 +152,35 @@ export const commonEnumProviders = {
].filter((item, idx, list)=>idx == list.findIndex(it=>it.value == item.value));
},
/**
* Enum values for numbers and variable names
*
* Includes all variable names and the ability to specify any number
*
* @param {SlashCommandExecutor} executor - The executor of the slash command
* @param {SlashCommandScope} scope - The scope of the slash command
* @returns {SlashCommandEnumValue[]} The enum values
*/
numbersAndVariables: (executor, scope) => [
...commonEnumProviders.variables('all')(executor, scope),
new SlashCommandEnumValue(
'any variable name',
null,
enumTypes.variable,
enumIcons.variable,
(input) => /^\w*$/.test(input),
(input) => input,
),
new SlashCommandEnumValue(
'any number',
null,
enumTypes.number,
enumIcons.number,
(input) => input == '' || !Number.isNaN(Number(input)),
(input) => input,
),
],
/**
* All possible char entities, like characters and groups. Can be filtered down to just one type.
*

View File

@ -669,8 +669,8 @@ function deleteGlobalVariable(name) {
}
/**
* Parses a series of numeric values from a string.
* @param {string} value A space-separated list of numeric values or variable names
* Parses a series of numeric values from a string or a string array.
* @param {string|string[]} value A space-separated list of numeric values or variable names
* @param {SlashCommandScope} scope Scope
* @returns {number[]} An array of numeric values
*/
@ -679,11 +679,17 @@ function parseNumericSeries(value, scope = null) {
return [value];
}
const array = value
.split(' ')
.map(i => i.trim())
/** @type {(string|number)[]} */
let values = Array.isArray(value) ? value : value.split(' ');
// If a JSON array was provided as the only value, convert it to an array
if (values.length === 1 && typeof values[0] === 'string' && values[0].startsWith('[')) {
values = convertValueType(values[0], 'array');
}
const array = values.map(i => typeof i === 'string' ? i.trim() : i)
.filter(i => i !== '')
.map(i => isNaN(Number(i)) ? Number(resolveVariable(i, scope)) : Number(i))
.map(i => isNaN(Number(i)) ? Number(resolveVariable(String(i), scope)) : Number(i))
.filter(i => !isNaN(i));
return array;
@ -703,7 +709,7 @@ function performOperation(value, operation, singleOperand = false, scope = null)
const result = singleOperand ? operation(array[0]) : operation(array);
if (isNaN(result) || !isFinite(result)) {
if (isNaN(result)) {
return 0;
}
@ -731,7 +737,7 @@ function maxValuesCallback(args, value) {
}
function subValuesCallback(args, value) {
return performOperation(value, (array) => array[0] - array[1], false, args._scope);
return performOperation(value, (array) => array.reduce((a, b) => a - b, array.shift() ?? 0), false, args._scope);
}
function divValuesCallback(args, value) {
@ -1595,36 +1601,15 @@ export function registerVariableCommands() {
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'add',
callback: (args, /**@type {string[]}*/value) => addValuesCallback(args, value.join(' ')),
callback: (args, value) => addValuesCallback(args, value),
returns: 'sum of the provided values',
unnamedArgumentList: [
SlashCommandArgument.fromProps({
description: 'values to sum',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
isRequired: true,
acceptsMultiple: true,
enumProvider: (executor, scope) => {
const vars = commonEnumProviders.variables('all')(executor, scope);
vars.push(
new SlashCommandEnumValue(
'any variable name',
null,
enumTypes.variable,
enumIcons.variable,
(input) => /^\w*$/.test(input),
(input) => input,
),
new SlashCommandEnumValue(
'any number',
null,
enumTypes.number,
enumIcons.number,
(input) => input == '' || !Number.isNaN(Number(input)),
(input) => input,
),
);
return vars;
},
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
@ -1632,7 +1617,9 @@ export function registerVariableCommands() {
helpString: `
<div>
Performs an addition of the set of values and passes the result down the pipe.
Can use variable names.
</div>
<div>
Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
</div>
<div>
<strong>Example:</strong>
@ -1640,6 +1627,9 @@ export function registerVariableCommands() {
<li>
<pre><code class="language-stscript">/add 10 i 30 j</code></pre>
</li>
<li>
<pre><code class="language-stscript">/add ["count", 15, 2, "i"]</code></pre>
</li>
</ul>
</div>
`,
@ -1651,16 +1641,20 @@ export function registerVariableCommands() {
unnamedArgumentList: [
SlashCommandArgument.fromProps({
description: 'values to multiply',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
isRequired: true,
acceptsMultiple: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
splitUnnamedArgument: true,
helpString: `
<div>
Performs a multiplication of the set of values and passes the result down the pipe. Can use variable names.
Performs a multiplication of the set of values and passes the result down the pipe.
</div>
<div>
Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
</div>
<div>
<strong>Examples:</strong>
@ -1668,6 +1662,9 @@ export function registerVariableCommands() {
<li>
<pre><code class="language-stscript">/mul 10 i 30 j</code></pre>
</li>
<li>
<pre><code class="language-stscript">/mul ["count", 15, 2, "i"]</code></pre>
</li>
</ul>
</div>
`,
@ -1679,16 +1676,20 @@ export function registerVariableCommands() {
unnamedArgumentList: [
SlashCommandArgument.fromProps({
description: 'values to find the max',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
isRequired: true,
acceptsMultiple: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
splitUnnamedArgument: true,
helpString: `
<div>
Returns the maximum value of the set of values and passes the result down the pipe. Can use variable names.
Returns the maximum value of the set of values and passes the result down the pipe.
</div>
<div>
Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
</div>
<div>
<strong>Examples:</strong>
@ -1696,6 +1697,9 @@ export function registerVariableCommands() {
<li>
<pre><code class="language-stscript">/max 10 i 30 j</code></pre>
</li>
<li>
<pre><code class="language-stscript">/max ["count", 15, 2, "i"]</code></pre>
</li>
</ul>
</div>
`,
@ -1707,17 +1711,20 @@ export function registerVariableCommands() {
unnamedArgumentList: [
SlashCommandArgument.fromProps({
description: 'values to find the min',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
isRequired: true,
acceptsMultiple: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
splitUnnamedArgument: true,
helpString: `
<div>
Returns the minimum value of the set of values and passes the result down the pipe.
Can use variable names.
</div>
<div>
Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
</div>
<div>
<strong>Example:</strong>
@ -1725,6 +1732,9 @@ export function registerVariableCommands() {
<li>
<pre><code class="language-stscript">/min 10 i 30 j</code></pre>
</li>
<li>
<pre><code class="language-stscript">/min ["count", 15, 2, "i"]</code></pre>
</li>
</ul>
</div>
`,
@ -1735,18 +1745,21 @@ export function registerVariableCommands() {
returns: 'difference of the provided values',
unnamedArgumentList: [
SlashCommandArgument.fromProps({
description: 'values to find the difference',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
description: 'values to subtract, starting form the first provided value',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
isRequired: true,
acceptsMultiple: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
splitUnnamedArgument: true,
helpString: `
<div>
Performs a subtraction of the set of values and passes the result down the pipe.
Can use variable names.
</div>
<div>
Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
</div>
<div>
<strong>Example:</strong>
@ -1754,6 +1767,9 @@ export function registerVariableCommands() {
<li>
<pre><code class="language-stscript">/sub i 5</code></pre>
</li>
<li>
<pre><code class="language-stscript">/sub ["count", 4, "i"]</code></pre>
</li>
</ul>
</div>
`,
@ -1767,17 +1783,18 @@ export function registerVariableCommands() {
description: 'dividend',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
SlashCommandArgument.fromProps({
description: 'divisor',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
splitUnnamedArgument: true,
helpString: `
<div>
Performs a division of two values and passes the result down the pipe.
@ -1802,17 +1819,18 @@ export function registerVariableCommands() {
description: 'dividend',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
SlashCommandArgument.fromProps({
description: 'divisor',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
splitUnnamedArgument: true,
helpString: `
<div>
Performs a modulo operation of two values and passes the result down the pipe.
@ -1837,17 +1855,18 @@ export function registerVariableCommands() {
description: 'base',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
SlashCommandArgument.fromProps({
description: 'exponent',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
splitUnnamedArgument: true,
helpString: `
<div>
Performs a power operation of two values and passes the result down the pipe.
@ -1872,7 +1891,7 @@ export function registerVariableCommands() {
description: 'value',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
@ -1900,7 +1919,7 @@ export function registerVariableCommands() {
description: 'value',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
@ -1929,7 +1948,7 @@ export function registerVariableCommands() {
description: 'value',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
@ -1957,7 +1976,7 @@ export function registerVariableCommands() {
description: 'value',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
@ -1985,7 +2004,7 @@ export function registerVariableCommands() {
description: 'value',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],
@ -2013,7 +2032,7 @@ export function registerVariableCommands() {
description: 'value',
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
enumProvider: commonEnumProviders.variables('all'),
enumProvider: commonEnumProviders.numbersAndVariables,
forceEnum: false,
}),
],