Improve error handling on script changing

This commit is contained in:
SpectralFlame 2022-07-31 05:29:48 -05:00 committed by cyip92
parent 7789b72834
commit fc82b60170
10 changed files with 58 additions and 28 deletions

View File

@ -293,14 +293,14 @@ export const AutomatorHighlighter = {
},
clearAllHighlightedLines() {
if (player.reality.automator.type === AUTOMATOR_TYPE.TEXT && AutomatorTextUI.editor) {
for (const lineType of Object.values(LineEnum)) {
for (const lineType of Object.values(LineEnum)) {
if (player.reality.automator.type === AUTOMATOR_TYPE.TEXT && AutomatorTextUI.editor) {
for (let line = 0; line < AutomatorTextUI.editor.doc.size; line++) {
AutomatorTextUI.editor.removeLineClass(line, "background", `c-automator-editor__${lineType}-line`);
AutomatorTextUI.editor.removeLineClass(line, "gutter", `c-automator-editor__${lineType}-line-gutter`);
}
this.lines[lineType] = -1;
}
this.lines[lineType] = -1;
}
}
};

View File

@ -9010,7 +9010,7 @@ kbd {
display: flex;
height: 2.85rem;
align-items: center;
margin: 0.3rem 0;
padding: 1.73rem 0;
}
.c-automator-block-row > * {

View File

@ -20,6 +20,7 @@ export default {
},
data() {
return {
errorCount: 0,
isCurrentlyBlocks: false
};
},
@ -32,9 +33,13 @@ export default {
this.$viewModel.tabs.reality.automator.editorScriptID = value;
}
},
otherMode() {
return this.isCurrentlyBlocks ? "Text" : "Block";
}
},
methods: {
update() {
this.errorCount = AutomatorData.currentErrors().length;
this.isCurrentlyBlocks = player.reality.automator.type === AUTOMATOR_TYPE.BLOCK;
},
toggleAutomatorMode() {
@ -51,25 +56,39 @@ export default {
@confirm="toggleAutomatorMode"
>
<template #header>
Change Automator to {{ isCurrentlyBlocks ? "text" : "block" }} editor
Change Automator to {{ otherMode }} editor
</template>
<div class="c-modal-message__text">
This will stop your current script if it is running!
<div v-if="lostBlocks">
Additionally, your script currently has some lines which cannot interpreted as particular commands. Switching
to the block editor will cause these lines to be automatically deleted, since blocks only exist for valid
commands.
<b>
Warning: If these errors are caused by malformed loops or IFs, this may end up deleting large portions of
your script! Changing editor modes currently will cause {{ quantifyInt("line", lostBlocks) }} of code to be
lost!
</b>
<div v-if="errorCount">
<br>
Your script has some errors which may not get converted properly to {{ otherMode }} mode. Continuing on will
make the Automator attempt to parse these lines anyway, although some information may get lost or not be
converted properly.
</div>
<!-- Note: this can only ever appear on text-to-block -->
<b v-if="lostBlocks">
<br>
Warning: Your script also currently has some lines which cannot interpreted as particular commands. These
lines will end up being deleted since there is no block they can be converted into.
If an error occurs at the start of a loop or IF, this may end up deleting large portions of your script!
<span class="l-lost-text">
Changing editor modes right now will cause {{ quantifyInt("line", lostBlocks) }} of code to be irreversibly
lost!
</span>
</b>
<br>
Are you sure you want to change to the {{ isCurrentlyBlocks ? "text" : "block" }} editor?
<br>
Are you sure you want to change to the {{ otherMode }} editor?
</div>
<template #confirm-text>
Change Modes
</template>
</ModalWrapperChoice>
</template>
<style scoped>
.l-lost-text {
color: var(--color-bad);
}
</style>

View File

@ -96,6 +96,7 @@ export const BlockAutomator = {
parseTextFromBlocks() {
const content = this.parseLines(BlockAutomator.lines).join("\n");
const automatorID = ui.view.tabs.reality.automator.editorScriptID;
AutomatorData.recalculateErrors();
AutomatorBackend.saveScript(automatorID, content);
},

View File

@ -126,8 +126,10 @@ export default {
this.textContents = this.initialSelection;
}
// This forces errors to show up immediately when the block is created instead of requiring user interaction
// This forces errors to show up immediately when the block is created instead of requiring user interaction, but
// we also want to hide tooltips because this causes poor UI if there are a lot of nearby errors upon conversion
this.recalculateErrorCount();
this.suppressTooltip = true;
},
// Destroying single inputs need to be handled carefully because there are three situations under which they will
// be removed, and they all require different behavior:
@ -237,11 +239,11 @@ export default {
// This gets called whenever blocks are changed, but we also need to halt execution if the currently visible script
// is also the one being run
recalculateErrorCount() {
BlockAutomator.parseTextFromBlocks();
this.validateInput();
if (AutomatorBackend.currentEditingScript.id === AutomatorBackend.currentRunningScript.id) {
AutomatorBackend.stop();
}
BlockAutomator.parseTextFromBlocks();
},
errorTooltip() {
if (!this.hasError || this.suppressTooltip) return undefined;
@ -276,6 +278,7 @@ export default {
"o-automator-block-input": true,
"c-automator-input-required": !this.isBoolTarget,
"c-automator-input-optional": this.isBoolTarget,
"l-error-textbox": this.hasError && !this.isBoolTarget && this.dropdownSelection === "",
};
},
revertToDropdown() {

View File

@ -198,8 +198,9 @@ export const automatorBlocksMap = automatorBlocks.mapToObject(b => b.cmd, b => b
<br>
<p>
Inputs with a <span class="c-automator-input-optional">brown</span> color are optional, while inputs with a
<span class="c-automator-input-required">teal</span> color are required. For more details, check the Scripting
Information pane.
<span class="c-automator-input-required">teal</span> color are required.
<span class="c-automator-block-row-error">Red</span> inputs are causing errors and must be changed before the
script can be run. For more details, check the Scripting Information pane.
</p>
<p>
Options in dropdown menus which start with a * will be replaced with a text box. This can be turned back into a

View File

@ -165,11 +165,14 @@ export default {
// have block-parsable commands. It additionally also gets checked on new script creation, where we need to
// suppress the error modal instead
if (this.isBlock && BlockAutomator.hasUnparsableCommands(this.currentScript) && this.currentScript !== "") {
player.reality.automator.type = AUTOMATOR_TYPE.TEXT;
AutomatorBackend.changeModes(this.currentScriptID);
Modal.message.show("Some script commands were unrecognizable - defaulting to text editor.");
}
this.$nextTick(() => BlockAutomator.fromText(this.currentScript));
this.$nextTick(() => {
BlockAutomator.fromText(this.currentScript);
if (!this.isBlock) AutomatorTextUI.editor.performLint();
});
},
rename() {
this.editingName = true;
@ -194,6 +197,7 @@ export default {
const menu = event.target;
if (menu.selectedIndex === menu.length - 1 && this.canMakeNewScript) this.createNewScript();
else player.reality.automator.state.editorScript = this.scripts[menu.selectedIndex].id;
AutomatorHighlighter.clearAllHighlightedLines();
this.updateCurrentScriptID();
},
nameEdited() {

View File

@ -64,7 +64,7 @@ export default {
if (BlockAutomator.hasUnparsableCommands(this.currentScript) &&
player.reality.automator.type === AUTOMATOR_TYPE.BLOCK) {
Modal.message.show(`Some script commands were unrecognizable - defaulting to text editor.`);
player.reality.automator.type = AUTOMATOR_TYPE.TEXT;
AutomatorBackend.changeModes(this.currentScriptID);
}
this.$nextTick(() => BlockAutomator.fromText(this.currentScript));
},

View File

@ -44,8 +44,10 @@ export default {
</div>
</span>
<i>
Note: Sometimes errors may cause the automator to be unable to scan the rest of the script.
This may result in some errors "disappearing" due to other errors occurring in earlier lines.
Note: Sometimes errors may cause the automator to be unable to scan the rest of the script properly.
This may result in some errors "disappearing" due to other errors occurring in earlier lines, or
errors in a command which has an inner block (eg. commands like IF or WHILE) causing errors to appear
on correctly-formatted later commands.
Additionally, some of the suggested fixes may be potentially misleading due to the cause of
the error being unclear.
</i>

View File

@ -57,18 +57,18 @@ export default {
if (BlockAutomator.hasUnparsableCommands(this.currentScript) &&
player.reality.automator.type === AUTOMATOR_TYPE.BLOCK) {
Modal.message.show(`Some script commands were unrecognizable - defaulting to text editor.`);
player.reality.automator.type = AUTOMATOR_TYPE.TEXT;
AutomatorBackend.changeModes(this.currentScriptID);
}
this.$nextTick(() => BlockAutomator.fromText(this.currentScript));
},
toggleAutomatorMode() {
const currScript = player.reality.automator.scripts[this.currentScriptID].content;
const hasInvalidCommands = BlockAutomator.hasUnparsableCommands(currScript) &&
this.automatorType === AUTOMATOR_TYPE.TEXT;
const hasTextErrors = this.automatorType === AUTOMATOR_TYPE.TEXT &&
(BlockAutomator.hasUnparsableCommands(currScript) || AutomatorData.currentErrors().length !== 0);
// While we normally have the player option override the modal, script deletion due to failed parsing can have a
// big enough adverse impact on the gameplay experience that we force the modal here regardless of the setting
if (hasInvalidCommands || (player.options.confirmations.switchAutomatorMode && AutomatorBackend.isRunning)) {
if (hasTextErrors || (player.options.confirmations.switchAutomatorMode && AutomatorBackend.isRunning)) {
const blockified = AutomatorGrammar.blockifyTextAutomator(currScript);
// We explicitly pass in 0 for lostBlocks if converting from block to text since nothing is ever lost in that