mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
debugger basics rough
This commit is contained in:
@ -2,8 +2,10 @@ import { substituteParams } from '../../script.js';
|
||||
import { delay, escapeRegex } from '../utils.js';
|
||||
import { SlashCommand } from './SlashCommand.js';
|
||||
import { SlashCommandAbortController } from './SlashCommandAbortController.js';
|
||||
import { SlashCommandBreakPoint } from './SlashCommandBreakPoint.js';
|
||||
import { SlashCommandClosureExecutor } from './SlashCommandClosureExecutor.js';
|
||||
import { SlashCommandClosureResult } from './SlashCommandClosureResult.js';
|
||||
import { SlashCommandDebugController } from './SlashCommandDebugController.js';
|
||||
import { SlashCommandExecutor } from './SlashCommandExecutor.js';
|
||||
import { SlashCommandNamedArgumentAssignment } from './SlashCommandNamedArgumentAssignment.js';
|
||||
import { SlashCommandScope } from './SlashCommandScope.js';
|
||||
@ -17,6 +19,7 @@ export class SlashCommandClosure {
|
||||
/**@type {SlashCommandNamedArgumentAssignment[]}*/ providedArgumentList = [];
|
||||
/**@type {SlashCommandExecutor[]}*/ executorList = [];
|
||||
/**@type {SlashCommandAbortController}*/ abortController;
|
||||
/**@type {SlashCommandDebugController}*/ debugController;
|
||||
/**@type {(done:number, total:number)=>void}*/ onProgress;
|
||||
/**@type {string}*/ rawText;
|
||||
|
||||
@ -87,6 +90,7 @@ export class SlashCommandClosure {
|
||||
closure.providedArgumentList = this.providedArgumentList;
|
||||
closure.executorList = this.executorList;
|
||||
closure.abortController = this.abortController;
|
||||
closure.debugController = this.debugController;
|
||||
closure.onProgress = this.onProgress;
|
||||
return closure;
|
||||
}
|
||||
@ -97,10 +101,29 @@ export class SlashCommandClosure {
|
||||
*/
|
||||
async execute() {
|
||||
const closure = this.getCopy();
|
||||
return await closure.executeDirect();
|
||||
const gen = closure.executeDirect();
|
||||
let step;
|
||||
while (!step?.done) {
|
||||
step = await gen.next(this.debugController?.isStepping ?? false);
|
||||
if (!(step.value instanceof SlashCommandClosureResult) && this.debugController) {
|
||||
this.debugController.isStepping = await this.debugController.awaitBreakPoint(step.value.closure, step.value.executor);
|
||||
}
|
||||
}
|
||||
return step.value;
|
||||
}
|
||||
|
||||
async executeDirect() {
|
||||
async * executeGenerator() {
|
||||
const closure = this.getCopy();
|
||||
const gen = closure.executeDirect();
|
||||
let step;
|
||||
while (!step?.done) {
|
||||
step = await gen.next(this.debugController?.isStepping);
|
||||
this.debugController.isStepping = yield step.value;
|
||||
}
|
||||
return step.value;
|
||||
}
|
||||
|
||||
async * executeDirect() {
|
||||
// closure arguments
|
||||
for (const arg of this.argumentList) {
|
||||
let v = arg.value;
|
||||
@ -153,7 +176,7 @@ export class SlashCommandClosure {
|
||||
if (this.executorList.length == 0) {
|
||||
this.scope.pipe = '';
|
||||
}
|
||||
for (const executor of this.executorList) {
|
||||
for (const executor of [] ?? this.executorList) {
|
||||
this.onProgress?.(done, this.commandCount);
|
||||
if (executor instanceof SlashCommandClosureExecutor) {
|
||||
const closure = this.scope.getVariable(executor.name);
|
||||
@ -258,10 +281,156 @@ export class SlashCommandClosure {
|
||||
}
|
||||
}
|
||||
}
|
||||
const stepper = this.executeStep();
|
||||
let step;
|
||||
while (!step?.done) {
|
||||
// get executor before execution
|
||||
step = await stepper.next();
|
||||
if (step.value instanceof SlashCommandBreakPoint) {
|
||||
console.log('encountered SlashCommandBreakPoint');
|
||||
if (this.debugController) {
|
||||
// "execute" breakpoint
|
||||
step = await stepper.next();
|
||||
// get next executor
|
||||
step = await stepper.next();
|
||||
this.debugController.isStepping = yield { closure:this, executor:step.value };
|
||||
}
|
||||
} else if (!step.done && this.debugController?.isStepping) {
|
||||
this.debugController.isSteppingInto = false;
|
||||
this.debugController.isStepping = yield { closure:this, executor:step.value };
|
||||
}
|
||||
// execute executor
|
||||
step = await stepper.next();
|
||||
}
|
||||
|
||||
// if execution has returned a closure result, return that (should only happen on abort)
|
||||
if (step.value instanceof SlashCommandClosureResult) {
|
||||
return step.value;
|
||||
}
|
||||
/**@type {SlashCommandClosureResult} */
|
||||
const result = Object.assign(new SlashCommandClosureResult(), { pipe: this.scope.pipe });
|
||||
return result;
|
||||
}
|
||||
async * executeStep() {
|
||||
let done = 0;
|
||||
for (const executor of this.executorList) {
|
||||
this.onProgress?.(done, this.commandCount);
|
||||
yield executor;
|
||||
if (executor instanceof SlashCommandClosureExecutor) {
|
||||
const closure = this.scope.getVariable(executor.name);
|
||||
if (!closure || !(closure instanceof SlashCommandClosure)) throw new Error(`${executor.name} is not a closure.`);
|
||||
closure.scope.parent = this.scope;
|
||||
closure.providedArgumentList = executor.providedArgumentList;
|
||||
const result = await closure.execute();
|
||||
this.scope.pipe = result.pipe;
|
||||
} else if (executor instanceof SlashCommandBreakPoint) {
|
||||
// no execution for breakpoints, just raise counter
|
||||
done++;
|
||||
} else {
|
||||
/**@type {import('./SlashCommand.js').NamedArguments} */
|
||||
let args = {
|
||||
_scope: this.scope,
|
||||
_parserFlags: executor.parserFlags,
|
||||
_abortController: this.abortController,
|
||||
_hasUnnamedArgument: executor.unnamedArgumentList.length > 0,
|
||||
};
|
||||
let value;
|
||||
// substitute named arguments
|
||||
for (const arg of executor.namedArgumentList) {
|
||||
if (arg.value instanceof SlashCommandClosure) {
|
||||
/**@type {SlashCommandClosure}*/
|
||||
const closure = arg.value;
|
||||
closure.scope.parent = this.scope;
|
||||
if (closure.executeNow) {
|
||||
args[arg.name] = (await closure.execute())?.pipe;
|
||||
} else {
|
||||
args[arg.name] = closure;
|
||||
}
|
||||
} else {
|
||||
args[arg.name] = this.substituteParams(arg.value);
|
||||
}
|
||||
// unescape named argument
|
||||
if (typeof args[arg.name] == 'string') {
|
||||
args[arg.name] = args[arg.name]
|
||||
?.replace(/\\\{/g, '{')
|
||||
?.replace(/\\\}/g, '}')
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
// substitute unnamed argument
|
||||
if (executor.unnamedArgumentList.length == 0) {
|
||||
if (executor.injectPipe) {
|
||||
value = this.scope.pipe;
|
||||
args._hasUnnamedArgument = this.scope.pipe !== null && this.scope.pipe !== undefined;
|
||||
}
|
||||
} else {
|
||||
value = [];
|
||||
for (let i = 0; i < executor.unnamedArgumentList.length; i++) {
|
||||
let v = executor.unnamedArgumentList[i].value;
|
||||
if (v instanceof SlashCommandClosure) {
|
||||
/**@type {SlashCommandClosure}*/
|
||||
const closure = v;
|
||||
closure.scope.parent = this.scope;
|
||||
if (closure.executeNow) {
|
||||
v = (await closure.execute())?.pipe;
|
||||
} else {
|
||||
v = closure;
|
||||
}
|
||||
} else {
|
||||
v = this.substituteParams(v);
|
||||
}
|
||||
value[i] = v;
|
||||
}
|
||||
if (!executor.command.splitUnnamedArgument) {
|
||||
if (value.length == 1) {
|
||||
value = value[0];
|
||||
} else if (!value.find(it=>it instanceof SlashCommandClosure)) {
|
||||
value = value.join('');
|
||||
}
|
||||
}
|
||||
}
|
||||
// unescape unnamed argument
|
||||
if (typeof value == 'string') {
|
||||
value = value
|
||||
?.replace(/\\\{/g, '{')
|
||||
?.replace(/\\\}/g, '}')
|
||||
;
|
||||
} else if (Array.isArray(value)) {
|
||||
value = value.map(v=>{
|
||||
if (typeof v == 'string') {
|
||||
return v
|
||||
?.replace(/\\\{/g, '{')
|
||||
?.replace(/\\\}/g, '}');
|
||||
}
|
||||
return v;
|
||||
});
|
||||
}
|
||||
|
||||
let abortResult = await this.testAbortController();
|
||||
if (abortResult) {
|
||||
return abortResult;
|
||||
}
|
||||
executor.onProgress = (subDone, subTotal)=>this.onProgress?.(done + subDone, this.commandCount);
|
||||
const isStepping = this.debugController?.isStepping;
|
||||
if (this.debugController) {
|
||||
this.debugController.isStepping = false || this.debugController.isSteppingInto;
|
||||
}
|
||||
this.scope.pipe = await executor.command.callback(args, value ?? '');
|
||||
if (this.debugController) {
|
||||
this.debugController.isStepping = isStepping;
|
||||
}
|
||||
this.#lintPipe(executor.command);
|
||||
done += executor.commandCount;
|
||||
this.onProgress?.(done, this.commandCount);
|
||||
abortResult = await this.testAbortController();
|
||||
if (abortResult) {
|
||||
return abortResult;
|
||||
}
|
||||
}
|
||||
yield executor;
|
||||
}
|
||||
}
|
||||
|
||||
async testPaused() {
|
||||
while (!this.abortController?.signal?.aborted && this.abortController?.signal?.paused) {
|
||||
|
Reference in New Issue
Block a user