diff --git a/public/img/step-into.svg b/public/img/step-into.svg new file mode 100644 index 000000000..fcfa7ef16 --- /dev/null +++ b/public/img/step-into.svg @@ -0,0 +1,149 @@ + + + + diff --git a/public/img/step-out.svg b/public/img/step-out.svg new file mode 100644 index 000000000..aa7dd3ea2 --- /dev/null +++ b/public/img/step-out.svg @@ -0,0 +1,149 @@ + + + + diff --git a/public/img/step-over.svg b/public/img/step-over.svg new file mode 100644 index 000000000..6f23ff22a --- /dev/null +++ b/public/img/step-over.svg @@ -0,0 +1,149 @@ + + + + diff --git a/public/img/step-resume.svg b/public/img/step-resume.svg new file mode 100644 index 000000000..bf3e0647f --- /dev/null +++ b/public/img/step-resume.svg @@ -0,0 +1,218 @@ + + + + diff --git a/public/index.html b/public/index.html index 1fa87231b..d3d0a6b64 100644 --- a/public/index.html +++ b/public/index.html @@ -4268,6 +4268,16 @@ +
@@ -43,6 +58,10 @@
+
+
+
+
{{input}}
macro for manual injection)
/qr-get set=MyPreset label=MyButton | /echo
+ /qr-get set=MyPreset id=42 | /echo
+ /qr-arg x foo |\n/echo {{arg::x}}
+ /let
or /var
.
+ /import from=LibraryQrSet.FooBar foo |\n/:foo
/import from=LibraryQrSet.FooBar\n\tfoo\n\tbar\n|\n/:foo |\n/:bar
/import from=LibraryQrSet.FooBar\n\tfoo as x\n\tbar as y\n|\n/:x |\n/:y
/pick-icon |\n/if left={{pipe}} rule=eq right=false\n\telse={: /echo chosen icon: "{{pipe}}" :}\n\t{: /echo cancelled icon selection :}\n|
+ ${ex.hint}+ `; + const clickHint = '
Click to see details
'; + toastr.error( + `${toast}${clickHint}`, + 'SlashCommandExecutionError', + { escapeHtml: false, timeOut: 10000, onclick: () => callPopup(toast, 'text') }, + ); + } else { + toastr.error(result.errorMessage); + } } } finally { delay(1000).then(() => clearCommandProgressDebounced()); @@ -3520,7 +3581,9 @@ async function executeSlashCommandsWithOptions(text, options = {}) { handleExecutionErrors: false, parserFlags: null, abortController: null, + debugController: null, onProgress: null, + source: null, }, options); let closure; @@ -3528,6 +3591,8 @@ async function executeSlashCommandsWithOptions(text, options = {}) { closure = parser.parse(text, true, options.parserFlags, options.abortController ?? new SlashCommandAbortController()); closure.scope.parent = options.scope; closure.onProgress = options.onProgress; + closure.debugController = options.debugController; + closure.source = options.source; } catch (e) { if (options.handleParserErrors && e instanceof SlashCommandParserError) { /**@type {SlashCommandParserError}*/ @@ -3559,7 +3624,23 @@ async function executeSlashCommandsWithOptions(text, options = {}) { return result; } catch (e) { if (options.handleExecutionErrors) { - toastr.error(e.message); + if (e instanceof SlashCommandExecutionError) { + /**@type {SlashCommandExecutionError}*/ + const ex = e; + const toast = ` +${ex.hint}+ `; + const clickHint = '
Click to see details
'; + toastr.error( + `${toast}${clickHint}`, + 'SlashCommandExecutionError', + { escapeHtml: false, timeOut: 10000, onclick: () => callPopup(toast, 'text') }, + ); + } else { + toastr.error(e.message); + } const result = new SlashCommandClosureResult(); result.isError = true; result.errorMessage = e.message; @@ -3596,6 +3677,7 @@ async function executeSlashCommands(text, handleParserErrors = true, scope = nul * * @param {HTMLTextAreaElement} textarea The textarea to receive autocomplete * @param {Boolean} isFloating Whether to show the auto complete as a floating window (e.g., large QR editor) + * @returns {Promiserepeats
number of times.
@@ -1459,7 +1482,7 @@ export function registerVariableCommands() {
}));
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'add',
- callback: addValuesCallback,
+ callback: (args, /**@type {string[]}*/value) => addValuesCallback(args, value.join(' ')),
returns: 'sum of the provided values',
unnamedArgumentList: [
SlashCommandArgument.fromProps({
@@ -1467,10 +1490,32 @@ export function registerVariableCommands() {
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
isRequired: true,
acceptsMultiple: true,
- enumProvider: commonEnumProviders.variables('all'),
+ 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;
+ },
forceEnum: false,
}),
],
+ splitUnnamedArgument: true,
helpString: `