Skip to content
docsv0.3.0

TerminalInterface

The terminal surface a TUI loop talks to. The PHP analog of pi-tui's `Terminal` interface. A `RetainedTuiLoop` (or any other TUI runtime) writes to, reads from, and controls a terminal through this seam — so the same loop can drive a real STDIN/STDOUT terminal, an in-memory test terminal, or a remote PTY-backed terminal without the loop body branching on the concrete backend. Implementations are expected to be cheap to construct and to be driven explicitly via {@see start()} / {@see stop()} — no implicit I/O in the constructor. `columns()` / `rows()` reflect the current size and may change between calls when the terminal is resized; {@see start()}'s `$onResize` callback lets the loop react.

TerminalInterface::start()

abstract public function start(callable $onInput, callable $onResize): void

Enters raw mode (or whatever the backend needs) and begins delivering input bytes to `$onInput`. `$onResize` is called when the terminal's columns/rows change so the loop can re-layout.

Parameters

Parameters of start()
NameTypeDescription
$onInputcallable(string): void
$onResizecallable(): void

TerminalInterface::stop()

abstract public function stop(): void

Restores the terminal to its pre-{@see start()} state (cooked mode, visible cursor, etc.). Safe to call after {@see start()} or when {@see start()} was never called.

TerminalInterface::write()

abstract public function write(string $data): void

Writes `$data` to the terminal output stream. The caller is responsible for framing; this method does no buffering.

Parameters

Parameters of write()
NameTypeDescription
$datastring

TerminalInterface::pollInput()

abstract public function pollInput(): string

Any input bytes waiting right now, or `''` when there are none. Never blocks. The contract carries BOTH input models on purpose. {@see self::start()} pushes bytes to its `$onInput` callback, which suits an event-driven host; a retained loop, which owns its own tick, needs to pull instead. Without this method a pulling loop has to reach past the contract to a concrete terminal's stream — which is exactly what kept the interactive loop untestable.

TerminalInterface::atEndOfInput()

abstract public function atEndOfInput(): bool

Whether no further input will ever arrive. {@see self::pollInput()} returns `''` for "nothing waiting right now", which a loop that idles between ticks reads as "keep going". A loop whose exit condition is the end of its input needs to tell that apart from "the input is over" — and only the terminal knows which it is. A real terminal answers false for its whole life; one backed by a finite stream answers true once the stream is drained.

TerminalInterface::columns()

abstract public function columns(): int

The terminal's current width in columns.

TerminalInterface::rows()

abstract public function rows(): int

The terminal's current height in rows.

TerminalInterface::moveBy()

abstract public function moveBy(int $lines): void

Moves the cursor by the given number of lines, negative being upwards.

Parameters

Parameters of moveBy()
NameTypeDescription
$linesint

TerminalInterface::hideCursor()

abstract public function hideCursor(): void

Hides the hardware cursor.

TerminalInterface::showCursor()

abstract public function showCursor(): void

Shows the hardware cursor.

TerminalInterface::clearLine()

abstract public function clearLine(): void

Clears the line the cursor is on.

TerminalInterface::clearFromCursor()

abstract public function clearFromCursor(): void

Clears from the cursor to the end of the screen.

TerminalInterface::clearScreen()

abstract public function clearScreen(): void

Clears the whole screen.

TerminalInterface::setTitle()

abstract public function setTitle(string $title): void

Sets the terminal window title.

Parameters

Parameters of setTitle()
NameTypeDescription
$titlestring