diff --git a/src/ScriptEditor/ui/Options.ts b/src/ScriptEditor/ui/Options.ts
index d7e43b83d..bab7d3917 100644
--- a/src/ScriptEditor/ui/Options.ts
+++ b/src/ScriptEditor/ui/Options.ts
@@ -16,4 +16,5 @@ export interface Options {
wordWrap: WordWrapOptions;
cursorStyle: CursorStyle;
cursorBlinking: CursorBlinking;
+ beautifyOnSave: boolean;
}
diff --git a/src/ScriptEditor/ui/OptionsModal.tsx b/src/ScriptEditor/ui/OptionsModal.tsx
index 27db47897..cc48253b6 100644
--- a/src/ScriptEditor/ui/OptionsModal.tsx
+++ b/src/ScriptEditor/ui/OptionsModal.tsx
@@ -142,6 +142,14 @@ export function OptionsModal(props: OptionsModalProps): ReactElement {
))}
+
+
+ Run Beautify on Save:
+ props.onOptionChange("beautifyOnSave", e.target.checked)}
+ checked={props.options.beautifyOnSave}
+ />
+
);
}
diff --git a/src/ScriptEditor/ui/ScriptEditorContext.tsx b/src/ScriptEditor/ui/ScriptEditorContext.tsx
index 92a290e5d..cc4c0f92a 100644
--- a/src/ScriptEditor/ui/ScriptEditorContext.tsx
+++ b/src/ScriptEditor/ui/ScriptEditorContext.tsx
@@ -91,6 +91,7 @@ export function ScriptEditorContextProvider({ children }: { children: React.Reac
wordWrap: Settings.MonacoWordWrap,
cursorStyle: Settings.MonacoCursorStyle,
cursorBlinking: Settings.MonacoCursorBlinking,
+ beautifyOnSave: Settings.MonacoBeautifyOnSave,
});
function saveOptions(options: Options) {
@@ -105,6 +106,7 @@ export function ScriptEditorContextProvider({ children }: { children: React.Reac
Settings.MonacoCursorStyle = options.cursorStyle;
Settings.MonacoCursorBlinking = options.cursorBlinking;
Settings.MonacoWordWrap = options.wordWrap;
+ Settings.MonacoBeautifyOnSave = options.beautifyOnSave;
}
return (
diff --git a/src/ScriptEditor/ui/ScriptEditorRoot.tsx b/src/ScriptEditor/ui/ScriptEditorRoot.tsx
index 18a59a348..9c6560443 100644
--- a/src/ScriptEditor/ui/ScriptEditorRoot.tsx
+++ b/src/ScriptEditor/ui/ScriptEditorRoot.tsx
@@ -176,15 +176,26 @@ function Root(props: IProps): React.ReactElement {
reloadModelOfCurrentScript();
}
- const { showRAMError, updateRAM, startUpdatingRAM, finishUpdatingRAM } = useScriptEditorContext();
+ const { options, showRAMError, updateRAM, startUpdatingRAM, finishUpdatingRAM } = useScriptEditorContext();
let decorations: monaco.editor.IEditorDecorationsCollection | undefined;
- const save = useCallback(() => {
+ const beautify = useCallback(async (): Promise => {
+ const action = editorRef.current?.getAction("editor.action.formatDocument");
+ if (action == null) {
+ return;
+ }
+ return action.run().catch((error) => console.error(error));
+ }, []);
+
+ const save = useCallback(async () => {
if (currentScript === null) {
console.error("currentScript is null when it shouldn't be. Unable to save script");
return;
}
+
+ const preSave = options.beautifyOnSave ? beautify : () => Promise.resolve();
+
// this is duplicate code with saving later.
if (ITutorial.isRunning && ITutorial.currStep === iTutorialSteps.TerminalEditScript) {
//Make sure filename + code properly follow tutorial
@@ -200,6 +211,7 @@ function Root(props: IProps): React.ReactElement {
}
//Save the script
+ await preSave();
saveScript(currentScript);
Router.toPage(Page.Terminal);
@@ -207,11 +219,12 @@ function Root(props: IProps): React.ReactElement {
return;
}
+ await preSave();
saveScript(currentScript);
rerender();
- }, [rerender]);
+ }, [rerender, options.beautifyOnSave, beautify]);
- const run = useCallback(() => {
+ const run = useCallback(async () => {
if (currentScript === null) {
return;
}
@@ -227,7 +240,7 @@ function Root(props: IProps): React.ReactElement {
}
// Always save before doing anything else.
- save();
+ await save();
const result = createRunningScriptInstance(server, currentScript.path, null, 1, []);
if (!result.success) {
@@ -238,7 +251,7 @@ function Root(props: IProps): React.ReactElement {
}, [save]);
useEffect(() => {
- function keydown(event: KeyboardEvent): void {
+ async function keydown(event: KeyboardEvent) {
if (Settings.DisableHotkeys) {
return;
}
@@ -246,7 +259,7 @@ function Root(props: IProps): React.ReactElement {
if (keyBindingTypes.has(ScriptEditorAction.Save)) {
event.preventDefault();
event.stopPropagation();
- save();
+ await save();
}
if (keyBindingTypes.has(ScriptEditorAction.GoToTerminal)) {
event.preventDefault();
@@ -254,11 +267,14 @@ function Root(props: IProps): React.ReactElement {
}
if (keyBindingTypes.has(ScriptEditorAction.Run)) {
event.preventDefault();
- run();
+ await run();
}
}
- document.addEventListener("keydown", keydown);
- return () => document.removeEventListener("keydown", keydown);
+ const listener = (event: KeyboardEvent) => {
+ keydown(event).catch((error) => console.error(error));
+ };
+ document.addEventListener("keydown", listener);
+ return () => document.removeEventListener("keydown", listener);
}, [save, run]);
function infLoop(ast: AST, code: string): void {
@@ -598,7 +614,7 @@ function Root(props: IProps): React.ReactElement {
{statusBarRef.current}
-
+
{!currentScript && }
>
diff --git a/src/ScriptEditor/ui/Toolbar.tsx b/src/ScriptEditor/ui/Toolbar.tsx
index 36a49e95f..bc7dac49c 100644
--- a/src/ScriptEditor/ui/Toolbar.tsx
+++ b/src/ScriptEditor/ui/Toolbar.tsx
@@ -31,21 +31,15 @@ type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor;
interface IProps {
editor: IStandaloneCodeEditor | null;
- onSave: () => void;
- onRun: () => void;
+ onSave: () => Promise;
+ onRun: () => Promise;
+ onBeautify: () => Promise;
}
-export function Toolbar({ editor, onSave, onRun }: IProps) {
+export function Toolbar({ editor, onSave, onRun, onBeautify }: IProps) {
const [ramInfoOpen, { on: openRAMInfo, off: closeRAMInfo }] = useBoolean(false);
const [optionsOpen, { on: openOptions, off: closeOptions }] = useBoolean(false);
- function beautify(): void {
- editor
- ?.getAction("editor.action.formatDocument")
- ?.run()
- .catch((error) => console.error(error));
- }
-
const { ram, ramEntries, isUpdatingRAM, options, saveOptions } = useScriptEditorContext();
const onOptionChange: OptionsModalProps["onOptionChange"] = (option, value) => {
@@ -68,12 +62,24 @@ export function Toolbar({ editor, onSave, onRun }: IProps) {
} onClick={openOptions} sx={{ mr: 1 }}>
Options
-
+
-
+
-
diff --git a/src/ScriptEditor/ui/useVimEditor.tsx b/src/ScriptEditor/ui/useVimEditor.tsx
index 27f8d4303..0df27d21e 100644
--- a/src/ScriptEditor/ui/useVimEditor.tsx
+++ b/src/ScriptEditor/ui/useVimEditor.tsx
@@ -13,7 +13,7 @@ interface IProps {
editor: IStandaloneCodeEditor | null;
onOpenNextTab: (step: number) => void;
onOpenPreviousTab: (step: number) => void;
- onSave: () => void;
+ onSave: () => Promise;
}
export function useVimEditor({ editor, vim, onOpenNextTab, onOpenPreviousTab, onSave }: IProps) {
@@ -32,7 +32,7 @@ export function useVimEditor({ editor, vim, onOpenNextTab, onOpenPreviousTab, on
setVimEditor(MonacoVim.initVimMode(editor, statusBarRef, StatusBar, rerender));
MonacoVim.VimMode.Vim.defineEx("write", "w", function () {
// your own implementation on what you want to do when :w is pressed
- actionsRef.current.save();
+ actionsRef.current.save().catch((error) => console.error(error));
});
MonacoVim.VimMode.Vim.defineEx("quit", "q", function () {
Router.toPage(Page.Terminal);
@@ -43,8 +43,12 @@ export function useVimEditor({ editor, vim, onOpenNextTab, onOpenPreviousTab, on
MonacoVim.VimMode.Vim.mapCommand("@", "", "", null, { context: "normal" });
const saveNQuit = (): void => {
- actionsRef.current.save();
- Router.toPage(Page.Terminal);
+ actionsRef.current
+ .save()
+ .then(() => {
+ Router.toPage(Page.Terminal);
+ })
+ .catch((error) => console.error(error));
};
// "wqriteandquit" & "xriteandquit" are not typos, prefix must be found in full string
MonacoVim.VimMode.Vim.defineEx("wqriteandquit", "wq", saveNQuit);
diff --git a/src/Settings/Settings.ts b/src/Settings/Settings.ts
index 8f1cd4924..e76a68e6b 100644
--- a/src/Settings/Settings.ts
+++ b/src/Settings/Settings.ts
@@ -176,6 +176,8 @@ export const Settings = {
MonacoDefaultToVim: false,
/** Word wrap setting for Script Editor. */
MonacoWordWrap: "off" as WordWrapOptions,
+ /** Whether to run Beautify code formatter on save */
+ MonacoBeautifyOnSave: false,
/** Control the cursor style*/
MonacoCursorStyle: "line" as CursorStyle,
/** Control the cursor animation style */