{"id":24016322,"url":"https://github.com/decodelabs/terminus","last_synced_at":"2025-04-15T14:07:37.747Z","repository":{"id":56964554,"uuid":"216921433","full_name":"decodelabs/terminus","owner":"decodelabs","description":"Simple CLI interactions for PHP","archived":false,"fork":false,"pushed_at":"2025-03-24T12:22:51.000Z","size":253,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-03-24T12:53:56.418Z","etag":null,"topics":["cli","console","php","terminal"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/decodelabs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-10-22T22:33:44.000Z","updated_at":"2025-03-24T12:22:55.000Z","dependencies_parsed_at":"2025-02-14T19:28:13.030Z","dependency_job_id":"fa968b62-b4f0-44d3-b576-9a0fb2651d0d","html_url":"https://github.com/decodelabs/terminus","commit_stats":{"total_commits":164,"total_committers":1,"mean_commits":164.0,"dds":0.0,"last_synced_commit":"cc3e4ac8912e4e5880d2d52deb2adae4542a57fc"},"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decodelabs%2Fterminus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decodelabs%2Fterminus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decodelabs%2Fterminus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/decodelabs%2Fterminus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/decodelabs","download_url":"https://codeload.github.com/decodelabs/terminus/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249085438,"owners_count":21210267,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","console","php","terminal"],"created_at":"2025-01-08T08:48:56.529Z","updated_at":"2025-04-15T14:07:37.741Z","avatar_url":"https://github.com/decodelabs.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Terminus\n\n[![PHP from Packagist](https://img.shields.io/packagist/php-v/decodelabs/terminus?style=flat)](https://packagist.org/packages/decodelabs/terminus)\n[![Latest Version](https://img.shields.io/packagist/v/decodelabs/terminus.svg?style=flat)](https://packagist.org/packages/decodelabs/terminus)\n[![Total Downloads](https://img.shields.io/packagist/dt/decodelabs/terminus.svg?style=flat)](https://packagist.org/packages/decodelabs/terminus)\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/decodelabs/terminus/integrate.yml?branch=develop)](https://github.com/decodelabs/terminus/actions/workflows/integrate.yml)\n[![PHPStan](https://img.shields.io/badge/PHPStan-enabled-44CC11.svg?longCache=true\u0026style=flat)](https://github.com/phpstan/phpstan)\n[![License](https://img.shields.io/packagist/l/decodelabs/terminus?style=flat)](https://packagist.org/packages/decodelabs/terminus)\n\n\n### Simple CLI interactions for PHP\n\nTerminus provides everything you need to build highly interactive, beautiful CLI processes.\n\n---\n\n\n## Installation\n```bash\ncomposer require decodelabs/terminus\n```\n\n## Usage\n\n### Writing output\n\nWrite standard text to output:\n\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nCli::write('Normal text'); // no newline\nCli::writeLine(' - end of line'); // with newline\n```\n\nError output works the same way, with \u003ccode\u003eError\u003c/code\u003e in the method name:\n\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nCli::writeError('Error text'); // no newline\nCli::writeErrorLine(' - end of line'); // with newline\n```\n\n### Reading input\n\nRead input from the user:\nNote, PHP by default buffers the input stream so input requires return to be pressed before it can be read.\n\n```php\nuse DecodeLabs\\Terminus as Cli;\n\n$data = Cli::read(3); // Read 3 bytes\n$line = Cli::readLine();\n```\n\nIf the connected terminal supports \u003ccode\u003estty\u003c/code\u003e (most Unix emulators), buffering can be turned off for instant input:\n\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nCli::toggleInputBuffer(false);\nCli::writeLine('Yes or no?')\n$char = Cli::read(1); // y or n\nCli::toggleInputBuffer(true);\n```\n\nMore on extended \u003ccode\u003eANSI\u003c/code\u003e and \u003ccode\u003estty\u003c/code\u003e support below.\n\n\n### Colors and styles\nIf the connected terminal can support \u003ccode\u003eANSI\u003c/code\u003e codes can be styled easily using a handy shortcut on the facade:\n\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nCli::{'blue'}('This is blue ');\nCli::{'yellow'}('This is yellow ');\nCli::{'red|green|underline'}(' This is red on green, underlined');\nCli::{'+'}('This starts on a new line');\nCli::{'.'}('- this ends on a new line');\nCli::{'\u003e\u003e'}('This is tabbed, twice!');\nCli::{'\u003c'}(' - this backspaces the last character');\nCli::writeLine();\nCli::{'++\u003e..:146|#CCC|bold|underline'}('A whole mix of parameters');\n```\n\nSupport for \u003ccode\u003eANSI\u003c/code\u003e codes can be checked with:\n\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nif(Cli::isAnsi()) {\n    // do stuff\n}\n```\n\nThe format of the style prefix is as follows:\n\n\u003ccode\u003e\\\u003cmodifiers\\\u003eforeground?|background?|option1?|option2?...\u003c/code\u003e\n\nModifiers are applied as many times as they appear sequentially.\n\n- Modifiers:\n    - \u003ccode\u003e^\u003c/code\u003e Clear line(s) above\n    - \u003ccode\u003e+\u003c/code\u003e Add lines before\n    - \u003ccode\u003e.\u003c/code\u003e Add lines after\n    - \u003ccode\u003e\\\u003e\u003c/code\u003e Add tabs before\n    - \u003ccode\u003e\\\u003c\u003c/code\u003e Backspace previous output\n    - \u003ccode\u003e!\u003c/code\u003e Considered an error\n    - \u003ccode\u003e!!\u003c/code\u003e Not considered an error\n- Foreground / background\n    - \u003ccode\u003eblack\u003c/code\u003e (ANSI)\n    - \u003ccode\u003ered\u003c/code\u003e (ANSI)\n    - \u003ccode\u003egreen\u003c/code\u003e (ANSI)\n    - \u003ccode\u003eyellow\u003c/code\u003e (ANSI)\n    - \u003ccode\u003eblue\u003c/code\u003e (ANSI)\n    - \u003ccode\u003emagenta\u003c/code\u003e (ANSI)\n    - \u003ccode\u003ecyan\u003c/code\u003e (ANSI)\n    - \u003ccode\u003ewhite\u003c/code\u003e (ANSI)\n    - \u003ccode\u003ereset\u003c/code\u003e (ANSI)\n    - \u003ccode\u003ebrightBlack\u003c/code\u003e (ANSI)\n    - \u003ccode\u003ebrightRed\u003c/code\u003e (ANSI)\n    - \u003ccode\u003ebrightGreen\u003c/code\u003e (ANSI)\n    - \u003ccode\u003ebrightYellow\u003c/code\u003e (ANSI)\n    - \u003ccode\u003ebrightBlue\u003c/code\u003e (ANSI)\n    - \u003ccode\u003ebrightMagenta\u003c/code\u003e (ANSI)\n    - \u003ccode\u003ebrightCyan\u003c/code\u003e (ANSI)\n    - \u003ccode\u003ebrightWhite\u003c/code\u003e (ANSI)\n    - \u003ccode\u003e:0\u003c/code\u003e to \u003ccode\u003e:255\u003c/code\u003e [8bit color code](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit)\n    - \u003ccode\u003e#000000\u003c/code\u003e to \u003ccode\u003e#FFFFFF\u003c/code\u003e 24bit hex color\n- Options\n    - \u003ccode\u003ebold\u003c/code\u003e\n    - \u003ccode\u003edim\u003c/code\u003e\n    - \u003ccode\u003eitalic\u003c/code\u003e\n    - \u003ccode\u003eunderline\u003c/code\u003e\n    - \u003ccode\u003eblink\u003c/code\u003e\n    - \u003ccode\u003estrobe\u003c/code\u003e\n    - \u003ccode\u003ereverse\u003c/code\u003e\n    - \u003ccode\u003eprivate\u003c/code\u003e\n    - \u003ccode\u003estrike\u003c/code\u003e\n\nNote, some options are not or only partially supported on many terminal emulators.\n\n### Line control\n\nDirectly control lines and the cursor:\nAll of the below methods allow passing a numeric value to control the number of times it should be applied.\n\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nCli::newLine(); // Write to a new line\nCli::newLine(5); // Write 5 new lines\nCli::deleteLine(); // Delete the previous line\nCli::clearLine(); // Clear the current line\nCli::clearLineBefore(); // Clear the current line from cursor to start\nCli::clearLineAfter(); // Clear the current line from cursor to end\nCli::backspace(); // Clear the previous character\nCli::tab(); // Write \\t to output\n\nCli::cursorUp(); // Move cursor up vertically\nCli::cursorLineUp(); // Move cursor up to start of previous line\nCli::cursorDown(); // Move cursor down vertically\nCli::cursorLineDown(); // Move cursor down to start of next line\nCli::cursorLeft(); // Move cursor left\nCli::cursorRight(); // Move cursor right\n\nCli::setCursor(5); // Set cursor horizontally to index 5\nCli::setCursorLine(30, 10); // Set absolute cursor position\n\n[$line, $pos] = Cli::getCursor(); // Attempt to get absolute cursor position\n$pos = Cli::getCursorH(); // Attempt to get horizontal cursor position\n$line = Cli::getCursorV(); // Attempt to get vertical cursor position\n\nCli::saveCursor(); // Store cursor position in terminal memory\nCli::restoreCursor(); // Attempt to restore cursor position from terminal memory\n\n$width = Cli::getWidth(); // Get line width of terminal\n$height = Cli::getHeight(); // Get line height of terminal\n```\n\n### stty\nSome extended functionality is dependent on \u003ccode\u003estty\u003c/code\u003e being available (most Unix emulators).\n\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nCli::toggleInputEcho(false); // Hide input characters\nCli::toggleInputBuffer(false); // Don't wait on return key for input\n```\n\n\u003ccode\u003estty\u003c/code\u003e can be controlled with the following methods:\n\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nif(Cli::hasStty()) {\n    $snapshot = Cli::snapshotStty(); // Take a snapshot of current settings\n    Cli::toggleInputEcho(false);\n    // do some stuff\n\n    Cli::restoreStty($snapshot); // Restore settings\n    // or\n    Cli::resetStty(); // Reset to original settings at the start of execution\n}\n```\n\n\n### Widgets\n\nSimplify common use cases with built in widgets:\n\n#### Question\n```php\nuse DecodeLabs\\Terminus as Cli;\n\n$answer = Cli::newQuestion('How are you?')\n    -\u003esetOptions('Great', 'Fine', 'OK')\n    -\u003esetDefaultValue('great')\n    -\u003eprompt();\n\n\n// Or direct..\n$answer = Cli::ask('How are you?', 'great');\n\nCli::{'..green'}('You are: '.$answer);\n```\n\n#### Password\n```php\n$password = Cli::newPasswordQuestion('Now enter a password...')\n    -\u003esetRequired(true)\n    -\u003esetRepeat(true)\n    -\u003eprompt();\n\n// Or direct\n$password = Cli::askPassword('Now enter a password...', true, true);\n\nCli::{'..green'}('Your password is: '.$password);\n```\n\n#### Confirmation\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nif (Cli::confirm('Do you like green?', true)) {\n    Cli::{'..brightGreen'}('Awesome!');\n} else {\n    Cli::{'..brightRed'}('Boo!');\n}\n```\n\n#### Spinner\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nCli::{'.'}('Progress spinner: ');\n$spinner = Cli::newSpinner();\n\nfor ($i = 0; $i \u003c 60; $i++) {\n    usleep(20000);\n    $spinner-\u003eadvance();\n}\n\n$spinner-\u003ecomplete('Done!');\n```\n\n#### Progress bar\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nCli::{'.'}('Progress bar: ');\n$spinner = Cli::newProgressBar(10, 50);\n\nfor ($i = 0; $i \u003c 80; $i++) {\n    usleep(20000);\n    $spinner-\u003eadvance(($i / 2) + 11);\n}\n\n$spinner-\u003ecomplete();\n```\n\n\n### Use Terminus as a PSR Logger\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nCli::debug('This is a debug');\nCli::info('This is an info message');\nCli::notice('This is a notice');\nCli::success('You\\'ve done a success, well done!');\nCli::warning('This is a warning');\nCli::error('Hold tight, we have an error');\nCli::critical('This is CRITICAL');\nCli::alert('alert alert alert');\nCli::emergency('Oh no this is an emergency!');\n```\n\n\n### Argument parsing\nQuickly parse input arguments from the request into the session:\n\n```php\nuse DecodeLabs\\Terminus as Cli;\n\nCli::$command\n    -\u003esetHelp('Test out Terminus functionality')\n    -\u003eaddArgument('action', 'Unnamed action argument')\n    -\u003eaddArgument('?-test|t=Test arg', 'Named test argument with default value');\n\n$action = Cli::$command['action'];\n$test = Cli::$command['test'];\n```\n\n### Session\n\nTerminus will by default create a standard session communicating via PHP's \u003ccode\u003eSTDIN\u003c/code\u003e, \u003ccode\u003eSTDOUT\u003c/code\u003e and \u003ccode\u003eSTDERR\u003c/code\u003e streams, with arguments from \u003ccode\u003e$\\_SERVER['argv']\u003c/code\u003e.\n\nYou can however customise the session by creating your own and setting it via the main \u003ccode\u003eTerminus\u003c/code\u003e frontage.\nSee [Deliverance Broker](https://github.com/decodelabs/atlas) for more information about controlling IO streams.\n\n```php\nuse DecodeLabs\\Deliverance;\nuse DecodeLabs\\Terminus as Cli;\n\n$session = Cli::newSession(\n    Cli::newRequest(['list', 'of', 'argv', 'params']),\n\n    // The Io Broker is optional, defaults to best fit\n    Deliverance::newIoBroker()\n        -\u003eaddInputProvider($inputStream)\n        -\u003eaddOutputReceiver($outputStream)\n        -\u003eaddErrorReceiver($errorStream)\n);\n\nCli::setSession($session);\n```\n\n### Veneer\n\nTerminus uses [Veneer](https://github.com/decodelabs/veneer) to provide a unified frontage under \u003ccode\u003eDecodeLabs\\Terminus\u003c/code\u003e.\nYou can access all the primary functionality via this static frontage without compromising testing and dependency injection.\n\n\n## Licensing\nTerminus is licensed under the MIT License. See [LICENSE](./LICENSE) for the full license text.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdecodelabs%2Fterminus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdecodelabs%2Fterminus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdecodelabs%2Fterminus/lists"}