diff options
Diffstat (limited to 'platform/www/vendor/splitbrain/php-cli/src/TableFormatter.php')
-rw-r--r-- | platform/www/vendor/splitbrain/php-cli/src/TableFormatter.php | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/platform/www/vendor/splitbrain/php-cli/src/TableFormatter.php b/platform/www/vendor/splitbrain/php-cli/src/TableFormatter.php new file mode 100644 index 0000000..23bb894 --- /dev/null +++ b/platform/www/vendor/splitbrain/php-cli/src/TableFormatter.php @@ -0,0 +1,325 @@ +<?php + +namespace splitbrain\phpcli; + +/** + * Class TableFormatter + * + * Output text in multiple columns + * + * @author Andreas Gohr <andi@splitbrain.org> + * @license MIT + */ +class TableFormatter +{ + /** @var string border between columns */ + protected $border = ' '; + + /** @var int the terminal width */ + protected $max = 74; + + /** @var Colors for coloring output */ + protected $colors; + + /** + * TableFormatter constructor. + * + * @param Colors|null $colors + */ + public function __construct(Colors $colors = null) + { + // try to get terminal width + $width = $this->getTerminalWidth(); + if ($width) { + $this->max = $width - 1; + } + + if ($colors) { + $this->colors = $colors; + } else { + $this->colors = new Colors(); + } + } + + /** + * The currently set border (defaults to ' ') + * + * @return string + */ + public function getBorder() + { + return $this->border; + } + + /** + * Set the border. The border is set between each column. Its width is + * added to the column widths. + * + * @param string $border + */ + public function setBorder($border) + { + $this->border = $border; + } + + /** + * Width of the terminal in characters + * + * initially autodetected + * + * @return int + */ + public function getMaxWidth() + { + return $this->max; + } + + /** + * Set the width of the terminal to assume (in characters) + * + * @param int $max + */ + public function setMaxWidth($max) + { + $this->max = $max; + } + + /** + * Tries to figure out the width of the terminal + * + * @return int terminal width, 0 if unknown + */ + protected function getTerminalWidth() + { + // from environment + if (isset($_SERVER['COLUMNS'])) return (int)$_SERVER['COLUMNS']; + + // via tput + $process = proc_open('tput cols', array( + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w'), + ), $pipes); + $width = (int)stream_get_contents($pipes[1]); + proc_close($process); + + return $width; + } + + /** + * Takes an array with dynamic column width and calculates the correct width + * + * Column width can be given as fixed char widths, percentages and a single * width can be given + * for taking the remaining available space. When mixing percentages and fixed widths, percentages + * refer to the remaining space after allocating the fixed width + * + * @param array $columns + * @return int[] + * @throws Exception + */ + protected function calculateColLengths($columns) + { + $idx = 0; + $border = $this->strlen($this->border); + $fixed = (count($columns) - 1) * $border; // borders are used already + $fluid = -1; + + // first pass for format check and fixed columns + foreach ($columns as $idx => $col) { + // handle fixed columns + if ((string)intval($col) === (string)$col) { + $fixed += $col; + continue; + } + // check if other colums are using proper units + if (substr($col, -1) == '%') { + continue; + } + if ($col == '*') { + // only one fluid + if ($fluid < 0) { + $fluid = $idx; + continue; + } else { + throw new Exception('Only one fluid column allowed!'); + } + } + throw new Exception("unknown column format $col"); + } + + $alloc = $fixed; + $remain = $this->max - $alloc; + + // second pass to handle percentages + foreach ($columns as $idx => $col) { + if (substr($col, -1) != '%') { + continue; + } + $perc = floatval($col); + + $real = (int)floor(($perc * $remain) / 100); + + $columns[$idx] = $real; + $alloc += $real; + } + + $remain = $this->max - $alloc; + if ($remain < 0) { + throw new Exception("Wanted column widths exceed available space"); + } + + // assign remaining space + if ($fluid < 0) { + $columns[$idx] += ($remain); // add to last column + } else { + $columns[$fluid] = $remain; + } + + return $columns; + } + + /** + * Displays text in multiple word wrapped columns + * + * @param int[] $columns list of column widths (in characters, percent or '*') + * @param string[] $texts list of texts for each column + * @param array $colors A list of color names to use for each column. use empty string for default + * @return string + * @throws Exception + */ + public function format($columns, $texts, $colors = array()) + { + $columns = $this->calculateColLengths($columns); + + $wrapped = array(); + $maxlen = 0; + + foreach ($columns as $col => $width) { + $wrapped[$col] = explode("\n", $this->wordwrap($texts[$col], $width, "\n", true)); + $len = count($wrapped[$col]); + if ($len > $maxlen) { + $maxlen = $len; + } + + } + + $last = count($columns) - 1; + $out = ''; + for ($i = 0; $i < $maxlen; $i++) { + foreach ($columns as $col => $width) { + if (isset($wrapped[$col][$i])) { + $val = $wrapped[$col][$i]; + } else { + $val = ''; + } + $chunk = $this->pad($val, $width); + if (isset($colors[$col]) && $colors[$col]) { + $chunk = $this->colors->wrap($chunk, $colors[$col]); + } + $out .= $chunk; + + // border + if ($col != $last) { + $out .= $this->border; + } + } + $out .= "\n"; + } + return $out; + + } + + /** + * Pad the given string to the correct length + * + * @param string $string + * @param int $len + * @return string + */ + protected function pad($string, $len) + { + $strlen = $this->strlen($string); + if ($strlen > $len) return $string; + + $pad = $len - $strlen; + return $string . str_pad('', $pad, ' '); + } + + /** + * Measures char length in UTF-8 when possible + * + * @param $string + * @return int + */ + protected function strlen($string) + { + // don't count color codes + $string = preg_replace("/\33\\[\\d+(;\\d+)?m/", '', $string); + + if (function_exists('mb_strlen')) { + return mb_strlen($string, 'utf-8'); + } + + return strlen($string); + } + + /** + * @param string $string + * @param int $start + * @param int|null $length + * @return string + */ + protected function substr($string, $start = 0, $length = null) + { + if (function_exists('mb_substr')) { + return mb_substr($string, $start, $length); + } else { + // mb_substr() treats $length differently than substr() + if ($length) { + return substr($string, $start, $length); + } else { + return substr($string, $start); + } + } + } + + /** + * @param string $str + * @param int $width + * @param string $break + * @param bool $cut + * @return string + * @link http://stackoverflow.com/a/4988494 + */ + protected function wordwrap($str, $width = 75, $break = "\n", $cut = false) + { + $lines = explode($break, $str); + foreach ($lines as &$line) { + $line = rtrim($line); + if ($this->strlen($line) <= $width) { + continue; + } + $words = explode(' ', $line); + $line = ''; + $actual = ''; + foreach ($words as $word) { + if ($this->strlen($actual . $word) <= $width) { + $actual .= $word . ' '; + } else { + if ($actual != '') { + $line .= rtrim($actual) . $break; + } + $actual = $word; + if ($cut) { + while ($this->strlen($actual) > $width) { + $line .= $this->substr($actual, 0, $width) . $break; + $actual = $this->substr($actual, $width); + } + } + $actual .= ' '; + } + } + $line .= trim($actual); + } + return implode($break, $lines); + } +}
\ No newline at end of file |