merged branch fabpot/console-render-exception (PR #9055)

This PR was merged into the 2.2 branch.

Discussion
----------

[Console] Fixed exception rendering

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #9045
| License       | MIT
| Doc PR        | n/a

When an exception message contains styles, the output is not the expected one. This PR addresses this issue.

Commits
-------

c8d0342 [Console] fixed exception rendering when nested styles
1f88a28 [Console] added some more information about OutputFormatter::replaceStyle()
a47d663 [Console] fixed the formatter for single-char tags
c6c35b3 [Console] Escape exception message during the rendering of an exception
This commit is contained in:
Fabien Potencier 2013-09-17 15:57:05 +02:00
commit 6f5de6315b
7 changed files with 74 additions and 27 deletions

View File

@ -808,29 +808,29 @@ class Application
$title = sprintf(' [%s] ', get_class($e));
$len = $strlen($title);
$width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX;
$formatter = $output->getFormatter();
$lines = array();
foreach (preg_split('/\r?\n/', $e->getMessage()) as $line) {
foreach (str_split($line, $width - 4) as $line) {
$lines[] = sprintf(' %s ', $line);
$len = max($strlen($line) + 4, $len);
// pre-format lines to get the right string length
$lineLength = $strlen(preg_replace('/\[[^m]*m/', '', $formatter->format($line))) + 4;
$lines[] = array($line, $lineLength);
$len = max($lineLength, $len);
}
}
$messages = array(str_repeat(' ', $len), $title.str_repeat(' ', max(0, $len - $strlen($title))));
$messages = array('', '');
$messages[] = $emptyLine = $formatter->format(sprintf('<error>%s</error>', str_repeat(' ', $len)));
$messages[] = $formatter->format(sprintf('<error>%s%s</error>', $title, str_repeat(' ', max(0, $len - $strlen($title)))));
foreach ($lines as $line) {
$messages[] = $line.str_repeat(' ', $len - $strlen($line));
$messages[] = $formatter->format(sprintf('<error> %s %s</error>', $line[0], str_repeat(' ', $len - $line[1])));
}
$messages[] = $emptyLine;
$messages[] = '';
$messages[] = '';
$messages[] = str_repeat(' ', $len);
$output->writeln("");
$output->writeln("");
foreach ($messages as $message) {
$output->writeln('<error>'.$message.'</error>');
}
$output->writeln("");
$output->writeln("");
$output->writeln($messages, OutputInterface::OUTPUT_RAW);
if (OutputInterface::VERBOSITY_VERBOSE === $output->getVerbosity()) {
$output->writeln('<comment>Exception trace:</comment>');

View File

@ -23,7 +23,7 @@ class OutputFormatter implements OutputFormatterInterface
/**
* The pattern to phrase the format.
*/
const FORMAT_PATTERN = '#(\\\\?)<(/?)([a-z][a-z0-9_=;-]+)?>((?: [^<\\\\]+ | (?!<(?:/?[a-z]|/>)). | .(?<=\\\\<) )*)#isx';
const FORMAT_PATTERN = '#(\\\\?)<(/?)([a-z][a-z0-9_=;-]*)?>((?: [^<\\\\]+ | (?!<(?:/?[a-z]|/>)). | .(?<=\\\\<) )*)#isx';
private $decorated;
private $styles = array();
@ -163,6 +163,8 @@ class OutputFormatter implements OutputFormatterInterface
/**
* Replaces style of the output.
*
* All escaped tags and tags that reference unknown styles are kept as is.
*
* @param array $match
*
* @return string The replaced style

View File

@ -429,6 +429,9 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
$tester->run(array('command' => 'foo3:bar'), array('decorated' => false));
$this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3.txt', $this->normalizeLineBreaks($tester->getDisplay()), '->renderException() renders a pretty exceptions with previous exceptions');
$tester->run(array('command' => 'foo3:bar'), array('decorated' => true));
$this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3decorated.txt', $tester->getDisplay(true), '->renderException() renders a pretty exceptions with previous exceptions');
$application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth'));
$application->setAutoExit(false);
$application->expects($this->any())

View File

@ -17,9 +17,13 @@ class Foo3Command extends Command
protected function execute(InputInterface $input, OutputInterface $output)
{
try {
throw new \Exception("First exception");
try {
throw new \Exception("First exception <p>this is html</p>");
} catch (\Exception $e) {
throw new \Exception("Second exception <comment>comment</comment>", 0, $e);
}
} catch (\Exception $e) {
throw new \Exception("Second exception", 0, $e);
throw new \Exception("Third exception <fg=blue;bg=red>comment</>", 0, $e);
}
}
}

View File

@ -1,17 +1,25 @@
[Exception]
Second exception
[Exception]
Third exception comment
[Exception]
First exception
[Exception]
Second exception comment
[Exception]
First exception <p>this is html</p>
foo3:bar

View File

@ -0,0 +1,27 @@
 
 [Exception] 
 Third exception comment 
 
 
 [Exception] 
 Second exception comment 
 
 
 [Exception] 
 First exception <p>this is html</p> 
 
foo3:bar

View File

@ -113,7 +113,10 @@ class FormatterStyleTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($style, $formatter->getStyle('test'));
$this->assertNotEquals($style, $formatter->getStyle('info'));
$this->assertEquals("\033[34;47msome custom msg\033[0m", $formatter->format('<test>some custom msg</test>'));
$style = new OutputFormatterStyle('blue', 'white');
$formatter->setStyle('b', $style);
$this->assertEquals("\033[34;47msome \033[0m\033[34;47mcustom\033[0m\033[34;47m msg\033[0m", $formatter->format('<test>some <b>custom</b> msg</test>'));
}
public function testRedefineStyle()
@ -137,7 +140,7 @@ class FormatterStyleTest extends \PHPUnit_Framework_TestCase
public function testNonStyleTag()
{
$formatter = new OutputFormatter(true);
$this->assertEquals("\033[32msome \033[0m\033[32m<tag> styled\033[0m", $formatter->format('<info>some <tag> styled</info>'));
$this->assertEquals("\033[32msome \033[0m\033[32m<tag> styled \033[0m\033[32m<p>single-char tag\033[0m\033[32m</p>\033[0m", $formatter->format('<info>some <tag> styled <p>single-char tag</p></info>'));
}
public function testNotDecoratedFormatter()