Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 157 additions & 34 deletions lib/cli/Arguments.php

Large diffs are not rendered by default.

36 changes: 31 additions & 5 deletions lib/cli/Colors.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* Reference: http://graphcomp.com/info/specs/ansi_col.html#colors
*/
class Colors {
/** @var array<string, array<string, int>> */
static protected $_colors = array(
'color' => array(
'black' => 30,
Expand Down Expand Up @@ -48,14 +49,28 @@ class Colors {
'white' => 47
)
);
/** @var bool|null */
static protected $_enabled = null;

/** @var array<string, array<string, string>> */
static protected $_string_cache = array();

/**
* Enable colorized output.
*
* @param bool $force Force enable.
* @return void
*/
static public function enable($force = true) {
self::$_enabled = $force === true ? true : null;
}

/**
* Disable colorized output.
*
* @param bool $force Force disable.
* @return void
*/
static public function disable($force = true) {
self::$_enabled = $force === true ? false : null;
}
Expand All @@ -64,6 +79,9 @@ static public function disable($force = true) {
* Check if we should colorize output based on local flags and shell type.
*
* Only check the shell type if `Colors::$_enabled` is null and `$colored` is null.
*
* @param bool|null $colored Force enable or disable the colorized output.
* @return bool
*/
static public function shouldColorize($colored = null) {
return self::$_enabled === true ||
Expand All @@ -75,8 +93,8 @@ static public function shouldColorize($colored = null) {
/**
* Set the color.
*
* @param string $color The name of the color or style to set.
* @return string
* @param string|array<string, string|int> $color The name of the color or style to set, or an array of options.
* @return string
*/
static public function color($color) {
if (!is_array($color)) {
Expand Down Expand Up @@ -171,6 +189,7 @@ static public function decolorize( $string, $keep = 0 ) {
* @param string $passed The original string before colorization.
* @param string $colorized The string after running through self::colorize.
* @param string $deprecated Optional. Not used. Default null.
* @return void
*/
static public function cacheString( $passed, $colorized, $deprecated = null ) {
self::$_string_cache[md5($passed)] = array(
Expand Down Expand Up @@ -225,7 +244,7 @@ static public function pad( $string, $length, $pre_colorized = false, $encoding
/**
* Get the color mapping array.
*
* @return array Array of color tokens mapped to colors and styles.
* @return array<string, array<string, string|int>> Array of color tokens mapped to colors and styles.
*/
static public function getColors() {
return array(
Expand Down Expand Up @@ -268,14 +287,16 @@ static public function getColors() {
/**
* Get the cached string values.
*
* @return array The cached string values.
* @return array<string, array<string, string>> The cached string values.
*/
static public function getStringCache() {
return self::$_string_cache;
}

/**
* Clear the string cache.
*
* @return void
*/
static public function clearStringCache() {
self::$_string_cache = array();
Expand Down Expand Up @@ -305,7 +326,7 @@ static public function getResetCode() {
* @param string $string The string to wrap (with ANSI codes).
* @param int $width The maximum display width per line.
* @param string|bool $encoding Optional. The encoding of the string. Default false.
* @return array Array of wrapped string segments.
* @return array<int, string> Array of wrapped string segments.
*/
static public function wrapPreColorized( $string, $width, $encoding = false ) {
$wrapped = array();
Expand All @@ -319,6 +340,10 @@ static public function wrapPreColorized( $string, $width, $encoding = false ) {
// Split the string into parts: ANSI codes and text
$parts = preg_split( $ansi_pattern, $string, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );

if ( false === $parts ) {
$parts = array( $string );
}

foreach ( $parts as $part ) {
// Check if this part is an ANSI code
if ( preg_match( $ansi_pattern, $part ) ) {
Expand All @@ -340,6 +365,7 @@ static public function wrapPreColorized( $string, $width, $encoding = false ) {

while ( $offset < $text_length ) {
$char = \cli\safe_substr( $part, $offset, 1, false, $encoding );
assert( is_string( $char ) );
$char_width = \cli\strwidth( $char, $encoding );

// Check if adding this character would exceed the width
Expand Down
16 changes: 14 additions & 2 deletions lib/cli/Memoize.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,15 @@
namespace cli;

abstract class Memoize {
/** @var array<string, mixed> */
protected $_memoCache = array();

/**
* Magic getter to retrieve memoized properties.
*
* @param string $name Property name.
* @return mixed
*/
public function __get($name) {
if (isset($this->_memoCache[$name])) {
return $this->_memoCache[$name];
Expand All @@ -29,11 +36,16 @@ public function __get($name) {
return ($this->_memoCache[$name] = null);
}

$method = array($this, $name);
($this->_memoCache[$name] = call_user_func($method));
($this->_memoCache[$name] = $this->$name());
return $this->_memoCache[$name];
}

/**
* Unmemoize a property or all properties.
*
* @param string|bool $name Property name to unmemoize, or true to unmemoize all.
* @return void
*/
protected function _unmemo($name) {
if ($name === true) {
$this->_memoCache = array();
Expand Down
19 changes: 17 additions & 2 deletions lib/cli/Notify.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,23 @@
* of characters to indicate progress is being made.
*/
abstract class Notify {
/** @var int */
protected $_current = 0;
/** @var bool */
protected $_first = true;
/** @var int */
protected $_interval;
/** @var string */
protected $_message;
/** @var int|null */
protected $_start;
/** @var float|null */
protected $_timer;
/** @var float|int|null */
protected $_tick;
/** @var int */
protected $_iteration = 0;
/** @var float|int */
protected $_speed = 0;

/**
Expand All @@ -52,11 +61,14 @@ public function __construct($msg, $interval = 100) {
* @abstract
* @param boolean $finish
* @see cli\Notify::tick()
* @return void
*/
abstract public function display($finish = false);

/**
* Reset the notifier state so the same instance can be used in multiple loops.
*
* @return void
*/
public function reset() {
$this->_current = 0;
Expand Down Expand Up @@ -92,7 +104,7 @@ public function elapsed() {
* Calculates the speed (number of ticks per second) at which the Notifier
* is being updated.
*
* @return int The number of ticks performed in 1 second.
* @return float|int The number of ticks performed in 1 second.
*/
public function speed() {
if (!$this->_start) {
Expand Down Expand Up @@ -120,14 +132,15 @@ public function speed() {
* @return string The formatted time span.
*/
public function formatTime($time) {
return floor($time / 60) . ':' . str_pad($time % 60, 2, 0, STR_PAD_LEFT);
return sprintf('%02d:%02d', (int)floor($time / 60), $time % 60);
}

/**
* Finish our Notification display. Should be called after the Notifier is
* no longer needed.
*
* @see cli\Notify::display()
* @return void
*/
public function finish() {
Streams::out("\r");
Expand All @@ -140,6 +153,7 @@ public function finish() {
* the ticker is incremented by 1.
*
* @param int $increment The amount to increment by.
* @return void
*/
public function increment($increment = 1) {
$this->_current += $increment;
Expand Down Expand Up @@ -174,6 +188,7 @@ public function shouldUpdate() {
* @see cli\Notify::increment()
* @see cli\Notify::shouldUpdate()
* @see cli\Notify::display()
* @return void
*/
public function tick($increment = 1) {
$this->increment($increment);
Expand Down
12 changes: 10 additions & 2 deletions lib/cli/Progress.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
* @see cli\Notify
*/
abstract class Progress extends \cli\Notify {
/** @var int */
protected $_total = 0;

/**
Expand All @@ -40,6 +41,7 @@ public function __construct($msg, $total, $interval = 100) {
*
* @param int $total The total number of times this indicator should be `tick`ed.
* @throws \InvalidArgumentException Thrown if the `$total` is less than 0.
* @return void
*/
public function setTotal($total) {
$this->_total = (int)$total;
Expand All @@ -51,6 +53,9 @@ public function setTotal($total) {

/**
* Reset the progress state so the same instance can be used in multiple loops.
*
* @param int|null $total Optional new total.
* @return void
*/
public function reset($total = null) {
parent::reset();
Expand Down Expand Up @@ -85,8 +90,8 @@ public function total() {
* Calculates the estimated total time for the tick count to reach the
* total ticks given.
*
* @return int The estimated total number of seconds for all ticks to be
* completed. This is not the estimated time left, but total.
* @return int|float The estimated total number of seconds for all ticks to be
* completed. This is not the estimated time left, but total.
* @see cli\Notify::speed()
* @see cli\Notify::elapsed()
*/
Expand All @@ -103,6 +108,8 @@ public function estimated() {
/**
* Forces the current tick count to the total ticks given at instantiation
* time before passing on to `cli\Notify::finish()`.
*
* @return void
*/
public function finish() {
$this->_current = $this->_total;
Expand All @@ -114,6 +121,7 @@ public function finish() {
* the ticker is incremented by 1.
*
* @param int $increment The amount to increment by.
* @return void
*/
public function increment($increment = 1) {
$this->_current = min($this->_total, $this->_current + $increment);
Expand Down
4 changes: 3 additions & 1 deletion lib/cli/Shell.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ static public function columns() {
}
} else {
$size = exec( '/usr/bin/env stty size 2>/dev/null' );
if ( '' !== $size && preg_match( '/[0-9]+ ([0-9]+)/', $size, $matches ) ) {
if ( $size && preg_match( '/[0-9]+ ([0-9]+)/', $size, $matches ) ) {
$columns = (int) $matches[1];
}
if ( ! $columns ) {
Expand Down Expand Up @@ -99,7 +99,9 @@ static public function isPiped() {

/**
* Uses `stty` to hide input/output completely.
*
* @param boolean $hidden Will hide/show the next data. Defaults to true.
* @return void
*/
static public function hide($hidden = true) {
system( 'stty ' . ( $hidden? '-echo' : 'echo' ) );
Expand Down
Loading