Merge pull request #82 from davidmonterocrespo24/feature/auto-compile-on-play

feat: auto-compile when pressing Play if code changed or no hex loaded
pull/90/head^2
David Montero Crespo 2026-03-31 23:10:25 -03:00 committed by GitHub
commit d44ea38dcf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 56 additions and 9 deletions

View File

@ -44,7 +44,7 @@ const BOARD_PILL_COLOR: Record<BoardKind, string> = {
}; };
export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compileLogs, setCompileLogs }: EditorToolbarProps) => { export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compileLogs, setCompileLogs }: EditorToolbarProps) => {
const { files } = useEditorStore(); const { files, codeChangedSinceLastCompile, markCompiled } = useEditorStore();
const { const {
boards, boards,
activeBoardId, activeBoardId,
@ -137,6 +137,7 @@ export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compi
compileBoardProgram(activeBoardId, program); compileBoardProgram(activeBoardId, program);
} }
setMessage({ type: 'success', text: 'Compiled successfully' }); setMessage({ type: 'success', text: 'Compiled successfully' });
markCompiled();
setMissingLibHint(false); setMissingLibHint(false);
} else { } else {
const errText = result.error || result.stderr || 'Compile failed'; 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) { if (activeBoardId) {
const board = boards.find((b) => b.id === activeBoardId); const board = boards.find((b) => b.id === activeBoardId);
const isQemuBoard = board?.boardKind === 'raspberry-pi-3' || board?.boardKind === 'esp32' || board?.boardKind === 'esp32-s3'; 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); trackRunSimulation(board?.boardKind);
startBoard(activeBoardId); startBoard(activeBoardId);
setMessage(null); setMessage(null);
return; 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(); trackRunSimulation();
startSimulation(); startSimulation();
setMessage(null); setMessage(null);
} else {
setMessage({ type: 'error', text: 'Compile first' });
} }
}; };
@ -337,9 +376,9 @@ export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compi
{/* Run */} {/* Run */}
<button <button
onClick={handleRun} onClick={handleRun}
disabled={running || (!['raspberry-pi-3','esp32','esp32-s3'].includes(activeBoard?.boardKind ?? '') && !compiledHex && !activeBoard?.compiledProgram)} disabled={running || compiling}
className="tb-btn tb-btn-run" className="tb-btn tb-btn-run"
title="Run" title="Run (auto-compiles if needed)"
> >
<svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor" stroke="none"> <svg width="22" height="22" viewBox="0 0 24 24" fill="currentColor" stroke="none">
<polygon points="5,3 19,12 5,21" /> <polygon points="5,3 19,12 5,21" />

View File

@ -89,6 +89,10 @@ interface EditorState {
setTheme: (theme: 'vs-dark' | 'light') => void; setTheme: (theme: 'vs-dark' | 'light') => void;
setFontSize: (size: number) => void; setFontSize: (size: number) => void;
// Dirty flag — tracks whether code changed since last compilation
codeChangedSinceLastCompile: boolean;
markCompiled: () => void;
// Legacy compat — sets content of the active file // Legacy compat — sets content of the active file
setCode: (code: string) => void; setCode: (code: string) => void;
} }
@ -108,6 +112,9 @@ export const useEditorStore = create<EditorState>((set, get) => ({
activeGroupFileId: { [DEFAULT_GROUP_ID]: MAIN_ID }, activeGroupFileId: { [DEFAULT_GROUP_ID]: MAIN_ID },
openGroupFileIds: { [DEFAULT_GROUP_ID]: [MAIN_ID] }, openGroupFileIds: { [DEFAULT_GROUP_ID]: [MAIN_ID] },
codeChangedSinceLastCompile: true,
markCompiled: () => set({ codeChangedSinceLastCompile: false }),
// ── File operations (legacy API — operate on active group) ────────────── // ── File operations (legacy API — operate on active group) ──────────────
createFile: (name: string) => { createFile: (name: string) => {
@ -178,6 +185,7 @@ export const useEditorStore = create<EditorState>((set, get) => ({
return { return {
files: s.files.map(mapper), files: s.files.map(mapper),
fileGroups: { ...s.fileGroups, [groupId]: (s.fileGroups[groupId] ?? []).map(mapper) }, fileGroups: { ...s.fileGroups, [groupId]: (s.fileGroups[groupId] ?? []).map(mapper) },
codeChangedSinceLastCompile: true,
}; };
}); });
}, },