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:
		@@ -116,6 +116,17 @@
 | 
			
		||||
				<i class="fa-solid fa-stop"></i>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div id="qr--modal-debugButtons">
 | 
			
		||||
			<div id="qr--modal-resume" class="qr--modal-debugButton menu_button">
 | 
			
		||||
				Resume
 | 
			
		||||
			</div>
 | 
			
		||||
			<div id="qr--modal-step" class="qr--modal-debugButton menu_button">
 | 
			
		||||
				Step
 | 
			
		||||
			</div>
 | 
			
		||||
			<div id="qr--modal-stepInto" class="qr--modal-debugButton menu_button">
 | 
			
		||||
				StepInto
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div id="qr--modal-executeProgress"></div>
 | 
			
		||||
		<label class="checkbox_label">
 | 
			
		||||
			<input type="checkbox" id="qr--modal-executeHide">
 | 
			
		||||
@@ -123,5 +134,6 @@
 | 
			
		||||
		</label>
 | 
			
		||||
		<div id="qr--modal-executeErrors"></div>
 | 
			
		||||
		<div id="qr--modal-executeResult"></div>
 | 
			
		||||
		<div id="qr--modal-debugState"></div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,10 @@
 | 
			
		||||
import { POPUP_TYPE, Popup } from '../../../popup.js';
 | 
			
		||||
import { setSlashCommandAutoComplete } from '../../../slash-commands.js';
 | 
			
		||||
import { SlashCommandAbortController } from '../../../slash-commands/SlashCommandAbortController.js';
 | 
			
		||||
import { SlashCommandClosure } from '../../../slash-commands/SlashCommandClosure.js';
 | 
			
		||||
import { SlashCommandClosureResult } from '../../../slash-commands/SlashCommandClosureResult.js';
 | 
			
		||||
import { SlashCommandDebugController } from '../../../slash-commands/SlashCommandDebugController.js';
 | 
			
		||||
import { SlashCommandExecutor } from '../../../slash-commands/SlashCommandExecutor.js';
 | 
			
		||||
import { SlashCommandParserError } from '../../../slash-commands/SlashCommandParserError.js';
 | 
			
		||||
import { SlashCommandScope } from '../../../slash-commands/SlashCommandScope.js';
 | 
			
		||||
import { debounce, getSortableDelay } from '../../../utils.js';
 | 
			
		||||
@@ -38,6 +42,7 @@ export class QuickReply {
 | 
			
		||||
    /**@type {String}*/ automationId = '';
 | 
			
		||||
 | 
			
		||||
    /**@type {Function}*/ onExecute;
 | 
			
		||||
    /**@type {(qr:QuickReply)=>AsyncGenerator<SlashCommandClosureResult|{closure:SlashCommandClosure, executor:SlashCommandExecutor|SlashCommandClosureResult}, SlashCommandClosureResult, boolean>}*/ onDebug;
 | 
			
		||||
    /**@type {Function}*/ onDelete;
 | 
			
		||||
    /**@type {Function}*/ onUpdate;
 | 
			
		||||
 | 
			
		||||
@@ -56,9 +61,11 @@ export class QuickReply {
 | 
			
		||||
    /**@type {HTMLElement}*/ editorExecuteProgress;
 | 
			
		||||
    /**@type {HTMLElement}*/ editorExecuteErrors;
 | 
			
		||||
    /**@type {HTMLElement}*/ editorExecuteResult;
 | 
			
		||||
    /**@type {HTMLElement}*/ editorDebugState;
 | 
			
		||||
    /**@type {HTMLInputElement}*/ editorExecuteHide;
 | 
			
		||||
    /**@type {Promise}*/ editorExecutePromise;
 | 
			
		||||
    /**@type {SlashCommandAbortController}*/ abortController;
 | 
			
		||||
    /**@type {SlashCommandDebugController}*/ debugController;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    get hasContext() {
 | 
			
		||||
@@ -298,6 +305,7 @@ export class QuickReply {
 | 
			
		||||
            });
 | 
			
		||||
            /**@type {HTMLTextAreaElement}*/
 | 
			
		||||
            const message = dom.querySelector('#qr--modal-message');
 | 
			
		||||
            this.editorMessage = message;
 | 
			
		||||
            message.value = this.message;
 | 
			
		||||
            message.addEventListener('input', () => {
 | 
			
		||||
                updateSyntax();
 | 
			
		||||
@@ -506,6 +514,9 @@ export class QuickReply {
 | 
			
		||||
            /**@type {HTMLElement}*/
 | 
			
		||||
            const executeResult = dom.querySelector('#qr--modal-executeResult');
 | 
			
		||||
            this.editorExecuteResult = executeResult;
 | 
			
		||||
            /**@type {HTMLElement}*/
 | 
			
		||||
            const debugState = dom.querySelector('#qr--modal-debugState');
 | 
			
		||||
            this.editorDebugState = debugState;
 | 
			
		||||
            /**@type {HTMLInputElement}*/
 | 
			
		||||
            const executeHide = dom.querySelector('#qr--modal-executeHide');
 | 
			
		||||
            this.editorExecuteHide = executeHide;
 | 
			
		||||
@@ -536,6 +547,22 @@ export class QuickReply {
 | 
			
		||||
                this.abortController?.abort('Stop button clicked');
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            /**@type {HTMLElement}*/
 | 
			
		||||
            const resumeBtn = dom.querySelector('#qr--modal-resume');
 | 
			
		||||
            resumeBtn.addEventListener('click', ()=>{
 | 
			
		||||
                this.debugController?.resume();
 | 
			
		||||
            });
 | 
			
		||||
            /**@type {HTMLElement}*/
 | 
			
		||||
            const stepBtn = dom.querySelector('#qr--modal-step');
 | 
			
		||||
            stepBtn.addEventListener('click', ()=>{
 | 
			
		||||
                this.debugController?.step();
 | 
			
		||||
            });
 | 
			
		||||
            /**@type {HTMLElement}*/
 | 
			
		||||
            const stepIntoBtn = dom.querySelector('#qr--modal-stepInto');
 | 
			
		||||
            stepIntoBtn.addEventListener('click', ()=>{
 | 
			
		||||
                this.debugController?.stepInto();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            await popupResult;
 | 
			
		||||
 | 
			
		||||
            window.removeEventListener('resize', resizeListener);
 | 
			
		||||
@@ -544,6 +571,47 @@ export class QuickReply {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    getEditorPosition(start, end) {
 | 
			
		||||
        const inputRect = this.editorMessage.getBoundingClientRect();
 | 
			
		||||
        const style = window.getComputedStyle(this.editorMessage);
 | 
			
		||||
        if (!this.clone) {
 | 
			
		||||
            this.clone = document.createElement('div');
 | 
			
		||||
            for (const key of style) {
 | 
			
		||||
                this.clone.style[key] = style[key];
 | 
			
		||||
            }
 | 
			
		||||
            this.clone.style.position = 'fixed';
 | 
			
		||||
            this.clone.style.visibility = 'hidden';
 | 
			
		||||
            document.body.append(this.clone);
 | 
			
		||||
            const mo = new MutationObserver(muts=>{
 | 
			
		||||
                if (muts.find(it=>Array.from(it.removedNodes).includes(this.editorMessage))) {
 | 
			
		||||
                    this.clone.remove();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
            mo.observe(this.editorMessage.parentElement, { childList:true });
 | 
			
		||||
        }
 | 
			
		||||
        this.clone.style.height = `${inputRect.height}px`;
 | 
			
		||||
        this.clone.style.left = `${inputRect.left}px`;
 | 
			
		||||
        this.clone.style.top = `${inputRect.top}px`;
 | 
			
		||||
        this.clone.style.whiteSpace = style.whiteSpace;
 | 
			
		||||
        this.clone.style.tabSize = style.tabSize;
 | 
			
		||||
        const text = this.editorMessage.value;
 | 
			
		||||
        const before = text.slice(0, start);
 | 
			
		||||
        this.clone.textContent = before;
 | 
			
		||||
        const locator = document.createElement('span');
 | 
			
		||||
        locator.textContent = text.slice(start, end);
 | 
			
		||||
        this.clone.append(locator);
 | 
			
		||||
        this.clone.append(text.slice(end));
 | 
			
		||||
        this.clone.scrollTop = this.editorMessage.scrollTop;
 | 
			
		||||
        this.clone.scrollLeft = this.editorMessage.scrollLeft;
 | 
			
		||||
        const locatorRect = locator.getBoundingClientRect();
 | 
			
		||||
        const location = {
 | 
			
		||||
            left: locatorRect.left,
 | 
			
		||||
            right: locatorRect.right,
 | 
			
		||||
            top: locatorRect.top,
 | 
			
		||||
            bottom: locatorRect.bottom,
 | 
			
		||||
        };
 | 
			
		||||
        return location;
 | 
			
		||||
    }
 | 
			
		||||
    async executeFromEditor() {
 | 
			
		||||
        if (this.editorExecutePromise) return;
 | 
			
		||||
        this.editorExecuteBtn.classList.add('qr--busy');
 | 
			
		||||
@@ -560,8 +628,44 @@ export class QuickReply {
 | 
			
		||||
            this.editorPopup.dom.classList.add('qr--hide');
 | 
			
		||||
        }
 | 
			
		||||
        try {
 | 
			
		||||
            this.editorExecutePromise = this.execute({}, true);
 | 
			
		||||
            const result = await this.editorExecutePromise;
 | 
			
		||||
            // 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();
 | 
			
		||||
                    return val;
 | 
			
		||||
                }, 2);
 | 
			
		||||
                this.editorDebugState.classList.add('qr--active');
 | 
			
		||||
                const loc = this.getEditorPosition(executor.start - 1, executor.end);
 | 
			
		||||
                const hi = document.createElement('div');
 | 
			
		||||
                hi.style.position = 'fixed';
 | 
			
		||||
                hi.style.left = `${loc.left}px`;
 | 
			
		||||
                hi.style.width = `${loc.right - loc.left}px`;
 | 
			
		||||
                hi.style.top = `${loc.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)';
 | 
			
		||||
                document.body.append(hi);
 | 
			
		||||
                const isStepping = await this.debugController.awaitContinue();
 | 
			
		||||
                hi.remove();
 | 
			
		||||
                this.editorDebugState.textContent = '';
 | 
			
		||||
                this.editorDebugState.classList.remove('qr--active');
 | 
			
		||||
                return isStepping;
 | 
			
		||||
            };
 | 
			
		||||
            const result = await this.onDebug(this);
 | 
			
		||||
            if (this.abortController?.signal?.aborted) {
 | 
			
		||||
                this.editorExecuteProgress.classList.add('qr--aborted');
 | 
			
		||||
            } else {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,6 @@
 | 
			
		||||
import { getRequestHeaders, substituteParams } from '../../../../script.js';
 | 
			
		||||
import { executeSlashCommands, executeSlashCommandsOnChatInput, executeSlashCommandsWithOptions } from '../../../slash-commands.js';
 | 
			
		||||
import { SlashCommandParser } from '../../../slash-commands/SlashCommandParser.js';
 | 
			
		||||
import { SlashCommandScope } from '../../../slash-commands/SlashCommandScope.js';
 | 
			
		||||
import { debounceAsync, warn } from '../index.js';
 | 
			
		||||
import { QuickReply } from './QuickReply.js';
 | 
			
		||||
@@ -100,6 +101,26 @@ export class QuickReplySet {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @param {QuickReply} qr
 | 
			
		||||
     */
 | 
			
		||||
    async debug(qr) {
 | 
			
		||||
        const parser = new SlashCommandParser();
 | 
			
		||||
        const closure = parser.parse(qr.message, true, [], qr.abortController, qr.debugController);
 | 
			
		||||
        closure.onProgress = (done, total) => qr.updateEditorProgress(done, total);
 | 
			
		||||
        // closure.abortController = qr.abortController;
 | 
			
		||||
        // closure.debugController = qr.debugController;
 | 
			
		||||
        // const stepper = closure.executeGenerator();
 | 
			
		||||
        // let step;
 | 
			
		||||
        // let isStepping = false;
 | 
			
		||||
        // while (!step?.done) {
 | 
			
		||||
        //     step = await stepper.next(isStepping);
 | 
			
		||||
        //     isStepping = yield(step.value);
 | 
			
		||||
        // }
 | 
			
		||||
        // return step.value;
 | 
			
		||||
        return (await closure.execute())?.pipe;
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @param {QuickReply} qr The QR to execute.
 | 
			
		||||
@@ -195,7 +216,12 @@ export class QuickReplySet {
 | 
			
		||||
        return qr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     *
 | 
			
		||||
     * @param {QuickReply} qr
 | 
			
		||||
     */
 | 
			
		||||
    hookQuickReply(qr) {
 | 
			
		||||
        qr.onDebug = ()=>this.debug(qr);
 | 
			
		||||
        qr.onExecute = (_, options)=>this.executeWithOptions(qr, options);
 | 
			
		||||
        qr.onDelete = ()=>this.removeQuickReply(qr);
 | 
			
		||||
        qr.onUpdate = ()=>this.save();
 | 
			
		||||
 
 | 
			
		||||
@@ -301,19 +301,19 @@
 | 
			
		||||
  text-align: left;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
.dialogue_popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder.qr--noSyntax > #qr--modal-messageSyntax {
 | 
			
		||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder.qr--noSyntax > #qr--modal-messageSyntax {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
.dialogue_popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder.qr--noSyntax > #qr--modal-message {
 | 
			
		||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder.qr--noSyntax > #qr--modal-message {
 | 
			
		||||
  background-color: var(--ac-style-color-background);
 | 
			
		||||
  color: var(--ac-style-color-text);
 | 
			
		||||
}
 | 
			
		||||
.dialogue_popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder.qr--noSyntax > #qr--modal-message::selection {
 | 
			
		||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder.qr--noSyntax > #qr--modal-message::selection {
 | 
			
		||||
  color: unset;
 | 
			
		||||
  background-color: rgba(108 171 251 / 0.25);
 | 
			
		||||
}
 | 
			
		||||
@supports (color: rgb(from white r g b / 0.25)) {
 | 
			
		||||
  .dialogue_popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder.qr--noSyntax > #qr--modal-message::selection {
 | 
			
		||||
  .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder.qr--noSyntax > #qr--modal-message::selection {
 | 
			
		||||
    background-color: rgb(from var(--ac-style-color-matchedText) r g b / 0.25);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -343,12 +343,12 @@
 | 
			
		||||
  visibility: hidden;
 | 
			
		||||
  cursor: default;
 | 
			
		||||
}
 | 
			
		||||
.dialogue_popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder > #qr--modal-message::selection {
 | 
			
		||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder > #qr--modal-message::selection {
 | 
			
		||||
  color: transparent;
 | 
			
		||||
  background-color: rgba(108 171 251 / 0.25);
 | 
			
		||||
}
 | 
			
		||||
@supports (color: rgb(from white r g b / 0.25)) {
 | 
			
		||||
  .dialogue_popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder > #qr--modal-message::selection {
 | 
			
		||||
  .popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor > #qr--main > .qr--modal-messageContainer > #qr--modal-messageHolder > #qr--modal-message::selection {
 | 
			
		||||
    background-color: rgb(from var(--ac-style-color-matchedText) r g b / 0.25);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -410,6 +410,10 @@
 | 
			
		||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-executeButtons #qr--modal-stop {
 | 
			
		||||
  border-color: #d78872;
 | 
			
		||||
}
 | 
			
		||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugButtons {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 1em;
 | 
			
		||||
}
 | 
			
		||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-executeProgress {
 | 
			
		||||
  --prog: 0;
 | 
			
		||||
  --progColor: #92befc;
 | 
			
		||||
@@ -469,6 +473,7 @@
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
  min-width: 100%;
 | 
			
		||||
  width: 0;
 | 
			
		||||
  white-space: pre-wrap;
 | 
			
		||||
}
 | 
			
		||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-executeResult.qr--hasResult {
 | 
			
		||||
  display: block;
 | 
			
		||||
@@ -476,6 +481,20 @@
 | 
			
		||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-executeResult:before {
 | 
			
		||||
  content: 'Result: ';
 | 
			
		||||
}
 | 
			
		||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState {
 | 
			
		||||
  display: none;
 | 
			
		||||
  text-align: left;
 | 
			
		||||
  font-size: smaller;
 | 
			
		||||
  color: white;
 | 
			
		||||
  padding: 0.5em;
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
  min-width: 100%;
 | 
			
		||||
  width: 0;
 | 
			
		||||
  white-space: pre-wrap;
 | 
			
		||||
}
 | 
			
		||||
.popup:has(#qr--modalEditor) .popup-content > #qr--modalEditor #qr--modal-debugState.qr--active {
 | 
			
		||||
  display: block;
 | 
			
		||||
}
 | 
			
		||||
@keyframes qr--progressPulse {
 | 
			
		||||
  0%,
 | 
			
		||||
  100% {
 | 
			
		||||
 
 | 
			
		||||
@@ -431,6 +431,10 @@
 | 
			
		||||
					border-color: rgb(215, 136, 114);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			#qr--modal-debugButtons {
 | 
			
		||||
				display: flex;
 | 
			
		||||
				gap: 1em;
 | 
			
		||||
			}
 | 
			
		||||
			#qr--modal-executeProgress {
 | 
			
		||||
				--prog: 0;
 | 
			
		||||
				--progColor: rgb(146, 190, 252);
 | 
			
		||||
@@ -494,6 +498,22 @@
 | 
			
		||||
				overflow: auto;
 | 
			
		||||
				min-width: 100%;
 | 
			
		||||
				width: 0;
 | 
			
		||||
				white-space: pre-wrap;
 | 
			
		||||
			}
 | 
			
		||||
			#qr--modal-debugState {
 | 
			
		||||
				display: none;
 | 
			
		||||
				&.qr--active {
 | 
			
		||||
					display: block;
 | 
			
		||||
				}
 | 
			
		||||
				text-align: left;
 | 
			
		||||
				font-size: smaller;
 | 
			
		||||
				// background-color: rgb(146, 190, 252);
 | 
			
		||||
				color: white;
 | 
			
		||||
				padding: 0.5em;
 | 
			
		||||
				overflow: auto;
 | 
			
		||||
				min-width: 100%;
 | 
			
		||||
				width: 0;
 | 
			
		||||
				white-space: pre-wrap;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user