mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-03-02 02:47:52 +01:00
Merge branch 'staging' into connection-profile-omit
This commit is contained in:
commit
3b1435ba77
@ -6090,7 +6090,10 @@
|
||||
<div class="alternate_grettings flexFlowColumn flex-container">
|
||||
<div class="title_restorable">
|
||||
<h3><span data-i18n="Alternate Greetings" class="mdhotkey_location">Alternate Greetings</span></h3>
|
||||
<div title="Add" class="menu_button fa-solid fa-plus add_alternate_greeting" data-i18n="[title]Add"></div>
|
||||
<div class="menu_button menu_button_icon add_alternate_greeting">
|
||||
<i class="fa-solid fa-plus"></i>
|
||||
<span data-i18n="Add">Add</span>
|
||||
</div>
|
||||
</div>
|
||||
<small class="justifyLeft" data-i18n="Alternate_Greetings_desc">
|
||||
These will be displayed as swipes on the first message when starting a new chat.
|
||||
@ -6106,11 +6109,18 @@
|
||||
</div>
|
||||
<div id="alternate_greeting_form_template" class="template_element">
|
||||
<div class="alternate_greeting">
|
||||
<div class="title_restorable">
|
||||
<strong><span data-i18n="Alternate Greeting #">Alternate Greeting #</span><span class="greeting_index"></span></strong>
|
||||
<div class="menu_button fa-solid fa-trash-alt delete_alternate_greeting"></div>
|
||||
</div>
|
||||
<textarea name="alternate_greetings" data-i18n="[placeholder](This will be the first message from the character that starts every chat)" placeholder="(This will be the first message from the character that starts every chat)" class="text_pole textarea_compact alternate_greeting_text mdHotkeys" value="" autocomplete="off" rows="16"></textarea>
|
||||
<details open>
|
||||
<summary>
|
||||
<div class="title_restorable">
|
||||
<strong><span data-i18n="Alternate Greeting #">Alternate Greeting #</span><span class="greeting_index"></span></strong>
|
||||
<div class="menu_button menu_button_icon delete_alternate_greeting">
|
||||
<i class="fa-solid fa-trash-alt"></i>
|
||||
<span data-i18n="Delete">Delete</span>
|
||||
</div>
|
||||
</div>
|
||||
</summary>
|
||||
<textarea name="alternate_greetings" data-i18n="[placeholder](This will be the first message from the character that starts every chat)" placeholder="(This will be the first message from the character that starts every chat)" class="text_pole textarea_compact alternate_greeting_text mdHotkeys" value="" autocomplete="off" rows="12"></textarea>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -7390,7 +7390,7 @@ function onScenarioOverrideRemoveClick() {
|
||||
*/
|
||||
export function callPopup(text, type, inputValue = '', { okButton, rows, wide, wider, large, allowHorizontalScrolling, allowVerticalScrolling, cropAspect } = {}) {
|
||||
function getOkButtonText() {
|
||||
if (['text', 'alternate_greeting', 'char_not_selected'].includes(popup_type)) {
|
||||
if (['text', 'char_not_selected'].includes(popup_type)) {
|
||||
$dialoguePopupCancel.css('display', 'none');
|
||||
return okButton ?? 'Ok';
|
||||
} else if (['delete_extension'].includes(popup_type)) {
|
||||
@ -7827,24 +7827,42 @@ function openAlternateGreetings() {
|
||||
|
||||
const template = $('#alternate_greetings_template .alternate_grettings').clone();
|
||||
const getArray = () => menu_type == 'create' ? create_save.alternate_greetings : characters[chid].data.alternate_greetings;
|
||||
const popup = new Popup(template, POPUP_TYPE.TEXT, '', {
|
||||
wide: true,
|
||||
large: true,
|
||||
allowVerticalScrolling: true,
|
||||
onClose: async () => {
|
||||
if (menu_type !== 'create') {
|
||||
await createOrEditCharacter();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (let index = 0; index < getArray().length; index++) {
|
||||
addAlternateGreeting(template, getArray()[index], index, getArray);
|
||||
addAlternateGreeting(template, getArray()[index], index, getArray, popup);
|
||||
}
|
||||
|
||||
template.find('.add_alternate_greeting').on('click', function () {
|
||||
const array = getArray();
|
||||
const index = array.length;
|
||||
array.push('');
|
||||
addAlternateGreeting(template, '', index, getArray);
|
||||
addAlternateGreeting(template, '', index, getArray, popup);
|
||||
updateAlternateGreetingsHintVisibility(template);
|
||||
});
|
||||
|
||||
updateAlternateGreetingsHintVisibility(template);
|
||||
callPopup(template, 'alternate_greeting', '', { wide: true, large: true });
|
||||
popup.show();
|
||||
}
|
||||
|
||||
function addAlternateGreeting(template, greeting, index, getArray) {
|
||||
/**
|
||||
* Adds an alternate greeting to the template.
|
||||
* @param {JQuery<HTMLElement>} template
|
||||
* @param {string} greeting
|
||||
* @param {number} index
|
||||
* @param {() => any[]} getArray
|
||||
* @param {Popup} popup
|
||||
*/
|
||||
function addAlternateGreeting(template, greeting, index, getArray, popup) {
|
||||
const greetingBlock = $('#alternate_greeting_form_template .alternate_greeting').clone();
|
||||
greetingBlock.find('.alternate_greeting_text').on('input', async function () {
|
||||
const value = $(this).val();
|
||||
@ -7852,11 +7870,16 @@ function addAlternateGreeting(template, greeting, index, getArray) {
|
||||
array[index] = value;
|
||||
}).val(greeting);
|
||||
greetingBlock.find('.greeting_index').text(index + 1);
|
||||
greetingBlock.find('.delete_alternate_greeting').on('click', async function () {
|
||||
greetingBlock.find('.delete_alternate_greeting').on('click', async function (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
if (confirm('Are you sure you want to delete this alternate greeting?')) {
|
||||
const array = getArray();
|
||||
array.splice(index, 1);
|
||||
|
||||
// We need to reopen the popup to update the index numbers
|
||||
await popup.complete(POPUP_RESULT.AFFIRMATIVE);
|
||||
openAlternateGreetings();
|
||||
}
|
||||
});
|
||||
@ -9574,9 +9597,6 @@ jQuery(async function () {
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
if (popup_type == 'alternate_greeting' && menu_type !== 'create') {
|
||||
createOrEditCharacter();
|
||||
}
|
||||
|
||||
if (dialogueResolve) {
|
||||
if (popup_type == 'input') {
|
||||
|
@ -3469,7 +3469,7 @@ function getModelOptions(quiet) {
|
||||
case 'openai':
|
||||
return oai_settings.chat_completion_source;
|
||||
default:
|
||||
return nullResult;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCom
|
||||
import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
|
||||
import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
||||
import { SlashCommandScope } from './slash-commands/SlashCommandScope.js';
|
||||
import { isFalseBoolean, convertValueType } from './utils.js';
|
||||
import { isFalseBoolean, convertValueType, isTrueBoolean } from './utils.js';
|
||||
|
||||
/** @typedef {import('./slash-commands/SlashCommandParser.js').NamedArguments} NamedArguments */
|
||||
/** @typedef {import('./slash-commands/SlashCommand.js').UnnamedArguments} UnnamedArguments */
|
||||
@ -488,7 +488,7 @@ function existsGlobalVariable(name) {
|
||||
/**
|
||||
* Parses boolean operands from command arguments.
|
||||
* @param {object} args Command arguments
|
||||
* @returns {{a: string | number, b: string | number, rule: string}} Boolean operands
|
||||
* @returns {{a: string | number, b: string | number?, rule: string}} Boolean operands
|
||||
*/
|
||||
export function parseBooleanOperands(args) {
|
||||
// Resolution order: numeric literal, local variable, global variable, string literal
|
||||
@ -497,6 +497,9 @@ export function parseBooleanOperands(args) {
|
||||
*/
|
||||
function getOperand(operand) {
|
||||
if (operand === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
if (operand === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -525,8 +528,8 @@ export function parseBooleanOperands(args) {
|
||||
return stringLiteral || '';
|
||||
}
|
||||
|
||||
const left = getOperand(args.a || args.left || args.first || args.x);
|
||||
const right = getOperand(args.b || args.right || args.second || args.y);
|
||||
const left = getOperand(args.a ?? args.left ?? args.first ?? args.x);
|
||||
const right = getOperand(args.b ?? args.right ?? args.second ?? args.y);
|
||||
const rule = args.rule;
|
||||
|
||||
return { a: left, b: right, rule };
|
||||
@ -534,84 +537,79 @@ export function parseBooleanOperands(args) {
|
||||
|
||||
/**
|
||||
* Evaluates a boolean comparison rule.
|
||||
* @param {string} rule Boolean comparison rule
|
||||
*
|
||||
* @param {string?} rule Boolean comparison rule
|
||||
* @param {string|number} a The left operand
|
||||
* @param {string|number} b The right operand
|
||||
* @param {string|number?} b The right operand
|
||||
* @returns {boolean} True if the rule yields true, false otherwise
|
||||
*/
|
||||
export function evalBoolean(rule, a, b) {
|
||||
if (!rule) {
|
||||
toastr.warning('The rule must be specified for the boolean comparison.', 'Invalid command');
|
||||
throw new Error('Invalid command.');
|
||||
if (a === undefined) {
|
||||
throw new Error('Left operand is not provided');
|
||||
}
|
||||
|
||||
let result = false;
|
||||
// If right-hand side was not provided, whe just check if the left side is truthy
|
||||
if (b === undefined) {
|
||||
switch (rule) {
|
||||
case undefined:
|
||||
case 'not': {
|
||||
const resultOnTruthy = rule !== 'not';
|
||||
if (isTrueBoolean(String(a))) return resultOnTruthy;
|
||||
if (isFalseBoolean(String(a))) return !resultOnTruthy;
|
||||
return a ? resultOnTruthy : !resultOnTruthy;
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unknown boolean comparison rule for truthy check. If right operand is not provided, the rule must not provided or be 'not'. Provided: ${rule}`);
|
||||
}
|
||||
}
|
||||
|
||||
// If no rule was provided, we are implicitly using 'eq', as defined for the slash commands
|
||||
rule ??= 'eq';
|
||||
|
||||
if (typeof a === 'number' && typeof b === 'number') {
|
||||
// only do numeric comparison if both operands are numbers
|
||||
const aNumber = Number(a);
|
||||
const bNumber = Number(b);
|
||||
|
||||
switch (rule) {
|
||||
case 'not':
|
||||
result = !aNumber;
|
||||
break;
|
||||
case 'gt':
|
||||
result = aNumber > bNumber;
|
||||
break;
|
||||
return aNumber > bNumber;
|
||||
case 'gte':
|
||||
result = aNumber >= bNumber;
|
||||
break;
|
||||
return aNumber >= bNumber;
|
||||
case 'lt':
|
||||
result = aNumber < bNumber;
|
||||
break;
|
||||
return aNumber < bNumber;
|
||||
case 'lte':
|
||||
result = aNumber <= bNumber;
|
||||
break;
|
||||
return aNumber <= bNumber;
|
||||
case 'eq':
|
||||
result = aNumber === bNumber;
|
||||
break;
|
||||
return aNumber === bNumber;
|
||||
case 'neq':
|
||||
result = aNumber !== bNumber;
|
||||
break;
|
||||
default:
|
||||
toastr.error('Unknown boolean comparison rule for type number.', 'Invalid command');
|
||||
throw new Error('Invalid command.');
|
||||
}
|
||||
} else {
|
||||
// otherwise do case-insensitive string comparsion, stringify non-strings
|
||||
let aString;
|
||||
let bString;
|
||||
if (typeof a == 'string') {
|
||||
aString = a.toLowerCase();
|
||||
} else {
|
||||
aString = JSON.stringify(a).toLowerCase();
|
||||
}
|
||||
if (typeof b == 'string') {
|
||||
bString = b.toLowerCase();
|
||||
} else {
|
||||
bString = JSON.stringify(b).toLowerCase();
|
||||
}
|
||||
|
||||
switch (rule) {
|
||||
return aNumber !== bNumber;
|
||||
case 'in':
|
||||
result = aString.includes(bString);
|
||||
break;
|
||||
case 'nin':
|
||||
result = !aString.includes(bString);
|
||||
break;
|
||||
case 'eq':
|
||||
result = aString === bString;
|
||||
break;
|
||||
case 'neq':
|
||||
result = aString !== bString;
|
||||
// Fall through to string comparison. Otherwise you could not check if 12345 contains 45 for example.
|
||||
console.debug(`Boolean comparison rule '${rule}' is not supported for type number. Falling back to string comparison.`);
|
||||
break;
|
||||
default:
|
||||
toastr.error('Unknown boolean comparison rule for type string.', 'Invalid /if command');
|
||||
throw new Error('Invalid command.');
|
||||
throw new Error(`Unknown boolean comparison rule for type number. Accepted: gt, gte, lt, lte, eq, neq. Provided: ${rule}`);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
// otherwise do case-insensitive string comparsion, stringify non-strings
|
||||
let aString = (typeof a === 'string') ? a.toLowerCase() : JSON.stringify(a).toLowerCase();
|
||||
let bString = (typeof b === 'string') ? b.toLowerCase() : JSON.stringify(b).toLowerCase();
|
||||
|
||||
switch (rule) {
|
||||
case 'in':
|
||||
return aString.includes(bString);
|
||||
case 'nin':
|
||||
return !aString.includes(bString);
|
||||
case 'eq':
|
||||
return aString === bString;
|
||||
case 'neq':
|
||||
return aString !== bString;
|
||||
default:
|
||||
throw new Error(`Unknown boolean comparison rule for type number. Accepted: in, nin, eq, neq. Provided: ${rule}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1317,32 +1315,36 @@ export function registerVariableCommands() {
|
||||
typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.variables('all'),
|
||||
forceEnum: false,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'right',
|
||||
description: 'right operand',
|
||||
typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.variables('all'),
|
||||
forceEnum: false,
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'rule', 'comparison rule', [ARGUMENT_TYPE.STRING], true, false, null, [
|
||||
new SlashCommandEnumValue('gt', 'a > b'),
|
||||
new SlashCommandEnumValue('gte', 'a >= b'),
|
||||
new SlashCommandEnumValue('lt', 'a < b'),
|
||||
new SlashCommandEnumValue('lte', 'a <= b'),
|
||||
new SlashCommandEnumValue('eq', 'a == b'),
|
||||
new SlashCommandEnumValue('neq', 'a !== b'),
|
||||
new SlashCommandEnumValue('not', '!a'),
|
||||
new SlashCommandEnumValue('in', 'a includes b'),
|
||||
new SlashCommandEnumValue('nin', 'a not includes b'),
|
||||
],
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'else', 'command to execute if not true', [ARGUMENT_TYPE.CLOSURE, ARGUMENT_TYPE.SUBCOMMAND], false,
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'rule',
|
||||
description: 'comparison rule',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: 'eq',
|
||||
enumList: [
|
||||
new SlashCommandEnumValue('eq', 'a == b (strings & numbers)'),
|
||||
new SlashCommandEnumValue('neq', 'a !== b (strings & numbers)'),
|
||||
new SlashCommandEnumValue('in', 'a includes b (strings & numbers as strings)'),
|
||||
new SlashCommandEnumValue('nin', 'a not includes b (strings & numbers as strings)'),
|
||||
new SlashCommandEnumValue('gt', 'a > b (numbers)'),
|
||||
new SlashCommandEnumValue('gte', 'a >= b (numbers)'),
|
||||
new SlashCommandEnumValue('lt', 'a < b (numbers)'),
|
||||
new SlashCommandEnumValue('lte', 'a <= b (numbers)'),
|
||||
new SlashCommandEnumValue('not', '!a (truthy)'),
|
||||
],
|
||||
forceEnum: true,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'else',
|
||||
description: 'command to execute if not true',
|
||||
typeList: [ARGUMENT_TYPE.CLOSURE, ARGUMENT_TYPE.SUBCOMMAND],
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -1359,18 +1361,26 @@ export function registerVariableCommands() {
|
||||
<div>
|
||||
Numeric values and string literals for left and right operands supported.
|
||||
</div>
|
||||
<div>
|
||||
If the rule is not provided, it defaults to <code>eq</code>.
|
||||
</div>
|
||||
<div>
|
||||
If no right operand is provided, it defaults to checking the <code>left</code> value to be truthy.
|
||||
A non-empty string or non-zero number is considered truthy, as is the value <code>true</code> or <code>on</code>.<br />
|
||||
Only acceptable rules for no provided right operand are <code>not</code>, and no provided rule - which default to returning whether it is not or is truthy.
|
||||
</div>
|
||||
<div>
|
||||
<strong>Available rules:</strong>
|
||||
<ul>
|
||||
<li>gt => a > b</li>
|
||||
<li>gte => a >= b</li>
|
||||
<li>lt => a < b</li>
|
||||
<li>lte => a <= b</li>
|
||||
<li>eq => a == b</li>
|
||||
<li>neq => a != b</li>
|
||||
<li>not => !a</li>
|
||||
<li>in (strings) => a includes b</li>
|
||||
<li>nin (strings) => a not includes b</li>
|
||||
<li><code>eq</code> => a == b <small>(strings & numbers)</small></li>
|
||||
<li><code>neq</code> => a !== b <small>(strings & numbers)</small></li>
|
||||
<li><code>in</code> => a includes b <small>(strings & numbers as strings)</small></li>
|
||||
<li><code>nin</code> => a not includes b <small>(strings & numbers as strings)</small></li>
|
||||
<li><code>gt</code> => a > b <small>(numbers)</small></li>
|
||||
<li><code>gte</code> => a >= b <small>(numbers)</small></li>
|
||||
<li><code>lt</code> => a < b <small>(numbers)</small></li>
|
||||
<li><code>lte</code> => a <= b <small>(numbers)</small></li>
|
||||
<li><code>not</code> => !a <small>(truthy)</small></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
@ -1380,6 +1390,17 @@ export function registerVariableCommands() {
|
||||
<pre><code class="language-stscript">/if left=score right=10 rule=gte "/speak You win"</code></pre>
|
||||
triggers a /speak command if the value of "score" is greater or equals 10.
|
||||
</li>
|
||||
<li>
|
||||
<pre><code class="language-stscript">/if left={{lastMessage}} rule=in right=surprise {: /echo SURPISE! :}</code></pre>
|
||||
executes a subcommand defined as a closure if the given value contains a specified word.
|
||||
<li>
|
||||
<pre><code class="language-stscript">/if left=myContent {: /echo My content had some content. :}</code></pre>
|
||||
executes the defined subcommand, if the provided value of left is truthy (contains some kind of contant that is not empty or false)
|
||||
</li>
|
||||
<li>
|
||||
<pre><code class="language-stscript">/if left=tree right={{getvar::object}} {: /echo The object is a tree! :}</code></pre>
|
||||
executes the defined subcommand, if the left and right values are equals.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`,
|
||||
@ -1395,32 +1416,38 @@ export function registerVariableCommands() {
|
||||
typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.variables('all'),
|
||||
forceEnum: false,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'right',
|
||||
description: 'right operand',
|
||||
typeList: [ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.NUMBER],
|
||||
isRequired: true,
|
||||
enumProvider: commonEnumProviders.variables('all'),
|
||||
forceEnum: false,
|
||||
}),
|
||||
new SlashCommandNamedArgument(
|
||||
'rule', 'comparison rule', [ARGUMENT_TYPE.STRING], true, false, null, [
|
||||
new SlashCommandEnumValue('gt', 'a > b'),
|
||||
new SlashCommandEnumValue('gte', 'a >= b'),
|
||||
new SlashCommandEnumValue('lt', 'a < b'),
|
||||
new SlashCommandEnumValue('lte', 'a <= b'),
|
||||
new SlashCommandEnumValue('eq', 'a == b'),
|
||||
new SlashCommandEnumValue('neq', 'a !== b'),
|
||||
new SlashCommandEnumValue('not', '!a'),
|
||||
new SlashCommandEnumValue('in', 'a includes b'),
|
||||
new SlashCommandEnumValue('nin', 'a not includes b'),
|
||||
],
|
||||
),
|
||||
new SlashCommandNamedArgument(
|
||||
'guard', 'disable loop iteration limit', [ARGUMENT_TYPE.STRING], false, false, null, commonEnumProviders.boolean('onOff')(),
|
||||
),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'rule',
|
||||
description: 'comparison rule',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: 'eq',
|
||||
enumList: [
|
||||
new SlashCommandEnumValue('eq', 'a == b (strings & numbers)'),
|
||||
new SlashCommandEnumValue('neq', 'a !== b (strings & numbers)'),
|
||||
new SlashCommandEnumValue('in', 'a includes b (strings & numbers as strings)'),
|
||||
new SlashCommandEnumValue('nin', 'a not includes b (strings & numbers as strings)'),
|
||||
new SlashCommandEnumValue('gt', 'a > b (numbers)'),
|
||||
new SlashCommandEnumValue('gte', 'a >= b (numbers)'),
|
||||
new SlashCommandEnumValue('lt', 'a < b (numbers)'),
|
||||
new SlashCommandEnumValue('lte', 'a <= b (numbers)'),
|
||||
new SlashCommandEnumValue('not', '!a (truthy)'),
|
||||
],
|
||||
forceEnum: true,
|
||||
}),
|
||||
SlashCommandNamedArgument.fromProps({
|
||||
name: 'guard',
|
||||
description: 'disable loop iteration limit',
|
||||
typeList: [ARGUMENT_TYPE.STRING],
|
||||
defaultValue: 'off',
|
||||
enumList: commonEnumProviders.boolean('onOff')(),
|
||||
}),
|
||||
],
|
||||
unnamedArgumentList: [
|
||||
new SlashCommandArgument(
|
||||
@ -1439,15 +1466,15 @@ export function registerVariableCommands() {
|
||||
<div>
|
||||
<strong>Available rules:</strong>
|
||||
<ul>
|
||||
<li>gt => a > b</li>
|
||||
<li>gte => a >= b</li>
|
||||
<li>lt => a < b</li>
|
||||
<li>lte => a <= b</li>
|
||||
<li>eq => a == b</li>
|
||||
<li>neq => a != b</li>
|
||||
<li>not => !a</li>
|
||||
<li>in (strings) => a includes b</li>
|
||||
<li>nin (strings) => a not includes b</li>
|
||||
<li><code>eq</code> => a == b <small>(strings & numbers)</small></li>
|
||||
<li><code>neq</code> => a !== b <small>(strings & numbers)</small></li>
|
||||
<li><code>in</code> => a includes b <small>(strings & numbers as strings)</small></li>
|
||||
<li><code>nin</code> => a not includes b <small>(strings & numbers as strings)</small></li>
|
||||
<li><code>gt</code> => a > b <small>(numbers)</small></li>
|
||||
<li><code>gte</code> => a >= b <small>(numbers)</small></li>
|
||||
<li><code>lt</code> => a < b <small>(numbers)</small></li>
|
||||
<li><code>lte</code> => a <= b <small>(numbers)</small></li>
|
||||
<li><code>not</code> => !a <small>(truthy)</small></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
@ -1457,7 +1484,11 @@ export function registerVariableCommands() {
|
||||
<pre><code class="language-stscript">/setvar key=i 0 | /while left=i right=10 rule=lte "/addvar key=i 1"</code></pre>
|
||||
adds 1 to the value of "i" until it reaches 10.
|
||||
</li>
|
||||
</ul>
|
||||
<li>
|
||||
<pre><code class="language-stscript">/while left={{getvar::currentword}} {: /setvar key=currentword {: /do-something-and-return :}() | /echo The current work is "{{getvar::currentword}}" :}</code></pre>
|
||||
executes the defined subcommand as long as the "currentword" variable is truthy (has any content that is not false/empty)
|
||||
</ul>
|
||||
</li>
|
||||
</div>
|
||||
<div>
|
||||
Loops are limited to 100 iterations by default, pass <code>guard=off</code> to disable.
|
||||
@ -1572,7 +1603,7 @@ export function registerVariableCommands() {
|
||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||
isRequired: true,
|
||||
acceptsMultiple: true,
|
||||
enumProvider: (executor, scope)=>{
|
||||
enumProvider: (executor, scope) => {
|
||||
const vars = commonEnumProviders.variables('all')(executor, scope);
|
||||
vars.push(
|
||||
new SlashCommandEnumValue(
|
||||
@ -1580,16 +1611,16 @@ export function registerVariableCommands() {
|
||||
null,
|
||||
enumTypes.variable,
|
||||
enumIcons.variable,
|
||||
(input)=>/^\w*$/.test(input),
|
||||
(input)=>input,
|
||||
(input) => /^\w*$/.test(input),
|
||||
(input) => input,
|
||||
),
|
||||
new SlashCommandEnumValue(
|
||||
'any number',
|
||||
null,
|
||||
enumTypes.number,
|
||||
enumIcons.number,
|
||||
(input)=>input == '' || !Number.isNaN(Number(input)),
|
||||
(input)=>input,
|
||||
(input) => input == '' || !Number.isNaN(Number(input)),
|
||||
(input) => input,
|
||||
),
|
||||
);
|
||||
return vars;
|
||||
|
@ -3154,6 +3154,26 @@ grammarly-extension {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.alternate_greeting details {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.alternate_greeting summary {
|
||||
list-style-position: outside;
|
||||
margin-left: 1em;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.alternate_greeting textarea {
|
||||
field-sizing: content;
|
||||
max-height: 50dvh;
|
||||
}
|
||||
|
||||
.alternate_greeting summary::marker,
|
||||
.alternate_greeting summary strong {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#rm_characters_block .form_create_bottom_buttons_block {
|
||||
justify-content: space-evenly !important;
|
||||
flex-grow: 0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user