add a little more details to execution exceptions
This commit is contained in:
parent
b1412d3bce
commit
91ffd141ef
|
@ -66,6 +66,7 @@ import { POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
|
|||
import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||
import { SlashCommandDebugController } from './slash-commands/SlashCommandDebugController.js';
|
||||
import { SlashCommandBreakController } from './slash-commands/SlashCommandBreakController.js';
|
||||
import { SlashCommandExecutionError } from './slash-commands/SlashCommandExecutionError.js';
|
||||
export {
|
||||
executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand,
|
||||
};
|
||||
|
@ -3405,7 +3406,23 @@ export async function executeSlashCommandsOnChatInput(text, options = {}) {
|
|||
result.isError = true;
|
||||
result.errorMessage = e.message || 'An unknown error occurred';
|
||||
if (e.cause !== 'abort') {
|
||||
toastr.error(result.errorMessage);
|
||||
if (e instanceof SlashCommandExecutionError) {
|
||||
/**@type {SlashCommandExecutionError}*/
|
||||
const ex = e;
|
||||
const toast = `
|
||||
<div>${ex.message}</div>
|
||||
<div>Line: ${ex.line} Column: ${ex.column}</div>
|
||||
<pre style="text-align:left;">${ex.hint}</pre>
|
||||
`;
|
||||
const clickHint = '<p>Click to see details</p>';
|
||||
toastr.error(
|
||||
`${toast}${clickHint}`,
|
||||
'SlashCommandExecutionError',
|
||||
{ escapeHtml: false, timeOut: 10000, onclick: () => callPopup(toast, 'text') },
|
||||
);
|
||||
} else {
|
||||
toastr.error(result.errorMessage);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
delay(1000).then(() => clearCommandProgressDebounced());
|
||||
|
@ -3474,7 +3491,23 @@ async function executeSlashCommandsWithOptions(text, options = {}) {
|
|||
return result;
|
||||
} catch (e) {
|
||||
if (options.handleExecutionErrors) {
|
||||
toastr.error(e.message);
|
||||
if (e instanceof SlashCommandExecutionError) {
|
||||
/**@type {SlashCommandExecutionError}*/
|
||||
const ex = e;
|
||||
const toast = `
|
||||
<div>${ex.message}</div>
|
||||
<div>Line: ${ex.line} Column: ${ex.column}</div>
|
||||
<pre style="text-align:left;">${ex.hint}</pre>
|
||||
`;
|
||||
const clickHint = '<p>Click to see details</p>';
|
||||
toastr.error(
|
||||
`${toast}${clickHint}`,
|
||||
'SlashCommandExecutionError',
|
||||
{ escapeHtml: false, timeOut: 10000, onclick: () => callPopup(toast, 'text') },
|
||||
);
|
||||
} else {
|
||||
toastr.error(e.message);
|
||||
}
|
||||
const result = new SlashCommandClosureResult();
|
||||
result.isError = true;
|
||||
result.errorMessage = e.message;
|
||||
|
|
|
@ -7,6 +7,7 @@ import { SlashCommandBreakController } from './SlashCommandBreakController.js';
|
|||
import { SlashCommandBreakPoint } from './SlashCommandBreakPoint.js';
|
||||
import { SlashCommandClosureResult } from './SlashCommandClosureResult.js';
|
||||
import { SlashCommandDebugController } from './SlashCommandDebugController.js';
|
||||
import { SlashCommandExecutionError } from './SlashCommandExecutionError.js';
|
||||
import { SlashCommandExecutor } from './SlashCommandExecutor.js';
|
||||
import { SlashCommandNamedArgumentAssignment } from './SlashCommandNamedArgumentAssignment.js';
|
||||
import { SlashCommandScope } from './SlashCommandScope.js';
|
||||
|
@ -370,7 +371,11 @@ export class SlashCommandClosure {
|
|||
if (this.debugController) {
|
||||
this.debugController.isStepping = false || this.debugController.isSteppingInto;
|
||||
}
|
||||
this.scope.pipe = await executor.command.callback(args, value ?? '');
|
||||
try {
|
||||
this.scope.pipe = await executor.command.callback(args, value ?? '');
|
||||
} catch (ex) {
|
||||
throw new SlashCommandExecutionError(ex, ex.message, executor.name, executor.start, executor.end, this.fullText.slice(executor.start, executor.end), this.fullText);
|
||||
}
|
||||
if (this.debugController) {
|
||||
this.debugController.namedArguments = undefined;
|
||||
this.debugController.unnamedArguments = undefined;
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
export class SlashCommandExecutionError extends Error {
|
||||
/**@type {string} */ commandName;
|
||||
/**@type {number} */ start;
|
||||
/**@type {number} */ end;
|
||||
/**@type {string} */ commandText;
|
||||
|
||||
/**@type {string} */ text;
|
||||
get index() { return this.start; }
|
||||
|
||||
get line() {
|
||||
return this.text.slice(0, this.index).replace(/[^\n]/g, '').length;
|
||||
}
|
||||
get column() {
|
||||
return this.text.slice(0, this.index).split('\n').pop().length;
|
||||
}
|
||||
get hint() {
|
||||
let lineOffset = this.line.toString().length;
|
||||
let lineStart = this.index;
|
||||
let start = this.index;
|
||||
let end = this.index;
|
||||
let offset = 0;
|
||||
let lineCount = 0;
|
||||
while (offset < 10000 && lineCount < 3 && start >= 0) {
|
||||
if (this.text[start] == '\n') lineCount++;
|
||||
if (lineCount == 0) lineStart--;
|
||||
offset++;
|
||||
start--;
|
||||
}
|
||||
if (this.text[start + 1] == '\n') start++;
|
||||
offset = 0;
|
||||
while (offset < 10000 && this.text[end] != '\n') {
|
||||
offset++;
|
||||
end++;
|
||||
}
|
||||
let hint = [];
|
||||
let lines = this.text.slice(start + 1, end - 1).split('\n');
|
||||
let lineNum = this.line - lines.length + 1;
|
||||
let tabOffset = 0;
|
||||
for (const line of lines) {
|
||||
const num = `${' '.repeat(lineOffset - lineNum.toString().length)}${lineNum}`;
|
||||
lineNum++;
|
||||
const untabbedLine = line.replace(/\t/g, ' '.repeat(4));
|
||||
tabOffset = untabbedLine.length - line.length;
|
||||
hint.push(`${num}: ${untabbedLine}`);
|
||||
}
|
||||
hint.push(`${' '.repeat(this.index - lineStart + lineOffset + 1 + tabOffset)}^^^^^`);
|
||||
return hint.join('\n');
|
||||
}
|
||||
|
||||
|
||||
|
||||
constructor(cause, message, commandName, start, end, commandText, fullText) {
|
||||
super(message, { cause });
|
||||
this.commandName = commandName;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.commandText = commandText;
|
||||
this.text = fullText;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue