Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Console] Upgrade word wrapping in SymfonyStyle #30519

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions src/Symfony/Component/Console/Style/SymfonyStyle.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class SymfonyStyle extends OutputStyle
private $progressBar;
private $lineLength;
private $bufferedOutput;
private $wordWrappers = array();

public function __construct(InputInterface $input, OutputInterface $output)
{
Expand Down Expand Up @@ -387,17 +388,18 @@ private function createBlock($messages, $type = null, $style = null, $prefix = '

if (null !== $type) {
$type = sprintf('[%s] ', $type);
$indentLength = \strlen($type);
$indentLength = \mb_strlen($type);
$lineIndentation = str_repeat(' ', $indentLength);
}

$wordWrapper = $this->getWordWrapper($this->lineLength - $prefixLength - $indentLength, PHP_EOL);
// wrap and add newlines for each element
foreach ($messages as $key => $message) {
if ($escape) {
$message = OutputFormatter::escape($message);
}

$lines = array_merge($lines, explode(PHP_EOL, wordwrap($message, $this->lineLength - $prefixLength - $indentLength, PHP_EOL, true)));
$lines = array_merge($lines, explode(PHP_EOL, $wordWrapper->formattedStringWordwrap($message, true)));

if (\count($messages) > 1 && $key < \count($messages) - 1) {
$lines[] = '';
Expand Down Expand Up @@ -426,4 +428,17 @@ private function createBlock($messages, $type = null, $style = null, $prefix = '

return $lines;
}

/**
* Cache for WordWrappers.
*/
private function getWordWrapper($width, $break)
{
$key = sprintf('%d - %s', $width, $break);
if (!\array_key_exists($key, $this->wordWrappers)) {
$this->wordWrappers[$key] = new WordWrapper($width, $break);
}

return $this->wordWrappers[$key];
}
}
239 changes: 239 additions & 0 deletions src/Symfony/Component/Console/Style/WordWrapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Console\Style;

/**
* This class can help you to create well formatted text blocks with "tags", like: <comment>, <info>, <question>.
*/
class WordWrapper
{
/**
* How many characters one line can contain.
*
* @var int
*/
protected $width;

/**
* End of the lines.
*
* @var string
*/
protected $break;

/**
* We collect the new lines into this array.
*
* @var array
*/
protected $newLines;

/**
* The current line "words".
*
* @var array
*/
protected $newLineTokens;

/**
* The current line "real" length, without the formatter "tags" and the spaces!
*
* @var int
*/
protected $currentLength;

public function __construct($width, $break)
{
if ($width <= 0) {
throw new \InvalidArgumentException('You have to set more than 0 width!');
}
if (0 == mb_strlen($break)) {
throw new \InvalidArgumentException('You have to use existing end of the line character or string!');
}
$this->width = $width;
$this->break = $break;
}

/**
* Close a line.
*/
protected function closeLine()
{
if (\count($this->newLineTokens)) {
$this->newLines[] = implode(' ', $this->newLineTokens);
$this->newLineTokens = array();
$this->currentLength = 0;
}
}

/**
* Register a token with setted length.
*
* @param string $token
* @param int $virtualTokenLength
*/
protected function addTokenToLine($token, $virtualTokenLength)
{
$this->newLineTokens[] = $token;
$this->currentLength += $virtualTokenLength;
}

/**
* Close everything and build the formatted text.
*
* @return string
*/
protected function finish()
{
$this->closeLine();

return implode($this->break, $this->newLines);
}

/**
* Reset the array containers.
*/
protected function reset()
{
$this->newLineTokens = array();
$this->newLines = array();
}

/**
* How long the current line is: currentLength + number of spaces (token numbers - 1).
*
* @return int
*/
protected function getCurrentLineLength()
{
return $this->currentLength + \count($this->newLineTokens) - 1;
}

/**
* Virtual token length = length without "formatter tags". Eg:
* - lorem --> 5
* - <comment>lorem</comment> --> 5.
*
* @param $token
*
* @return int
*/
protected function getVirtualTokenLength($token)
{
$virtualTokenLength = mb_strlen($token);
if (false !== strpos($token, '<')) {
$untaggedToken = preg_replace('/<[^>]+>/', '', $token);
$virtualTokenLength = mb_strlen($untaggedToken);
}

return $virtualTokenLength;
}

/**
* @param string $string The text
* @param bool $cutLongWords How the function handles the too long words that is longer then a line. It ignores
* this settings if the word is an URL!
*
* @return string
*/
public function formattedStringWordwrap($string, $cutLongWords = true)
{
$this->reset();
$lines = explode($this->break, $string);
foreach ($lines as $n => $line) {
// Token can be a word
foreach (explode(' ', $line) as $token) {
$virtualTokenLength = $this->getVirtualTokenLength($token);
$lineLength = $this->getCurrentLineLength();
// If width would be greater with the new token/word. The count()-1 is the number of spaces!
if ($lineLength + $virtualTokenLength < $this->width) {
$this->addTokenToLine($token, $virtualTokenLength);
} else {
if ($virtualTokenLength < $this->width) {
$this->closeLine();
$this->addTokenToLine($token, $virtualTokenLength);
} elseif (!$cutLongWords || 'http' == mb_substr($token, 0, 4)) {
// We don't cat the long word if the $catLongWords is false or the word is an URL
$this->closeLine();
$this->addTokenToLine($token, $virtualTokenLength);
$this->closeLine();
} else {
$this->handleLongToken($token);
}
}
}
$this->closeLine();
}

return $this->finish();
}

/**
* If the word is longer than how long one line can be.
*
* @param string $token
*/
protected function handleLongToken($token)
{
$freeChars = $this->width - ($this->getCurrentLineLength() + 1);
// We start a new line if there is less space than 5 characters.
if ($freeChars < 5) {
$this->closeLine();
$freeChars = $this->width;
}
// We try to finds "formatter tags":
// verylongword<comment>withtags</comment> --> verylongword <comment> withtags </comment>
$tokenBlocks = explode(' ', preg_replace('/<[^>]+>/', ' \\0 ', $token));
$slicedToken = '';
$slicedTokenVirtualLength = 0;
foreach ($tokenBlocks as $block) {
while ($block) {
list($token, $block, $blockLength) = $this->sliceTokenBlock($block, $freeChars);
$freeChars -= $blockLength;
$slicedTokenVirtualLength += $blockLength;
$slicedToken .= $token;
if (!$freeChars) {
$this->addTokenToLine($slicedToken, $slicedTokenVirtualLength);
$this->closeLine();
$slicedToken = '';
$slicedTokenVirtualLength = 0;
$freeChars = $this->width;
}
}
}
$this->addTokenToLine($slicedToken, $slicedTokenVirtualLength);
}

/**
* It handles the long word "blocks".
*
* @param $tokenBlock
* @param $freeChars
*
* @return array [$token, $block, $blockLength]
*/
protected function sliceTokenBlock($tokenBlock, $freeChars)
{
if ('<' == $tokenBlock[0] && '>' == mb_substr($tokenBlock, -1)) {
return array($tokenBlock, '', 0);
}
$blockLength = mb_strlen($tokenBlock);
if ($blockLength <= $freeChars) {
return array($tokenBlock, '', $blockLength);
}

return array(
mb_substr($tokenBlock, 0, $freeChars),
mb_substr($tokenBlock, $freeChars),
$freeChars,
);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@

 // Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et 
 // dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea 
 // commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla 
 // pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim
 // id est laborum
 // Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
 // aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. 
 // Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
 // sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis ex in dolor mollis aliquet. Maecenas pharetra massa ipsum, id tincidunt velit tincidunt et. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas dignissim augue non risus bibendum, id volutpat elit varius. Phasellus a aliquam elit. Integer sem ipsum, posuere vel mauris et, lobortis tempor urna. Morbi in metus lobortis, iaculis nulla id, dapibus dolor. Donec cursus, justo a finibus faucibus, enim sapien venenatis tortor, id pretium felis dolor ut nunc. Integer viverra feugiat dolor, in ornare lacus porta ac. Cras at arcu quam. Proin fringilla vestibulum magna ut feugiat. Sed at tempor tellus. Aliquam erat volutpat. Aliquam erat volutpat. Fusce efficitur arcu efficitur nibh varius, quis tempor enim imperdiet. Sed sagittis purus non urna imperdiet blandit.

Aliquam a bibendum diam, nec semper ipsum. Donec magna felis, molestie in nulla ut, cursus luctus nisl. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla lobortis nulla mi. Fusce a libero nec lorem aliquet molestie. Praesent sem diam, ultricies et posuere eu, blandit at lacus. Proin eleifend nisi id neque porta tincidunt. Quisque tempus purus sit amet erat posuere hendrerit. Proin vitae nisi eros. In hac habitasse platea dictumst. Ut ut metus eu diam aliquam feugiat. Pellentesque leo urna, efficitur ac velit quis, tempor molestie odio. Cras vitae cursus leo.

Duis in libero ut odio porta dignissim. In molestie diam at ante dictum ullamcorper. Ut auctor eros elit, nec molestie erat viverra ut. Vestibulum nisl ex, cursus quis magna id, pulvinar condimentum sem. Nunc ac orci volutpat turpis luctus tempor. Phasellus non ultrices est. Proin quis risus ut risus interdum pellentesque. Vestibulum lobortis, est in accumsan porttitor, nunc neque vulputate ipsum, vel varius metus orci condimentum magna. Duis vulputate leo et mi interdum sollicitudin. Suspendisse malesuada sagittis urna ac mattis. Cras vel nisi eu enim interdum maximus in mollis augue. In faucibus vestibulum lectus at pharetra. Maecenas maximus massa ac massa ornare, sit amet blandit lacus ultricies. Suspendisse tristique pellentesque velit, a finibus libero pellentesque vel. Quisque pellentesque ornare tincidunt.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis ex in dolor mollis aliquet. <comment>Maecenas pharetra massa ipsum, id tincidunt velit tincidunt et.</comment> Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas dignissim augue non risus bibendum, id volutpat elit varius. Phasellus a aliquam elit. Integer sem ipsum, posuere vel mauris et, lobortis tempor urna. Morbi in metus lobortis, iaculis nulla id, dapibus dolor. Donec cursus, justo a finibus faucibus, enim sapien venenatis tortor, id pretium felis dolor ut nunc. Integer viverra feugiat dolor, in ornare lacus porta ac. Cras at arcu quam. Proin fringilla vestibulum magna ut feugiat. Sed at tempor tellus. Aliquam erat volutpat. Aliquam erat volutpat. Fusce efficitur arcu efficitur nibh varius, quis tempor enim imperdiet. Sed sagittis purus non urna imperdiet blandit.

<comment>Aliquam</comment> a bibendum diam, nec semper ipsum. Donec magna felis, molestie in nulla ut, cursus luctus nisl. <info>Lorem ipsum dolor</info> sit amet, consectetur adipiscing elit. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla lobortis nulla mi. Fusce a libero nec lorem aliquet molestie. Praesent sem diam, ultricies et posuere eu, blandit at lacus. Proin eleifend nisi id neque porta tincidunt. Quisque tempus purus sit amet erat posuere hendrerit. Proin vitae nisi eros. In hac habitasse platea dictumst. Ut ut metus eu diam aliquam feugiat. Pellentesque leo urna, efficitur ac velit quis, tempor molestie odio. Cras vitae cursus leo.

<question>Duis in libero ut <comment>odio</comment> <info>porta</info> dignissim. In molestie diam at ante dictum ullamcorper. Ut auctor eros elit, nec molestie erat viverra ut. Vestibulum nisl ex, cursus quis magna id, pulvinar condimentum sem. Nunc ac orci volutpat turpis luctus tempor. Phasellus non ultrices est. Proin quis risus ut risus interdum pellentesque. Vestibulum lobortis, est in accumsan porttitor, nunc neque vulputate ipsum, vel varius metus orci condimentum magna. Duis vulputate leo et mi interdum sollicitudin. Suspendisse malesuada sagittis urna ac mattis. Cras vel nisi eu enim interdum maximus in mollis augue. In faucibus vestibulum lectus at pharetra. Maecenas maximus massa ac massa ornare, sit amet blandit lacus ultricies. Suspendisse tristique pellentesque velit, a finibus libero pellentesque vel. Quisque pellentesque ornare tincidunt.</question>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis ex in dolor mollis aliquet. <comment>Maecenas pharetra massa ipsum, id tincidunt velit tincidunt et.</comment> Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Maecenas dignissim augue non risus bibendum, id volutpat elit varius. Phasellus a aliquam elit. Integer sem ipsum, posuere vel mauris et, lobortis tempor urna. Morbi in metus lobortis, iaculis nulla id, dapibus dolor. Donec cursus, justo a finibus faucibus, enim sapien venenatis tortor, id pretium felis dolor ut nunc. Integer viverra feugiat dolor, in ornare lacus porta ac. Cras at arcu quam. Proin fringilla vestibulum magna ut feugiat. Sed at tempor tellus. Aliquam erat volutpat. Aliquam erat volutpat. Fusce efficitur arcu efficitur nibh varius, quis tempor enim imperdiet. Sed sagittis purus non urna imperdiet blandit.__break__
__break__
<comment>Aliquam</comment> a bibendum diam, nec semper ipsum. Donec magna felis, molestie in nulla ut, cursus luctus nisl. <info>Lorem ipsum dolor</info> sit amet, consectetur adipiscing elit. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nulla lobortis nulla mi. Fusce a libero nec lorem aliquet molestie. Praesent sem diam, ultricies et posuere eu, blandit at lacus. Proin eleifend nisi id neque porta tincidunt. Quisque tempus purus sit amet erat posuere hendrerit. Proin vitae nisi eros. In hac habitasse platea dictumst. Ut ut metus eu diam aliquam feugiat. Pellentesque leo urna, efficitur ac velit quis, tempor molestie odio. Cras vitae cursus leo.__break__
__break__
<question>Duis in libero ut <comment>odio</comment> <info>porta</info> dignissim. In molestie diam at ante dictum ullamcorper. Ut auctor eros elit, nec molestie erat viverra ut. Vestibulum nisl ex, cursus quis magna id, pulvinar condimentum sem. Nunc ac orci volutpat turpis luctus tempor. Phasellus non ultrices est. Proin quis risus ut risus interdum pellentesque. Vestibulum lobortis, est in accumsan porttitor, nunc neque vulputate ipsum, vel varius metus orci condimentum magna. Duis vulputate leo et mi interdum sollicitudin. Suspendisse malesuada sagittis urna ac mattis. Cras vel nisi eu enim interdum maximus in mollis augue. In faucibus vestibulum lectus at pharetra. Maecenas maximus massa ac massa ornare, sit amet blandit lacus ultricies. Suspendisse tristique pellentesque velit, a finibus libero pellentesque vel. Quisque pellentesque ornare tincidunt.</question>__break__
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam quis ex in dolor mollis aliquet. UTF8:öüóőúéáűíÖÜÓŐÚÉÁŰÍ
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Lorem <comment>ipsum</comment> dolor sit amet: https://www.google.com/search?safe=off&ei=5jSGXIGbGofCkwWcpLGIBA&q=Lorem+ipsum+dolor+sit+amet%2C+consectetur+adipiscing+elit.&oq=Lorem+ipsum+dolor+sit+amet%2C+consectetur+adipiscing+elit.&gs_l=psy-ab.3..0j0i22i30l9.24765.24765..26089...0.0..0.98.98.1......0....2j1..gws-wiz.......0i71.RLWmD-mYSAY Lorem ipsum dolor

Test longer than 5 chars in the end:
Simple long word: thisisaverylongwordthisisaverylongwordthisisaverylongword

Test less than 5 chars in the end:
Simple long word.........: thisisaverylongwordthisisaverylongwordthisisaverylongword

Long word with "tags": <question>thisisaverylongword<comment>thisisaverylongword</comment><info>thisisaverylongword</info></question>
Loading