Skip to main content

Installation

Install the package with Composer:

composer require drevops/phptui

The package is a library you consume programmatically - it has no CLI entry point of its own. You'll work with two classes:

  • DrevOps\PhpTui\Tui - the facade: collects a form's answers, headlessly or through the interactive panel TUI.
  • DrevOps\PhpTui\Builder\Form - the fluent builder for declaring a form's panels and fields.

Usage

Declare a form with the fluent Form builder, then hand it to the Tui facade - one class that wires up collection, the input resolver, the schema tools and the interactive screen so you don't have to:

use DrevOps\PhpTui\Builder\Form;
use DrevOps\PhpTui\Builder\PanelBuilder;
use DrevOps\PhpTui\Tui;

$form = Form::create('Quick start')
->panel('order', 'New order', function (PanelBuilder $p): void {
// A required single-line text field.
$p->text('name', 'Order name')->required();

// A single choice, starting on "Banana".
$p->select('fruit', 'Fruit')->default('banana')->options([
'apple' => 'Apple',
'banana' => 'Banana',
'cherry' => 'Cherry',
]);

// A multi-select, with one option pre-checked.
$p->select('veg', 'Vegetables')->multiple()->default(['carrot'])->options([
'carrot' => 'Carrot',
'tomato' => 'Tomato',
'spinach' => 'Spinach',
]);

// An integer bounded to a sensible quantity.
$p->number('quantity', 'Quantity')->min(1)->max(99)->default(6);

// A yes/no gate.
$p->confirm('organic', 'Organic only?')->default(FALSE);
});

$tui = new Tui($form);

// Interactive panel TUI on a terminal, headless otherwise.
$answers = $tui->run();

// Or drive a mode directly:
echo $tui->collect('{"name":"Weekly Box"}')->toJson(); // headless: JSON + environment
$answers = $tui->interact(); // interactive panel TUI

run() picks the mode for you: on a terminal it drives the interactive panel TUI, and anywhere else - or whenever prompts are supplied - it collects headlessly. The facade also exposes schema(), agentHelp() and validate(), and - when you want finer control - root() for the declared block tree and registry() for the handler registry.

Aborting with Ctrl-C or Cancel

Pressing Ctrl-C part-way through an interactive session aborts it: the panel TUI restores the terminal, clears the screen, and the facade raises a DrevOps\PhpTui\InterruptException instead of returning the partial answers - so an abort can never be mistaken for a completed submission. The Cancel button aborts the same way, raising DrevOps\PhpTui\CancelException. That's a subclass of InterruptException, so one catch covers both:

use DrevOps\PhpTui\InterruptException;

try {
$answers = $tui->run();
}
catch (InterruptException) {
// The user pressed Ctrl-C or cancelled: leave without printing a result.
exit(130);
}

echo $answers->toSummary();

Catch CancelException first when an explicit cancel should react differently from a Ctrl-C. Only the interactive session raises these: headless collection - collect(), or run() when prompts are supplied or the input is piped - never interacts, so it never aborts this way.

Headless collection has its own ending. A value the form refuses raises DrevOps\PhpTui\CollectException naming the field and the reason: with no screen there is nobody to retype it, so the whole collection fails rather than handing back answers one of which was never accepted. It sits in the same namespace as the other two, so one import covers every way a collection ends short.

Next steps