[Console] Support formatted text cutting

This commit is contained in:
Roland Franssen 2017-04-07 15:24:28 +02:00 committed by Robin Chalas
parent 8f5229f768
commit 09f8ad935d
4 changed files with 67 additions and 6 deletions

View File

@ -9,6 +9,7 @@ CHANGELOG
* deprecated passing a command as a string to `ProcessHelper::run()`,
pass it the command as an array of its arguments instead
* made the `ProcessHelper` class final
* added `WrappableOutputFormatterInterface::formatAndWrap()` (implemented in `OutputFormatter`)
4.1.0
-----

View File

@ -17,8 +17,9 @@ use Symfony\Component\Console\Exception\InvalidArgumentException;
* Formatter class for console output.
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
* @author Roland Franssen <franssen.roland@gmail.com>
*/
class OutputFormatter implements OutputFormatterInterface
class OutputFormatter implements WrappableOutputFormatterInterface
{
private $decorated;
private $styles = array();
@ -130,7 +131,14 @@ class OutputFormatter implements OutputFormatterInterface
*/
public function format($message)
{
$message = (string) $message;
return $this->formatAndWrap((string) $message, 0);
}
/**
* {@inheritdoc}
*/
public function formatAndWrap(string $message, int $width)
{
$offset = 0;
$output = '';
$tagRegex = '[a-z][a-z0-9,_=;-]*+';
@ -144,7 +152,7 @@ class OutputFormatter implements OutputFormatterInterface
}
// add the text up to the next tag
$output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset));
$output .= $this->applyCurrentStyle(substr($message, $offset, $pos - $offset), $output, $width);
$offset = $pos + \strlen($text);
// opening tag?
@ -158,7 +166,7 @@ class OutputFormatter implements OutputFormatterInterface
// </>
$this->styleStack->pop();
} elseif (false === $style = $this->createStyleFromString(strtolower($tag))) {
$output .= $this->applyCurrentStyle($text);
$output .= $this->applyCurrentStyle($text, $output, $width);
} elseif ($open) {
$this->styleStack->push($style);
} else {
@ -166,7 +174,7 @@ class OutputFormatter implements OutputFormatterInterface
}
}
$output .= $this->applyCurrentStyle(substr($message, $offset));
$output .= $this->applyCurrentStyle(substr($message, $offset), $output, $width);
if (false !== strpos($output, "\0")) {
return strtr($output, array("\0" => '\\', '\\<' => '<'));
@ -223,8 +231,24 @@ class OutputFormatter implements OutputFormatterInterface
/**
* Applies current style from stack to text, if must be applied.
*/
private function applyCurrentStyle(string $text): string
private function applyCurrentStyle(string $text, string $current, int $width): string
{
if ('' === $text) {
return '';
}
if ($width) {
if ('' !== $current) {
$text = ltrim($text);
}
$text = wordwrap($text, $width, "\n", true);
if ('' !== $current && "\n" !== substr($current, -1)) {
$text = "\n".$text;
}
}
return $this->isDecorated() && \strlen($text) > 0 ? $this->styleStack->getCurrent()->apply($text) : $text;
}
}

View File

@ -0,0 +1,25 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Console\Formatter;
/**
* Formatter interface for console output that supports word wrapping.
*
* @author Roland Franssen <franssen.roland@gmail.com>
*/
interface WrappableOutputFormatterInterface extends OutputFormatterInterface
{
/**
* Formats a message according to the given styles, wrapping at `$width` (0 means no wrapping).
*/
public function formatAndWrap(string $message, int $width);
}

View File

@ -322,6 +322,17 @@ more text
EOF
));
}
public function testFormatAndWrap()
{
$formatter = new OutputFormatter(true);
$this->assertSame("pre\n\033[37;41mfoo\nbar\nbaz\033[39;49m\npos\nt", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 3));
$formatter = new OutputFormatter();
$this->assertSame("pre\nfoo\nbar\nbaz\npos\nt", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 3));
}
}
class TableCell