ФорумПрограммированиеPHP для идиотов → CLI env php- code share

CLI env php- code share

  • AlexanderC

    Сообщения: 270 Репутация: N Группа: Кто попало

    Spritz 15 июня 2012 г. 18:31

    Если кто делал интеракривные(типа шэл) приложения в консольном режиме то сталкивался с проблемой лишних символов когда печатешь в консоль(стрелкики, бэкспэйс, делит итд.),
    дык вот шарю код который немного может помочь. Если есть вопросы о том как он работает- милость прошу. Для работы нужно сделать пару ходов(забыл сказал работает на никс с ncurses)

    passthru("stty sane");
    passthru("stty -icanon");

    … и унлокнуть инпут стрим


    <?php

    /*
    * @author AlexanderC
    */

    namespace Phverbose\CLI;

    use Phverbose\Application;

    class KeyBinder {

    /**
    * Keys map
    *
    * @var array
    */
    private $keyMap;

    /**
    * Backspace char
    *
    * @var string
    */
    private $bckspace;

    /**
    * The keys from the key map
    *
    * @var array
    */
    private $mapKeys;

    /**
    * Array of commands
    *
    * @var array
    */
    private $commandsDump = array();

    /**
    * Main costructor
    */
    function __construct(){
    $this->bckspace = chr(8);

    // set keys map
    $this->keyMap = array(
    chr(27).chr(91).chr(65) => 'up',
    chr(27).chr(91).chr(66) => 'down',
    chr(27).chr(91).chr(68) => 'left',
    chr(27).chr(91).chr(67) => 'right',
    chr(127) => 'bckspace',
    chr(27).chr(91).chr(51).chr(126) => 'del',
    );
    // set keys only
    $this->mapKeys = array_keys($this->keyMap);
    }

    /**
    * Log the previous command
    *
    * @param string $command
    * @return void
    */
    public function logCommand($command){
    array_unshift($this->commandsDump, rtrim((string) $command));
    reset($this->commandsDump);
    }

    /**
    * Check if any from binded keys pressed
    *
    * @param string reference $input
    * @return void
    */
    public function bindKeys(&$input){
    // check for each key
    foreach($this->keyMap as $key => $prefix){
    // case any action for an combination available
    if(false !== strpos($input, $key)){
    // collect garbages
    $input = str_replace($key, '', $input);
    // fire the action
    $action = "{$prefix}Action";
    $this->$action($input, $key);
    }
    }
    }

    /**
    * Hook to remove printed characters
    *
    * @param int $num
    * @param string $input
    * @param bool $delin
    * @return void
    */
    public function removePrintedChars($num, &$input, $delin = false){
    $num = (int) $num;
    // backspace first
    print str_repeat($this->bckspace, $num);
    // than print whitespaces
    print str_repeat(' ', $num);
    // than return
    print str_repeat($this->bckspace, $num);
    // remove from $input
    if(!$delin) return;
    if(($len = strlen($input)) > 1){
    $input = substr($input, 0, $len - $num);
    } else {
    $input = '';
    }
    }

    /**
    * The action for up key press
    *
    * @param string $input
    * @param string $key
    * @return void
    */
    private function upAction(&$input, $key){
    // remove: ^[[A
    $this->removePrintedChars(4, $input);

    if(!empty($this->commandsDump)){
    $this->removePrintedChars(strlen($input), $input, true);
    $current = current($this->commandsDump);
    $input = $current;
    print $current;

    if(next($this->commandsDump) === false){
    reset($this->commandsDump);
    }
    }
    }

    /**
    * Down key action
    *
    * @param type $input
    * @param type $key
    * @return void
    */
    private function downAction(&$input, $key){
    // remove: ^[[B
    $this->removePrintedChars(4, $input);

    if(false !== ($prev = prev($this->commandsDump))){
    $this->removePrintedChars(strlen($input), $input, true);
    $input = $prev;
    print $prev;
    } elseif(isset($this->commandsDump[0])){
    $this->removePrintedChars(strlen($input), $input, true);
    $next = end($this->commandsDump);
    $input = $next;
    print $next;
    }
    }

    /**
    * Get available keys bindings
    *
    * @return array
    */
    public function getKeys(){
    return $this->mapKeys;
    }

    /**
    * The action for backspace
    *
    * @param string $input
    * @param string $key
    * @return void
    */
    private function bckspaceAction(&$input, $key){
    // remove: ^? or ^@
    $this->removePrintedChars(2, $input);

    // print backspace case possible
    if(($len = strlen($input)) > 0){
    $this->removePrintedChars(1, $input, true);
    }
    }

    /**
    * Delete key action
    *
    * @param string $input
    * @param string $key
    * @return void
    */
    private function delAction(&$input, $key){
    // remove: ^[[3~
    $this->removePrintedChars(5, $input);

    $this->removePrintedChars(strlen($input), $input, true);
    }

    /**
    * Action for left arrow press
    *
    * @param string $input
    * @param string $key
    */
    private function leftAction(&$input, $key){
    // remove: ^[[D
    $this->removePrintedChars(4, $input);

    // move back case possible
    if(($len = strlen($input)) > 0){
    if($len == 1){
    $input = "";
    } else {
    $input = substr($input, 0, $len - 1);
    }
    print $key;
    }
    }

    /**
    * Action for right arrow press
    *
    * @param string $input
    * @param string $key
    */
    private function rightAction(&$input, $key){
    // remove: ^[[C
    $this->removePrintedChars(4, $input);

    $input .= " ";
    print $key;
    }
    }

    // AND

    <?php

    /*
    * @author AlexanderC
    */

    namespace Phverbose\CLI;

    use Phverbose\Application;

    class In {
    use \Phverbose\Singleton;

    /**
    * Input dump
    *
    * @var string
    */
    private $in;

    /**
    * Input buffer
    *
    * @var string
    */
    private $buffer = '';

    /**
    * Key binder
    *
    * @var Phverbose\CLI\KeyBinder
    */
    private static $keyBinder;

    /**
    * method use after construct
    *
    * @return void
    */
    private function onAfterConstruct(){
    self::$keyBinder = new KeyBinder;
    }

    /**
    * Write data to the input wrapper
    *
    * @param string $input
    * @return void
    */
    public function write($input){
    $this->in = rtrim($input, " \n");
    }

    /**
    * Read data from input stream
    *
    * @return void
    */
    public function readIn(){
    do {
    $input = fread(STDIN, 1);
    $this->buffer .= $input;
    self::$keyBinder->bindKeys($this->buffer);
    Application::getInstance()->fireEvent('sys.inseq', $input);
    } while($input !== "\n");

    $this->write($this->buffer);
    // log the command
    if($this->is()){
    self::$keyBinder->logCommand($this->in);
    } else {
    Application::getInstance()->printMe();
    }
    $this->buffer = '';
    }

    /**
    * Get input buffer
    *
    * @return string
    */
    public function read(){
    return $this->in;
    }

    /**
    * Check buffer isn't empty
    *
    * @return string
    */
    public function is(){
    return !empty($this->in);
    }

    /**
    * Display buffer on object printing
    *
    * @return string
    */
    public function __toString() {
    return $this->in;
    }
    }

    [/php]

Пожалуйста, авторизуйтесь, чтобы написать комментарий!