Skip to content

Commit

Permalink
Merge 45c1848 into 83fbce5
Browse files Browse the repository at this point in the history
  • Loading branch information
AydinHassan committed Apr 4, 2019
2 parents 83fbce5 + 45c1848 commit 371d9b2
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 6 deletions.
34 changes: 34 additions & 0 deletions examples/shortcuts.php
@@ -0,0 +1,34 @@
<?php

use PhpSchool\CliMenu\Builder\SplitItemBuilder;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\Builder\CliMenuBuilder;

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

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

$menu = (new CliMenuBuilder)
->disableAutoShortcuts()
->setTitle('Basic CLI Menu')
->addItem('[F]irst Item', $itemCallable)
->addItem('Se[c]ond Item', $itemCallable)
->addItem('Third [I]tem', $itemCallable)
->addSubMenu('[O]ptions', function (CliMenuBuilder $b) {
$b->setTitle('CLI Menu > Options')
->addItem('[F]irst option', function (CliMenu $menu) {
echo sprintf('Executing option: %s', $menu->getSelectedItem()->getText());
})
->addLineBreak('-');
})
->addSplitItem(function (SplitItemBuilder $b) {
$b->addItem('Split Item [1]', function() { echo 'Split Item 1!'; })
->addItem('Split Item [2]', function() { echo 'Split Item 2!'; })
->addItem('Split Item [3]', function() { echo 'Split Item 3!'; });
})
->addLineBreak('-')
->build();

$menu->open();
80 changes: 75 additions & 5 deletions src/Builder/CliMenuBuilder.php
Expand Up @@ -10,6 +10,7 @@
use PhpSchool\CliMenu\MenuItem\MenuMenuItem;
use PhpSchool\CliMenu\MenuItem\SelectableItem;
use PhpSchool\CliMenu\CliMenu;
use PhpSchool\CliMenu\MenuItem\SplitItem;
use PhpSchool\CliMenu\MenuItem\StaticItem;
use PhpSchool\CliMenu\MenuStyle;
use PhpSchool\CliMenu\Terminal\TerminalFactory;
Expand Down Expand Up @@ -56,6 +57,14 @@ class CliMenuBuilder
*/
private $disabled = false;

/**
* Whether or not to auto create keyboard shortcuts for items
* when they contain square brackets. Eg: [M]y item
*
* @var bool
*/
private $autoShortcuts = true;

/**
* @var bool
*/
Expand Down Expand Up @@ -87,6 +96,8 @@ public function addMenuItem(MenuItemInterface $item) : self
{
$this->menu->addItem($item);

$this->processItemShortcut($item);

return $this;
}

Expand Down Expand Up @@ -147,12 +158,14 @@ public function addSubMenu(string $text, \Closure $callback) : self
$menu->setStyle($this->menu->getStyle());
}

$this->menu->addItem(new MenuMenuItem(
$this->menu->addItem($item = new MenuMenuItem(
$text,
$menu,
$builder->isMenuDisabled()
));


$this->processItemShortcut($item);

return $this;
}

Expand All @@ -167,24 +180,81 @@ public function addSubMenuFromBuilder(string $text, CliMenuBuilder $builder) : s
$menu->setStyle($this->menu->getStyle());
}

$this->menu->addItem(new MenuMenuItem(
$this->menu->addItem($item = new MenuMenuItem(
$text,
$menu,
$builder->isMenuDisabled()
));

$this->processItemShortcut($item);

return $this;
}

public function disableAutoShortcuts() : self
{
$this->autoShortcuts = false;

return $this;
}

private function extractShortcut(string $title) : ?string
{
preg_match('/\[(.)\]/', $title, $match);
return isset($match[1]) ? strtolower($match[1]) : null;
}

private function processItemShortcut(MenuItemInterface $item) : void
{
$this->processIndividualShortcut($item, function (CliMenu $menu) use ($item) {
$menu->executeAsSelected($item);
});
}

private function processSplitItemShortcuts(SplitItem $splitItem) : void
{
foreach ($splitItem->getItems() as $item) {
$this->processIndividualShortcut($item, function (CliMenu $menu) use ($splitItem, $item) {
$current = $splitItem->getSelectedItemIndex();

$splitItem->setSelectedItemIndex(
array_search($item, $splitItem->getItems(), true)
);

$menu->executeAsSelected($splitItem);

if ($current !== null) {
$splitItem->setSelectedItemIndex($current);
}
});
}
}

private function processIndividualShortcut(MenuItemInterface $item, callable $callback) : void
{
if (!$this->autoShortcuts) {
return;
}

if ($shortcut = $this->extractShortcut($item->getText())) {
$this->menu->addCustomControlMapping(
$shortcut,
$callback
);
}
}

public function addSplitItem(\Closure $callback) : self
{
$builder = new SplitItemBuilder($this->menu);

$callback = $callback->bindTo($builder);
$callback($builder);

$this->menu->addItem($builder->build());

$this->menu->addItem($splitItem = $builder->build());

$this->processSplitItemShortcuts($splitItem);

return $this;
}

Expand Down
19 changes: 19 additions & 0 deletions src/CliMenu.php
Expand Up @@ -379,6 +379,25 @@ public function getSelectedItem() : MenuItemInterface
: $item;
}

public function setSelectedItem(MenuItemInterface $item) : void
{
$key = array_search($item, $this->items, true);

if (false === $key) {
throw new \InvalidArgumentException('Item does not exist in menu');
}

$this->selectedItem = $key;
}

public function executeAsSelected(MenuItemInterface $item) : void
{
$current = $this->items[$this->selectedItem];
$this->setSelectedItem($item);
$this->executeCurrentItem();
$this->setSelectedItem($current);
}

/**
* Execute the current item
*/
Expand Down
2 changes: 1 addition & 1 deletion test/Builder/CliMenuBuilderTest.php
Expand Up @@ -779,7 +779,7 @@ public function testAddSplitItemWithClosureBinding() : void

$this->checkItems($menu->getItems()[0]->getItems(), $expected);
}

private function checkMenuItems(CliMenu $menu, array $expected) : void
{
$this->checkItems($this->readAttribute($menu, 'items'), $expected);
Expand Down

0 comments on commit 371d9b2

Please sign in to comment.