Merge pull request #2925 from SillyTavern/fix-math-commands Fix and improve math slash commands
Signed| @@ -153,6 +153,35 @@ export const commonEnumProviders = { | ||
| 153 | 153 | }, |
| 154 | 154 | |
| 155 | 155 | /** |
| 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 | + /** | |
| 156 | 185 | * All possible char entities, like characters and groups. Can be filtered down to just one type. |
| 157 | 186 | * |
| 158 | 187 | * @param {('all' | 'character' | 'group')?} [mode='all'] - Which type to return |
| @@ -669,8 +669,8 @@ function deleteGlobalVariable(name) { | ||
| 669 | 669 | } |
| 670 | 670 | |
| 671 | 671 | /** |
| 672 | 672 | * Parses a series of numeric values from a string or a string array. |
| 673 | 673 | * @param {string|string[]} value A space-separated list of numeric values or variable names |
| 674 | 674 | * @param {SlashCommandScope} scope Scope |
| 675 | 675 | * @returns {number[]} An array of numeric values |
| 676 | 676 | */ |
| @@ -679,11 +679,17 @@ function parseNumericSeries(value, scope = null) { | ||
| 679 | 679 | return [value]; |
| 680 | 680 | } |
| 681 | 681 | |
| 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) | |
| 685 | 691 | .filter(i => i !== '') |
| 686 | 692 | .map(i => isNaN(Number(i)) ? Number(resolveVariable(String(i), scope)) : Number(i)) |
| 687 | 693 | .filter(i => !isNaN(i)); |
| 688 | 694 | |
| 689 | 695 | return array; |
| @@ -703,7 +709,7 @@ function performOperation(value, operation, singleOperand = false, scope = null) | ||
| 703 | 709 | |
| 704 | 710 | const result = singleOperand ? operation(array[0]) : operation(array); |
| 705 | 711 | |
| 706 | 712 | if (isNaN(result) || !isFinite(result)) { |
| 707 | 713 | return 0; |
| 708 | 714 | } |
| 709 | 715 | |
| @@ -731,7 +737,7 @@ function maxValuesCallback(args, value) { | ||
| 731 | 737 | } |
| 732 | 738 | |
| 733 | 739 | function subValuesCallback(args, value) { |
| 734 | 740 | return performOperation(value, (array) => array[0].reduce((a, b) => a - b, array[1].shift() ?? 0), false, args._scope); |
| 735 | 741 | } |
| 736 | 742 | |
| 737 | 743 | function divValuesCallback(args, value) { |
| @@ -1595,36 +1601,15 @@ export function registerVariableCommands() { | ||
| 1595 | 1601 | })); |
| 1596 | 1602 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1597 | 1603 | name: 'add', |
| 1598 | 1604 | callback: (args, /**@type {string[]}*/value) => addValuesCallback(args, value.join(' ')), |
| 1599 | 1605 | returns: 'sum of the provided values', |
| 1600 | 1606 | unnamedArgumentList: [ |
| 1601 | 1607 | SlashCommandArgument.fromProps({ |
| 1602 | 1608 | description: 'values to sum', |
| 1603 | 1609 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST], |
| 1604 | 1610 | isRequired: true, |
| 1605 | 1611 | 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 | - }, | |
| 1628 | 1613 | forceEnum: false, |
| 1629 | 1614 | }), |
| 1630 | 1615 | ], |
| @@ -1632,7 +1617,9 @@ export function registerVariableCommands() { | ||
| 1632 | 1617 | helpString: ` |
| 1633 | 1618 | <div> |
| 1634 | 1619 | 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). | |
| 1636 | 1623 | </div> |
| 1637 | 1624 | <div> |
| 1638 | 1625 | <strong>Example:</strong> |
| @@ -1640,6 +1627,9 @@ export function registerVariableCommands() { | ||
| 1640 | 1627 | <li> |
| 1641 | 1628 | <pre><code class="language-stscript">/add 10 i 30 j</code></pre> |
| 1642 | 1629 | </li> |
| 1630 | + <li> | |
| 1631 | + <pre><code class="language-stscript">/add ["count", 15, 2, "i"]</code></pre> | |
| 1632 | + </li> | |
| 1643 | 1633 | </ul> |
| 1644 | 1634 | </div> |
| 1645 | 1635 | `, |
| @@ -1651,16 +1641,20 @@ export function registerVariableCommands() { | ||
| 1651 | 1641 | unnamedArgumentList: [ |
| 1652 | 1642 | SlashCommandArgument.fromProps({ |
| 1653 | 1643 | description: 'values to multiply', |
| 1654 | 1644 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST], |
| 1655 | 1645 | isRequired: true, |
| 1656 | 1646 | acceptsMultiple: true, |
| 1657 | 1647 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1658 | 1648 | forceEnum: false, |
| 1659 | 1649 | }), |
| 1660 | 1650 | ], |
| 1651 | + splitUnnamedArgument: true, | |
| 1661 | 1652 | helpString: ` |
| 1662 | 1653 | <div> |
| 1663 | 1654 | 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). | |
| 1664 | 1658 | </div> |
| 1665 | 1659 | <div> |
| 1666 | 1660 | <strong>Examples:</strong> |
| @@ -1668,6 +1662,9 @@ export function registerVariableCommands() { | ||
| 1668 | 1662 | <li> |
| 1669 | 1663 | <pre><code class="language-stscript">/mul 10 i 30 j</code></pre> |
| 1670 | 1664 | </li> |
| 1665 | + <li> | |
| 1666 | + <pre><code class="language-stscript">/mul ["count", 15, 2, "i"]</code></pre> | |
| 1667 | + </li> | |
| 1671 | 1668 | </ul> |
| 1672 | 1669 | </div> |
| 1673 | 1670 | `, |
| @@ -1679,16 +1676,20 @@ export function registerVariableCommands() { | ||
| 1679 | 1676 | unnamedArgumentList: [ |
| 1680 | 1677 | SlashCommandArgument.fromProps({ |
| 1681 | 1678 | description: 'values to find the max', |
| 1682 | 1679 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST], |
| 1683 | 1680 | isRequired: true, |
| 1684 | 1681 | acceptsMultiple: true, |
| 1685 | 1682 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1686 | 1683 | forceEnum: false, |
| 1687 | 1684 | }), |
| 1688 | 1685 | ], |
| 1686 | + splitUnnamedArgument: true, | |
| 1689 | 1687 | helpString: ` |
| 1690 | 1688 | <div> |
| 1691 | 1689 | 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). | |
| 1692 | 1693 | </div> |
| 1693 | 1694 | <div> |
| 1694 | 1695 | <strong>Examples:</strong> |
| @@ -1696,6 +1697,9 @@ export function registerVariableCommands() { | ||
| 1696 | 1697 | <li> |
| 1697 | 1698 | <pre><code class="language-stscript">/max 10 i 30 j</code></pre> |
| 1698 | 1699 | </li> |
| 1700 | + <li> | |
| 1701 | + <pre><code class="language-stscript">/max ["count", 15, 2, "i"]</code></pre> | |
| 1702 | + </li> | |
| 1699 | 1703 | </ul> |
| 1700 | 1704 | </div> |
| 1701 | 1705 | `, |
| @@ -1707,17 +1711,20 @@ export function registerVariableCommands() { | ||
| 1707 | 1711 | unnamedArgumentList: [ |
| 1708 | 1712 | SlashCommandArgument.fromProps({ |
| 1709 | 1713 | description: 'values to find the min', |
| 1710 | 1714 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST], |
| 1711 | 1715 | isRequired: true, |
| 1712 | 1716 | acceptsMultiple: true, |
| 1713 | 1717 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1714 | 1718 | forceEnum: false, |
| 1715 | 1719 | }), |
| 1716 | 1720 | ], |
| 1721 | + splitUnnamedArgument: true, | |
| 1717 | 1722 | helpString: ` |
| 1718 | 1723 | <div> |
| 1719 | 1724 | 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). | |
| 1721 | 1728 | </div> |
| 1722 | 1729 | <div> |
| 1723 | 1730 | <strong>Example:</strong> |
| @@ -1725,6 +1732,9 @@ export function registerVariableCommands() { | ||
| 1725 | 1732 | <li> |
| 1726 | 1733 | <pre><code class="language-stscript">/min 10 i 30 j</code></pre> |
| 1727 | 1734 | </li> |
| 1735 | + <li> | |
| 1736 | + <pre><code class="language-stscript">/min ["count", 15, 2, "i"]</code></pre> | |
| 1737 | + </li> | |
| 1728 | 1738 | </ul> |
| 1729 | 1739 | </div> |
| 1730 | 1740 | `, |
| @@ -1735,18 +1745,21 @@ export function registerVariableCommands() { | ||
| 1735 | 1745 | returns: 'difference of the provided values', |
| 1736 | 1746 | unnamedArgumentList: [ |
| 1737 | 1747 | SlashCommandArgument.fromProps({ |
| 1738 | 1748 | description: 'values to findsubtract, starting form the differencefirst provided value', |
| 1739 | 1749 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST], |
| 1740 | 1750 | isRequired: true, |
| 1741 | 1751 | acceptsMultiple: true, |
| 1742 | 1752 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1743 | 1753 | forceEnum: false, |
| 1744 | 1754 | }), |
| 1745 | 1755 | ], |
| 1756 | + splitUnnamedArgument: true, | |
| 1746 | 1757 | helpString: ` |
| 1747 | 1758 | <div> |
| 1748 | 1759 | 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). | |
| 1750 | 1763 | </div> |
| 1751 | 1764 | <div> |
| 1752 | 1765 | <strong>Example:</strong> |
| @@ -1754,6 +1767,9 @@ export function registerVariableCommands() { | ||
| 1754 | 1767 | <li> |
| 1755 | 1768 | <pre><code class="language-stscript">/sub i 5</code></pre> |
| 1756 | 1769 | </li> |
| 1770 | + <li> | |
| 1771 | + <pre><code class="language-stscript">/sub ["count", 4, "i"]</code></pre> | |
| 1772 | + </li> | |
| 1757 | 1773 | </ul> |
| 1758 | 1774 | </div> |
| 1759 | 1775 | `, |
| @@ -1767,17 +1783,18 @@ export function registerVariableCommands() { | ||
| 1767 | 1783 | description: 'dividend', |
| 1768 | 1784 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], |
| 1769 | 1785 | isRequired: true, |
| 1770 | 1786 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1771 | 1787 | forceEnum: false, |
| 1772 | 1788 | }), |
| 1773 | 1789 | SlashCommandArgument.fromProps({ |
| 1774 | 1790 | description: 'divisor', |
| 1775 | 1791 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], |
| 1776 | 1792 | isRequired: true, |
| 1777 | 1793 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1778 | 1794 | forceEnum: false, |
| 1779 | 1795 | }), |
| 1780 | 1796 | ], |
| 1797 | + splitUnnamedArgument: true, | |
| 1781 | 1798 | helpString: ` |
| 1782 | 1799 | <div> |
| 1783 | 1800 | Performs a division of two values and passes the result down the pipe. |
| @@ -1802,17 +1819,18 @@ export function registerVariableCommands() { | ||
| 1802 | 1819 | description: 'dividend', |
| 1803 | 1820 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], |
| 1804 | 1821 | isRequired: true, |
| 1805 | 1822 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1806 | 1823 | forceEnum: false, |
| 1807 | 1824 | }), |
| 1808 | 1825 | SlashCommandArgument.fromProps({ |
| 1809 | 1826 | description: 'divisor', |
| 1810 | 1827 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], |
| 1811 | 1828 | isRequired: true, |
| 1812 | 1829 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1813 | 1830 | forceEnum: false, |
| 1814 | 1831 | }), |
| 1815 | 1832 | ], |
| 1833 | + splitUnnamedArgument: true, | |
| 1816 | 1834 | helpString: ` |
| 1817 | 1835 | <div> |
| 1818 | 1836 | Performs a modulo operation of two values and passes the result down the pipe. |
| @@ -1837,17 +1855,18 @@ export function registerVariableCommands() { | ||
| 1837 | 1855 | description: 'base', |
| 1838 | 1856 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], |
| 1839 | 1857 | isRequired: true, |
| 1840 | 1858 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1841 | 1859 | forceEnum: false, |
| 1842 | 1860 | }), |
| 1843 | 1861 | SlashCommandArgument.fromProps({ |
| 1844 | 1862 | description: 'exponent', |
| 1845 | 1863 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], |
| 1846 | 1864 | isRequired: true, |
| 1847 | 1865 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1848 | 1866 | forceEnum: false, |
| 1849 | 1867 | }), |
| 1850 | 1868 | ], |
| 1869 | + splitUnnamedArgument: true, | |
| 1851 | 1870 | helpString: ` |
| 1852 | 1871 | <div> |
| 1853 | 1872 | Performs a power operation of two values and passes the result down the pipe. |
| @@ -1872,7 +1891,7 @@ export function registerVariableCommands() { | ||
| 1872 | 1891 | description: 'value', |
| 1873 | 1892 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], |
| 1874 | 1893 | isRequired: true, |
| 1875 | 1894 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1876 | 1895 | forceEnum: false, |
| 1877 | 1896 | }), |
| 1878 | 1897 | ], |
| @@ -1900,7 +1919,7 @@ export function registerVariableCommands() { | ||
| 1900 | 1919 | description: 'value', |
| 1901 | 1920 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], |
| 1902 | 1921 | isRequired: true, |
| 1903 | 1922 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1904 | 1923 | forceEnum: false, |
| 1905 | 1924 | }), |
| 1906 | 1925 | ], |
| @@ -1929,7 +1948,7 @@ export function registerVariableCommands() { | ||
| 1929 | 1948 | description: 'value', |
| 1930 | 1949 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], |
| 1931 | 1950 | isRequired: true, |
| 1932 | 1951 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1933 | 1952 | forceEnum: false, |
| 1934 | 1953 | }), |
| 1935 | 1954 | ], |
| @@ -1957,7 +1976,7 @@ export function registerVariableCommands() { | ||
| 1957 | 1976 | description: 'value', |
| 1958 | 1977 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], |
| 1959 | 1978 | isRequired: true, |
| 1960 | 1979 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1961 | 1980 | forceEnum: false, |
| 1962 | 1981 | }), |
| 1963 | 1982 | ], |
| @@ -1985,7 +2004,7 @@ export function registerVariableCommands() { | ||
| 1985 | 2004 | description: 'value', |
| 1986 | 2005 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], |
| 1987 | 2006 | isRequired: true, |
| 1988 | 2007 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 1989 | 2008 | forceEnum: false, |
| 1990 | 2009 | }), |
| 1991 | 2010 | ], |
| @@ -2013,7 +2032,7 @@ export function registerVariableCommands() { | ||
| 2013 | 2032 | description: 'value', |
| 2014 | 2033 | typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME], |
| 2015 | 2034 | isRequired: true, |
| 2016 | 2035 | enumProvider: commonEnumProviders.variables('all')numbersAndVariables, |
| 2017 | 2036 | forceEnum: false, |
| 2018 | 2037 | }), |
| 2019 | 2038 | ], |