Skip to content
docsv0.3.0

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

Parameters of __construct()
NameTypeDescription
$renderersMilpa\Live\Contracts\Rendering\ComponentRendererRegistryInterface
$instancesarray<int, TuiComponentInstance>
$stateManager?Milpa\Live\Contracts\Tui\TuiStateManagerInterface
$widthint
$titlestring

InteractiveTuiLoop::focusedId()

public function focusedId(): ?string

The id of the node holding focus, or null when nothing does.

InteractiveTuiLoop::running()

public function running(): bool

InteractiveTuiLoop::renderScreen()

public function renderScreen(): string

The full screen as a string, ready to be written.

InteractiveTuiLoop::dispatchKey()

public function dispatchKey(string $key): bool

Routes a key to the focused component, returning whether it was consumed.

Parameters

Parameters of dispatchKey()
NameTypeDescription
$keystring

InteractiveTuiLoop::runOn()

public function runOn(Milpa\Live\Contracts\Tui\TerminalInterface $terminal, int $idleMicroseconds = 100000, int $escapeTimeoutMicroseconds = 50000): void

Runs 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

Parameters of runOn()
NameTypeDescription
$terminalMilpa\Live\Contracts\Tui\TerminalInterface
$idleMicrosecondsintHow long to idle when a tick produced no key.
$escapeTimeoutMicrosecondsintHow 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): void

Adopts 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

Parameters of resizeTo()
NameTypeDescription
$widthint

InteractiveTuiLoop::run()

public function run(?mixed $input = null, ?mixed $output = null): void

Runs 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

Parameters of run()
NameTypeDescription
$input(resource | null)
$output(resource | null)

InteractiveTuiLoop::sessionState()

public function sessionState(): array

The loop's current session state, suitable for persisting.