From 09f8ad935defc372ce364c98b71391c0508d6fa0 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Fri, 7 Apr 2017 15:24:28 +0200 Subject: [PATCH] [Console] Support formatted text cutting --- src/Symfony/Component/Console/CHANGELOG.md | 1 + .../Console/Formatter/OutputFormatter.php | 36 +++++++++++++++---- .../WrappableOutputFormatterInterface.php | 25 +++++++++++++ .../Tests/Formatter/OutputFormatterTest.php | 11 ++++++ 4 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 src/Symfony/Component/Console/Formatter/WrappableOutputFormatterInterface.php diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index 06e4355ad9..87979d7cac 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -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 ----- diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatter.php b/src/Symfony/Component/Console/Formatter/OutputFormatter.php index eebac82e70..255f3031d9 100644 --- a/src/Symfony/Component/Console/Formatter/OutputFormatter.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatter.php @@ -17,8 +17,9 @@ use Symfony\Component\Console\Exception\InvalidArgumentException; * Formatter class for console output. * * @author Konstantin Kudryashov + * @author Roland Franssen */ -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; } } diff --git a/src/Symfony/Component/Console/Formatter/WrappableOutputFormatterInterface.php b/src/Symfony/Component/Console/Formatter/WrappableOutputFormatterInterface.php new file mode 100644 index 0000000000..6694053f05 --- /dev/null +++ b/src/Symfony/Component/Console/Formatter/WrappableOutputFormatterInterface.php @@ -0,0 +1,25 @@ + + * + * 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 + */ +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); +} diff --git a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php index c1addbab9b..b9a8559766 100644 --- a/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php +++ b/src/Symfony/Component/Console/Tests/Formatter/OutputFormatterTest.php @@ -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 foo bar baz post', 3)); + + $formatter = new OutputFormatter(); + + $this->assertSame("pre\nfoo\nbar\nbaz\npos\nt", $formatter->formatAndWrap('pre foo bar baz post', 3)); + } } class TableCell