InteractiveTuiLoop
The component-driven loop: mounts Live components, dispatches keys into their state, and re-renders the whole screen each tick. Simpler and more wasteful than {@see RetainedTuiLoop}, which diffs instead of repainting.
InteractiveTuiLoop::__construct()
public function __construct(Milpa\Live\Contracts\Rendering\ComponentRendererRegistryInterface $renderers, array $instances, ?Milpa\Live\Contracts\Tui\TuiStateManagerInterface $stateManager = null, int $width = 88, string $title = 'Milpa TUI'):Parameters
| Name | Type | Description |
|---|---|---|
| $renderers | Milpa\Live\Contracts\Rendering\ComponentRendererRegistryInterface | |
| $instances | array<int, TuiComponentInstance> | |
| $stateManager | ?Milpa\Live\Contracts\Tui\TuiStateManagerInterface | |
| $width | int | |
| $title | string |
InteractiveTuiLoop::focusedId()
public function focusedId(): ?stringThe id of the node holding focus, or null when nothing does.
InteractiveTuiLoop::running()
public function running(): boolInteractiveTuiLoop::renderScreen()
public function renderScreen(): stringThe full screen as a string, ready to be written.
InteractiveTuiLoop::dispatchKey()
public function dispatchKey(string $key): boolRoutes a key to the focused component, returning whether it was consumed.
Parameters
| Name | Type | Description |
|---|---|---|
| $key | string |
InteractiveTuiLoop::runOn()
public function runOn(Milpa\Live\Contracts\Tui\TerminalInterface $terminal, int $idleMicroseconds = 100000, int $escapeTimeoutMicroseconds = 50000): voidRuns the loop against a {@see TerminalInterface} instead of raw streams. Two things are different from {@see self::run()}: 1. Key assembly goes through {@see InputBuffer}, the same one the retained loop uses, so a sequence split across reads is reassembled instead of emitted as its separate bytes. 2. Painting moved OUT of the top of the loop. Polling means many ticks with no key, and this loop repaints in full — leaving the paint where it was would redraw the whole screen on every idle tick.
Parameters
| Name | Type | Description |
|---|---|---|
| $terminal | Milpa\Live\Contracts\Tui\TerminalInterface | |
| $idleMicroseconds | int | How long to idle when a tick produced no key. |
| $escapeTimeoutMicroseconds | int | How long a partial sequence may sit before it is emitted as-is. A terminal delivers the rest of a CSI in microseconds; a person leaves an Escape pending for as long as they like. |
InteractiveTuiLoop::resizeTo()
public function resizeTo(int $width): voidAdopts a new terminal width. There is no previous frame to forget here: this loop repaints in full on every key, so the next paint is already whole. Height is not tracked — what it renders is a flowing document, not a fixed grid.
Parameters
| Name | Type | Description |
|---|---|---|
| $width | int |
InteractiveTuiLoop::run()
public function run(?mixed $input = null, ?mixed $output = null): voidRuns the loop against the given input and output streams until it is asked to stop. Kept alongside {@see self::runOn()} rather than delegating to it: over a non-TTY this path deliberately emits no ANSI, and the terminal contract has no way to say "this surface takes no escape sequences". It keeps its own reader, which assembles at most three bytes after an ESC. Blocking one byte at a time makes fragmentation a non-issue here, but a sequence longer than three bytes — a bracketed paste, for one — still arrives in pieces. {@see self::runOn()} does not have that limit.
Parameters
| Name | Type | Description |
|---|---|---|
| $input | (resource | null) | |
| $output | (resource | null) |
InteractiveTuiLoop::sessionState()
public function sessionState(): arrayThe loop's current session state, suitable for persisting.