From 89ea3fef037d4391c32bd63618de0fdab0bca1d5 Mon Sep 17 00:00:00 2001 From: Carsten Brandt Date: Sat, 25 May 2013 04:19:59 +0200 Subject: [PATCH] Next iteration on console commands issue #33 - implemted getScreenSize for linux systems - tiny adjustments and better naming for console color methods - color switch in base Controller changed to magic property - colorized Help command --- framework/yii/console/Controller.php | 35 +++++- .../yii/console/controllers/HelpController.php | 60 ++++----- framework/yii/helpers/base/Console.php | 138 ++++++++++++++------- tests/unit/framework/helpers/ConsoleTest.php | 79 ++++++++++++ 4 files changed, 232 insertions(+), 80 deletions(-) create mode 100644 tests/unit/framework/helpers/ConsoleTest.php diff --git a/framework/yii/console/Controller.php b/framework/yii/console/Controller.php index fe32daa..22ec39f 100644 --- a/framework/yii/console/Controller.php +++ b/framework/yii/console/Controller.php @@ -36,12 +36,35 @@ class Controller extends \yii\base\Controller public $interactive = true; /** - * @var bool whether to enable ANSI style in output. + * @var boolean whether to enable ANSI style in output. + * Defaults to null meaning auto-detect. + */ + private $_colors; + + /** + * Whether to enable ANSI style in output. + * * Setting this will affect [[ansiFormat()]], [[stdout()]] and [[stderr()]]. * If not set it will be auto detected using [[yii\helpers\Console::streamSupportsAnsiColors()]] with STDOUT * for [[ansiFormat()]] and [[stdout()]] and STDERR for [[stderr()]]. + * @param resource $stream + * @return boolean Whether to enable ANSI style in output. + */ + public function getColors($stream = STDOUT) + { + if ($this->_colors === null) { + return Console::streamSupportsAnsiColors($stream); + } + return $this->_colors; + } + + /** + * Whether to enable ANSI style in output. */ - public $colors; + public function setColors($value) + { + $this->_colors = (bool) $value; + } /** * Runs an action with the specified action ID and parameters. @@ -138,7 +161,7 @@ class Controller extends \yii\base\Controller */ public function ansiFormat($string) { - if ($this->ansi === true || $this->ansi === null && Console::streamSupportsAnsiColors(STDOUT)) { + if ($this->getColors()) { $args = func_get_args(); array_shift($args); $string = Console::ansiFormat($string, $args); @@ -162,7 +185,7 @@ class Controller extends \yii\base\Controller */ public function stdout($string) { - if ($this->ansi === true || $this->ansi === null && Console::streamSupportsAnsiColors(STDOUT)) { + if ($this->getColors()) { $args = func_get_args(); array_shift($args); $string = Console::ansiFormat($string, $args); @@ -186,7 +209,7 @@ class Controller extends \yii\base\Controller */ public function stderr($string) { - if ($this->ansi === true || $this->ansi === null && Console::streamSupportsAnsiColors(STDERR)) { + if ($this->getColors(STDERR)) { $args = func_get_args(); array_shift($args); $string = Console::ansiFormat($string, $args); @@ -259,6 +282,6 @@ class Controller extends \yii\base\Controller */ public function globalOptions() { - return array(); + return array('colors', 'interactive'); } } diff --git a/framework/yii/console/controllers/HelpController.php b/framework/yii/console/controllers/HelpController.php index a729f78..9319163 100644 --- a/framework/yii/console/controllers/HelpController.php +++ b/framework/yii/console/controllers/HelpController.php @@ -13,6 +13,7 @@ use yii\base\InlineAction; use yii\console\Controller; use yii\console\Exception; use yii\console\Request; +use yii\helpers\Console; use yii\helpers\Inflector; /** @@ -56,7 +57,7 @@ class HelpController extends Controller $result = Yii::$app->createController($command); if ($result === false) { throw new Exception(Yii::t('yii', 'No help for unknown command "{command}".', array( - '{command}' => $command, + '{command}' => $this->ansiFormat($command, Console::FG_YELLOW), ))); } @@ -143,14 +144,15 @@ class HelpController extends Controller { $commands = $this->getCommands(); if (!empty($commands)) { - echo "The following commands are available:\n\n"; + $this->stdout("\nThe following commands are available:\n\n", Console::BOLD); foreach ($commands as $command) { - echo "* $command\n"; + echo "- " . $this->ansiFormat($command, Console::FG_YELLOW) . "\n"; } - echo "\nTo see the help of each command, enter:\n"; - echo "\n yii help \n\n"; + $this->stdout("\nTo see the help of each command, enter:\n", Console::BOLD); + echo "\n yii " . $this->ansiFormat('help', Console::FG_YELLOW) . ' ' + . $this->ansiFormat('', Console::FG_CYAN) . "\n\n"; } else { - echo "\nNo commands are found.\n"; + $this->stdout("\nNo commands are found.\n\n", Console::BOLD); } } @@ -167,19 +169,18 @@ class HelpController extends Controller } if ($comment !== '') { - echo "\nDESCRIPTION\n"; - echo "\n" . $comment . "\n\n"; + $this->stdout("\nDESCRIPTION\n", Console::BOLD); + echo "\n" . Console::renderColoredString($comment) . "\n\n"; } $actions = $this->getActions($controller); if (!empty($actions)) { - echo "\nSUB-COMMANDS\n\n"; + $this->stdout("\nSUB-COMMANDS\n\n", Console::BOLD); $prefix = $controller->getUniqueId(); foreach ($actions as $action) { + echo '- ' . $this->ansiFormat($prefix.'/'.$action, Console::FG_YELLOW); if ($action === $controller->defaultAction) { - echo "* $prefix/$action (default)"; - } else { - echo "* $prefix/$action"; + $this->stdout(' (default)', Console::FG_GREEN); } $summary = $this->getActionSummary($controller, $action); if ($summary !== '') { @@ -187,8 +188,9 @@ class HelpController extends Controller } echo "\n"; } - echo "\n\nTo see the detailed information about individual sub-commands, enter:\n"; - echo "\n yii help \n\n"; + echo "\nTo see the detailed information about individual sub-commands, enter:\n"; + echo "\n yii " . $this->ansiFormat('help', Console::FG_YELLOW) . ' ' + . $this->ansiFormat('', Console::FG_CYAN) . "\n\n"; } } @@ -253,25 +255,25 @@ class HelpController extends Controller $options = $this->getOptionHelps($controller); if ($tags['description'] !== '') { - echo "\nDESCRIPTION"; - echo "\n\n" . $tags['description'] . "\n\n"; + $this->stdout("\nDESCRIPTION\n", Console::BOLD); + echo "\n" . Console::renderColoredString($tags['description']) . "\n\n"; } - echo "\nUSAGE\n\n"; + $this->stdout("\nUSAGE\n\n", Console::BOLD); if ($action->id === $controller->defaultAction) { - echo 'yii ' . $controller->getUniqueId(); + echo 'yii ' . $this->ansiFormat($controller->getUniqueId(), Console::FG_YELLOW); } else { - echo "yii " . $action->getUniqueId(); + echo 'yii ' . $this->ansiFormat($action->getUniqueId(), Console::FG_YELLOW); } list ($required, $optional) = $this->getArgHelps($method, isset($tags['param']) ? $tags['param'] : array()); - if (!empty($required)) { - echo ' <' . implode('> <', array_keys($required)) . '>'; + foreach ($required as $arg => $description) { + $this->stdout(' <' . $arg . '>', Console::FG_CYAN); } - if (!empty($optional)) { - echo ' [' . implode('] [', array_keys($optional)) . ']'; + foreach ($optional as $arg => $description) { + $this->stdout(' [' . $arg . ']', Console::FG_CYAN); } if (!empty($options)) { - echo ' [...options...]'; + $this->stdout(' [...options...]', Console::FG_RED); } echo "\n\n"; @@ -281,7 +283,7 @@ class HelpController extends Controller $options = $this->getOptionHelps($controller); if (!empty($options)) { - echo "\nOPTIONS\n\n"; + $this->stdout("\nOPTIONS\n\n", Console::BOLD); echo implode("\n\n", $options) . "\n\n"; } } @@ -310,9 +312,9 @@ class HelpController extends Controller $comment = $tag; } if ($param->isDefaultValueAvailable()) { - $optional[$name] = $this->formatOptionHelp('* ' . $name, false, $type, $param->getDefaultValue(), $comment); + $optional[$name] = $this->formatOptionHelp('- ' . $this->ansiFormat($name, Console::FG_CYAN), false, $type, $param->getDefaultValue(), $comment); } else { - $required[$name] = $this->formatOptionHelp('* ' . $name, true, $type, null, $comment); + $required[$name] = $this->formatOptionHelp('- ' . $this->ansiFormat($name, Console::FG_CYAN), true, $type, null, $comment); } } @@ -352,9 +354,9 @@ class HelpController extends Controller $type = null; $comment = $doc; } - $options[$name] = $this->formatOptionHelp('--' . $name, false, $type, $defaultValue, $comment); + $options[$name] = $this->formatOptionHelp($this->ansiFormat('--' . $name, Console::FG_RED), false, $type, $defaultValue, $comment); } else { - $options[$name] = $this->formatOptionHelp('--' . $name, false, null, $defaultValue, ''); + $options[$name] = $this->formatOptionHelp($this->ansiFormat('--' . $name, Console::FG_RED), false, null, $defaultValue, ''); } } ksort($options); diff --git a/framework/yii/helpers/base/Console.php b/framework/yii/helpers/base/Console.php index b611919..603f0bd 100644 --- a/framework/yii/helpers/base/Console.php +++ b/framework/yii/helpers/base/Console.php @@ -45,6 +45,7 @@ class Console const BG_CYAN = 46; const BG_GREY = 47; + const RESET = 0; const NORMAL = 0; const BOLD = 1; const ITALIC = 3; @@ -240,34 +241,41 @@ class Console } /** - * Sets the ANSI format for any text that is printed afterwards. + * Returns the ANSI format code. * - * You can pass any of the FG_*, BG_* and TEXT_* constants and also [[xterm256ColorFg]] and [[xterm256ColorBg]]. + * @param array $format You can pass any of the FG_*, BG_* and TEXT_* constants and also [[xtermFgColor]] and [[xtermBgColor]]. * TODO: documentation + * @return string */ - public static function ansiFormatBegin() + public static function ansiFormatCode($format) { - echo "\033[" . implode(';', func_get_args()) . 'm'; + return "\033[" . implode(';', $format) . 'm'; } /** - * Resets any ANSI format set by previous method [[ansiFormatBegin()]] - * Any output after this is will have default text style. + * Sets the ANSI format for any text that is printed afterwards. + * + * @param array $format You can pass any of the FG_*, BG_* and TEXT_* constants and also [[xtermFgColor]] and [[xtermBgColor]]. + * TODO: documentation + * @see ansiFormatEnd() */ - public static function ansiFormatReset() + public static function beginAnsiFormat($format) { - echo "\033[0m"; + echo "\033[" . implode(';', $format) . 'm'; } /** - * Returns the ANSI format code. + * Resets any ANSI format set by previous method [[ansiFormatBegin()]] + * Any output after this is will have default text style. + * This is equal to * - * You can pass any of the FG_*, BG_* and TEXT_* constants and also [[xterm256ColorFg]] and [[xterm256ColorBg]]. - * TODO: documentation + * ```php + * echo Console::ansiFormatCode(array(Console::RESET)) + * ``` */ - public static function ansiFormatCode($format) + public static function endAnsiFormat() { - return "\033[" . implode(';', $format) . 'm'; + echo "\033[0m"; } /** @@ -275,7 +283,7 @@ class Console * * @param string $string the string to be formatted * @param array $format array containing formatting values. - * You can pass any of the FG_*, BG_* and TEXT_* constants and also [[xterm256ColorFg]] and [[xterm256ColorBg]]. + * You can pass any of the FG_*, BG_* and TEXT_* constants and also [[xtermFgColor]] and [[xtermBgColor]]. * @return string */ public static function ansiFormat($string, $format=array()) @@ -284,15 +292,32 @@ class Console return "\033[0m" . ($code !== '' ? "\033[" . $code . "m" : '') . $string . "\033[0m"; } - //const COLOR_XTERM256 = 38;// http://en.wikipedia.org/wiki/Talk:ANSI_escape_code#xterm-256colors - public static function xterm256ColorFg($i) // TODO naming! + /** + * Returns the ansi format code for xterm foreground color. + * You can pass the returnvalue of this to one of the formatting methods: + * [[ansiFormat]], [[ansiFormatCode]], [[beginAnsiFormat]] + * + * @param integer $colorCode xterm color code + * @return string + * @see http://en.wikipedia.org/wiki/Talk:ANSI_escape_code#xterm-256colors + */ + public static function xtermFgColor($colorCode) { - return '38;5;' . $i; + return '38;5;' . $colorCode; } - public static function xterm256ColorBg($i) // TODO naming! + /** + * Returns the ansi format code for xterm foreground color. + * You can pass the returnvalue of this to one of the formatting methods: + * [[ansiFormat]], [[ansiFormatCode]], [[beginAnsiFormat]] + * + * @param integer $colorCode xterm color code + * @return string + * @see http://en.wikipedia.org/wiki/Talk:ANSI_escape_code#xterm-256colors + */ + public static function xtermBgColor($colorCode) { - return '48;5;' . $i; + return '48;5;' . $colorCode; } /** @@ -303,7 +328,7 @@ class Console */ public static function stripAnsiFormat($string) { - return preg_replace('/\033\[[\d;]+m/', '', $string); // TODO currently only strips color + return preg_replace('/\033\[[\d;?]*\w/', '', $string); } // TODO refactor and review @@ -418,10 +443,11 @@ class Console } /** - * TODO syntax copied from https://github.com/pear/Console_Color2/blob/master/Console/Color2.php + * Converts a string to ansi formatted by replacing patterns like %y (for yellow) with ansi control codes * - * Converts colorcodes in the format %y (for yellow) into ansi-control - * codes. The conversion table is: ('bold' meaning 'light' on some + * // TODO documentation + * Uses almost the same syntax as https://github.com/pear/Console_Color2/blob/master/Console/Color2.php + * The conversion table is: ('bold' meaning 'light' on some * terminals). It's almost the same conversion table irssi uses. *
 	 *                  text      text            background
@@ -450,7 +476,6 @@ class Console
 	 *
 	 * @param string $string  String to convert
 	 * @param bool   $colored Should the string be colored?
-	 *
 	 * @return string
 	 */
 	public static function renderColoredString($string, $colored = true)
@@ -508,13 +533,14 @@ class Console
 	}
 
 	/**
-	* Escapes % so they don't get interpreted as color codes
-	*
-	* @param string $string String to escape
-	*
-	* @access public
-	* @return string
-	*/
+	 * Escapes % so they don't get interpreted as color codes when
+	 * the string is parsed by [[renderColoredString]]
+	 *
+	 * @param string $string String to escape
+	 *
+	 * @access public
+	 * @return string
+	 */
 	public static function escape($string)
 	{
 		return str_replace('%', '%%', $string);
@@ -548,12 +574,38 @@ class Console
 	/**
 	 * Usage: list($w, $h) = ConsoleHelper::getScreenSize();
 	 *
-	 * @return array
+	 * @return array|boolean An array of ($width, $height) or false when it was not able to determine size.
 	 */
-	public static function getScreenSize()
+	public static function getScreenSize($refresh = false)
 	{
-		// TODO implement
-		return array(150, 50);
+		static $size;
+		if ($size !== null && !$refresh) {
+			return $size;
+		}
+
+		if (static::isRunningOnWindows()) {
+			// TODO implement for windows
+			return $size = false;
+		} else {
+
+			// try stty if available
+			$stty = array();
+			if (exec('stty -a 2>&1', $stty) && preg_match('/rows\s+(\d+);\s*columns\s+(\d+);/mi', implode(' ', $stty), $matches)) {
+				return $size = array($matches[2], $matches[1]);
+			}
+
+			// fallback to tput, which may not be updated on terminal resize
+			if (($width = (int) exec('tput cols 2>&1')) > 0 && ($height = (int) exec('tput lines 2>&1')) > 0) {
+				return $size = array($width, $height);
+			}
+
+			// fallback to ENV variables, which may not be updated on terminal resize
+			if (($width = (int) getenv('COLUMNS')) > 0 && ($height = (int) getenv('LINES')) > 0) {
+				return $size = array($width, $height);
+			}
+		}
+
+		return $size = false;
 	}
 
 	/**
@@ -607,27 +659,23 @@ class Console
 	/**
 	 * Prints text to STDOUT appended with a carriage return (PHP_EOL).
 	 *
-	 * @param string $text
-	 * @param bool $raw
-	 *
+	 * @param string $string
 	 * @return mixed Number of bytes printed or bool false on error
 	 */
-	public static function output($text = null)
+	public static function output($string = null)
 	{
-		return static::stdout($text . PHP_EOL);
+		return static::stdout($string . PHP_EOL);
 	}
 
 	/**
 	 * Prints text to STDERR appended with a carriage return (PHP_EOL).
 	 *
-	 * @param string $text
-	 * @param bool   $raw
-	 *
+	 * @param string $string
 	 * @return mixed Number of bytes printed or false on error
 	 */
-	public static function error($text = null)
+	public static function error($string = null)
 	{
-		return static::stderr($text . PHP_EOL);
+		return static::stderr($string . PHP_EOL);
 	}
 
 	/**
diff --git a/tests/unit/framework/helpers/ConsoleTest.php b/tests/unit/framework/helpers/ConsoleTest.php
new file mode 100644
index 0000000..3bfa56d
--- /dev/null
+++ b/tests/unit/framework/helpers/ConsoleTest.php
@@ -0,0 +1,79 @@
+assertEquals(str_repeat('a', 25), $ouput);
+	}
+
+/*	public function testScreenSize()
+	{
+		for($i = 1; $i < 20; $i++) {
+			echo implode(', ', Console::getScreenSize(true)) . "\n";
+			ob_flush();
+			sleep(1);
+		}
+	}*/
+
+}