step into closures from elsewhere (draft)

This commit is contained in:
LenAnderson 2024-06-27 11:49:12 -04:00
parent aefa31a912
commit 173c5ef53e
5 changed files with 39 additions and 0 deletions

View File

@ -747,6 +747,7 @@ export class QuickReply {
}
async executeFromEditor() {
if (this.isExecuting) return;
const oText = this.message;
this.isExecuting = true;
this.editorDom.classList.add('qr--isExecuting');
const noSyntax = this.editorDom.querySelector('#qr--modal-messageHolder').classList.contains('qr--noSyntax');
@ -797,6 +798,12 @@ export class QuickReply {
this.abortController = new SlashCommandAbortController();
this.debugController = new SlashCommandDebugController();
this.debugController.onBreakPoint = async(closure, executor)=>{
//TODO move debug code into its own element, separate from the QR
//TODO populate debug code from closure.fullText and get locations, highlights, etc. from that
//TODO keep some kind of reference (human identifier) *where* the closure code comes from?
//TODO QR name, chat input, deserialized closure, ... ?
this.editorMessage.value = closure.fullText;
this.editorMessage.dispatchEvent(new Event('input', { bubbles:true }));
this.editorDebugState.innerHTML = '';
let ci = -1;
const varNames = [];
@ -1177,6 +1184,8 @@ export class QuickReply {
if (noSyntax) {
this.editorDom.querySelector('#qr--modal-messageHolder').classList.add('qr--noSyntax');
}
this.editorMessage.value = oText;
this.editorMessage.dispatchEvent(new Event('input', { bubbles:true }));
this.editorExecutePromise = null;
this.editorExecuteBtn.classList.remove('qr--busy');
this.editorPopup.dlg.classList.remove('qr--hide');

View File

@ -1737,6 +1737,10 @@ async function runCallback(args, name) {
throw new Error(`"${name}" is not callable.`);
}
closure.scope.parent = scope;
if (args._debugController && !closure.debugController) {
closure.debugController = args._debugController;
}
while (closure.providedArgumentList.pop());
closure.argumentList.forEach(arg => {
if (Object.keys(args).includes(arg.name)) {
const providedArg = new SlashCommandNamedArgumentAssignment();

View File

@ -1,6 +1,7 @@
import { SlashCommandAbortController } from './SlashCommandAbortController.js';
import { SlashCommandArgument, SlashCommandNamedArgument } from './SlashCommandArgument.js';
import { SlashCommandClosure } from './SlashCommandClosure.js';
import { SlashCommandDebugController } from './SlashCommandDebugController.js';
import { PARSER_FLAG } from './SlashCommandParser.js';
import { SlashCommandScope } from './SlashCommandScope.js';
@ -12,6 +13,7 @@ import { SlashCommandScope } from './SlashCommandScope.js';
* _scope:SlashCommandScope,
* _parserFlags:{[id:PARSER_FLAG]:boolean},
* _abortController:SlashCommandAbortController,
* _debugController:SlashCommandDebugController,
* _hasUnnamedArgument:boolean,
* [id:string]:string|SlashCommandClosure,
* }} NamedArguments

View File

@ -24,6 +24,8 @@ export class SlashCommandClosure {
/**@type {SlashCommandDebugController}*/ debugController;
/**@type {(done:number, total:number)=>void}*/ onProgress;
/**@type {string}*/ rawText;
/**@type {string}*/ fullText;
/**@type {string}*/ parserContext;
/**@type {number}*/
get commandCount() {
@ -58,6 +60,12 @@ export class SlashCommandClosure {
const after = remaining.slice(match.index + match[0].length);
const replacer = match[1] ? scope.pipe : match[2] ? scope.getVariable(match[2], match[3]) : scope.macroList.find(it=>it.key == match[4])?.value;
if (replacer instanceof SlashCommandClosure) {
replacer.abortController = this.abortController;
replacer.breakController = this.breakController;
replacer.scope.parent = this.scope;
if (this.debugController && !replacer.debugController) {
replacer.debugController = this.debugController;
}
isList = true;
if (match.index > 0) {
listValues.push(before);
@ -94,6 +102,9 @@ export class SlashCommandClosure {
closure.abortController = this.abortController;
closure.breakController = this.breakController;
closure.debugController = this.debugController;
closure.rawText = this.rawText;
closure.fullText = this.fullText;
closure.parserContext = this.parserContext;
closure.onProgress = this.onProgress;
return closure;
}
@ -256,6 +267,7 @@ export class SlashCommandClosure {
_scope: this.scope,
_parserFlags: executor.parserFlags,
_abortController: this.abortController,
_debugController: this.debugController,
_hasUnnamedArgument: executor.unnamedArgumentList.length > 0,
};
let value;
@ -266,6 +278,9 @@ export class SlashCommandClosure {
const closure = arg.value;
closure.scope.parent = this.scope;
closure.breakController = this.breakController;
if (this.debugController && !closure.debugController) {
closure.debugController = this.debugController;
}
if (closure.executeNow) {
args[arg.name] = (await closure.execute())?.pipe;
} else {
@ -285,6 +300,7 @@ export class SlashCommandClosure {
// substitute unnamed argument
if (executor.unnamedArgumentList.length == 0) {
//TODO no pipe injection on first executor in a closure?
if (executor.injectPipe) {
value = this.scope.pipe;
args._hasUnnamedArgument = this.scope.pipe !== null && this.scope.pipe !== undefined;
@ -298,6 +314,9 @@ export class SlashCommandClosure {
const closure = v;
closure.scope.parent = this.scope;
closure.breakController = this.breakController;
if (this.debugController && !closure.debugController) {
closure.debugController = this.debugController;
}
if (closure.executeNow) {
v = (await closure.execute())?.pipe;
} else {

View File

@ -117,6 +117,8 @@ export class SlashCommandParser {
/**@type {SlashCommandExecutor[]}*/ commandIndex;
/**@type {SlashCommandScope[]}*/ scopeIndex;
/**@type {string}*/ parserContext;
get userIndex() { return this.index; }
get ahead() {
@ -610,6 +612,7 @@ export class SlashCommandParser {
this.commandIndex = [];
this.scopeIndex = [];
this.macroIndex = [];
this.parserContext = uuidv4();
const closure = this.parseClosure(true);
return closure;
}
@ -637,6 +640,8 @@ export class SlashCommandParser {
if (!isRoot) this.take(2); // discard opening {:
const textStart = this.index;
let closure = new SlashCommandClosure(this.scope);
closure.parserContext = this.parserContext;
closure.fullText = this.text;
closure.abortController = this.abortController;
closure.debugController = this.debugController;
this.scope = closure.scope;