debugger stuff

This commit is contained in:
LenAnderson 2024-06-20 13:06:58 -04:00
parent 02e1ef7606
commit 538724739b
5 changed files with 264 additions and 20 deletions

View File

@ -54,6 +54,7 @@ export class QuickReply {
/**@type {HTMLTextAreaElement}*/ settingsDomMessage;
/**@type {Popup}*/ editorPopup;
/**@type {HTMLElement}*/ editorDom;
/**@type {HTMLElement}*/ editorExecuteBtn;
/**@type {HTMLElement}*/ editorExecuteBtnPause;
@ -215,6 +216,7 @@ export class QuickReply {
/**@type {HTMLElement} */
// @ts-ignore
const dom = this.template.cloneNode(true);
this.editorDom = dom;
this.editorPopup = new Popup(dom, POPUP_TYPE.TEXT, undefined, { okButton: 'OK', wide: true, large: true, rows: 1 });
const popupResult = this.editorPopup.show();
@ -614,6 +616,7 @@ export class QuickReply {
}
async executeFromEditor() {
if (this.editorExecutePromise) return;
this.editorDom.classList.add('qr--isExecuting');
this.editorExecuteBtn.classList.add('qr--busy');
this.editorExecuteProgress.style.setProperty('--prog', '0');
this.editorExecuteErrors.classList.remove('qr--hasErrors');
@ -628,26 +631,133 @@ export class QuickReply {
this.editorPopup.dlg.classList.add('qr--hide');
}
try {
// this.editorExecutePromise = this.execute({}, true);
// const result = await this.editorExecutePromise;
this.abortController = new SlashCommandAbortController();
this.debugController = new SlashCommandDebugController();
this.debugController.onBreakPoint = async(closure, executor)=>{
const vars = closure.scope.variables;
vars['#pipe'] = closure.scope.pipe;
let v = vars;
let s = closure.scope.parent;
while (s) {
v['#parent'] = s.variables;
v = v['#parent'];
v['#pipe'] = s.pipe;
s = s.parent;
}
this.editorDebugState.textContent = JSON.stringify(closure.scope.variables, (key, val)=>{
if (val instanceof SlashCommandClosure) return val.toString();
if (val === undefined) return null;
return val;
}, 2);
this.editorDebugState.innerHTML = '';
let ci = -1;
const varNames = [];
const macroNames = [];
/**
* @param {SlashCommandScope} scope
*/
const buildVars = (scope, isCurrent = false)=>{
if (!isCurrent) {
ci--;
}
const c = this.debugController.stack.slice(ci)[0];
const wrap = document.createElement('div'); {
wrap.classList.add('qr--scope');
const title = document.createElement('div'); {
title.classList.add('qr--title');
title.textContent = isCurrent ? 'Current Scope' : 'Parent Scope';
let hi;
title.addEventListener('pointerenter', ()=>{
const loc = this.getEditorPosition(c.executorList[0].start, c.executorList.slice(-1)[0].end);
const layer = this.editorPopup.dlg.getBoundingClientRect();
hi = document.createElement('div');
hi.style.position = 'fixed';
hi.style.left = `${loc.left - layer.left}px`;
hi.style.width = `${loc.right - loc.left}px`;
hi.style.top = `${loc.top - layer.top}px`;
hi.style.height = `${loc.bottom - loc.top}px`;
hi.style.zIndex = '50000';
hi.style.pointerEvents = 'none';
hi.style.border = '3px solid red';
this.editorPopup.dlg.append(hi);
});
title.addEventListener('pointerleave', ()=>hi?.remove());
wrap.append(title);
}
for (const key of Object.keys(scope.variables)) {
const isHidden = varNames.includes(key);
if (!isHidden) varNames.push(key);
const item = document.createElement('div'); {
item.classList.add('qr--var');
if (isHidden) item.classList.add('qr--isHidden');
const k = document.createElement('div'); {
k.classList.add('qr--key');
k.textContent = key;
item.append(k);
}
const v = document.createElement('div'); {
v.classList.add('qr--val');
const val = scope.variables[key];
if (val instanceof SlashCommandClosure) {
v.classList.add('qr--closure');
v.title = val.rawText;
v.textContent = val.toString();
} else if (val === undefined) {
v.classList.add('qr--undefined');
v.textContent = 'undefined';
} else {
v.textContent = val;
}
item.append(v);
}
wrap.append(item);
}
}
for (const key of Object.keys(scope.macros)) {
const isHidden = macroNames.includes(key);
if (!isHidden) macroNames.push(key);
const item = document.createElement('div'); {
item.classList.add('qr--macro');
if (isHidden) item.classList.add('qr--isHidden');
const k = document.createElement('div'); {
k.classList.add('qr--key');
k.textContent = key;
item.append(k);
}
const v = document.createElement('div'); {
v.classList.add('qr--val');
const val = scope.macros[key];
if (val instanceof SlashCommandClosure) {
v.classList.add('qr--closure');
v.title = val.rawText;
v.textContent = val.toString();
} else if (val === undefined) {
v.classList.add('qr--undefined');
v.textContent = 'undefined';
} else {
v.textContent = val;
}
item.append(v);
}
wrap.append(item);
}
}
const pipeItem = document.createElement('div'); {
pipeItem.classList.add('qr--pipe');
const k = document.createElement('div'); {
k.classList.add('qr--key');
k.textContent = 'pipe';
pipeItem.append(k);
}
const v = document.createElement('div'); {
v.classList.add('qr--val');
const val = scope.pipe;
if (val instanceof SlashCommandClosure) {
v.classList.add('qr--closure');
v.title = val.rawText;
v.textContent = val.toString();
} else if (val === undefined) {
v.classList.add('qr--undefined');
v.textContent = 'undefined';
} else {
v.textContent = val;
}
pipeItem.append(v);
}
wrap.append(pipeItem);
}
if (scope.parent) {
wrap.append(buildVars(scope.parent));
}
}
return wrap;
};
this.editorDebugState.append(buildVars(closure.scope, true));
this.editorDebugState.classList.add('qr--active');
const loc = this.getEditorPosition(executor.start - 1, executor.end);
const layer = this.editorPopup.dlg.getBoundingClientRect();
@ -695,6 +805,7 @@ export class QuickReply {
this.editorExecutePromise = null;
this.editorExecuteBtn.classList.remove('qr--busy');
this.editorPopup.dlg.classList.remove('qr--hide');
this.editorDom.classList.remove('qr--isExecuting');
}
updateEditorProgress(done, total) {

View File

@ -238,6 +238,9 @@
.popup:has(#qr--modalEditor) {
aspect-ratio: unset;
}
.popup:has(#qr--modalEditor):has(.qr--isExecuting) .popup-controls {
display: none;
}
.popup:has(#qr--modalEditor) .popup-content {
display: flex;
flex-direction: column;
@ -249,6 +252,16 @@
gap: 1em;
overflow: hidden;
}
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--main > h3:first-child,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--main > .qr--labels,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--main > .qr--modal-messageContainer > .qr--modal-editorSettings,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--qrOptions > h3:first-child,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--qrOptions > #qr--ctxEditor,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--qrOptions > .qr--ctxEditorActions,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--qrOptions > .qr--ctxEditorActions + h3,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--qrOptions > .qr--ctxEditorActions + h3 + div {
display: none;
}
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main {
flex: 1 1 auto;
display: flex;
@ -485,8 +498,9 @@
display: none;
text-align: left;
font-size: smaller;
font-family: var(--monoFontFamily);
color: white;
padding: 0.5em;
padding: 0.5em 0;
overflow: auto;
min-width: 100%;
width: 0;
@ -495,6 +509,52 @@
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState.qr--active {
display: block;
}
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope {
display: grid;
grid-template-columns: 0fr 1fr;
column-gap: 1em;
}
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--title {
grid-column: 1 / 3;
font-weight: bold;
background-color: var(--black50a);
padding: 0.25em;
margin-top: 0.5em;
}
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--var,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--macro,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--pipe {
display: contents;
}
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--var.qr--isHidden .qr--key,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--macro.qr--isHidden .qr--key,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--pipe.qr--isHidden .qr--key,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--var.qr--isHidden .qr--val,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--macro.qr--isHidden .qr--val,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--pipe.qr--isHidden .qr--val {
opacity: 0.5;
}
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--key {
margin-left: 0.5em;
}
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--key:after {
content: ": ";
}
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--pipe > .qr--key:before,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--macro > .qr--key:before {
content: "{{";
}
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--pipe > .qr--key:after,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--macro > .qr--key:after {
content: "}}: ";
}
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--scope {
grid-column: 1 / 3;
}
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--scope .qr--pipe .qr--key,
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--scope .qr--pipe .qr--val {
opacity: 0.5;
}
@keyframes qr--progressPulse {
0%,
100% {

View File

@ -262,6 +262,10 @@
.popup:has(#qr--modalEditor) {
aspect-ratio: unset;
&:has(.qr--isExecuting) .popup-controls {
display: none;
}
.popup-content {
display: flex;
flex-direction: column;
@ -273,6 +277,21 @@
gap: 1em;
overflow: hidden;
&.qr--isExecuting {
#qr--main > h3:first-child,
#qr--main > .qr--labels,
#qr--main > .qr--modal-messageContainer > .qr--modal-editorSettings,
#qr--qrOptions > h3:first-child,
#qr--qrOptions > #qr--ctxEditor,
#qr--qrOptions > .qr--ctxEditorActions,
#qr--qrOptions > .qr--ctxEditorActions + h3,
#qr--qrOptions > .qr--ctxEditorActions + h3 + div
{
display: none;
}
}
> #qr--main {
flex: 1 1 auto;
display: flex;
@ -507,13 +526,53 @@
}
text-align: left;
font-size: smaller;
font-family: var(--monoFontFamily);
// background-color: rgb(146, 190, 252);
color: white;
padding: 0.5em;
padding: 0.5em 0;
overflow: auto;
min-width: 100%;
width: 0;
white-space: pre-wrap;
.qr--scope {
display: grid;
grid-template-columns: 0fr 1fr;
column-gap: 1em;
.qr--title {
grid-column: 1 / 3;
font-weight: bold;
background-color: var(--black50a);
padding: 0.25em;
margin-top: 0.5em;
}
.qr--var, .qr--macro, .qr--pipe {
display: contents;
&.qr--isHidden {
.qr--key, .qr--val {
opacity: 0.5;
}
}
}
.qr--key {
margin-left: 0.5em;
&:after { content: ": "; }
}
.qr--pipe, .qr--macro {
> .qr--key {
&:before { content: "{{"; }
&:after { content: "}}: "; }
}
}
.qr--scope {
grid-column: 1 / 3;
.qr--pipe {
.qr--key, .qr--val {
opacity: 0.5;
}
}
}
}
}
}
}

View File

@ -97,7 +97,7 @@ export class SlashCommandClosure {
/**
*
* @returns Promise<SlashCommandClosureResult>
* @returns {Promise<SlashCommandClosureResult>}
*/
async execute() {
const closure = this.getCopy();
@ -124,6 +124,7 @@ export class SlashCommandClosure {
}
async * executeDirect() {
this.debugController?.down(this);
// closure arguments
for (const arg of this.argumentList) {
let v = arg.value;
@ -305,10 +306,12 @@ export class SlashCommandClosure {
// if execution has returned a closure result, return that (should only happen on abort)
if (step.value instanceof SlashCommandClosureResult) {
this.debugController?.up();
return step.value;
}
/**@type {SlashCommandClosureResult} */
const result = Object.assign(new SlashCommandClosureResult(), { pipe: this.scope.pipe });
this.debugController?.up();
return result;
}
async * executeStep() {

View File

@ -2,6 +2,7 @@ import { SlashCommandClosure } from './SlashCommandClosure.js';
import { SlashCommandExecutor } from './SlashCommandExecutor.js';
export class SlashCommandDebugController {
/**@type {SlashCommandClosure[]} */ stack = [];
/**@type {boolean} */ isStepping = false;
/**@type {boolean} */ isSteppingInto = false;
@ -12,6 +13,16 @@ export class SlashCommandDebugController {
down(closure) {
this.stack.push(closure);
}
up() {
this.stack.pop();
}
resume() {
this.continueResolver?.(false);
this.continuePromise = null;