-
Notifications
You must be signed in to change notification settings - Fork 106
Inputs #81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Inputs #81
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
f0c075c
Refactor IO
AydinHassan 8e04ad1
CS
AydinHassan f79a18e
Number, Text and Password inputs
AydinHassan 3652302
Fix some static analysis bugs
AydinHassan 06f04c9
Unit tests for inputs
AydinHassan 3ac115b
Remove IO - moved to php-school/terminal
AydinHassan bd8d8a8
Remove IO - moved to php-school/terminal
AydinHassan 19ddd28
Terminal has moved to php-school/terminal
AydinHassan fdcf19e
Bring in php-school/terminal
AydinHassan 2a2e6ed
Refactor to use php-school/terminal
AydinHassan 2b673eb
Remove windows line endings
AydinHassan 03c371a
CS
AydinHassan 422d5e9
Allow decrement to work with negative numbers
AydinHassan 70bf6e5
Allow to set validation failed message in the custom validator
AydinHassan 27779f8
Update password ask example to illustrate custom validation message
AydinHassan 32b500a
Only switch handled controls
AydinHassan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
<?php | ||
|
||
use PhpSchool\CliMenu\CliMenu; | ||
use PhpSchool\CliMenu\CliMenuBuilder; | ||
|
||
require_once(__DIR__ . '/../vendor/autoload.php'); | ||
|
||
$itemCallable = function (CliMenu $menu) { | ||
$username = $menu->askText() | ||
->setPromptText('Enter username') | ||
->setPlaceholderText('alice') | ||
->ask(); | ||
|
||
$age = $menu->askNumber() | ||
->setPromptText('Enter age') | ||
->setPlaceholderText('28') | ||
->ask(); | ||
|
||
$password = $menu->askPassword() | ||
->setPromptText('Enter password') | ||
->ask(); | ||
|
||
var_dump($username->fetch(), $age->fetch(), $password->fetch()); | ||
}; | ||
|
||
$menu = (new CliMenuBuilder) | ||
->setTitle('User Manager') | ||
->addItem('Create New User', $itemCallable) | ||
->addLineBreak('-') | ||
->build(); | ||
|
||
$menu->open(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
use PhpSchool\CliMenu\CliMenu; | ||
use PhpSchool\CliMenu\CliMenuBuilder; | ||
|
||
require_once(__DIR__ . '/../vendor/autoload.php'); | ||
|
||
$itemCallable = function (CliMenu $menu) { | ||
$result = $menu->askNumber() | ||
->setPlaceholderText(10) | ||
->ask(); | ||
|
||
var_dump($result->fetch()); | ||
}; | ||
|
||
$menu = (new CliMenuBuilder) | ||
->setTitle('Basic CLI Menu') | ||
->addItem('Enter number', $itemCallable) | ||
->addItem('Second Item', $itemCallable) | ||
->addItem('Third Item', $itemCallable) | ||
->addLineBreak('-') | ||
->build(); | ||
|
||
$menu->open(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<?php | ||
|
||
use PhpSchool\CliMenu\CliMenu; | ||
use PhpSchool\CliMenu\CliMenuBuilder; | ||
|
||
require_once(__DIR__ . '/../vendor/autoload.php'); | ||
|
||
$itemCallable = function (CliMenu $menu) { | ||
$result = $menu->askPassword() | ||
->setPlaceholderText('') | ||
->setValidator(function ($password) { | ||
if ($password === 'password') { | ||
$this->setValidationFailedText('Password is too weak'); | ||
return false; | ||
} else if (strlen($password) <= 6) { | ||
$this->setValidationFailedText('Password is not long enough'); | ||
return false; | ||
} | ||
|
||
return true; | ||
}) | ||
->ask(); | ||
|
||
var_dump($result->fetch()); | ||
}; | ||
|
||
$menu = (new CliMenuBuilder) | ||
->setTitle('Basic CLI Menu') | ||
->addItem('Enter password', $itemCallable) | ||
->addItem('Second Item', $itemCallable) | ||
->addItem('Third Item', $itemCallable) | ||
->addLineBreak('-') | ||
->build(); | ||
|
||
$menu->open(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
<?php | ||
|
||
use PhpSchool\CliMenu\CliMenu; | ||
use PhpSchool\CliMenu\CliMenuBuilder; | ||
|
||
require_once(__DIR__ . '/../vendor/autoload.php'); | ||
|
||
$itemCallable = function (CliMenu $menu) { | ||
$result = $menu->askText() | ||
->setPlaceholderText('Enter something here') | ||
->ask(); | ||
|
||
var_dump($result->fetch()); | ||
}; | ||
|
||
$menu = (new CliMenuBuilder) | ||
->setTitle('Basic CLI Menu') | ||
->addItem('Enter text', $itemCallable) | ||
->addItem('Second Item', $itemCallable) | ||
->addItem('Third Item', $itemCallable) | ||
->addLineBreak('-') | ||
->build(); | ||
|
||
$menu->open(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,25 +2,34 @@ | |
|
||
namespace PhpSchool\CliMenu; | ||
|
||
use PhpSchool\CliMenu\Dialogue\NumberInput; | ||
use PhpSchool\CliMenu\Exception\InvalidInstantiationException; | ||
use PhpSchool\CliMenu\Exception\InvalidTerminalException; | ||
use PhpSchool\CliMenu\Exception\MenuNotOpenException; | ||
use PhpSchool\CliMenu\Input\InputIO; | ||
use PhpSchool\CliMenu\Input\Number; | ||
use PhpSchool\CliMenu\Input\Password; | ||
use PhpSchool\CliMenu\Input\Text; | ||
use PhpSchool\CliMenu\MenuItem\LineBreakItem; | ||
use PhpSchool\CliMenu\MenuItem\MenuItemInterface; | ||
use PhpSchool\CliMenu\MenuItem\StaticItem; | ||
use PhpSchool\CliMenu\Dialogue\Confirm; | ||
use PhpSchool\CliMenu\Dialogue\Flash; | ||
use PhpSchool\CliMenu\Terminal\TerminalFactory; | ||
use PhpSchool\CliMenu\Terminal\TerminalInterface; | ||
use PhpSchool\CliMenu\Util\StringUtil as s; | ||
use PhpSchool\Terminal\Exception\NotInteractiveTerminal; | ||
use PhpSchool\Terminal\InputCharacter; | ||
use PhpSchool\Terminal\NonCanonicalReader; | ||
use PhpSchool\Terminal\Terminal; | ||
use PhpSchool\Terminal\TerminalReader; | ||
|
||
/** | ||
* @author Michael Woodward <mikeymike.mw@gmail.com> | ||
*/ | ||
class CliMenu | ||
{ | ||
/** | ||
* @var TerminalInterface | ||
* @var Terminal | ||
*/ | ||
protected $terminal; | ||
|
||
|
@@ -62,7 +71,7 @@ class CliMenu | |
public function __construct( | ||
?string $title, | ||
array $items, | ||
TerminalInterface $terminal = null, | ||
Terminal $terminal = null, | ||
MenuStyle $style = null | ||
) { | ||
$this->title = $title; | ||
|
@@ -75,40 +84,33 @@ public function __construct( | |
|
||
/** | ||
* Configure the terminal to work with CliMenu | ||
* | ||
* @throws InvalidTerminalException | ||
*/ | ||
protected function configureTerminal() : void | ||
{ | ||
$this->assertTerminalIsValidTTY(); | ||
|
||
$this->terminal->setCanonicalMode(); | ||
$this->terminal->disableCanonicalMode(); | ||
$this->terminal->disableEchoBack(); | ||
$this->terminal->disableCursor(); | ||
$this->terminal->clear(); | ||
} | ||
|
||
/** | ||
* Revert changes made to the terminal | ||
* | ||
* @throws InvalidTerminalException | ||
*/ | ||
protected function tearDownTerminal() : void | ||
{ | ||
$this->assertTerminalIsValidTTY(); | ||
|
||
$this->terminal->setCanonicalMode(false); | ||
$this->terminal->enableCursor(); | ||
$this->terminal->restoreOriginalConfiguration(); | ||
} | ||
|
||
private function assertTerminalIsValidTTY() : void | ||
{ | ||
if (!$this->terminal->isTTY()) { | ||
throw new InvalidTerminalException( | ||
sprintf('Terminal "%s" is not a valid TTY', $this->terminal->getDetails()) | ||
); | ||
if (!$this->terminal->isInteractive()) { | ||
throw new InvalidTerminalException('Terminal is not interactive (TTY)'); | ||
} | ||
} | ||
|
||
|
||
public function setParent(CliMenu $parent) : void | ||
{ | ||
$this->parent = $parent; | ||
|
@@ -119,7 +121,7 @@ public function getParent() : ?CliMenu | |
return $this->parent; | ||
} | ||
|
||
public function getTerminal() : TerminalInterface | ||
public function getTerminal() : Terminal | ||
{ | ||
return $this->terminal; | ||
} | ||
|
@@ -161,14 +163,28 @@ private function display() : void | |
{ | ||
$this->draw(); | ||
|
||
while ($this->isOpen() && $input = $this->terminal->getKeyedInput()) { | ||
switch ($input) { | ||
case 'up': | ||
case 'down': | ||
$this->moveSelection($input); | ||
$reader = new NonCanonicalReader($this->terminal); | ||
$reader->addControlMappings([ | ||
'^P' => InputCharacter::UP, | ||
'k' => InputCharacter::UP, | ||
'^K' => InputCharacter::DOWN, | ||
'j' => InputCharacter::DOWN, | ||
"\r" => InputCharacter::ENTER, | ||
' ' => InputCharacter::ENTER, | ||
]); | ||
|
||
while ($this->isOpen() && $char = $reader->readCharacter()) { | ||
if (!$char->isHandledControl()) { | ||
continue; | ||
} | ||
|
||
switch ($char->getControl()) { | ||
case InputCharacter::UP: | ||
case InputCharacter::DOWN: | ||
$this->moveSelection($char->getControl()); | ||
$this->draw(); | ||
break; | ||
case 'enter': | ||
case InputCharacter::ENTER: | ||
$this->executeCurrentItem(); | ||
break; | ||
} | ||
|
@@ -183,12 +199,12 @@ protected function moveSelection(string $direction) : void | |
do { | ||
$itemKeys = array_keys($this->items); | ||
|
||
$direction === 'up' | ||
$direction === 'UP' | ||
? $this->selectedItem-- | ||
: $this->selectedItem++; | ||
|
||
if (!array_key_exists($this->selectedItem, $this->items)) { | ||
$this->selectedItem = $direction === 'up' | ||
$this->selectedItem = $direction === 'UP' | ||
? end($itemKeys) | ||
: reset($itemKeys); | ||
} elseif ($this->getSelectedItem()->canSelect()) { | ||
|
@@ -219,12 +235,16 @@ protected function executeCurrentItem() : void | |
* Redraw the menu | ||
*/ | ||
public function redraw() : void | ||
{ | ||
$this->assertOpen(); | ||
$this->draw(); | ||
} | ||
|
||
private function assertOpen() : void | ||
{ | ||
if (!$this->isOpen()) { | ||
throw new MenuNotOpenException; | ||
} | ||
|
||
$this->draw(); | ||
} | ||
|
||
/** | ||
|
@@ -254,7 +274,7 @@ protected function draw() : void | |
$frame->newLine(2); | ||
|
||
foreach ($frame->getRows() as $row) { | ||
echo $row; | ||
$this->terminal->write($row); | ||
} | ||
|
||
$this->currentFrame = $frame; | ||
|
@@ -277,7 +297,7 @@ protected function drawMenuItem(MenuItemInterface $item, bool $selected = false) | |
|
||
return array_map(function ($row) use ($setColour, $unsetColour) { | ||
return sprintf( | ||
"%s%s%s%s%s%s%s\n\r", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dropped this |
||
"%s%s%s%s%s%s%s\n", | ||
str_repeat(' ', $this->style->getMargin()), | ||
$setColour, | ||
str_repeat(' ', $this->style->getPadding()), | ||
|
@@ -359,9 +379,7 @@ public function getCurrentFrame() : Frame | |
|
||
public function flash(string $text) : Flash | ||
{ | ||
if (strpos($text, "\n") !== false) { | ||
throw new \InvalidArgumentException; | ||
} | ||
$this->guardSingleLine($text); | ||
|
||
$style = (new MenuStyle($this->terminal)) | ||
->setBg('yellow') | ||
|
@@ -372,14 +390,52 @@ public function flash(string $text) : Flash | |
|
||
public function confirm($text) : Confirm | ||
{ | ||
if (strpos($text, "\n") !== false) { | ||
throw new \InvalidArgumentException; | ||
} | ||
$this->guardSingleLine($text); | ||
|
||
$style = (new MenuStyle($this->terminal)) | ||
->setBg('yellow') | ||
->setFg('red'); | ||
|
||
return new Confirm($this, $style, $this->terminal, $text); | ||
} | ||
|
||
public function askNumber() : Number | ||
{ | ||
$this->assertOpen(); | ||
|
||
$style = (new MenuStyle($this->terminal)) | ||
->setBg('yellow') | ||
->setFg('red'); | ||
|
||
return new Number(new InputIO($this, $this->terminal), $style); | ||
} | ||
|
||
public function askText() : Text | ||
{ | ||
$this->assertOpen(); | ||
|
||
$style = (new MenuStyle($this->terminal)) | ||
->setBg('yellow') | ||
->setFg('red'); | ||
|
||
return new Text(new InputIO($this, $this->terminal), $style); | ||
} | ||
|
||
public function askPassword() : Password | ||
{ | ||
$this->assertOpen(); | ||
|
||
$style = (new MenuStyle($this->terminal)) | ||
->setBg('yellow') | ||
->setFg('red'); | ||
|
||
return new Password(new InputIO($this, $this->terminal), $style); | ||
} | ||
|
||
private function guardSingleLine($text) | ||
{ | ||
if (strpos($text, "\n") !== false) { | ||
throw new \InvalidArgumentException; | ||
} | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what I mentioned in the
php-school/terminal
PR. If it's not a valid TTY - then there is no name.