diff --git a/examples/flinger.php b/examples/flinger.php deleted file mode 100644 index 30ec80b..0000000 --- a/examples/flinger.php +++ /dev/null @@ -1,46 +0,0 @@ -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(); diff --git a/examples/simple.php b/examples/simple.php new file mode 100644 index 0000000..85bc09d --- /dev/null +++ b/examples/simple.php @@ -0,0 +1,58 @@ +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"; diff --git a/lib/Command.php b/lib/Command.php new file mode 100644 index 0000000..ce036fe --- /dev/null +++ b/lib/Command.php @@ -0,0 +1,38 @@ +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); + } +} diff --git a/lib/LineRead.php b/lib/LineRead.php index 6cfee54..a17d392 100644 --- a/lib/LineRead.php +++ b/lib/LineRead.php @@ -29,13 +29,13 @@ class LineRead public function __construct() { stream_set_blocking(STDIN, false); - $this->sttyOld = exec('stty -g'); - exec('stty raw -echo isig'); + $this->sttyOld = trim(exec('stty -g')); + exec('stty raw -echo'); // isig'); } public function __destruct() { - exec('stty {$this->sttyOld}'); + exec('stty '.$this->sttyOld); } public function update() @@ -57,8 +57,8 @@ class LineRead { $prompt = $this->prompt; $buffer = $this->buffer; - $cursor = strlen($this->prompt) + 2 + $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); + $cursor = strlen($this->prompt) + 1 + $this->posCursor - $this->posScroll; + fprintf(STDOUT, "\r\e[2K\e[32;1m%s\e[37m%s\e[%dG\e[0m", $prompt, $buffer, $cursor); } protected function handleInput() @@ -75,6 +75,11 @@ class LineRead $keyBuffer = substr($keyBuffer, 3); $this->parseControlCode($ctrlChar); } + } elseif ($keyBuffer[0]=="\x03") { + $this->posCursor = 0; + $this->buffer = null; + fprintf(STDOUT, "\r\n"); + return $keyBuffer[0]; } else { $keyChar = $keyBuffer[0]; $keyCode = ord($keyChar); @@ -95,7 +100,7 @@ class LineRead $returnBuffer = $this->buffer; $this->buffer = null; $this->posCursor = 0; - printf("\n"); + printf("\n\r"); $this->state = self::STATE_IDLE; } } @@ -133,4 +138,9 @@ class LineRead } } + public function setPrompt($prompt) + { + $this->prompt = $prompt; + } + } diff --git a/lib/Shell.php b/lib/Shell.php index ae19cfd..778f6d9 100644 --- a/lib/Shell.php +++ b/lib/Shell.php @@ -13,26 +13,50 @@ abstract class Shell 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) { + if (is_array($command)) { + foreach ($command as $cmd) { + $this->execute($cmd); + } + return; + } + $buffer = str_getcsv($command, " ", "\"", "\\"); if (count($buffer)>0) { - $this->executeBuffer($buffer); + $this->onCommand($buffer); } } + + protected function onCommand($buffer) + { + $this->executeBuffer($buffer); + } protected function executeBuffer(array $buffer) { $commandName = array_shift($buffer); if (array_key_exists($commandName, $this->commands)) { $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; } $this->writeln("Bad command: ".$commandName); @@ -47,35 +71,32 @@ abstract class Shell { } - public function run(callable $updateFunc=null) + public function run() { $lineRead = new LineRead(); $this->running = true; - - - + do { + $lineRead->setPrompt($this->getPrompt()); $buffer = $lineRead->update(); - ob_start(); - if (is_callable($updateFunc)) { - call_user_func($updateFunc); + if ($buffer == "\x03") { + $this->stop(); + continue; } + ob_start(); $this->onUpdate(); + if ($buffer !== null) { + $this->execute($buffer); + } $buf = ob_get_contents(); ob_end_clean(); if ($buf) { $lineRead->erase(); - echo rtrim($buf)."\n"; + echo str_replace("\n", "\r\n", rtrim($buf)."\n"); $lineRead->redraw(); } - //$buffer = readline($this->getPrompt()); - if ($buffer === null) { - usleep(10000); - continue; - } else { - $this->execute($buffer); - } + usleep(10000); } while ($this->running); }