separate abort logic for commands

This commit is contained in:
LenAnderson
2024-04-30 09:12:21 -04:00
parent 0ce37981bf
commit f63f4ef304
12 changed files with 450 additions and 85 deletions

View File

@@ -190,7 +190,7 @@ const init = async () => {
}
}
if (qr && qr.onExecute) {
return await qr.execute(args);
return await qr.execute(args, false, true);
} else {
throw new Error(`No Quick Reply found for "${name}".`);
}

View File

@@ -1,5 +1,6 @@
import { POPUP_TYPE, Popup } from '../../../popup.js';
import { setSlashCommandAutoComplete } from '../../../slash-commands.js';
import { SlashCommandParserError } from '../../../slash-commands/SlashCommandParserError.js';
import { SlashCommandScope } from '../../../slash-commands/SlashCommandScope.js';
import { getSortableDelay } from '../../../utils.js';
import { log, warn } from '../index.js';
@@ -452,10 +453,23 @@ export class QuickReply {
this.editorPopup.dom.classList.add('qr--hide');
}
try {
this.editorExecutePromise = this.execute();
this.editorExecutePromise = this.execute({}, true);
await this.editorExecutePromise;
this.editorExecuteErrors.classList.remove('qr--hasErrors');
this.editorExecuteErrors.innerHTML = '';
} catch (ex) {
this.editorExecuteErrors.textContent = ex.message;
this.editorExecuteErrors.classList.add('qr--hasErrors');
if (ex instanceof SlashCommandParserError) {
this.editorExecuteErrors.innerHTML = `
<div>${ex.message}</div>
<div>Line: ${ex.line} Column: ${ex.column}</div>
<pre style="text-align:left;">${ex.hint}</pre>
`;
} else {
this.editorExecuteErrors.innerHTML = `
<div>${ex.message}</div>
`;
}
}
this.editorExecutePromise = null;
this.editorExecuteBtn.classList.remove('qr--busy');
@@ -537,13 +551,19 @@ export class QuickReply {
}
async execute(args = {}) {
async execute(args = {}, isEditor = false, isRun = false) {
if (this.message?.length > 0 && this.onExecute) {
const scope = new SlashCommandScope();
for (const key of Object.keys(args)) {
scope.setMacro(`arg::${key}`, args[key]);
}
return await this.onExecute(this, this.message, args.isAutoExecute ?? false, scope);
return await this.onExecute(this, {
message:this.message,
isAutoExecute: args.isAutoExecute ?? false,
isEditor,
isRun,
scope,
});
}
}

View File

@@ -1,5 +1,5 @@
import { getRequestHeaders, substituteParams } from '../../../../script.js';
import { executeSlashCommands } from '../../../slash-commands.js';
import { executeSlashCommands, executeSlashCommandsOnChatInput, executeSlashCommandsWithOptions } from '../../../slash-commands.js';
import { SlashCommandScope } from '../../../slash-commands/SlashCommandScope.js';
import { debounceAsync, warn } from '../index.js';
import { QuickReply } from './QuickReply.js';
@@ -101,16 +101,29 @@ export class QuickReplySet {
/**
* @param {QuickReply} qr
* @param {String} [message] - optional altered message to be used
* @param {SlashCommandScope} [scope] - optional scope to be used when running the command
*
* @param {QuickReply} qr The QR to execute.
* @param {object} options
* @param {string} [options.message] (null) altered message to be used
* @param {boolean} [options.isAutoExecute] (false) whether the execution is triggered by auto execute
* @param {boolean} [options.isEditor] (false) whether the execution is triggered by the QR editor
* @param {boolean} [options.isRun] (false) whether the execution is triggered by /run or /: (window.executeQuickReplyByName)
* @param {SlashCommandScope} [options.scope] (null) scope to be used when running the command
* @returns
*/
async execute(qr, message = null, isAutoExecute = false, scope = null) {
async executeWithOptions(qr, options = {}) {
options = Object.assign({
message:null,
isAutoExecute:false,
isEditor:false,
isRun:false,
scope:null,
}, options);
/**@type {HTMLTextAreaElement}*/
const ta = document.querySelector('#send_textarea');
const finalMessage = message ?? qr.message;
const finalMessage = options.message ?? qr.message;
let input = ta.value;
if (!isAutoExecute && this.injectInput && input.length > 0) {
if (!options.isAutoExecute && !options.isEditor && !options.isRun && this.injectInput && input.length > 0) {
if (this.placeBeforeInput) {
input = `${finalMessage} ${input}`;
} else {
@@ -121,7 +134,22 @@ export class QuickReplySet {
}
if (input[0] == '/' && !this.disableSend) {
const result = await executeSlashCommands(input, true, scope);
let result;
if (options.isAutoExecute || options.isRun) {
result = await executeSlashCommandsWithOptions(input, {
handleParserErrors: true,
scope: options.scope,
});
} else if (options.isEditor) {
result = await executeSlashCommandsWithOptions(input, {
handleParserErrors: false,
scope: options.scope,
});
} else {
result = await executeSlashCommandsOnChatInput(input, {
scope: options.scope,
});
}
return typeof result === 'object' ? result?.pipe : '';
}
@@ -133,6 +161,18 @@ export class QuickReplySet {
document.querySelector('#send_but').click();
}
}
/**
* @param {QuickReply} qr
* @param {String} [message] - optional altered message to be used
* @param {SlashCommandScope} [scope] - optional scope to be used when running the command
*/
async execute(qr, message = null, isAutoExecute = false, scope = null) {
return this.executeWithOptions(qr, {
message,
isAutoExecute,
scope,
});
}
@@ -154,7 +194,7 @@ export class QuickReplySet {
}
hookQuickReply(qr) {
qr.onExecute = (_, message, isAutoExecute)=>this.execute(qr, message, isAutoExecute);
qr.onExecute = (_, options)=>this.executeWithOptions(qr, options);
qr.onDelete = ()=>this.removeQuickReply(qr);
qr.onUpdate = ()=>this.save();
}

View File

@@ -295,6 +295,20 @@
opacity: 0.5;
cursor: wait;
}
.dialogue_popup:has(#qr--modalEditor) .dialogue_popup_text > #qr--modalEditor #qr--modal-executeErrors {
display: none;
text-align: left;
font-size: smaller;
background-color: #bd362f;
color: white;
padding: 0.5em;
overflow: auto;
min-width: 100%;
width: 0;
}
.dialogue_popup:has(#qr--modalEditor) .dialogue_popup_text > #qr--modalEditor #qr--modal-executeErrors.qr--hasErrors {
display: block;
}
.shadow_popup.qr--hide {
opacity: 0 !important;
}

View File

@@ -322,6 +322,20 @@
cursor: wait;
}
}
#qr--modal-executeErrors {
display: none;
&.qr--hasErrors {
display: block;
}
text-align: left;
font-size: smaller;
background-color: rgb(189, 54, 47);
color: white;
padding: 0.5em;
overflow: auto;
min-width: 100%;
width: 0;
}
}
}
}