Skip to content

P18 phase 1: one console and Stop (IDE and embed, protocol v4) - #29

Merged
cedricvogel-leo merged 2 commits into
mainfrom
feature/stop-and-console
Oct 25, 2026
Merged

cedricvogel-leo merged 2 commits into
mainfrom
feature/stop-and-console

Conversation

@cedricvogel-leo

Copy link
Copy Markdown
Collaborator

Phase 1 of P18 (spec: teaching-agent journal.md → Visual Identity → «glpython-IDE (Hülle um den Editor)»): behaviour in the IDE and the embed.

Stop

  • While Python is busy for more than 300 ms, ▶ Ausführen becomes ■ Stoppen. Busy means a program, a REPL input such as endlos(), Tests or a visualization. The 300 ms delay keeps quick REPL inputs from making the button flicker.
  • Stopping ends the worker and starts a new one:
    • The code stays.
    • The console keeps what was printed and adds «Gestoppt. Python wurde neu gestartet.» (en: "Stopped. Python was restarted.").
    • The REPL starts in an empty namespace. Earlier entries lose «Visualisieren», since their session is gone.
  • Hosts can use command: { type: 'stop' } and the new onBusyChange prop.
  • Interrupt without restart is possible where the page is cross-origin isolated (the IDE: Pyodide's setInterruptBuffer → KeyboardInterrupt, keeping the namespace). It is not possible in LiaScript's embed, where the iframe isn't isolated. I kept one behaviour everywhere, the restart, and list the interrupt as a follow-up.

Embed protocol version 4

  • glpython:stop (parent → embed).
  • glpython:busy {busy} (embed → parent), only to parents that speak version 4.
  • capabilities.stop in glpython:ready.
  • On a reset, the embed also sends busy: false.
  • Earlier versions keep working. check-embed-protocol.mjs covers version 4. embed/demo.html's Run becomes Stop while busy.
  • The macro's ▶ → ■ comes in a separate glpython-liascript PR.

One console («Konsole»)

  • One transcript: the program's output, then REPL inputs, Tests reports and notes, in the order they happen. A Tests report is now appended instead of replacing the output. Errors and hints stand where they happened. Run and Reset clear it.
  • Streamed output: what a program or REPL input prints appears while it runs, not only at the end. The worker sends at most 50 messages per 50 ms and the page applies them every 40 ms, so a printing loop doesn't flood the page. The final result brings the whole output, so nothing is doubled or lost.
  • Long output: the console keeps the last 100,000 characters, and follows new output unless the learner has scrolled up.
  • In the embed: the console grows with its content up to 480px, then scrolls. Before, a printing loop would have stretched the iframe beyond the macro's 1200px cap.

A bug fixed on the way

A REPL input before any Run (now also right after a stop) failed with ModuleNotFoundError: No module named 'gturtle', because only a Run put / on sys.path. session.py adds it when it loads.

Tested

In the built embed via its protocol, and in the IDE with this build (laptop 1440 and iPad 820 widths):

Case Result
while True: printing every 200,000 output appears while running; busy: true; Stop → note, busy: false
REPL after Stop zahl → NameError + hint «Wurde die Datei schon ausgeführt?»; 1 + 1 → 2
endlos() in the REPL ■ appears, Stop works, the entry stays without «Visualisieren»
Tests after a REPL input report appended after >>> quadrat(4)
IDE, keyboard Stop focused + Enter stops

lint (known warning only), both builds, test:protocol, test:runtime and test:hints pass. Screenshots are in the phase report.

🤖 Generated with Claude Code

Stop: while Python is busy for more than 300 ms (a program, a REPL input,
Tests, a visualization) the run button becomes «■ Stoppen». Stopping ends
the worker and starts a new one: the code stays, the console keeps what
was printed and says that Python restarted. Hosts can stop through the
command { type: 'stop' } and learn about busy through onBusyChange; the
embed passes both on to its parent as protocol version 4
(glpython:stop, glpython:busy, capabilities.stop).

One console («Konsole»): the program's output, REPL inputs, Tests reports
and notes form one chronological transcript; a Tests report is appended
instead of replacing it. Output streams while a program or REPL input runs
(at most 50 messages per 50 ms, shown every 40 ms), so an endless loop shows
what it prints. The console keeps the last 100,000 characters, follows new
output unless scrolled up, and in the embed grows up to 480px.

A REPL input before any Run (e.g. right after a stop) failed with
"No module named 'gturtle'": "/" was only put on sys.path by a Run.
session.py now adds it when it loads.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… stays

Starting with Enter and stopping with Enter again kept failing: the button
was swapped for another element, and disabled in the 300 ms before Stop
shows, and either drops keyboard focus.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cedricvogel-leo

Copy link
Copy Markdown
Collaborator Author

Added: Run and Stop are now one button that is never disabled (aria-disabled in the 300 ms before Stop shows), so keyboard focus stays on it: Enter starts, Enter stops (checked in the IDE).

@cedricvogel-leo
cedricvogel-leo merged commit a0598cb into main Oct 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant