Improvements

This commit is contained in:
Christopher Vagnetoft 2016-04-25 20:47:30 +02:00
parent e6f6fbe3d3
commit 0c64bc2f70
5 changed files with 152 additions and 71 deletions

View File

@ -1,46 +0,0 @@
<?php
require_once __DIR__."/../vendor/autoload.php";
use NoccyLabs\Shell\Shell;
class MyShell extends Shell
{
protected $params;
protected function setParam($key, $value=null)
{
$this->params[$key] = $value;
$this->writeln(" ** {$key} = {$value}");
}
protected function configure(array $config)
{
$this->addCommand("set", [$this,"setParam"]);
$this->addCommand("exit", [$this,"stop"]);
}
protected function getPrompt()
{
return "flinger: ";
}
protected function onUpdate()
{
static $lt;
$t = floor(microtime(true));
if ($t > $lt) {
$lt = $t + 5;
echo date("Y-m-d h:i:s")."\n";
}
}
protected function onInput($buffer)
{
}
}
$myShell = new MyShell();
$myShell->run();

58
examples/simple.php Normal file
View File

@ -0,0 +1,58 @@
<?php
require_once __DIR__."/../vendor/autoload.php";
use NoccyLabs\Shell\Shell;
use NoccyLabs\Shell\Command;
class MyCommand extends Command
{
public function getName()
{
return "mycommand";
}
public function execute()
{
$this->writeln("Executing command");
}
}
class MyShell extends Shell
{
protected $seq = 0;
protected function configure(array $config)
{
$this->addCommand("hello", function () {
echo "world\n\rthis\n\ris\n\ra\ntest\n\r";
});
$this->addCommand(new MyCommand());
}
protected function getPrompt()
{
return "test[{$this->seq}]: ";
}
protected function onUpdate()
{
static $lt;
$t = floor(microtime(true));
if ($t > $lt) {
$lt = $t + 5;
echo date("Y-m-d h:i:s")."\n";
}
}
protected function onCommand($buffer)
{
$this->seq++;
parent::onCommand($buffer);
}
}
$myShell = new MyShell();
$myShell->run();
echo "Exiting\n";

38
lib/Command.php Normal file
View File

@ -0,0 +1,38 @@
<?php
namespace NoccyLabs\Shell;
use NoccyLabs\Shell\LineRead;
abstract class Command
{
protected $name;
protected $deescription;
protected $shell;
public function setShell(Shell $shell)
{
$this->shell = $shell;
}
protected function writeln($str)
{
$this->shell->writeln($str);
}
abstract public function getName();
public function getDescription()
{}
public function getHelp()
{}
public function run(array $args)
{
call_user_func_array([$this,"execute"], $args);
}
}

View File

@ -29,13 +29,13 @@ class LineRead
public function __construct() public function __construct()
{ {
stream_set_blocking(STDIN, false); stream_set_blocking(STDIN, false);
$this->sttyOld = exec('stty -g'); $this->sttyOld = trim(exec('stty -g'));
exec('stty raw -echo isig'); exec('stty raw -echo'); // isig');
} }
public function __destruct() public function __destruct()
{ {
exec('stty {$this->sttyOld}'); exec('stty '.$this->sttyOld);
} }
public function update() public function update()
@ -57,8 +57,8 @@ class LineRead
{ {
$prompt = $this->prompt; $prompt = $this->prompt;
$buffer = $this->buffer; $buffer = $this->buffer;
$cursor = strlen($this->prompt) + 2 + $this->posCursor - $this->posScroll; $cursor = strlen($this->prompt) + 1 + $this->posCursor - $this->posScroll;
fprintf(STDOUT, "\r\e[2K\e[36;1;4m%s\e[37;24m %s\e[%dG\e[0m", $prompt, $buffer, $cursor); fprintf(STDOUT, "\r\e[2K\e[32;1m%s\e[37m%s\e[%dG\e[0m", $prompt, $buffer, $cursor);
} }
protected function handleInput() protected function handleInput()
@ -75,6 +75,11 @@ class LineRead
$keyBuffer = substr($keyBuffer, 3); $keyBuffer = substr($keyBuffer, 3);
$this->parseControlCode($ctrlChar); $this->parseControlCode($ctrlChar);
} }
} elseif ($keyBuffer[0]=="\x03") {
$this->posCursor = 0;
$this->buffer = null;
fprintf(STDOUT, "\r\n");
return $keyBuffer[0];
} else { } else {
$keyChar = $keyBuffer[0]; $keyChar = $keyBuffer[0];
$keyCode = ord($keyChar); $keyCode = ord($keyChar);
@ -95,7 +100,7 @@ class LineRead
$returnBuffer = $this->buffer; $returnBuffer = $this->buffer;
$this->buffer = null; $this->buffer = null;
$this->posCursor = 0; $this->posCursor = 0;
printf("\n"); printf("\n\r");
$this->state = self::STATE_IDLE; $this->state = self::STATE_IDLE;
} }
} }
@ -133,4 +138,9 @@ class LineRead
} }
} }
public function setPrompt($prompt)
{
$this->prompt = $prompt;
}
} }

View File

@ -13,26 +13,50 @@ abstract class Shell
abstract protected function configure(array $config); abstract protected function configure(array $config);
public function addCommand($command, callable $handler) public function addCommand($command, callable $handler=null)
{ {
$this->commands[$command] = $handler; if (!$handler) {
if (!($command instanceof Command)) {
throw new \RuntimeException("Handler is not callable nor a Command");
}
$command->setShell($this);
$this->commands[$command->getName()] = $command;
} else {
$this->commands[$command] = $handler;
}
} }
public function execute($command) public function execute($command)
{ {
if (is_array($command)) {
foreach ($command as $cmd) {
$this->execute($cmd);
}
return;
}
$buffer = str_getcsv($command, " ", "\"", "\\"); $buffer = str_getcsv($command, " ", "\"", "\\");
if (count($buffer)>0) { if (count($buffer)>0) {
$this->executeBuffer($buffer); $this->onCommand($buffer);
} }
} }
protected function onCommand($buffer)
{
$this->executeBuffer($buffer);
}
protected function executeBuffer(array $buffer) protected function executeBuffer(array $buffer)
{ {
$commandName = array_shift($buffer); $commandName = array_shift($buffer);
if (array_key_exists($commandName, $this->commands)) { if (array_key_exists($commandName, $this->commands)) {
$command = $this->commands[$commandName]; $command = $this->commands[$commandName];
call_user_func_array($command,$buffer); if ($command instanceof Command) {
$command->run($buffer);
} else {
call_user_func_array($command,$buffer);
}
return; return;
} }
$this->writeln("Bad command: ".$commandName); $this->writeln("Bad command: ".$commandName);
@ -47,35 +71,32 @@ abstract class Shell
{ {
} }
public function run(callable $updateFunc=null) public function run()
{ {
$lineRead = new LineRead(); $lineRead = new LineRead();
$this->running = true; $this->running = true;
do { do {
$lineRead->setPrompt($this->getPrompt());
$buffer = $lineRead->update(); $buffer = $lineRead->update();
ob_start(); if ($buffer == "\x03") {
if (is_callable($updateFunc)) { $this->stop();
call_user_func($updateFunc); continue;
} }
ob_start();
$this->onUpdate(); $this->onUpdate();
if ($buffer !== null) {
$this->execute($buffer);
}
$buf = ob_get_contents(); $buf = ob_get_contents();
ob_end_clean(); ob_end_clean();
if ($buf) { if ($buf) {
$lineRead->erase(); $lineRead->erase();
echo rtrim($buf)."\n"; echo str_replace("\n", "\r\n", rtrim($buf)."\n");
$lineRead->redraw(); $lineRead->redraw();
} }
//$buffer = readline($this->getPrompt()); usleep(10000);
if ($buffer === null) {
usleep(10000);
continue;
} else {
$this->execute($buffer);
}
} while ($this->running); } while ($this->running);
} }