ITADN

Add --interactive Textual TUI for browse + build

#104Pull Requestmattytrentini 创建于 2026-04-25
M
mattytrentinicommented
## Summary Adds an interactive TUI launched via `mpbuild --interactive` (or `-i`). **Layout** (per the plan): ``` ┌──────────────────────────────────────────────────────────┐ │ Header │ ├──────────────┬───────────────────────────────────────────┤ │ │ #info-pane │ │ #board-tree │ Vendor / Product / MCU / Port / URL │ │ (Tree of │ Variant ▼ (when board has variants) │ │ ports → │ ▕ Build ▏ ▕ Clean ▏ │ │ boards) ├───────────────────────────────────────────┤ │ │ #build-log (RichLog, streaming output) │ ├──────────────┴───────────────────────────────────────────┤ │ Footer — q · b · c │ └──────────────────────────────────────────────────────────┘ ``` **Behaviour** - Tree populated from the existing `Database` (ports → boards), sorted. - Selecting a leaf populates the info pane, enables Build/Clean, and reveals/hides the variant `Select` based on whether the board has variants. - Build/Clean both run via `docker_build_cmd()` reused verbatim, then a small `_stream_command` helper that runs the result in a `subprocess.Popen` line-buffered and yields stdout/stderr lines. A Textual `@work(thread=True, exclusive=True, group="build")` worker pushes each line into a `RichLog` via `call_from_thread` — clicking Build twice in a row cancels the in-flight build. - `docker_interactive=False` is passed to `docker_build_cmd` so docker doesn't try to re-attach `-it` while the TUI owns the terminal. **CLI integration** `--interactive` is added to the existing `@app.callback()` with `is_eager=True`, mirroring `--version`. That sidesteps `chain=True`'s "missing command" complaint without restructuring the app. The `from .interactive import start_app` is lazy so non-TUI users don't pay the textual import cost on every CLI call. **Tests** — 8 new (107 total) `tests/test_interactive.py` (6, async, using `Pilot`): - Tree populates with ports/boards from a synthesised `mpy_root`. - Build/Clean/Variant Select all start disabled. - Selecting a board fills the info pane (vendor, product, MCU) and enables Build/Clean. - Variant Select is shown for boards with variants, hidden otherwise. - Selecting a port (non-leaf) keeps actions disabled. `tests/test_cli.py` (2 added): `--interactive` and `-i` both call `start_app` and exit 0 (with `start_app` monkeypatched). **Not tested**: the actual subprocess invocation of docker. The streaming worker is an integration concern; `docker_build_cmd` is already well covered, and the worker is a thin stitch between it and `RichLog`. ## Prior work acknowledged The abandoned `origin/interactive-mode` branch had a partial Textual app (`90535ec`). I lifted structural ideas (tree population, compose shape) but rewrote against current main — that branch references `typing_extensions` (removed in #96), a renamed `IDF_DEFAULT` constant, and stops short of actually invoking a build. ## Test plan - [x] `uv run pytest -v` — 107 passed. - [x] `uv run ruff check && uv run ruff format --check` — green. - [x] `uv run ty check` — `All checks passed!` - [x] `uv run pre-commit run --all-files` — all hooks green (incl. local `ty` hook). - [x] `uv build --wheel` — wheel includes `mpbuild/interactive.tcss`. - [ ] Manual smoke from inside a MicroPython tree (next time I'm at the bench): tree populates, selecting boards updates the info pane, Build streams docker output to the log, q quits.
合并状态:未合并 关闭于 2026-04-26 1 条评论