From 67f9bc70c60b3c9653b046a77c30c9e49f21f145 Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Sun, 29 Mar 2026 01:46:07 -0300 Subject: [PATCH] feat: auto-compile when pressing Play if code changed or no hex loaded Closes #81 - Add `codeChangedSinceLastCompile` dirty flag to useEditorStore - Play button now triggers compilation automatically when no compiled program exists or code has changed since last compile - Show compilation progress during auto-compile before run - If compilation fails, show errors instead of running stale code - Keep separate Compile button for manual compile-only workflow - Play button always enabled (disabled only while running/compiling) Co-Authored-By: Claude Opus 4.6 --- .../src/components/editor/EditorToolbar.tsx | 57 ++++++++++++++++--- frontend/src/store/useEditorStore.ts | 8 +++ 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/editor/EditorToolbar.tsx b/frontend/src/components/editor/EditorToolbar.tsx index 07cbb6a..6d43dbd 100644 --- a/frontend/src/components/editor/EditorToolbar.tsx +++ b/frontend/src/components/editor/EditorToolbar.tsx @@ -44,7 +44,7 @@ const BOARD_PILL_COLOR: Record = { }; export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compileLogs, setCompileLogs }: EditorToolbarProps) => { - const { files } = useEditorStore(); + const { files, codeChangedSinceLastCompile, markCompiled } = useEditorStore(); const { boards, activeBoardId, @@ -137,6 +137,7 @@ export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compi compileBoardProgram(activeBoardId, program); } setMessage({ type: 'success', text: 'Compiled successfully' }); + markCompiled(); setMissingLibHint(false); } else { const errText = result.error || result.stderr || 'Compile failed'; @@ -155,24 +156,62 @@ export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compi } }; - const handleRun = () => { + // Track whether we should auto-run after compilation completes + const autoRunAfterCompile = useRef(false); + + const handleRun = async () => { if (activeBoardId) { const board = boards.find((b) => b.id === activeBoardId); const isQemuBoard = board?.boardKind === 'raspberry-pi-3' || board?.boardKind === 'esp32' || board?.boardKind === 'esp32-s3'; - if (isQemuBoard || board?.compiledProgram) { + + // QEMU boards don't need compilation + if (isQemuBoard) { trackRunSimulation(board?.boardKind); startBoard(activeBoardId); setMessage(null); return; } + + // Auto-compile if no program or code changed since last compile + if (!board?.compiledProgram || codeChangedSinceLastCompile) { + autoRunAfterCompile.current = true; + await handleCompile(); + // After compile, check if it succeeded and run + const updatedBoard = useSimulatorStore.getState().boards.find((b) => b.id === activeBoardId); + if (autoRunAfterCompile.current && updatedBoard?.compiledProgram) { + autoRunAfterCompile.current = false; + trackRunSimulation(updatedBoard.boardKind); + startBoard(activeBoardId); + setMessage(null); + } else { + autoRunAfterCompile.current = false; + } + return; + } + + trackRunSimulation(board?.boardKind); + startBoard(activeBoardId); + setMessage(null); + return; } - // legacy fallback - if (compiledHex) { + + // Legacy fallback + if (!compiledHex || codeChangedSinceLastCompile) { + autoRunAfterCompile.current = true; + await handleCompile(); + const hex = useSimulatorStore.getState().compiledHex; + if (autoRunAfterCompile.current && hex) { + autoRunAfterCompile.current = false; + trackRunSimulation(); + startSimulation(); + setMessage(null); + } else { + autoRunAfterCompile.current = false; + } + } else { trackRunSimulation(); startSimulation(); setMessage(null); - } else { - setMessage({ type: 'error', text: 'Compile first' }); } }; @@ -337,9 +376,9 @@ export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compi {/* Run */}