diff --git a/cake/console/console_output.php b/cake/console/console_output.php index 7fc4b6c86..5df2f7820 100644 --- a/cake/console/console_output.php +++ b/cake/console/console_output.php @@ -37,7 +37,8 @@ * `$this->out('Overwrite: foo.php was overwritten.');` * * This would create orange 'Overwrite:' text, while the rest of the text would remain the normal colour. - * See ConsoleOutput::styles() to learn more about defining your own styles. + * See ConsoleOutput::styles() to learn more about defining your own styles. Nested styles are not supported + * at this time. * * @package cake.console */ @@ -132,7 +133,47 @@ class ConsoleOutput { if (is_array($message)) { $message = implode(self::LF, $message); } - return $this->_write($message . str_repeat(self::LF, $newlines)); + return $this->_write($this->styleText($message . str_repeat(self::LF, $newlines))); + } + +/** + * Apply styling to text. + * + * @param string $text Text with styling tags. + * @return string String with color codes added. + */ + public function styleText($text) { + return preg_replace_callback( + '/<(?[a-z0-9-_]+)>(?.*)<\/(\1)>/i', array($this, '_replaceTags'), $text + ); + } + +/** + * Replace tags with color codes. + * + * @param array $matches. + * @return string + */ + protected function _replaceTags($matches) { + $style = $this->styles($matches['tag']); + if (empty($style)) { + return $matches['text']; + } + + $styleInfo = array(); + if (!empty($style['text']) && isset(self::$_foregroundColors[$style['text']])) { + $styleInfo[] = self::$_foregroundColors[$style['text']]; + } + if (!empty($style['background']) && isset(self::$_foregroundColors[$style['background']])) { + $styleInfo[] = self::$_foregroundColors[$style['background']]; + } + unset($style['text'], $style['background']); + foreach ($style as $option => $value) { + if ($value) { + $styleInfo[] = self::$_options[$option]; + } + } + return "\033[" . implode($styleInfo, ';') . 'm' . $matches['text'] . "\033[0m"; } /** @@ -148,12 +189,32 @@ class ConsoleOutput { /** * Get the current styles offered, or append new ones in. * + * ### Get a style definition + * + * `$this->output->styles('error');` + * + * ### Get all the style definitions + * + * `$this->output->styles();` + * + * ### Create or modify an existing style + * + * `$this->output->styles('annoy', array('text' => 'purple', 'background' => 'yellow', 'blink' => true));` + * + * ### Remove a style + * + * `$this->output->styles('annoy', false);` + * * @param string $style The style to get or create. * @param mixed $definition The array definition of the style to change or create a style * or false to remove a style. - * @return mixed + * @return mixed If you are getting styles, the style or null will be returned. If you are creating/modifying + * styles true will be returned. */ function styles($style = null, $definition = null) { + if ($style === null && $definition === null) { + return self::$_styles; + } if (is_string($style) && $definition === null) { return isset(self::$_styles[$style]) ? self::$_styles[$style] : null; } @@ -162,6 +223,7 @@ class ConsoleOutput { return true; } self::$_styles[$style] = $definition; + return true; } /** diff --git a/cake/tests/cases/console/console_output.test.php b/cake/tests/cases/console/console_output.test.php index b3c2efd47..da060267e 100644 --- a/cake/tests/cases/console/console_output.test.php +++ b/cake/tests/cases/console/console_output.test.php @@ -98,8 +98,12 @@ class ConsoleOutputTest extends CakeTestCase { $result = $this->output->styles('error'); $expected = array('text' => 'red'); $this->assertEqual($result, $expected); - + $this->assertNull($this->output->styles('made_up_goop')); + + $result = $this->output->styles(); + $this->assertNotEmpty($result, 'error', 'Error is missing'); + $this->assertNotEmpty($result, 'warning', 'Warning is missing'); } /** @@ -117,4 +121,40 @@ class ConsoleOutputTest extends CakeTestCase { $this->assertNull($this->output->styles('test'), 'Removed styles should be null.'); } +/** + * test formatting text with styles. + * + * @return void + */ + function testFormattingSimple() { + $this->output->expects($this->once())->method('_write') + ->with("\033[31mError:\033[0m Something bad"); + + $this->output->write('Error: Something bad', false); + } + +/** + * test formatting text with missing styles. + * + * @return void + */ + function testFormattingMissingStyleName() { + $this->output->expects($this->once())->method('_write') + ->with("Error: Something bad"); + + $this->output->write('Error: Something bad', false); + } + +/** + * test formatting text with multiple styles. + * + * @return void + */ + function testFormattingMultipleStylesName() { + $this->output->expects($this->once())->method('_write') + ->with("\033[31mBad\033[0m \033[33mWarning\033[0m Regular"); + + $this->output->write('Bad Warning Regular', false); + } + } \ No newline at end of file