diff --git a/src/lang/KclSingleton.tsx b/src/lang/KclSingleton.tsx index 8fca3fff2..f00cd7849 100644 --- a/src/lang/KclSingleton.tsx +++ b/src/lang/KclSingleton.tsx @@ -228,7 +228,17 @@ class KclManager { } } - async executeAst(ast: Program = this._ast, updateCode = false) { + private _cancelTokens: Map = new Map() + + async executeAst( + ast: Program = this._ast, + updateCode = false, + executionId?: number + ) { + console.trace('executeAst') + const currentExecutionId = executionId || Date.now() + this._cancelTokens.set(currentExecutionId, false) + await this.ensureWasmInit() this.isExecuting = true const { logs, errors, programMemory } = await executeAst({ @@ -236,6 +246,11 @@ class KclManager { engineCommandManager: this.engineCommandManager, }) this.isExecuting = false + // Check the cancellation token for this execution before applying side effects + if (this._cancelTokens.get(currentExecutionId)) { + this._cancelTokens.delete(currentExecutionId) + return + } this.logs = logs this.kclErrors = errors this.programMemory = programMemory @@ -248,6 +263,7 @@ class KclManager { type: 'execution-done', data: null, }) + this._cancelTokens.delete(currentExecutionId) } async executeAstMock( ast: Program = this._ast, @@ -295,7 +311,13 @@ class KclManager { } ) } - async executeCode(code?: string) { + async executeCode(code?: string, executionId?: number) { + const currentExecutionId = executionId || Date.now() + this._cancelTokens.set(currentExecutionId, false) + if (this._cancelTokens.get(currentExecutionId)) { + this._cancelTokens.delete(currentExecutionId) + return + } await this.ensureWasmInit() await this?.engineCommandManager?.waitForReady const result = await executeCode({ @@ -304,6 +326,11 @@ class KclManager { lastAst: this._ast, force: false, }) + // Check the cancellation token for this execution before applying side effects + if (this._cancelTokens.get(currentExecutionId)) { + this._cancelTokens.delete(currentExecutionId) + return + } if (!result.isChange) return const { logs, errors, programMemory, ast } = result this.logs = logs @@ -311,6 +338,12 @@ class KclManager { this.programMemory = programMemory this.ast = ast if (code) this.code = code + this._cancelTokens.delete(currentExecutionId) + } + cancelAllExecutions() { + this._cancelTokens.forEach((_, key) => { + this._cancelTokens.set(key, true) + }) } setCode(code: string, shouldWriteFile = true) { if (shouldWriteFile) { diff --git a/src/routes/Home.tsx b/src/routes/Home.tsx index 5190f6088..ca5f1c8e8 100644 --- a/src/routes/Home.tsx +++ b/src/routes/Home.tsx @@ -36,6 +36,7 @@ import { sep } from '@tauri-apps/api/path' import { homeCommandBarConfig } from 'lib/commandBarConfigs/homeCommandConfig' import { useHotkeys } from 'react-hotkeys-hook' import { isTauri } from 'lib/isTauri' +import { kclManager } from 'lang/KclSingleton' // This route only opens in the Tauri desktop context for now, // as defined in Router.tsx, so we can use the Tauri APIs and types. @@ -55,6 +56,7 @@ const Home = () => { // during the loading of the home page. This is wrapped // in a single-use effect to avoid a potential infinite loop. useEffect(() => { + kclManager.cancelAllExecutions() if (newDefaultDirectory) { sendToSettings({ type: 'Set Default Directory',