Skip to content

Commit b58974c

Browse files
committed
feat(simulator): integrate PyScript terminal REPL with dynamic mip loading
1 parent cfd8a51 commit b58974c

13 files changed

Lines changed: 186 additions & 348 deletions

simulator/index.html

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
<script src="https://cdnjs.cloudflare.com/ajax/libs/lz-string/1.5.0/lz-string.min.js"></script>
1616
<!-- Monaco Editor AMD Loader -->
1717
<script src="https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.45.0/min/vs/loader.js"></script>
18+
<!-- PyScript Core & Terminal -->
19+
<link rel="stylesheet" href="https://pyscript.net/releases/2024.11.1/core.css">
20+
<script type="module" src="https://pyscript.net/releases/2024.11.1/core.js"></script>
1821
</head>
1922
<body>
2023
<!-- Top Global App Bar -->
@@ -63,8 +66,8 @@
6366
<!-- Runtime Engine Selector -->
6467
<div class="sim-select-wrap">
6568
<select id="runtime-select" aria-label="Select Execution Runtime">
66-
<option value="pyodide" selected>Pyodide (CPython)</option>
67-
<option value="mpy">MicroPython</option>
69+
<option value="mpy" selected>MicroPython</option>
70+
<option value="pyodide">Pyodide (CPython)</option>
6871
</select>
6972
</div>
7073
</div>
@@ -108,10 +111,10 @@
108111
</section>
109112

110113
<!-- Vertical Drag Splitter -->
111-
<div class="sim-splitter" id="splitter-v" role="separator" aria-orientation="vertical"></div>
114+
<div class="sim-splitter-v" id="splitter-v" role="separator" aria-orientation="vertical"></div>
112115

113-
<!-- Right Pane: Simulator & Console -->
114-
<section class="sim-preview-pane" id="preview-pane" aria-label="Simulator and Console Output">
116+
<!-- Right Pane: Device Preview & Interactive REPL -->
117+
<section class="sim-preview-pane" id="preview-pane" aria-label="Device Preview and Console">
115118
<!-- Top Sub-Pane: Hardware Canvas Bezel Stage -->
116119
<div class="sim-device-stage" id="device-stage">
117120
<div class="sim-device-bezel" id="device-bezel">
@@ -123,8 +126,8 @@
123126
<!-- Horizontal Drag Splitter -->
124127
<div class="sim-splitter-h" id="splitter-h" role="separator" aria-orientation="horizontal"></div>
125128

126-
<!-- Bottom Sub-Pane: Interactive REPL -->
127-
<section class="sim-console-pane" id="console-pane" aria-label="Interactive Python REPL">
129+
<!-- Bottom Sub-Pane: Interactive PyScript Terminal REPL -->
130+
<section class="sim-console-pane" id="console-pane" aria-label="Interactive Python Terminal REPL">
128131
<div class="sim-pane-header">
129132
<div class="sim-tab">
130133
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="4 17 10 11 4 5"/><line x1="12" y1="19" x2="20" y2="19"/></svg>
@@ -134,11 +137,45 @@
134137
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/></svg>
135138
</button>
136139
</div>
137-
<div class="sim-console-body" id="console-log"></div>
138-
<form class="sim-repl-form" id="repl-form" autocomplete="off">
139-
<span class="sim-repl-prompt" id="repl-prompt">&gt;&gt;&gt;</span>
140-
<input type="text" class="sim-repl-input" id="repl-input" placeholder="Type Python expression or command (e.g. dir(), lv.screen_active()...)" spellcheck="false" autocomplete="off" autocapitalize="off">
141-
</form>
140+
<div class="sim-console-body sim-terminal-body" id="console-log">
141+
<script id="sim-terminal-script" type="mpy" terminal>
142+
import sys, os
143+
from pyscript import window
144+
145+
def _save_main_file(code_content):
146+
with open("main.py", "w") as f:
147+
f.write(code_content)
148+
149+
window._save_main_file = _save_main_file
150+
151+
# Write initial main.py from editor / template
152+
try:
153+
_initial_code = window.getEditorCode() if hasattr(window, "getEditorCode") else ""
154+
if _initial_code:
155+
_save_main_file(_initial_code)
156+
except Exception:
157+
pass
158+
159+
# Bootstrap core desktop stack via mip from PyDevices MIP index
160+
try:
161+
import mip
162+
mip.install("pydevices-desktop", index="https://PyDevices.github.io/mip")
163+
try:
164+
import utils.path
165+
except Exception:
166+
pass
167+
except Exception as _e:
168+
print("MIP bootstrap:", _e)
169+
170+
try:
171+
import main
172+
except Exception as _e:
173+
sys.print_exception(_e) if hasattr(sys, "print_exception") else print(_e)
174+
175+
import code
176+
code.interact(local=globals())
177+
</script>
178+
</div>
142179
</section>
143180
</section>
144181
</main>

simulator/simulator.css

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -403,51 +403,40 @@ html, body {
403403
.sim-console-body .log-prompt { color: var(--accent); font-weight: 600; }
404404
.sim-console-body .log-repl-out { color: #a5b4fc; }
405405

406-
/* Interactive REPL Input Form */
407-
.sim-repl-form {
406+
.sim-terminal-body {
407+
padding: 0;
408+
overflow: hidden;
409+
background: #080c14;
408410
display: flex;
409-
align-items: center;
410-
gap: 8px;
411-
padding: 6px 12px;
412-
background: var(--bg-panel-subtle);
413-
border-top: 1px solid var(--border-color);
414-
font-family: var(--font-mono);
415-
font-size: 0.84rem;
416-
flex: none;
411+
flex-direction: column;
417412
}
418413

419-
[data-theme="light"] .sim-console-body {
420-
background: #f8fafc;
421-
color: #1e293b;
414+
.sim-terminal-body .py-terminal {
415+
flex: 1;
416+
height: 100% !important;
417+
width: 100% !important;
418+
display: block;
422419
}
423420

424-
[data-theme="light"] .sim-console-body .log-repl-out {
425-
color: #4338ca;
421+
.sim-terminal-body .xterm {
422+
height: 100% !important;
423+
padding: 8px 12px;
424+
background: #080c14 !important;
426425
}
427426

428-
.sim-repl-prompt {
429-
color: var(--accent);
430-
font-weight: 700;
431-
font-family: var(--font-mono);
432-
user-select: none;
433-
font-size: 0.85rem;
427+
.sim-terminal-body .xterm-viewport {
428+
overflow-y: auto !important;
429+
background: #080c14 !important;
434430
}
435431

436-
.sim-repl-input {
437-
flex: 1;
438-
background: transparent;
439-
border: none;
440-
color: var(--text-main);
441-
font-family: var(--font-mono);
442-
font-size: 0.84rem;
443-
outline: none;
444-
padding: 4px 0;
432+
.sim-terminal-body .xterm-screen {
433+
width: 100% !important;
445434
}
446435

447-
.sim-repl-input::placeholder {
448-
color: var(--text-subtle);
449-
font-style: italic;
450-
font-size: 0.78rem;
436+
[data-theme="light"] .sim-terminal-body,
437+
[data-theme="light"] .sim-terminal-body .xterm,
438+
[data-theme="light"] .sim-terminal-body .xterm-viewport {
439+
background: #ffffff !important;
451440
}
452441

453442
/* Status indicator pill in status bar */

0 commit comments

Comments
 (0)