From 1846bd5ce59ee71a4262297513673d662f6a38b6 Mon Sep 17 00:00:00 2001 From: Ruben Fiszel Date: Thu, 6 Aug 2026 09:59:19 +0200 Subject: [PATCH] fix(frontend): take the editor's post-edit content, not setCode's argument (#10562) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #10560 changed the script editor's change handler to read `e.detail` instead of `editorCode`, on the reasoning that the two only diverge while the editor is being torn down. They also diverge in a live editor: `setCode` dispatches the string it was handed, but `alignCodeWithEditor` applies that string to Monaco first, and the resulting `onDidChangeModelContent` runs `updateCode` re-entrantly — so if the model normalized the text (EOL is the reachable case; `ScriptBuilder` builds template content with a `\r\n` join), `editorCode` already holds the buffer's version and the payload is the pre-normalization one. Taking the payload leaves `code` disagreeing with what the editor shows, which the external-write effect then tries to reconcile on every change. The language-switch fix in that PR is `alignCodeWithEditor` clearing the timer its own write armed; that part stands and is unaffected. This restores the handler to the buffer-true read. Co-authored-by: Claude Opus 5 (1M context) --- frontend/src/lib/components/ScriptEditor.svelte | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/frontend/src/lib/components/ScriptEditor.svelte b/frontend/src/lib/components/ScriptEditor.svelte index 8110805179..4b2a2927ac 100644 --- a/frontend/src/lib/components/ScriptEditor.svelte +++ b/frontend/src/lib/components/ScriptEditor.svelte @@ -2762,11 +2762,12 @@ awareness={wsProvider?.awareness} on:change={(e) => { if (activeModuleTab === null) { - // The payload, not `editorCode`: the editor also fires this while it is - // being torn down (the unmount flush), and a destroyed component's - // `bind:` writes no longer reach us — re-reading would take the value - // from before the change and write it back over `code`. - code = e.detail + // `editorCode`, not the payload: `setCode` dispatches the string it was + // handed, but Monaco may have normalized it (EOL) while applying it, and + // the re-entrant `updateCode` that runs inside `setCode` has already put + // that normalized text here. Taking the payload would leave `code` + // disagreeing with the buffer. + code = editorCode lastSyncedCode = code inferSchema(e.detail) } else {