예제 #1
0
 /**
  * Tab binding.
  *
  * @param   \Hoa\Console\Readline  $self    Self.
  * @return  int
  */
 public function _bindTab(Readline $self)
 {
     $autocompleter = $self->getAutocompleter();
     $state = static::STATE_CONTINUE | static::STATE_NO_ECHO;
     if (null === $autocompleter) {
         return $state;
     }
     $current = $self->getLineCurrent();
     $line = $self->getLine();
     if (0 === $current) {
         return $state;
     }
     $matches = preg_match_all('#' . $autocompleter->getWordDefinition() . '#u', $line, $words, PREG_OFFSET_CAPTURE);
     if (0 === $matches) {
         return $state;
     }
     for ($i = 0, $max = count($words[0]); $i < $max && $current > $words[0][$i][1]; ++$i) {
     }
     $word = $words[0][$i - 1];
     if ('' === trim($word[0])) {
         return $state;
     }
     $prefix = mb_substr($word[0], 0, $current - $word[1]);
     $solution = $autocompleter->complete($prefix);
     $length = mb_strlen($prefix);
     if (null === $solution) {
         return $state;
     }
     if (is_array($solution)) {
         $_solution = $solution;
         $count = count($_solution) - 1;
         $cWidth = 0;
         $window = Console\Window::getSize();
         $wWidth = $window['x'];
         $cursor = Console\Cursor::getPosition();
         array_walk($_solution, function (&$value) use(&$cWidth) {
             $handle = mb_strlen($value);
             if ($handle > $cWidth) {
                 $cWidth = $handle;
             }
             return;
         });
         array_walk($_solution, function (&$value) use(&$cWidth) {
             $handle = mb_strlen($value);
             if ($handle >= $cWidth) {
                 return;
             }
             $value .= str_repeat(' ', $cWidth - $handle);
             return;
         });
         $mColumns = (int) floor($wWidth / ($cWidth + 2));
         $mLines = (int) ceil(($count + 1) / $mColumns);
         --$mColumns;
         $i = 0;
         if (0 > $window['y'] - $cursor['y'] - $mLines) {
             Console\Window::scroll('↑', $mLines);
             Console\Cursor::move('↑', $mLines);
         }
         Console\Cursor::save();
         Console\Cursor::hide();
         Console\Cursor::move('↓ LEFT');
         Console\Cursor::clear('↓');
         foreach ($_solution as $j => $s) {
             echo "", $s, "";
             if ($i++ < $mColumns) {
                 echo '  ';
             } else {
                 $i = 0;
                 if (isset($_solution[$j + 1])) {
                     echo "\n";
                 }
             }
         }
         Console\Cursor::restore();
         Console\Cursor::show();
         ++$mColumns;
         $read = [STDIN];
         $mColumn = -1;
         $mLine = -1;
         $coord = -1;
         $unselect = function () use(&$mColumn, &$mLine, &$coord, &$_solution, &$cWidth) {
             Console\Cursor::save();
             Console\Cursor::hide();
             Console\Cursor::move('↓ LEFT');
             Console\Cursor::move('→', $mColumn * ($cWidth + 2));
             Console\Cursor::move('↓', $mLine);
             echo "" . $_solution[$coord] . "";
             Console\Cursor::restore();
             Console\Cursor::show();
             return;
         };
         $select = function () use(&$mColumn, &$mLine, &$coord, &$_solution, &$cWidth) {
             Console\Cursor::save();
             Console\Cursor::hide();
             Console\Cursor::move('↓ LEFT');
             Console\Cursor::move('→', $mColumn * ($cWidth + 2));
             Console\Cursor::move('↓', $mLine);
             echo "" . $_solution[$coord] . "";
             Console\Cursor::restore();
             Console\Cursor::show();
             return;
         };
         $init = function () use(&$mColumn, &$mLine, &$coord, &$select) {
             $mColumn = 0;
             $mLine = 0;
             $coord = 0;
             $select();
             return;
         };
         while (true) {
             @stream_select($read, $write, $except, 30, 0);
             if (empty($read)) {
                 $read = [STDIN];
                 continue;
             }
             switch ($char = $self->_read()) {
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = max(0, $coord - $mColumns);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = min($count, $coord + $mColumns);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "\t":
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = min($count, $coord + 1);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = max(0, $coord - 1);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "\n":
                     if (-1 !== $mColumn && -1 !== $mLine) {
                         $tail = mb_substr($line, $current);
                         $current -= $length;
                         $self->setLine(mb_substr($line, 0, $current) . $solution[$coord] . $tail);
                         $self->setLineCurrent($current + mb_strlen($solution[$coord]));
                         Console\Cursor::move('←', $length);
                         echo $solution[$coord];
                         Console\Cursor::clear('→');
                         echo $tail;
                         Console\Cursor::move('←', mb_strlen($tail));
                     }
                 default:
                     $mColumn = -1;
                     $mLine = -1;
                     $coord = -1;
                     Console\Cursor::save();
                     Console\Cursor::move('↓ LEFT');
                     Console\Cursor::clear('↓');
                     Console\Cursor::restore();
                     if ("" !== $char && "\n" !== $char) {
                         $self->setBuffer($char);
                         return $self->_readLine($char);
                     }
                     break 2;
             }
         }
         return $state;
     }
     $tail = mb_substr($line, $current);
     $current -= $length;
     $self->setLine(mb_substr($line, 0, $current) . $solution . $tail);
     $self->setLineCurrent($current + mb_strlen($solution));
     Console\Cursor::move('←', $length);
     echo $solution;
     Console\Cursor::clear('→');
     echo $tail;
     Console\Cursor::move('←', mb_strlen($tail));
     return $state;
 }
예제 #2
0
파일: Readliner.php 프로젝트: alexpw/boris
 /**
  * Tab binding.
  *
  * @access  public
  * @param   Readline  $self    Self.
  * @return  int
  */
 public function _bindTab(Readline $self)
 {
     $autocompleter = $self->getAutocompleter();
     $state = static::STATE_CONTINUE | static::STATE_NO_ECHO;
     if (null === $autocompleter) {
         return $state;
     }
     $current = $self->getLineCurrent();
     $line = $self->getLine();
     // we need at least 1 char to work with
     // and if it's the start of a line, we'll echo it.
     if (0 === $current || trim($line) === '') {
         $this->appendLine("\t");
         $this->_buffer .= "\t";
         return static::STATE_CONTINUE;
     }
     $matches = preg_match_all('#' . $autocompleter->getWordDefinition() . '#u', $line, $words, PREG_OFFSET_CAPTURE);
     if (0 === $matches) {
         return $state;
     }
     for ($i = 0, $max = count($words[1]); $i < $max && $current > $words[1][$i][1]; ++$i) {
     }
     $word = $words[1][$i - 1];
     if ('' === trim($word[0])) {
         return $state;
     }
     $prefix = mb_substr($word[0], 0, $current - $word[1]);
     //Debug::log('prefix', compact('line','current','words','word','prefix'));
     $solution = $autocompleter->complete($prefix);
     #Debug::log('solution', $solution);
     if (null === $solution || empty($solution)) {
         return $state;
     }
     if (preg_match('/[\\S]+([\\W]+)([\\S]*)/', $prefix, $m, PREG_OFFSET_CAPTURE)) {
         #Debug::log('matchPrefix', compact('prefix', 'm'));
         $suffixLength = mb_strlen($m[2][0]);
         $prefix = mb_substr($prefix, -$suffixLength);
         $tail = mb_substr($line, $current);
         $head = mb_substr($line, 0, $current - $suffixLength);
         $line = $head . $tail;
         $current -= $suffixLength;
         $length = $suffixLength;
     } else {
         $length = mb_strlen($prefix);
         $tail = mb_substr($line, $current);
         $head = mb_substr($line, 0, $current - $length);
         $line = $head . $tail;
         $current -= $length;
     }
     #Debug::log('completionSetup', compact('prefix','line','current','head','tail','length'));
     if (is_array($solution)) {
         if (count($solution) === 1) {
             $line = $head . $solution[0] . $tail;
             $self->setLine($line);
             $self->setLineCurrent($current + mb_strlen($solution[0]));
             $self->setBuffer($line);
             Cursor::move('left', $length);
             echo $solution[0];
             Cursor::clear('right');
             echo $tail;
             Cursor::move('left', mb_strlen($tail));
             #Debug::log('completion', array(
             #  'line'    =>$self->getLine(),
             #  'current' =>$self->getLineCurrent(),
             #  'buffer'  =>$self->getBuffer(),
             #));
             return $state;
         }
         $_solution = $solution;
         $window = Window::getSize();
         $cursor = Cursor::getPosition();
         $wWidth = $window['x'];
         while (1) {
             $count = count($_solution) - 1;
             $cWidth = 0;
             array_walk($_solution, function ($value) use(&$cWidth) {
                 $handle = mb_strlen($value);
                 if ($handle > $cWidth) {
                     $cWidth = $handle;
                 }
             });
             array_walk($_solution, function (&$value) use($cWidth) {
                 $handle = mb_strlen($value);
                 if ($handle < $cWidth) {
                     $value .= str_repeat(' ', $cWidth - $handle);
                 }
             });
             $mColumns = (int) floor($wWidth / ($cWidth + 2));
             $mLines = (int) ceil(($count + 1) / $mColumns);
             --$mColumns;
             if ($mLines >= $window['y']) {
                 $toRemove = ($mLines - $window['y']) * $mColumns + 1;
                 for ($i = 0; $i < $toRemove; $i++) {
                     array_pop($_solution);
                 }
             } else {
                 break;
             }
         }
         $pos = Cursor::getPosition();
         if ($window['y'] - $cursor['y'] - $mLines < 0) {
             echo str_repeat("\n", $mLines + 1);
             Cursor::move('up', $mLines + 1);
             Cursor::clear('LEFT');
             echo $this->getPrefix() . $this->getLine() . "\n";
             Cursor::move('up LEFT');
             Cursor::move('right', $pos['x'] - 1);
         }
         Cursor::save();
         Cursor::hide();
         Cursor::move('down LEFT');
         Cursor::clear('down');
         $i = 0;
         foreach ($_solution as $j => $s) {
             echo "", $s, "";
             if ($i++ < $mColumns) {
                 echo '  ';
             } else {
                 $i = 0;
                 if (isset($_solution[$j + 1])) {
                     echo "\n";
                 }
             }
         }
         Cursor::restore();
         Cursor::show();
         ++$mColumns;
         $read = array(STDIN);
         $mColumn = -1;
         $mLine = -1;
         $coord = -1;
         $unselect = function () use(&$mColumn, &$mLine, &$coord, &$_solution, &$cWidth) {
             Cursor::save();
             Cursor::hide();
             Cursor::move('down LEFT');
             Cursor::move('right', $mColumn * ($cWidth + 2));
             Cursor::move('down', $mLine);
             echo "" . $_solution[$coord] . "";
             Cursor::restore();
             Cursor::show();
         };
         $select = function () use(&$mColumn, &$mLine, &$coord, &$_solution, &$cWidth) {
             Cursor::save();
             Cursor::hide();
             Cursor::move('down LEFT');
             Cursor::move('right', $mColumn * ($cWidth + 2));
             Cursor::move('down', $mLine);
             echo "" . $_solution[$coord] . "";
             Cursor::restore();
             Cursor::show();
         };
         $init = function () use(&$mColumn, &$mLine, &$coord, &$select) {
             $mColumn = 0;
             $mLine = 0;
             $coord = 0;
             $select();
         };
         while (true) {
             @stream_select($read, $write, $except, 30, 0);
             if (empty($read)) {
                 $read = array(STDIN);
                 continue;
             }
             switch ($char = $self->_read()) {
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = max(0, $coord - $mColumns);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = min($count, $coord + $mColumns);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "\t":
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = min($count, $coord + 1);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "":
                     if (-1 === $mColumn && -1 === $mLine) {
                         $init();
                         break;
                     }
                     $unselect();
                     $coord = max(0, $coord - 1);
                     $mLine = (int) floor($coord / $mColumns);
                     $mColumn = $coord % $mColumns;
                     $select();
                     break;
                 case "\n":
                     if (-1 !== $mColumn && -1 !== $mLine) {
                         $self->setLine($head . $solution[$coord] . $tail);
                         $self->setLineCurrent($current + mb_strlen($solution[$coord]));
                         Cursor::move('left', $length);
                         echo $solution[$coord];
                         Cursor::clear('right');
                         echo $tail;
                         Cursor::move('left', mb_strlen($tail));
                     }
                 default:
                     $mColumn = -1;
                     $mLine = -1;
                     $coord = -1;
                     Cursor::save();
                     Cursor::move('down LEFT');
                     Cursor::clear('down');
                     Cursor::restore();
                     if ("" !== $char && "\n" !== $char) {
                         $self->setBuffer($char);
                         return $self->_readLine($char);
                     }
                     break 2;
             }
         }
         return $state;
     }
 }