Skip to content

Commit 0892ccd

Browse files
committed
Allow registering custom item styles
1 parent db978a6 commit 0892ccd

File tree

6 files changed

+108
-0
lines changed

6 files changed

+108
-0
lines changed

examples/basic.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,50 @@
11
<?php
22

3+
use PhpSchool\CliMenu\Builder\SplitItemBuilder;
34
use PhpSchool\CliMenu\CliMenu;
45
use PhpSchool\CliMenu\Builder\CliMenuBuilder;
6+
use PhpSchool\CliMenu\MenuItem\SelectableItem;
7+
use PhpSchool\CliMenu\Style\SelectableStyle;
58

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

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

15+
class MyItem extends SelectableItem {
16+
17+
};
18+
19+
class MySelectableStyle extends SelectableStyle {
20+
21+
}
22+
23+
$myItem = new MyItem('YO', $itemCallable);
24+
$myItem2 = new MyItem('YO2', $itemCallable);
25+
1226
$menu = (new CliMenuBuilder)
27+
->registerItemStyle(MyItem::class, new MySelectableStyle())
28+
// ->modifyStyle(MySelectableStyle::class, function (MySelectableStyle $style) {
29+
// $style->setUnselectedMarker('[#]');
30+
// })
1331
->setTitle('Basic CLI Menu')
1432
->addItem('First Item', $itemCallable)
1533
->addItem('Second Item', $itemCallable)
1634
->addItem('Third Item', $itemCallable)
1735
->addLineBreak('-')
36+
->addMenuItem($myItem)
37+
->addMenuItem($myItem2)
38+
->addSubMenu('OPT', function (CliMenuBuilder $b) use ($myItem) {
39+
$b->addMenuItem($myItem);
40+
})
41+
->addSplitItem(function (SplitItemBuilder $b) use ($itemCallable, $myItem) {
42+
$b->addItem('FIRST SPLIT', $itemCallable);
43+
$b->addSubMenu('SUB', function (CliMenuBuilder $b) use ($myItem) {
44+
$b->addMenuItem($myItem);
45+
});
46+
$b->addMenuItem($myItem);
47+
})
1848
->build();
1949

2050
$menu->open();

src/Builder/CliMenuBuilder.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
use PhpSchool\CliMenu\MenuStyle;
1919
use PhpSchool\CliMenu\Style\CheckboxStyle;
2020
use PhpSchool\CliMenu\Style\DefaultStyle;
21+
use PhpSchool\CliMenu\Style\ItemStyle;
2122
use PhpSchool\CliMenu\Style\RadioStyle;
2223
use PhpSchool\CliMenu\Style\SelectableStyle;
2324
use PhpSchool\CliMenu\Terminal\TerminalFactory;
2425
use PhpSchool\Terminal\Terminal;
26+
use function PhpSchool\CliMenu\Util\each;
2527

2628
/**
2729
* @author Michael Woodward <[email protected]>
@@ -80,6 +82,11 @@ class CliMenuBuilder
8082
*/
8183
private $autoShortcutsRegex = '/\[(.)\]/';
8284

85+
/**
86+
* @var array
87+
*/
88+
private $extraItemStyles = [];
89+
8390
/**
8491
* @var bool
8592
*/
@@ -187,6 +194,10 @@ public function addSubMenu(string $text, \Closure $callback) : self
187194
$builder->enableAutoShortcuts($this->autoShortcutsRegex);
188195
}
189196

197+
each($this->extraItemStyles, function (int $i, array $extraItemStyle) use ($builder) {
198+
$builder->registerItemStyle($extraItemStyle['class'], $extraItemStyle['style']);
199+
});
200+
190201
$callback($builder);
191202

192203
$menu = $builder->build();
@@ -293,6 +304,10 @@ public function addSplitItem(\Closure $callback) : self
293304
$builder->enableAutoShortcuts($this->autoShortcutsRegex);
294305
}
295306

307+
foreach ($this->extraItemStyles as $extraItemStyle) {
308+
$builder->registerItemStyle($extraItemStyle['class'], $extraItemStyle['style']);
309+
}
310+
296311
$callback($builder);
297312

298313
$this->menu->addItem($splitItem = $builder->build());
@@ -603,4 +618,21 @@ public function modifyRadioStyle(callable $itemCallable) : self
603618

604619
return $this;
605620
}
621+
622+
public function modifyStyle(string $styleClass, callable $itemCallable) : self
623+
{
624+
$itemCallable($this->menu->getItemStyle($styleClass));
625+
626+
return $this;
627+
}
628+
629+
public function registerItemStyle(string $itemClass, ItemStyle $itemStyle) : self
630+
{
631+
$this->menu->getStyleLocator()
632+
->registerItemStyle($itemClass, $itemStyle);
633+
634+
$this->extraItemStyles[] = ['class' => $itemClass, 'style' => $itemStyle];
635+
636+
return $this;
637+
}
606638
}

src/Builder/SplitItemBuilder.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@
55
use PhpSchool\CliMenu\CliMenu;
66
use PhpSchool\CliMenu\MenuItem\CheckboxItem;
77
use PhpSchool\CliMenu\MenuItem\LineBreakItem;
8+
use PhpSchool\CliMenu\MenuItem\MenuItemInterface;
89
use PhpSchool\CliMenu\MenuItem\MenuMenuItem;
910
use PhpSchool\CliMenu\MenuItem\RadioItem;
1011
use PhpSchool\CliMenu\MenuItem\SelectableItem;
1112
use PhpSchool\CliMenu\MenuItem\SplitItem;
1213
use PhpSchool\CliMenu\MenuItem\StaticItem;
14+
use PhpSchool\CliMenu\Style\ItemStyle;
15+
use function \PhpSchool\CliMenu\Util\each;
1316

1417
/**
1518
* @author Aydin Hassan <[email protected]>
@@ -42,6 +45,11 @@ class SplitItemBuilder
4245
*/
4346
private $autoShortcutsRegex = '/\[(.)\]/';
4447

48+
/**
49+
* @var array
50+
*/
51+
private $extraItemStyles = [];
52+
4553
public function __construct(CliMenu $menu)
4654
{
4755
$this->menu = $menu;
@@ -103,6 +111,10 @@ public function addSubMenu(string $text, \Closure $callback) : self
103111
$builder->enableAutoShortcuts($this->autoShortcutsRegex);
104112
}
105113

114+
each($this->extraItemStyles, function (int $i, array $extraItemStyle) use ($builder) {
115+
$builder->registerItemStyle($extraItemStyle['class'], $extraItemStyle['style']);
116+
});
117+
106118
$callback($builder);
107119

108120
$menu = $builder->build();
@@ -117,6 +129,13 @@ public function addSubMenu(string $text, \Closure $callback) : self
117129
return $this;
118130
}
119131

132+
public function addMenuItem(MenuItemInterface $item) : self
133+
{
134+
$this->splitItem->addItem($item);
135+
136+
return $this;
137+
}
138+
120139
public function setGutter(int $gutter) : self
121140
{
122141
$this->splitItem->setGutter($gutter);
@@ -135,6 +154,13 @@ public function enableAutoShortcuts(string $regex = null) : self
135154
return $this;
136155
}
137156

157+
public function registerItemStyle(string $itemClass, ItemStyle $itemStyle) : self
158+
{
159+
$this->extraItemStyles[] = ['class' => $itemClass, 'style' => $itemStyle];
160+
161+
return $this;
162+
}
163+
138164
public function build() : SplitItem
139165
{
140166
return $this->splitItem;

src/CliMenu.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,11 @@ public function getItemStyleForItem(MenuItemInterface $item) : ItemStyle
666666
return $this->itemStyleLocator->getStyleForMenuItem($item);
667667
}
668668

669+
public function getStyleLocator() : Locator
670+
{
671+
return $this->itemStyleLocator;
672+
}
673+
669674
public function importStyles(CliMenu $menu) : void
670675
{
671676
if (!$this->style->hasChangedFromDefaults()) {

src/Style/Exception/InvalidStyle.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,9 @@ public static function unregisteredItem(string $itemClass) : self
2222
{
2323
return new self("Menu item: '$itemClass' does not have a registered style class");
2424
}
25+
26+
public static function itemAlreadyRegistered(string $itemClass) : self
27+
{
28+
return new self("Menu item: '$itemClass' already has a registered style class");
29+
}
2530
}

src/Style/Locator.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,4 +97,14 @@ public function getStyleForMenuItem(MenuItemInterface $item) : ItemStyle
9797

9898
return $this->getStyle($styleClass);
9999
}
100+
101+
public function registerItemStyle(string $itemClass, ItemStyle $itemStyle) : void
102+
{
103+
if (isset($this->itemStyleMap[$itemClass])) {
104+
throw InvalidStyle::itemAlreadyRegistered($itemClass);
105+
}
106+
107+
$this->itemStyleMap[$itemClass] = get_class($itemStyle);
108+
$this->styles[get_class($itemStyle)] = $itemStyle;
109+
}
100110
}

0 commit comments

Comments
 (0)