Merge pull request #2925 from SillyTavern/fix-math-commands Fix and improve math slash commands

c42df886c57f3df66430819ecd40f3ce0ab76086

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

Signed
2 files changed, +106 -58Ignore whitespace
public/scripts/slash-commands/SlashCommandCommonEnumsProvider.js+29 -0
@@ -153,6 +153,35 @@ export const commonEnumProviders = {
153153 },
154154
155155 /**
156+ * Enum values for numbers and variable names
157+ *
158+ * Includes all variable names and the ability to specify any number
159+ *
160+ * @param {SlashCommandExecutor} executor - The executor of the slash command
161+ * @param {SlashCommandScope} scope - The scope of the slash command
162+ * @returns {SlashCommandEnumValue[]} The enum values
163+ */
164+ numbersAndVariables: (executor, scope) => [
165+ ...commonEnumProviders.variables('all')(executor, scope),
166+ new SlashCommandEnumValue(
167+ 'any variable name',
168+ null,
169+ enumTypes.variable,
170+ enumIcons.variable,
171+ (input) => /^\w*$/.test(input),
172+ (input) => input,
173+ ),
174+ new SlashCommandEnumValue(
175+ 'any number',
176+ null,
177+ enumTypes.number,
178+ enumIcons.number,
179+ (input) => input == '' || !Number.isNaN(Number(input)),
180+ (input) => input,
181+ ),
182+ ],
183+
184+ /**
156185 * All possible char entities, like characters and groups. Can be filtered down to just one type.
157186 *
158187 * @param {('all' | 'character' | 'group')?} [mode='all'] - Which type to return
public/scripts/variables.js+77 -58
@@ -669,8 +669,8 @@ function deleteGlobalVariable(name) {
669669}
670670
671671/**
672672 * Parses a series of numeric values from a string or a string array.
673673 * @param {string|string[]} value A space-separated list of numeric values or variable names
674674 * @param {SlashCommandScope} scope Scope
675675 * @returns {number[]} An array of numeric values
676676 */
@@ -679,11 +679,17 @@ function parseNumericSeries(value, scope = null) {
679679 return [value];
680680 }
681681
682- const array = value
682+ /** @type {(string|number)[]} */
683- .split(' ')
683+ let values = Array.isArray(value) ? value : value.split(' ');
684- .map(i => i.trim())
684+
685+ // If a JSON array was provided as the only value, convert it to an array
686+ if (values.length === 1 && typeof values[0] === 'string' && values[0].startsWith('[')) {
687+ values = convertValueType(values[0], 'array');
688+ }
689+
690+ const array = values.map(i => typeof i === 'string' ? i.trim() : i)
685691 .filter(i => i !== '')
686692 .map(i => isNaN(Number(i)) ? Number(resolveVariable(String(i), scope)) : Number(i))
687693 .filter(i => !isNaN(i));
688694
689695 return array;
@@ -703,7 +709,7 @@ function performOperation(value, operation, singleOperand = false, scope = null)
703709
704710 const result = singleOperand ? operation(array[0]) : operation(array);
705711
706712 if (isNaN(result) || !isFinite(result)) {
707713 return 0;
708714 }
709715
@@ -731,7 +737,7 @@ function maxValuesCallback(args, value) {
731737}
732738
733739function subValuesCallback(args, value) {
734740 return performOperation(value, (array) => array[0].reduce((a, b) => a - b, array[1].shift() ?? 0), false, args._scope);
735741}
736742
737743function divValuesCallback(args, value) {
@@ -1595,36 +1601,15 @@ export function registerVariableCommands() {
15951601 }));
15961602 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
15971603 name: 'add',
15981604 callback: (args, /**@type {string[]}*/value) => addValuesCallback(args, value.join(' ')),
15991605 returns: 'sum of the provided values',
16001606 unnamedArgumentList: [
16011607 SlashCommandArgument.fromProps({
16021608 description: 'values to sum',
16031609 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
16041610 isRequired: true,
16051611 acceptsMultiple: true,
1606- enumProvider: (executor, scope) => {
1612+ enumProvider: commonEnumProviders.numbersAndVariables,
1607- const vars = commonEnumProviders.variables('all')(executor, scope);
1608- vars.push(
1609- new SlashCommandEnumValue(
1610- 'any variable name',
1611- null,
1612- enumTypes.variable,
1613- enumIcons.variable,
1614- (input) => /^\w*$/.test(input),
1615- (input) => input,
1616- ),
1617- new SlashCommandEnumValue(
1618- 'any number',
1619- null,
1620- enumTypes.number,
1621- enumIcons.number,
1622- (input) => input == '' || !Number.isNaN(Number(input)),
1623- (input) => input,
1624- ),
1625- );
1626- return vars;
1627- },
16281613 forceEnum: false,
16291614 }),
16301615 ],
@@ -1632,7 +1617,9 @@ export function registerVariableCommands() {
16321617 helpString: `
16331618 <div>
16341619 Performs an addition of the set of values and passes the result down the pipe.
1635- Can use variable names.
1620+ </div>
1621+ <div>
1622+ Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
16361623 </div>
16371624 <div>
16381625 <strong>Example:</strong>
@@ -1640,6 +1627,9 @@ export function registerVariableCommands() {
16401627 <li>
16411628 <pre><code class="language-stscript">/add 10 i 30 j</code></pre>
16421629 </li>
1630+ <li>
1631+ <pre><code class="language-stscript">/add ["count", 15, 2, "i"]</code></pre>
1632+ </li>
16431633 </ul>
16441634 </div>
16451635 `,
@@ -1651,16 +1641,20 @@ export function registerVariableCommands() {
16511641 unnamedArgumentList: [
16521642 SlashCommandArgument.fromProps({
16531643 description: 'values to multiply',
16541644 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
16551645 isRequired: true,
16561646 acceptsMultiple: true,
16571647 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
16581648 forceEnum: false,
16591649 }),
16601650 ],
1651+ splitUnnamedArgument: true,
16611652 helpString: `
16621653 <div>
16631654 Performs a multiplication of the set of values and passes the result down the pipe. Can use variable names.
1655+ </div>
1656+ <div>
1657+ Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
16641658 </div>
16651659 <div>
16661660 <strong>Examples:</strong>
@@ -1668,6 +1662,9 @@ export function registerVariableCommands() {
16681662 <li>
16691663 <pre><code class="language-stscript">/mul 10 i 30 j</code></pre>
16701664 </li>
1665+ <li>
1666+ <pre><code class="language-stscript">/mul ["count", 15, 2, "i"]</code></pre>
1667+ </li>
16711668 </ul>
16721669 </div>
16731670 `,
@@ -1679,16 +1676,20 @@ export function registerVariableCommands() {
16791676 unnamedArgumentList: [
16801677 SlashCommandArgument.fromProps({
16811678 description: 'values to find the max',
16821679 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
16831680 isRequired: true,
16841681 acceptsMultiple: true,
16851682 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
16861683 forceEnum: false,
16871684 }),
16881685 ],
1686+ splitUnnamedArgument: true,
16891687 helpString: `
16901688 <div>
16911689 Returns the maximum value of the set of values and passes the result down the pipe. Can use variable names.
1690+ </div>
1691+ <div>
1692+ Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
16921693 </div>
16931694 <div>
16941695 <strong>Examples:</strong>
@@ -1696,6 +1697,9 @@ export function registerVariableCommands() {
16961697 <li>
16971698 <pre><code class="language-stscript">/max 10 i 30 j</code></pre>
16981699 </li>
1700+ <li>
1701+ <pre><code class="language-stscript">/max ["count", 15, 2, "i"]</code></pre>
1702+ </li>
16991703 </ul>
17001704 </div>
17011705 `,
@@ -1707,17 +1711,20 @@ export function registerVariableCommands() {
17071711 unnamedArgumentList: [
17081712 SlashCommandArgument.fromProps({
17091713 description: 'values to find the min',
17101714 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
17111715 isRequired: true,
17121716 acceptsMultiple: true,
17131717 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
17141718 forceEnum: false,
17151719 }),
17161720 ],
1721+ splitUnnamedArgument: true,
17171722 helpString: `
17181723 <div>
17191724 Returns the minimum value of the set of values and passes the result down the pipe.
1720- Can use variable names.
1725+ </div>
1726+ <div>
1727+ Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
17211728 </div>
17221729 <div>
17231730 <strong>Example:</strong>
@@ -1725,6 +1732,9 @@ export function registerVariableCommands() {
17251732 <li>
17261733 <pre><code class="language-stscript">/min 10 i 30 j</code></pre>
17271734 </li>
1735+ <li>
1736+ <pre><code class="language-stscript">/min ["count", 15, 2, "i"]</code></pre>
1737+ </li>
17281738 </ul>
17291739 </div>
17301740 `,
@@ -1735,18 +1745,21 @@ export function registerVariableCommands() {
17351745 returns: 'difference of the provided values',
17361746 unnamedArgumentList: [
17371747 SlashCommandArgument.fromProps({
17381748 description: 'values to findsubtract, starting form the differencefirst provided value',
17391749 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
17401750 isRequired: true,
17411751 acceptsMultiple: true,
17421752 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
17431753 forceEnum: false,
17441754 }),
17451755 ],
1756+ splitUnnamedArgument: true,
17461757 helpString: `
17471758 <div>
17481759 Performs a subtraction of the set of values and passes the result down the pipe.
1749- Can use variable names.
1760+ </div>
1761+ <div>
1762+ Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
17501763 </div>
17511764 <div>
17521765 <strong>Example:</strong>
@@ -1754,6 +1767,9 @@ export function registerVariableCommands() {
17541767 <li>
17551768 <pre><code class="language-stscript">/sub i 5</code></pre>
17561769 </li>
1770+ <li>
1771+ <pre><code class="language-stscript">/sub ["count", 4, "i"]</code></pre>
1772+ </li>
17571773 </ul>
17581774 </div>
17591775 `,
@@ -1767,17 +1783,18 @@ export function registerVariableCommands() {
17671783 description: 'dividend',
17681784 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
17691785 isRequired: true,
17701786 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
17711787 forceEnum: false,
17721788 }),
17731789 SlashCommandArgument.fromProps({
17741790 description: 'divisor',
17751791 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
17761792 isRequired: true,
17771793 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
17781794 forceEnum: false,
17791795 }),
17801796 ],
1797+ splitUnnamedArgument: true,
17811798 helpString: `
17821799 <div>
17831800 Performs a division of two values and passes the result down the pipe.
@@ -1802,17 +1819,18 @@ export function registerVariableCommands() {
18021819 description: 'dividend',
18031820 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
18041821 isRequired: true,
18051822 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
18061823 forceEnum: false,
18071824 }),
18081825 SlashCommandArgument.fromProps({
18091826 description: 'divisor',
18101827 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
18111828 isRequired: true,
18121829 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
18131830 forceEnum: false,
18141831 }),
18151832 ],
1833+ splitUnnamedArgument: true,
18161834 helpString: `
18171835 <div>
18181836 Performs a modulo operation of two values and passes the result down the pipe.
@@ -1837,17 +1855,18 @@ export function registerVariableCommands() {
18371855 description: 'base',
18381856 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
18391857 isRequired: true,
18401858 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
18411859 forceEnum: false,
18421860 }),
18431861 SlashCommandArgument.fromProps({
18441862 description: 'exponent',
18451863 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
18461864 isRequired: true,
18471865 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
18481866 forceEnum: false,
18491867 }),
18501868 ],
1869+ splitUnnamedArgument: true,
18511870 helpString: `
18521871 <div>
18531872 Performs a power operation of two values and passes the result down the pipe.
@@ -1872,7 +1891,7 @@ export function registerVariableCommands() {
18721891 description: 'value',
18731892 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
18741893 isRequired: true,
18751894 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
18761895 forceEnum: false,
18771896 }),
18781897 ],
@@ -1900,7 +1919,7 @@ export function registerVariableCommands() {
19001919 description: 'value',
19011920 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
19021921 isRequired: true,
19031922 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
19041923 forceEnum: false,
19051924 }),
19061925 ],
@@ -1929,7 +1948,7 @@ export function registerVariableCommands() {
19291948 description: 'value',
19301949 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
19311950 isRequired: true,
19321951 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
19331952 forceEnum: false,
19341953 }),
19351954 ],
@@ -1957,7 +1976,7 @@ export function registerVariableCommands() {
19571976 description: 'value',
19581977 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
19591978 isRequired: true,
19601979 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
19611980 forceEnum: false,
19621981 }),
19631982 ],
@@ -1985,7 +2004,7 @@ export function registerVariableCommands() {
19852004 description: 'value',
19862005 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
19872006 isRequired: true,
19882007 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
19892008 forceEnum: false,
19902009 }),
19912010 ],
@@ -2013,7 +2032,7 @@ export function registerVariableCommands() {
20132032 description: 'value',
20142033 typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
20152034 isRequired: true,
20162035 enumProvider: commonEnumProviders.variables('all')numbersAndVariables,
20172036 forceEnum: false,
20182037 }),
20192038 ],