decodelabs/terminus

Simple CLI interactions

v0.13.0 2025-05-21 09:33 UTC

README

PHP from Packagist Latest Version Total Downloads GitHub Workflow Status PHPStan License

Simple CLI interactions for PHP

Terminus provides everything you need to build highly interactive, beautiful CLI processes.

Installation

composer require decodelabs/terminus

Usage

Writing output

Write standard text to output:

use DecodeLabs\Terminus\Session;

$io = Session::getDefault();

$io->$write('Normal text'); // no newline
$io->writeLine(' - end of line'); // with newline

Error output works the same way, with Error in the method name:

$io->writeError('Error text'); // no newline
$io->writeErrorLine(' - end of line'); // with newline

Reading input

Read input from the user: Note, PHP by default buffers the input stream so input requires return to be pressed before it can be read.

$data = $io->read(3); // Read 3 bytes
$line = $io->readLine();

If the connected terminal supports stty (most Unix emulators), buffering can be turned off for instant input:

$io->toggleInputBuffer(false);
$io->writeLine('Yes or no?')
$char = $io->read(1); // y or n
$io->toggleInputBuffer(true);

More on extended ANSI and stty support below.

Colors and styles

If the connected terminal can support ANSI codes can be styled easily using a handy shortcut on the facade:

$io->{'blue'}('This is blue ');
$io->{'yellow'}('This is yellow ');
$io->{'red|green|underline'}(' This is red on green, underlined');
$io->{'+'}('This starts on a new line');
$io->{'.'}('- this ends on a new line');
$io->{'>>'}('This is tabbed, twice!');
$io->{'<'}(' - this backspaces the last character');
$io->writeLine();
$io->{'++>..:146|#CCC|bold|underline'}('A whole mix of parameters');

Support for ANSI codes can be checked with:

if($io->isAnsi()) {
    // do stuff
}

The format of the style prefix is as follows:

<modifiers>foreground?|background?|option1?|option2?...

Modifiers are applied as many times as they appear sequentially.

  • Modifiers:
    • ^ Clear line(s) above
    • + Add lines before
    • . Add lines after
    • > Add tabs before
    • < Backspace previous output
    • ! Considered an error
    • !! Not considered an error
  • Foreground / background
    • black (ANSI)
    • red (ANSI)
    • green (ANSI)
    • yellow (ANSI)
    • blue (ANSI)
    • magenta (ANSI)
    • cyan (ANSI)
    • white (ANSI)
    • reset (ANSI)
    • brightBlack (ANSI)
    • brightRed (ANSI)
    • brightGreen (ANSI)
    • brightYellow (ANSI)
    • brightBlue (ANSI)
    • brightMagenta (ANSI)
    • brightCyan (ANSI)
    • brightWhite (ANSI)
    • :0 to :255 8bit color code
    • #000000 to #FFFFFF 24bit hex color
  • Options
    • bold
    • dim
    • italic
    • underline
    • blink
    • strobe
    • reverse
    • private
    • strike

Note, some options are not or only partially supported on many terminal emulators.

Line control

Directly control lines and the cursor: All of the below methods allow passing a numeric value to control the number of times it should be applied.

$io->newLine(); // Write to a new line
$io->newLine(5); // Write 5 new lines
$io->deleteLine(); // Delete the previous line
$io->clearLine(); // Clear the current line
$io->clearLineBefore(); // Clear the current line from cursor to start
$io->clearLineAfter(); // Clear the current line from cursor to end
$io->backspace(); // Clear the previous character
$io->tab(); // Write \t to output

$io->cursorUp(); // Move cursor up vertically
$io->cursorLineUp(); // Move cursor up to start of previous line
$io->cursorDown(); // Move cursor down vertically
$io->cursorLineDown(); // Move cursor down to start of next line
$io->cursorLeft(); // Move cursor left
$io->cursorRight(); // Move cursor right

$io->setCursor(5); // Set cursor horizontally to index 5
$io->setCursorLine(30, 10); // Set absolute cursor position

[$line, $pos] = $io->getCursor(); // Attempt to get absolute cursor position
$pos = $io->getCursorH(); // Attempt to get horizontal cursor position
$line = $io->getCursorV(); // Attempt to get vertical cursor position

$io->saveCursor(); // Store cursor position in terminal memory
$io->restoreCursor(); // Attempt to restore cursor position from terminal memory

$width = $io->getWidth(); // Get line width of terminal
$height = $io->getHeight(); // Get line height of terminal

stty

Some extended functionality is dependent on stty being available (most Unix emulators).

$io->toggleInputEcho(false); // Hide input characters
$io->toggleInputBuffer(false); // Don't wait on return key for input

stty can be controlled with the following methods:

if($io->hasStty()) {
    $snapshot = $io->snapshotStty(); // Take a snapshot of current settings
    $io->toggleInputEcho(false);
    // do some stuff

    $io->restoreStty($snapshot); // Restore settings
    // or
    $io->resetStty(); // Reset to original settings at the start of execution
}

Widgets

Simplify common use cases with built in widgets:

Question

$answer = $io->newQuestion(
        message: 'How are you?',
        options: ['Great', 'Fine', 'OK'],
        default: 'great'
    )
    ->prompt();


// Or direct..
$answer = $io->ask(
    message: 'How are you?',
    default: 'great'
);

$io->{'..green'}('You are: '.$answer);

Password

$password = $io->newPasswordQuestion(
        message: 'Now enter a password...',
        repeat: true,
        required: true,
    )
    ->prompt();

// Or direct
$password = $io->askPassword(
    message: 'Now enter a password...',
    repeat: true,
    required: true
);

$io->{'..green'}('Your password is: '.$password);

Confirmation

if ($io->confirm(
    message: 'Do you like green?',
    default: true
)) {
    $io->{'..brightGreen'}('Awesome!');
} else {
    $io->{'..brightRed'}('Boo!');
}

Spinner

$io->{'.'}('Progress spinner: ');
$spinner = $io->newSpinner();

for ($i = 0; $i < 60; $i++) {
    usleep(20000);
    $spinner->advance();
}

$spinner->complete('Done!');

Progress bar

$io->{'.'}('Progress bar: ');
$spinner = $io->newProgressBar(
    min: 10,
    max: 50
);

for ($i = 0; $i < 80; $i++) {
    usleep(20000);
    $spinner->advance(($i / 2) + 11);
}

$spinner->complete();

Use Terminus as a PSR Logger

$io->debug('This is a debug');
$io->info('This is an info message');
$io->notice('This is a notice');
$io->success('You\'ve done a success, well done!');
$io->warning('This is a warning');
$io->error('Hold tight, we have an error');
$io->critical('This is CRITICAL');
$io->alert('alert alert alert');
$io->emergency('Oh no this is an emergency!');

Session

Terminus will by default create a standard session communicating via PHP's STDIN, STDOUT and STDERR streams.

You can however customise the session by creating your own and setting it via the main Terminus frontage. See Deliverance Broker for more information about controlling IO streams.

use DecodeLabs\Deliverance;
use DecodeLabs\Terminus\Session;

$io = new Session(
    // The Io Broker is optional, defaults to best fit
    Deliverance::newIoBroker()
        ->addInputProvider($inputStream)
        ->addOutputReceiver($outputStream)
        ->addErrorReceiver($errorStream)
);

Licensing

Terminus is licensed under the MIT License. See LICENSE for the full license text.