cli-menu

🖥 Build beautiful PHP CLI menus. Simple yet Powerful. Expressive DSL.

Subscribe to updates I use cli-menu


Statistics on cli-menu

Number of watchers on Github 1272
Number of open issues 8
Average time to close an issue about 2 months
Main language PHP
Average time to merge a PR about 11 hours
Open pull requests 1+
Closed pull requests 1+
Last commit 3 months ago
Repo Created over 2 years ago
Repo Last Updated 2 months ago
Size 178 KB
Homepage http://www.phpsch...
Organization / Authorphp-school
Latest Release2.1.0
Contributors5
Page Updated
Do you use cli-menu? Leave a review!
View open issues (8)
View cli-menu activity
View TODOs for cli-menu (4)
View on github
Latest Open Source Launches
Trendy new open source projects in your inbox! View examples

Subscribe to our mailing list

Evaluating cli-menu for your project? Score Explanation
Commits Score (?)
Issues & PR Score (?)


Contents

Installation

composer require php-school/cli-menu

Usage

Quick Setup

Here is a super basic example menu which will echo out the text of the selected item to get you started.

<?php

use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\CliMenuBuilder;

require_once(__DIR__ . '/../vendor/autoload.php');

$itemCallable = function (CliMenu $menu) {
    echo $menu->getSelectedItem()->getText();
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable)
    ->addItem('Third Item', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

Examples

Check out the examples directory and run them to check out what is possible!

Basic Menu

basic

Basic Menu with separation

basic-seperation

Menu with crazy separation

crazy-seperation

Custom Styles

custom-styles

Useful Separation

useful-seperation

Item Extra

item-extra

Remove Defaults

remove-defaults

Submenu

submenu submenu-options

Disabled Items & Submenus

submenu

Flash Dialogue

submenu

Confirm Dialogue

submenu

API

The CliMenu object is constructed via the Builder class

$menu = (new CliMenuBuilder)
    /**
     *  Customise
    **/
    ->build();

Once you have a menu object, you can open and close it like so:

$menu->open();
$menu->close();

Appearance

You can change the foreground and background colour of the menu to any of the following colours:

  • black
  • red
  • green
  • yellow
  • blue
  • magenta
  • cyan
  • white
$menu = (new CliMenuBuilder)
    ->setForegroundColour('green')
    ->setBackgroundColour('black')
    ->build();

The width, padding and margin can also be customised:

$menu = (new CliMenuBuilder)
    ->setWidth(200)
    ->setPadding(10)
    ->setMargin(5)
    ->build();

Modify the exit button text:

$menu = (new CliMenuBuilder)
    ->setExitButtonText("Don't you want me baby?")
    ->build();

You can remove the exit button altogether:

$menu = (new CliMenuBuilder)
    ->disableDefaultItems()
    ->build();

Note: This will also disable the Go Back button for sub menus.

The marker displayed by the side of the currently active item can be modified, UTF-8 characters are supported. The marker for un-selected items can also be modified. If you want to disable it, just set it to a space character.

$menu = (new CliMenuBuilder)
    ->setUnselectedMarker('')
    ->setSelectedMarker('')

    //disable unselected marker
    ->setUnselectedMarker(' ')
    ->build();

You can give your menu a title and you can customise the separator, a line which displays under the title. Whatever string you pass to setTitleSeparator will be repeated for the width of the Menu.

$menu = (new CliMenuBuilder)
    ->setTitle('One Menu to rule them all!')
    ->setTitleSeparator('*-')
    ->build();

Item Extra

You can optionally display some arbitrary text on the right hand side of an item. You can customise this text and you indicate which items to display it on. We use it to display [COMPLETED] on completed exercises, where the menu lists exercises for a workshop application.

The third parameter to addItem is a boolean whether to show the item extra or not. It defaults to false.

$menu = (new CliMenuBuilder)
    ->setItemExtra('')
    ->addItem('Exercise 1', function (CliMenu $menu) { echo 'I am complete!'; }, true)
    ->build();

Items

There a few different types of items you can add to your menu

  • Selectable Item - This is the type of item you need for something to be selectable (you can hit enter and it will call your invokable)
  • Line Break Item - This is used to break up areas, it can span multiple lines and will be the width of Menu. Whatever string is passed will be repeated.
  • Static Item - This will print whatever text is passed, useful for headings.
  • Ascii Art Item - Special item which allows usage of Ascii art. It takes care of padding and alignment.
  • Sub Menu Item - Special item to allow an item to open another menu. Useful for an options menu.

Selectable Item

$menu = (new CliMenuBuilder)
    ->addItem('The Item Text', function (CliMenu $menu) { 
        echo 'I am alive!'; 
    })
    ->build();

You can add multiple items at once like so:

$callable = function (CliMenu $menu) {
    echo 'I am alive!';
};

$menu = (new CliMenuBuilder)
    ->addItems([
        ['Item 1', $callable],
        ['Item 2', $callable],
        ['Item 3', $callable],
    ])
    ->build();

Note: You can add as many items as you want and they can all have a different action. The action is the separate parameter and must be a valid PHP callable. Try using an Invokable class to keep your actions easily testable.

Line Break Item

$menu = (new CliMenuBuilder)
    ->addLineBreak('<3', 2)
    ->build();

The above would repeat the character sequence <3 across the Menu for 2 lines

Static Item

Static items are similar to Line Breaks, however, they don't repeat and fill. It is output as is. If the text is longer than the width of the Menu, it will be continued on the next line.

$menu = (new CliMenuBuilder)
    ->addStaticItem('AREA 1')
    //add some items here
    ->addStaticItem('AREA 2')
    //add some boring items here
    ->addStaticItem('AREA 51')
    //add some top secret items here 
    ->build();

Ascii Art Item

The following will place the Ascii art in the centre of your menu. Use these constants to alter the alignment:

  • AsciiArtItem::POSITION_CENTER
  • AsciiArtItem::POSITION_LEFT
  • AsciiArtItem::POSITION_RIGHT

$art = <<<ART
        _ __ _
       / |..| \
       \/ || \/
        |_''_|
      PHP SCHOOL
LEARNING FOR ELEPHANTS
ART;

$menu = (new CliMenuBuilder)
    ->addAsciiArt($art, AsciiArtItem::POSITION_CENTER)
    ->build();

Sub Menu Item

Sub Menus are really powerful! You can add Menus to Menus, whattttt?? You can have your main menu and then an options menu. The options item will look like a normal item except when you hit it, you will enter to another menu, which can have different styles and colours!


$callable = function (CliMenu $menu) {
    echo "I'm just a boring selectable item";
};

$menu = (new CliMenuBuilder)
    ->addItem('Normal Item', $callable)
    ->addSubMenu('Super Sub Menu')
        ->setTitle('Behold the awesomeness')
        ->addItem(/** **/)
        ->end()
    ->build();

In this example a single sub menu will be created. Upon entering the sub menu, you will be able to return to the main menu or exit completely. A Go Back button will be automatically added, you can customise this text like so:

->addSubMenu('Super Sub Menu')
    ->setTitle('Behold the awesomeness')
    ->setGoBackButtonText('Descend to chaos')

There are a few things to note about the syntax and builder process here

  1. addSubMenu returns an instance of CliMenuBuilder so you can can customise exactly the same way you would the parent.
  2. If you do not modify the styles of the sub menu (eg, colours) it will inherit styles from the parent!
  3. You can call end() on the sub menu CliMenuBuilder instance to get the parent CliMenuBuilder back again. This is useful for chaining.

If you need the CliMenu instance of the Sub Menu you can grab it after the main menu has been built.

$mainMenuBuilder = new CliMenuBuilder;
$subMenuBuilder = $mainMenuBuilder->addSubMenu('Super Sub Menu');

$menu = $mainMenuBuilder->build();
$subMenu = $mainMenuBuilder->getSubMenu('Super Sub Menu');

You can only do this after the main menu has been built, this is because the main menu builder takes care of building all sub menus.

Disabling Items & Sub Menus

In this example we are disabling certain items and a submenu but still having them shown in the output.

$itemCallable = function (CliMenu $menu) {
    echo $menu->getSelectedItem()->getText();
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu Disabled Items')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable, false, true)
    ->addItem('Third Item', $itemCallable, false, true)
    ->addSubMenu('Submenu')
        ->setTitle('Basic CLI Menu Disabled Items > Submenu')
        ->addItem('You can go in here!', $itemCallable)
        ->end()
    ->addSubMenu('Disabled Submenu')
        ->setTitle('Basic CLI Menu Disabled Items > Disabled Submenu')
        ->addItem('Nope can\'t see this!', $itemCallable)
        ->disableMenu()
        ->end()
    ->addLineBreak('-')
    ->build();

The third param on the ->addItem call is what disables an item while the ->disableMenu() call disables the relevent menu.

The outcome is a full menu with dimmed rows to denote them being disabled. When a user navigates these items are jumped over to the next available selectable item.

Redrawing the menu

You can modify the menu and its style when executing an action and then you can redraw it! In this example we will toggle the background colour in an action.

$itemCallable = function (CliMenu $menu) {
    $menu->getStyle()->setBg($menu->getStyle()->getBg() === 'red' ? 'blue' : 'red');
    $menu->redraw();
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable)
    ->addItem('Third Item', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

Getting, Removing and Adding items

You can also interact with the menu items in an action:

use PhpSchool\CliMenu\MenuItem\LineBreakItem;

require_once(__DIR__ . '/../vendor/autoload.php');

$itemCallable = function (CliMenu $menu) {
    foreach ($menu->getItems() as $item) {
        $menu->removeItem($item);
    }

    $menu->addItem(new LineBreakItem('-'));

    $menu->redraw();
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable)
    ->addItem('Third Item', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

Dialogues

Flash

Show a one line message over the top of the menu. It has a separate style object which is colored by default different to the menu. It can be modified to suit your own style. The dialogue is dismissed with any key press. In the example below we change the background color on the flash to green.

use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\CliMenuBuilder;

require_once(__DIR__ . '/../vendor/autoload.php');

$itemCallable = function (CliMenu $menu) {
    $flash = $menu->flash("PHP School FTW!!");
    $flash->getStyle()->setBg('green');
    $flash->display();
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable)
    ->addItem('Third Item', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();
Confirm

Prompts are very similar to flashes except that a button is shown which has to be selected to dismiss them. The button text can be customised.

use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\CliMenuBuilder;

require_once(__DIR__ . '/../vendor/autoload.php');

$itemCallable = function (CliMenu $menu) {
    $menu->confirm('PHP School FTW!')
        ->display('OK!');
};

$menu = (new CliMenuBuilder)
    ->setTitle('Basic CLI Menu')
    ->addItem('First Item', $itemCallable)
    ->addItem('Second Item', $itemCallable)
    ->addItem('Third Item', $itemCallable)
    ->addLineBreak('-')
    ->build();

$menu->open();

Once you get going you might just end up with something that looks a little like this...

Learn You PHP CLI Menu

You can see the construction code here for more clarity on how to perform advanced configuration: PHP School

Docs Translations

(This might not be kept up-to-date since it's a community translation) See this doc in Brazilian Portuguese (pt_BR)

Integrations

cli-menu open issues Ask a question     (View All Issues)
  • over 1 year Prompt Dialogue
  • over 1 year Consistant API documentation in README
  • over 1 year What about Hoa\Console
  • over 1 year Improve test coverage of CliMenu
  • about 2 years Option to not clear the terminal window
  • about 2 years Usage with symfony/console
  • over 2 years Don't output ascii art if it doesn't fit
cli-menu open pull requests (View All Pulls)
  • Improved confirm
cli-menu questions on Stackoverflow (View All Questions)
  • CLI menu for programming assignments, dividing code into chunks
  • Python CLI Menu
cli-menu list of languages used
cli-menu latest release notes
2.1.0 2.1.0

[2.1.0]

Changed

  • Use new static for submenu to allow subclassing (#68)

Added

  • Add emacs style up/down shortcuts ctrl+n and ctrl+p (#67)
2.0.2 2.0.2

[2.0.2]

Fixed

  • Don't output ascii art if the terminal width is too small (#63)
2.0.1 2.0.1

[2.0.1]

Fixed

  • Reset array keys after removing an item from the menu (#61)
Other projects in PHP