mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-02-05 05:39:36 +01:00
debugger
This commit is contained in:
parent
ec122d7050
commit
e964a10612
@ -43,6 +43,10 @@
|
||||
|
||||
|
||||
|
||||
<div id="qr--resizeHandle"></div>
|
||||
|
||||
|
||||
|
||||
<div id="qr--qrOptions">
|
||||
<h3 data-i18n="Context Menu">Context Menu</h3>
|
||||
<div id="qr--ctxEditor">
|
||||
|
@ -65,6 +65,7 @@ export class QuickReply {
|
||||
/**@type {HTMLElement}*/ editorDebugState;
|
||||
/**@type {HTMLInputElement}*/ editorExecuteHide;
|
||||
/**@type {Promise}*/ editorExecutePromise;
|
||||
/**@type {boolean}*/ isExecuting;
|
||||
/**@type {SlashCommandAbortController}*/ abortController;
|
||||
/**@type {SlashCommandDebugController}*/ debugController;
|
||||
|
||||
@ -244,9 +245,15 @@ export class QuickReply {
|
||||
if (wrap.checked) {
|
||||
message.style.whiteSpace = 'pre-wrap';
|
||||
messageSyntaxInner.style.whiteSpace = 'pre-wrap';
|
||||
if (this.clone) {
|
||||
this.clone.style.whiteSpace = 'pre-wrap';
|
||||
}
|
||||
} else {
|
||||
message.style.whiteSpace = 'pre';
|
||||
messageSyntaxInner.style.whiteSpace = 'pre';
|
||||
if (this.clone) {
|
||||
this.clone.style.whiteSpace = 'pre';
|
||||
}
|
||||
}
|
||||
updateScrollDebounced();
|
||||
};
|
||||
@ -317,6 +324,7 @@ export class QuickReply {
|
||||
setSlashCommandAutoComplete(message, true);
|
||||
//TODO move tab support for textarea into its own helper(?) and use for both this and .editor_maximize
|
||||
message.addEventListener('keydown', async(evt) => {
|
||||
if (this.isExecuting) return;
|
||||
if (evt.key == 'Tab' && !evt.shiftKey && !evt.ctrlKey && !evt.altKey) {
|
||||
evt.preventDefault();
|
||||
const start = message.selectionStart;
|
||||
@ -569,6 +577,28 @@ export class QuickReply {
|
||||
stepOutBtn.addEventListener('click', ()=>{
|
||||
this.debugController?.stepOut();
|
||||
});
|
||||
/**@type {boolean}*/
|
||||
let isResizing = false;
|
||||
let resizeStart;
|
||||
let wStart;
|
||||
/**@type {HTMLElement}*/
|
||||
const resizeHandle = dom.querySelector('#qr--resizeHandle');
|
||||
resizeHandle.addEventListener('pointerdown', (evt)=>{
|
||||
if (isResizing) return;
|
||||
isResizing = true;
|
||||
evt.preventDefault();
|
||||
resizeStart = evt.x;
|
||||
wStart = dom.querySelector('#qr--qrOptions').offsetWidth;
|
||||
const dragListener = debounce((evt)=>{
|
||||
const w = wStart + resizeStart - evt.x;
|
||||
dom.querySelector('#qr--qrOptions').style.setProperty('--width', `${w}px`);
|
||||
}, 5);
|
||||
window.addEventListener('pointerup', ()=>{
|
||||
window.removeEventListener('pointermove', dragListener);
|
||||
isResizing = false;
|
||||
}, { once:true });
|
||||
window.addEventListener('pointermove', dragListener);
|
||||
});
|
||||
|
||||
await popupResult;
|
||||
|
||||
@ -596,6 +626,7 @@ export class QuickReply {
|
||||
});
|
||||
mo.observe(this.editorMessage.parentElement, { childList:true });
|
||||
}
|
||||
this.clone.style.width = `${inputRect.width}px`;
|
||||
this.clone.style.height = `${inputRect.height}px`;
|
||||
this.clone.style.left = `${inputRect.left}px`;
|
||||
this.clone.style.top = `${inputRect.top}px`;
|
||||
@ -620,8 +651,13 @@ export class QuickReply {
|
||||
return location;
|
||||
}
|
||||
async executeFromEditor() {
|
||||
if (this.editorExecutePromise) return;
|
||||
if (this.isExecuting) return;
|
||||
this.isExecuting = true;
|
||||
this.editorDom.classList.add('qr--isExecuting');
|
||||
const noSyntax = this.editorDom.querySelector('#qr--modal-messageHolder').classList.contains('qr--noSyntax');
|
||||
if (noSyntax) {
|
||||
this.editorDom.querySelector('#qr--modal-messageHolder').classList.remove('qr--noSyntax');
|
||||
}
|
||||
this.editorExecuteBtn.classList.add('qr--busy');
|
||||
this.editorExecuteProgress.style.setProperty('--prog', '0');
|
||||
this.editorExecuteErrors.classList.remove('qr--hasErrors');
|
||||
@ -658,17 +694,14 @@ export class QuickReply {
|
||||
title.textContent = isCurrent ? 'Current Scope' : 'Parent Scope';
|
||||
let hi;
|
||||
title.addEventListener('pointerenter', ()=>{
|
||||
const loc = this.getEditorPosition(c.executorList[0].start - 1, c.executorList.slice(-1)[0].end);
|
||||
const loc = this.getEditorPosition(Math.max(0, c.executorList[0].start - 1), c.executorList.slice(-1)[0].end);
|
||||
const layer = this.editorPopup.dlg.getBoundingClientRect();
|
||||
hi = document.createElement('div');
|
||||
hi.style.position = 'fixed';
|
||||
hi.classList.add('qr--highlight-secondary');
|
||||
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());
|
||||
@ -696,7 +729,13 @@ export class QuickReply {
|
||||
v.classList.add('qr--undefined');
|
||||
v.textContent = 'undefined';
|
||||
} else {
|
||||
v.textContent = val;
|
||||
let jsonVal;
|
||||
try { jsonVal = JSON.parse(val); } catch { /* empty */ }
|
||||
if (jsonVal && typeof jsonVal == 'object') {
|
||||
v.textContent = JSON.stringify(jsonVal, null, 2);
|
||||
} else {
|
||||
v.textContent = val;
|
||||
}
|
||||
}
|
||||
item.append(v);
|
||||
}
|
||||
@ -725,7 +764,13 @@ export class QuickReply {
|
||||
v.classList.add('qr--undefined');
|
||||
v.textContent = 'undefined';
|
||||
} else {
|
||||
v.textContent = val;
|
||||
let jsonVal;
|
||||
try { jsonVal = JSON.parse(val); } catch { /* empty */ }
|
||||
if (jsonVal && typeof jsonVal == 'object') {
|
||||
v.textContent = JSON.stringify(jsonVal, null, 2);
|
||||
} else {
|
||||
v.textContent = val;
|
||||
}
|
||||
}
|
||||
item.append(v);
|
||||
}
|
||||
@ -750,7 +795,13 @@ export class QuickReply {
|
||||
v.classList.add('qr--undefined');
|
||||
v.textContent = 'undefined';
|
||||
} else {
|
||||
v.textContent = val;
|
||||
let jsonVal;
|
||||
try { jsonVal = JSON.parse(val); } catch { /* empty */ }
|
||||
if (jsonVal && typeof jsonVal == 'object') {
|
||||
v.textContent = JSON.stringify(jsonVal, null, 2);
|
||||
} else {
|
||||
v.textContent = val;
|
||||
}
|
||||
}
|
||||
pipeItem.append(v);
|
||||
}
|
||||
@ -762,19 +813,51 @@ export class QuickReply {
|
||||
}
|
||||
return wrap;
|
||||
};
|
||||
const buildStack = ()=>{
|
||||
const wrap = document.createElement('div'); {
|
||||
wrap.classList.add('qr--stack');
|
||||
const title = document.createElement('div'); {
|
||||
title.classList.add('qr--title');
|
||||
title.textContent = 'Call Stack';
|
||||
wrap.append(title);
|
||||
}
|
||||
for (const executor of this.debugController.cmdStack.toReversed()) {
|
||||
const item = document.createElement('div'); {
|
||||
item.classList.add('qr--item');
|
||||
item.textContent = `/${executor.name}`;
|
||||
if (executor.command.name == 'run') {
|
||||
item.textContent += `${(executor.name == ':' ? '' : ' ')}${executor.unnamedArgumentList[0]?.value}`;
|
||||
}
|
||||
let hi;
|
||||
item.addEventListener('pointerenter', ()=>{
|
||||
const loc = this.getEditorPosition(Math.max(0, executor.start - 1), executor.end);
|
||||
const layer = this.editorPopup.dlg.getBoundingClientRect();
|
||||
hi = document.createElement('div');
|
||||
hi.classList.add('qr--highlight-secondary');
|
||||
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`;
|
||||
this.editorPopup.dlg.append(hi);
|
||||
});
|
||||
item.addEventListener('pointerleave', ()=>hi?.remove());
|
||||
wrap.append(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
return wrap;
|
||||
};
|
||||
this.editorDebugState.append(buildVars(closure.scope, true));
|
||||
this.editorDebugState.append(buildStack());
|
||||
this.editorDebugState.classList.add('qr--active');
|
||||
const loc = this.getEditorPosition(executor.start - 1, executor.end);
|
||||
const loc = this.getEditorPosition(Math.max(0, executor.start - 1), executor.end);
|
||||
const layer = this.editorPopup.dlg.getBoundingClientRect();
|
||||
const hi = document.createElement('div');
|
||||
hi.style.position = 'fixed';
|
||||
hi.classList.add('qr--highlight');
|
||||
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.backgroundColor = 'rgb(255 255 0 / 0.5)';
|
||||
this.editorPopup.dlg.append(hi);
|
||||
const isStepping = await this.debugController.awaitContinue();
|
||||
hi.remove();
|
||||
@ -807,10 +890,14 @@ export class QuickReply {
|
||||
`;
|
||||
}
|
||||
}
|
||||
if (noSyntax) {
|
||||
this.editorDom.querySelector('#qr--modal-messageHolder').classList.add('qr--noSyntax');
|
||||
}
|
||||
this.editorExecutePromise = null;
|
||||
this.editorExecuteBtn.classList.remove('qr--busy');
|
||||
this.editorPopup.dlg.classList.remove('qr--hide');
|
||||
this.editorDom.classList.remove('qr--isExecuting');
|
||||
this.isExecuting = false;
|
||||
}
|
||||
|
||||
updateEditorProgress(done, total) {
|
||||
|
@ -241,6 +241,18 @@
|
||||
.popup:has(#qr--modalEditor):has(.qr--isExecuting) .popup-controls {
|
||||
display: none;
|
||||
}
|
||||
.popup:has(#qr--modalEditor):has(.qr--isExecuting) .qr--highlight {
|
||||
position: fixed;
|
||||
z-index: 50000;
|
||||
pointer-events: none;
|
||||
background-color: rgba(255, 255, 0, 0.5);
|
||||
}
|
||||
.popup:has(#qr--modalEditor):has(.qr--isExecuting) .qr--highlight-secondary {
|
||||
position: fixed;
|
||||
z-index: 50000;
|
||||
pointer-events: none;
|
||||
border: 3px solid red;
|
||||
}
|
||||
.popup:has(#qr--modalEditor) .popup-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -262,9 +274,26 @@
|
||||
.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--isExecuting #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder > #qr--modal-message {
|
||||
visibility: hidden;
|
||||
}
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--modal-debugButtons {
|
||||
display: flex;
|
||||
}
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--resizeHandle {
|
||||
width: 6px;
|
||||
background-color: var(--SmartThemeBorderColor);
|
||||
border: 2px solid var(--SmartThemeBlurTintColor);
|
||||
transition: border-color 200ms, background-color 200ms;
|
||||
cursor: w-resize;
|
||||
}
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--resizeHandle:hover {
|
||||
background-color: var(--SmartThemeQuoteColor);
|
||||
border-color: var(--SmartThemeQuoteColor);
|
||||
}
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor.qr--isExecuting #qr--qrOptions {
|
||||
width: var(--width, auto);
|
||||
}
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
@ -435,6 +464,7 @@
|
||||
}
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugButtons .qr--modal-debugButton {
|
||||
aspect-ratio: 1.25 / 1;
|
||||
width: 2.25em;
|
||||
}
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugButtons .qr--modal-debugButton.qr--glyph-combo {
|
||||
display: grid;
|
||||
@ -544,12 +574,12 @@
|
||||
.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:nth-child(2n + 2) .qr--key,
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--macro:nth-child(2n + 2) .qr--key,
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--pipe:nth-child(2n + 2) .qr--key,
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--var:nth-child(2n + 2) .qr--val,
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--macro:nth-child(2n + 2) .qr--val,
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--pipe:nth-child(2n + 2) .qr--val {
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--var:nth-child(2n + 1) .qr--key,
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--macro:nth-child(2n + 1) .qr--key,
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--pipe:nth-child(2n + 1) .qr--key,
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--var:nth-child(2n + 1) .qr--val,
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--macro:nth-child(2n + 1) .qr--val,
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--pipe:nth-child(2n + 1) .qr--val {
|
||||
background-color: rgb(from var(--SmartThemeEmColor) r g b / 0.25);
|
||||
}
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--var.qr--isHidden .qr--key,
|
||||
@ -582,6 +612,19 @@
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--scope .qr--scope .qr--pipe .qr--val {
|
||||
opacity: 0.5;
|
||||
}
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--stack .qr--title {
|
||||
grid-column: 1 / 3;
|
||||
font-weight: bold;
|
||||
background-color: var(--black50a);
|
||||
padding: 0.25em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--stack .qr--item {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState .qr--stack .qr--item:nth-child(2n + 1) {
|
||||
background-color: rgb(from var(--SmartThemeEmColor) r g b / 0.25);
|
||||
}
|
||||
@keyframes qr--progressPulse {
|
||||
0%,
|
||||
100% {
|
||||
|
@ -262,8 +262,23 @@
|
||||
.popup:has(#qr--modalEditor) {
|
||||
aspect-ratio: unset;
|
||||
|
||||
&:has(.qr--isExecuting) .popup-controls {
|
||||
display: none;
|
||||
&:has(.qr--isExecuting) {
|
||||
.popup-controls {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.qr--highlight {
|
||||
position: fixed;
|
||||
z-index: 50000;
|
||||
pointer-events: none;
|
||||
background-color: rgba(255, 255, 0, 0.5);
|
||||
}
|
||||
.qr--highlight-secondary {
|
||||
position: fixed;
|
||||
z-index: 50000;
|
||||
pointer-events: none;
|
||||
border: 3px solid red;
|
||||
}
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
@ -289,9 +304,26 @@
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
#qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder > #qr--modal-message {
|
||||
visibility: hidden;
|
||||
}
|
||||
#qr--modal-debugButtons {
|
||||
display: flex;
|
||||
}
|
||||
#qr--resizeHandle {
|
||||
width: 6px;
|
||||
background-color: var(--SmartThemeBorderColor);
|
||||
border: 2px solid var(--SmartThemeBlurTintColor);
|
||||
transition: border-color 200ms, background-color 200ms;
|
||||
cursor: w-resize;
|
||||
&:hover {
|
||||
background-color: var(--SmartThemeQuoteColor);
|
||||
border-color: var(--SmartThemeQuoteColor);
|
||||
}
|
||||
}
|
||||
#qr--qrOptions {
|
||||
width: var(--width, auto);
|
||||
}
|
||||
}
|
||||
|
||||
> #qr--main {
|
||||
@ -461,6 +493,7 @@
|
||||
gap: 1em;
|
||||
.qr--modal-debugButton {
|
||||
aspect-ratio: 1.25 / 1;
|
||||
width: 2.25em;
|
||||
&.qr--glyph-combo {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
@ -566,7 +599,7 @@
|
||||
}
|
||||
.qr--var, .qr--macro, .qr--pipe {
|
||||
display: contents;
|
||||
&:nth-child(2n + 2) {
|
||||
&:nth-child(2n + 1) {
|
||||
.qr--key, .qr--val {
|
||||
background-color: rgb(from var(--SmartThemeEmColor) r g b / 0.25);
|
||||
}
|
||||
@ -597,6 +630,22 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.qr--stack {
|
||||
.qr--title {
|
||||
grid-column: 1 / 3;
|
||||
font-weight: bold;
|
||||
background-color: var(--black50a);
|
||||
padding: 0.25em;
|
||||
margin-top: 1em;
|
||||
}
|
||||
.qr--item {
|
||||
margin-left: 0.5em;
|
||||
&:nth-child(2n + 1) {
|
||||
background-color: rgb(from var(--SmartThemeEmColor) r g b / 0.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -213,6 +213,7 @@ export class SlashCommandClosure {
|
||||
let done = 0;
|
||||
for (const executor of this.executorList) {
|
||||
this.onProgress?.(done, this.commandCount);
|
||||
this.debugController?.setExecutor(executor);
|
||||
yield executor;
|
||||
if (executor instanceof SlashCommandClosureExecutor) {
|
||||
const closure = this.scope.getVariable(executor.name);
|
||||
|
@ -3,6 +3,7 @@ import { SlashCommandExecutor } from './SlashCommandExecutor.js';
|
||||
|
||||
export class SlashCommandDebugController {
|
||||
/**@type {SlashCommandClosure[]} */ stack = [];
|
||||
/**@type {SlashCommandExecutor[]} */ cmdStack = [];
|
||||
/**@type {boolean[]} */ stepStack = [];
|
||||
/**@type {boolean} */ isStepping = false;
|
||||
/**@type {boolean} */ isSteppingInto = false;
|
||||
@ -31,9 +32,14 @@ export class SlashCommandDebugController {
|
||||
}
|
||||
up() {
|
||||
this.stack.pop();
|
||||
while (this.cmdStack.length > this.stack.length) this.cmdStack.pop();
|
||||
this.stepStack.pop();
|
||||
}
|
||||
|
||||
setExecutor(executor) {
|
||||
this.cmdStack[this.stack.length - 1] = executor;
|
||||
}
|
||||
|
||||
|
||||
|
||||
resume() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user