merged branch jfsimon/issue-4752 (PR #4832)
Commits -------50cf928
[Console] Removed pointless constant.14bd5ba
[Console] 'formatBlock' helper now escape messages.aaf4950
[Console] Implemented '<' escaping.8cf82b7
[Console] Added '<' escaping tests. Discussion ---------- Issue 4752 Bug fix: no Feature addition: no Backwards compatibility break: no Symfony2 tests pass: yes Fixes the following tickets: #4752 This PR adds possibility to escape `<` chars with `\` to avoid formatting mess. In addition, `FormatterHelper::formatBlock()` method auto-escapes messages.
This commit is contained in:
commit
6782c78b95
|
@ -23,12 +23,24 @@ class OutputFormatter implements OutputFormatterInterface
|
|||
/**
|
||||
* The pattern to phrase the format.
|
||||
*/
|
||||
const FORMAT_PATTERN = '#<(/?)([a-z][a-z0-9_=;-]+)?>([^<]*)#is';
|
||||
const FORMAT_PATTERN = '#(\\\\?)<(/?)([a-z][a-z0-9_=;-]+)?>([^\\\\<]*)#is';
|
||||
|
||||
private $decorated;
|
||||
private $styles = array();
|
||||
private $styleStack;
|
||||
|
||||
/**
|
||||
* Escapes "<" special char in given text.
|
||||
*
|
||||
* @param string $text Text to escape
|
||||
*
|
||||
* @return string Escaped text
|
||||
*/
|
||||
public static function escape($text)
|
||||
{
|
||||
return preg_replace('/([^\\\\]?)</is', '$1\\<', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes console output formatter.
|
||||
*
|
||||
|
@ -135,7 +147,9 @@ class OutputFormatter implements OutputFormatterInterface
|
|||
*/
|
||||
public function format($message)
|
||||
{
|
||||
return preg_replace_callback(self::FORMAT_PATTERN, array($this, 'replaceStyle'), $message);
|
||||
$message = preg_replace_callback(self::FORMAT_PATTERN, array($this, 'replaceStyle'), $message);
|
||||
|
||||
return str_replace('\\<', '<', $message);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,35 +169,40 @@ class OutputFormatter implements OutputFormatterInterface
|
|||
*/
|
||||
private function replaceStyle($match)
|
||||
{
|
||||
if ('' === $match[2]) {
|
||||
if ('/' === $match[1]) {
|
||||
// we got "\<" escaped char
|
||||
if ('\\' === $match[1]) {
|
||||
return $match[0];
|
||||
}
|
||||
|
||||
if ('' === $match[3]) {
|
||||
if ('/' === $match[2]) {
|
||||
// we got "</>" tag
|
||||
$this->styleStack->pop();
|
||||
|
||||
return $this->applyStyle($this->styleStack->getCurrent(), $match[3]);
|
||||
return $this->applyStyle($this->styleStack->getCurrent(), $match[4]);
|
||||
}
|
||||
|
||||
// we got "<>" tag
|
||||
return '<>'.$match[3];
|
||||
return '<>'.$match[4];
|
||||
}
|
||||
|
||||
if (isset($this->styles[strtolower($match[2])])) {
|
||||
$style = $this->styles[strtolower($match[2])];
|
||||
if (isset($this->styles[strtolower($match[3])])) {
|
||||
$style = $this->styles[strtolower($match[3])];
|
||||
} else {
|
||||
$style = $this->createStyleFromString($match[2]);
|
||||
$style = $this->createStyleFromString($match[3]);
|
||||
|
||||
if (false === $style) {
|
||||
return $match[0];
|
||||
}
|
||||
}
|
||||
|
||||
if ('/' === $match[1]) {
|
||||
if ('/' === $match[2]) {
|
||||
$this->styleStack->pop($style);
|
||||
} else {
|
||||
$this->styleStack->push($style);
|
||||
}
|
||||
|
||||
return $this->applyStyle($this->styleStack->getCurrent(), $match[3]);
|
||||
return $this->applyStyle($this->styleStack->getCurrent(), $match[4]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
namespace Symfony\Component\Console\Helper;
|
||||
|
||||
use Symfony\Component\Console\Formatter\OutputFormatter;
|
||||
|
||||
/**
|
||||
* The Formatter class provides helpers to format messages.
|
||||
*
|
||||
|
@ -48,6 +50,7 @@ class FormatterHelper extends Helper
|
|||
$len = 0;
|
||||
$lines = array();
|
||||
foreach ($messages as $message) {
|
||||
$message = OutputFormatter::escape($message);
|
||||
$lines[] = sprintf($large ? ' %s ' : ' %s ', $message);
|
||||
$len = max($this->strlen($message) + ($large ? 4 : 2), $len);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,14 @@ class FormatterStyleTest extends \PHPUnit_Framework_TestCase
|
|||
$this->assertEquals("foo<>bar", $formatter->format('foo<>bar'));
|
||||
}
|
||||
|
||||
public function testLGCharEscaping()
|
||||
{
|
||||
$formatter = new OutputFormatter(true);
|
||||
$this->assertEquals("foo<bar", $formatter->format('foo\\<bar'));
|
||||
$this->assertEquals("<info>some info</info>", $formatter->format('\\<info>some info\\</info>'));
|
||||
$this->assertEquals("\\<info>some info\\</info>", OutputFormatter::escape('<info>some info</info>'));
|
||||
}
|
||||
|
||||
public function testBundledStyles()
|
||||
{
|
||||
$formatter = new OutputFormatter(true);
|
||||
|
|
|
@ -68,4 +68,17 @@ class FormatterHelperTest extends \PHPUnit_Framework_TestCase
|
|||
'::formatBlock() formats a message in a block'
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormatBlockLGEscaping()
|
||||
{
|
||||
$formatter = new FormatterHelper();
|
||||
|
||||
$this->assertEquals(
|
||||
'<error> </error>' . "\n" .
|
||||
'<error> \<info>some info\</info> </error>' . "\n" .
|
||||
'<error> </error>',
|
||||
$formatter->formatBlock('<info>some info</info>', 'error', true),
|
||||
'::formatBlock() escapes \'<\' chars'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Reference in New Issue