fix(micropython): the \r poke must not fire once the prompt is already up

Stage 1 arms a \r at banner+800ms to flush QEMU's held ">>> " prompt, and
stage 2 arms Ctrl-A at prompt+200ms. Nothing kept the first from firing
after the second: if the prompt ever arrives on its own within 600ms, the
\r lands inside the pasted source, and MicroPython reads a lone \r as a
newline - it cuts a source line in half with no diagnostic of its own.

Here that is still latent; the in-browser JS engines, which deliver serial
per byte, hit it on every single run.
This commit is contained in:
David Montero Crespo 2026-08-03 05:48:40 +02:00
parent fd18e8db30
commit 6877099e78
1 changed files with 8 additions and 0 deletions

View File

@ -397,10 +397,18 @@ export class Esp32Bridge {
// Stage 1: banner "Type help()" → poke UART with \r to flush ">>> "
// The >>> prompt has no \n so the backend UART buffer holds it until
// we send a byte that causes another write.
// The poke only fires while the prompt is STILL missing. If the
// backend ever delivers ">>>" on its own within 600 ms, stage 2
// arms Ctrl-A (+200 ms) before this timer (+800 ms) fires, and the
// \r then lands inside the pasted code — MicroPython reads a lone
// \r as a newline, so it silently cuts a source line in half. That
// is exactly what broke the in-browser JS engines, where the prompt
// arrives immediately (see pro microPythonRepl.ts).
if (this._replState === 'idle' && this._serialBuffer.includes('Type "help()"')) {
this._replState = 'banner_seen';
console.log('[Esp32Bridge] Stage 1: banner seen → poking UART with \\r');
setTimeout(() => {
if (this._replState !== 'banner_seen') return; // prompt already arrived
this._send({ type: 'esp32_serial_input', data: { bytes: [0x0d] } });
}, 800);
}