Skip to main content

Output

A form is rarely the whole program. A market-stall order opens with a welcome box, says what it is doing between steps, and closes with a summary and its next steps. The output() primitives draw that chrome with the same theme the panel uses, so the text around the form belongs to the same program as the form itself.

output() returns a DrevOps\Tui\Primitive\Output carrying the pieces: a box and a card, an aligned table, five status lines, a definition list, wrapped text, a rule and a banner. Like progress(), it is a primitive: it collects no answer and never runs inside the interactive panel. Hold onto the object and call it as often as you need - every call returns it, so the calls chain.

$out = $tui->output();

$out->box('Everything below is picked the morning it ships.', 'Welcome');

$answers = $tui->run();

$out->success('Preserves are ready')
->definitions(['Jars' => '12', 'Fruit' => 'Apricot'])
->note('Anything short is refunded, never substituted');

Box

box() frames a body under an optional title, sized to its widest line and capped at the terminal. Pass a string, or a list of lines when you want to control the spacing - an empty entry stays a blank line.

Output boxOutput box

$out->box([
'Everything below is picked the morning it ships.',
'',
'Nothing is charged until the box leaves the packing shed.',
], 'Welcome to the produce box');

Long lines wrap inside the border rather than being clipped by it, so you can hand box() a paragraph and let it fit itself to the terminal.

Runnable in playground/18-output-box.php.

In all four display modes - Unicode or ASCII, colour on or off:

ANSINo ANSI
UnicodeBox: Unicode + ANSIBox: Unicode + ANSIBox: Unicode + No ANSIBox: Unicode + No ANSI
ASCIIBox: ASCII + ANSIBox: ASCII + ANSIBox: ASCII + No ANSIBox: ASCII + No ANSI

Table

table() lays headers and rows into a bordered grid, sizing each column to its widest cell and capping the whole thing at the terminal. It is the same renderer a note field's grid uses, so a standalone table matches the ones inside the panel.

Output tableOutput table

$out->table(['Item', 'Crates', 'Picked'], [
['Apricot', '4', 'Tuesday'],
['Peach', '2', 'Tuesday'],
['Carrot', '6', 'Wednesday'],
]);

Pass an empty header list to draw the rows with no header row. When the natural width exceeds the terminal, the widest columns shrink and over-long cells are cut short with an ellipsis, so the borders always stay whole.

Runnable in playground/18-output-table.php.

ANSINo ANSI
UnicodeTable: Unicode + ANSITable: Unicode + ANSITable: Unicode + No ANSITable: Unicode + No ANSI
ASCIITable: ASCII + ANSITable: ASCII + ANSITable: ASCII + No ANSITable: ASCII + No ANSI

Card

card() is the full form of box(): a title, a body and a grid, boxed together when the three belong to one another. It is the same renderer behind a note field's card, so a standalone card and a note card are the same object drawn twice.

Output cardOutput card

$out->card('Loaded for delivery', 'Everything below leaves the shed at seven.', ['Item', 'Crates'], [
['Apricot', '4'],
['Peach', '2'],
]);

The grid is sized to fit inside the card's own border, so the two frames never collide. Pass bordered: false for the indented card a note field draws without ->border().

Status lines

Five kinds, each with its own glyph and its own colour: note(), info(), success(), warning() and error().

Status linesStatus lines

$out->info('Checking the morning harvest')
->success('Apricots picked and weighed')
->warning('Only two crates of pears left')
->error('The cherry shelf is empty')
->note('Anything short is refunded, never substituted');

The glyph carries the meaning on its own, so the five stay distinguishable with colour off and in ASCII alike. Every glyph is one column wide in any terminal, so a run of status lines always aligns.

To choose the kind at runtime, pass a Status case to status():

use DrevOps\Tui\Primitive\Status;

$out->status($ok ? Status::Success : Status::Error, 'Packed the box');

Runnable in playground/18-output-status.php.

ANSINo ANSI
UnicodeStatus: Unicode + ANSIStatus: Unicode + ANSIStatus: Unicode + No ANSIStatus: Unicode + No ANSI
ASCIIStatus: ASCII + ANSIStatus: ASCII + ANSIStatus: ASCII + No ANSIStatus: ASCII + No ANSI

Definition list

definitions() lays label/value pairs into two columns - the labels sized to the widest of them, a long value wrapped under its own column. It is the natural way to read a collected form back to the person who filled it in.

Definition listDefinition list

$out->definitions([
'Order' => 'Summer Box',
'Fruit' => 'Apricot, Peach, Plum',
'Vegetables' => 'Carrot, Spinach, Tomato',
'Quantity' => '6 baskets',
'Note' => 'Everything is picked the morning it ships, packed in the shed, and loaded onto the van before seven.',
]);

Runnable in playground/18-output-definitions.php.

ANSINo ANSI
UnicodeDefinitions: Unicode + ANSIDefinitions: Unicode + ANSIDefinitions: Unicode + No ANSIDefinitions: Unicode + No ANSI
ASCIIDefinitions: ASCII + ANSIDefinitions: ASCII + ANSIDefinitions: ASCII + No ANSIDefinitions: ASCII + No ANSI

Text, rules and a banner

Three smaller pieces round out the set. text() wraps a paragraph to the terminal and renders the same markdown subset a field description carries, so prose outside the form reads like prose inside it. rule() draws a themed separator between sections, and banner() opens the program with a logo above an optional version line.

Banner, rule and wrapped textBanner, rule and wrapped text

$out->banner('Produce Box', '1.2.3');
$out->rule();
$out->text('Every box is picked the morning it ships. Nothing is charged until the crates leave the packing shed.');

The markdown subset is off by default, exactly as it is for field descriptions - turn it on with $tui->markdown() before reaching for output():

$out = $tui->markdown()->output();

$out->text("**Before you order:**\n\n- Pick a *delivery day* between Monday and Saturday\n- Leave a note if the gate code is not `1234`");

Runnable in playground/18-output-text.php.

Theme-drawn

The colours and glyphs come from the active theme, the same way every widget does, and the pieces reuse the atoms the panel already styles: a box takes the frame's border and heading, a success line the value colour, an info line the theme's accent. So ->theme('ember') prints info lines in ember's orange and ->theme('frost') in frost's blue, with no extra configuration and nothing a custom theme has to override to inherit its own palette.

To go further and restyle one piece outright, override its render*() method on your theme - renderCard(), renderTable(), renderStatus(), renderDefinitions(), renderText() or renderBanner().

renderCard() and renderTable() are each the single renderer behind both the standalone piece and its in-panel counterpart, so overriding one restyles the note card - or the note grid - at the same time. None of them takes a field, a panel or an answer set: they take plain strings and arrays, which is what makes them usable outside a form at all.

Degrading off a TTY

Output is chrome, not data, so it is written to standard error and leaves standard output for your program's own results. Piped, redirected or captured, the escape codes would land in the text rather than on a terminal, so the colour is dropped and the plain lines remain:

php playground/18-output-status.php 2>&1 | cat
# › Checking the morning harvest
# ✓ Apricots picked and weighed
# ! Only two crates of pears left

The frames, glyphs and alignment survive, because they are text. Forcing wins over the detection either way, and both switches are set on the facade before you reach for output(): $tui->color(true)->output() keeps the colour in a captured log, and $tui->unicode(false)->output() draws the ASCII glyphs on a capable terminal. See display modes for the full set of switches.

To write somewhere other than standard error - standard output, or a stream you control - pass your own terminal:

use DrevOps\Tui\Render\Terminal;

$out = $tui->output(new Terminal(STDOUT));