Skip to content

Commit

Permalink
[Console] Fix linewraps in OutputFormatter
Browse files Browse the repository at this point in the history
  • Loading branch information
maxbeckers committed Aug 7, 2023
1 parent b504a3d commit f4f7184
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 43 deletions.
11 changes: 10 additions & 1 deletion Formatter/OutputFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

use Symfony\Component\Console\Exception\InvalidArgumentException;

use function Symfony\Component\String\b;

/**
* Formatter class for console output.
*
Expand Down Expand Up @@ -258,7 +260,7 @@ private function applyCurrentStyle(string $text, string $current, int $width, in
}

preg_match('~(\\n)$~', $text, $matches);
$text = $prefix.preg_replace('~([^\\n]{'.$width.'})\\ *~', "\$1\n", $text);
$text = $prefix.$this->addLineBreaks($text, $width);
$text = rtrim($text, "\n").($matches[1] ?? '');

if (!$currentLineLength && '' !== $current && "\n" !== substr($current, -1)) {
Expand All @@ -282,4 +284,11 @@ private function applyCurrentStyle(string $text, string $current, int $width, in

return implode("\n", $lines);
}

private function addLineBreaks(string $text, int $width): string
{
$encoding = mb_detect_encoding($text, null, true) ?: 'UTF-8';

return b($text)->toCodePointString($encoding)->wordwrap($width, "\n", true)->toByteString($encoding);
}
}
14 changes: 8 additions & 6 deletions Tests/Formatter/OutputFormatterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -367,21 +367,23 @@ public function testFormatAndWrap()
$formatter = new OutputFormatter(true);

$this->assertSame("fo\no\e[37;41mb\e[39;49m\n\e[37;41mar\e[39;49m\nba\nz", $formatter->formatAndWrap('foo<error>bar</error> baz', 2));
$this->assertSame("pr\ne \e[37;41m\e[39;49m\n\e[37;41mfo\e[39;49m\n\e[37;41mo \e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mr \e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mz\e[39;49m \npo\nst", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 2));
$this->assertSame("pr\ne \e[37;41m\e[39;49m\n\e[37;41mfo\e[39;49m\n\e[37;41mo\e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mr\e[39;49m\n\e[37;41mba\e[39;49m\n\e[37;41mz\e[39;49m \npo\nst", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 2));
$this->assertSame("pre\e[37;41m\e[39;49m\n\e[37;41mfoo\e[39;49m\n\e[37;41mbar\e[39;49m\n\e[37;41mbaz\e[39;49m\npos\nt", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 3));
$this->assertSame("pre \e[37;41m\e[39;49m\n\e[37;41mfoo \e[39;49m\n\e[37;41mbar \e[39;49m\n\e[37;41mbaz\e[39;49m \npost", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 4));
$this->assertSame("pre \e[37;41mf\e[39;49m\n\e[37;41moo ba\e[39;49m\n\e[37;41mr baz\e[39;49m\npost", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 5));
$this->assertSame("pre \e[37;41m\e[39;49m\n\e[37;41mfoo\e[39;49m\n\e[37;41mbar\e[39;49m\n\e[37;41mbaz\e[39;49m \npost", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 4));
$this->assertSame("pre \e[37;41mf\e[39;49m\n\e[37;41moo\e[39;49m\n\e[37;41mbar\e[39;49m\n\e[37;41mbaz\e[39;49m p\nost", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 5));
$this->assertSame("Lore\nm \e[37;41mip\e[39;49m\n\e[37;41msum\e[39;49m \ndolo\nr \e[32msi\e[39m\n\e[32mt\e[39m am\net", $formatter->formatAndWrap('Lorem <error>ipsum</error> dolor <info>sit</info> amet', 4));
$this->assertSame("Lorem \e[37;41mip\e[39;49m\n\e[37;41msum\e[39;49m dolo\nr \e[32msit\e[39m am\net", $formatter->formatAndWrap('Lorem <error>ipsum</error> dolor <info>sit</info> amet', 8));
$this->assertSame("Lorem \e[37;41mipsum\e[39;49m dolor \e[32m\e[39m\n\e[32msit\e[39m, \e[37;41mamet\e[39;49m et \e[32mlauda\e[39m\n\e[32mntium\e[39m architecto", $formatter->formatAndWrap('Lorem <error>ipsum</error> dolor <info>sit</info>, <error>amet</error> et <info>laudantium</info> architecto', 18));

$formatter = new OutputFormatter();

$this->assertSame("fo\nob\nar\nba\nz", $formatter->formatAndWrap('foo<error>bar</error> baz', 2));
$this->assertSame("pr\ne \nfo\no \nba\nr \nba\nz \npo\nst", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 2));
$this->assertSame("pr\ne \nfo\no\nba\nr\nba\nz \npo\nst", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 2));
$this->assertSame("pre\nfoo\nbar\nbaz\npos\nt", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 3));
$this->assertSame("pre \nfoo \nbar \nbaz \npost", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 4));
$this->assertSame("pre f\noo ba\nr baz\npost", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 5));
$this->assertSame("pre \nfoo\nbar\nbaz \npost", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 4));
$this->assertSame("pre f\noo\nbar\nbaz p\nost", $formatter->formatAndWrap('pre <error>foo bar baz</error> post', 5));
$this->assertSame("Â rèälly\nlöng tîtlè\nthät cöüld\nnèêd\nmúltîplê\nlínès", $formatter->formatAndWrap('Â rèälly löng tîtlè thät cöüld nèêd múltîplê línès', 10));
$this->assertSame("Â rèälly\nlöng tîtlè\nthät cöüld\nnèêd\nmúltîplê\n línès", $formatter->formatAndWrap("Â rèälly löng tîtlè thät cöüld nèêd múltîplê\n línès", 10));
$this->assertSame('', $formatter->formatAndWrap(null, 5));
}
}
Expand Down
75 changes: 39 additions & 36 deletions Tests/Helper/TableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,30 +118,30 @@ public static function renderProvider()
['ISBN', 'Title', 'Author'],
$books,
'compact',
<<<'TABLE'
ISBN Title Author
99921-58-10-7 Divine Comedy Dante Alighieri
9971-5-0210-0 A Tale of Two Cities Charles Dickens
960-425-059-0 The Lord of the Rings J. R. R. Tolkien
80-902734-1-6 And Then There Were None Agatha Christie

TABLE
implode("\n", [
'ISBN Title Author ',
'99921-58-10-7 Divine Comedy Dante Alighieri ',
'9971-5-0210-0 A Tale of Two Cities Charles Dickens ',
'960-425-059-0 The Lord of the Rings J. R. R. Tolkien ',
'80-902734-1-6 And Then There Were None Agatha Christie ',
'',
]),
],
[
['ISBN', 'Title', 'Author'],
$books,
'borderless',
<<<'TABLE'
=============== ========================== ==================
ISBN Title Author
=============== ========================== ==================
99921-58-10-7 Divine Comedy Dante Alighieri
9971-5-0210-0 A Tale of Two Cities Charles Dickens
960-425-059-0 The Lord of the Rings J. R. R. Tolkien
80-902734-1-6 And Then There Were None Agatha Christie
=============== ========================== ==================

TABLE
implode("\n", [
' =============== ========================== ================== ',
' ISBN Title Author ',
' =============== ========================== ================== ',
' 99921-58-10-7 Divine Comedy Dante Alighieri ',
' 9971-5-0210-0 A Tale of Two Cities Charles Dickens ',
' 960-425-059-0 The Lord of the Rings J. R. R. Tolkien ',
' 80-902734-1-6 And Then There Were None Agatha Christie ',
' =============== ========================== ================== ',
'',
]),
],
[
['ISBN', 'Title', 'Author'],
Expand Down Expand Up @@ -1378,12 +1378,14 @@ public function testColumnMaxWidths()

$expected =
<<<TABLE
+---------------+-------+------------+-----------------+
| Divine Comedy | A Tal | The Lord o | And Then There |
| | e of | f the Ring | Were None |
| | Two C | s | |
| | ities | | |
+---------------+-------+------------+-----------------+
+---------------+-------+----------+----------------+
| Divine Comedy | A | The Lord | And Then There |
| | Tale | of the | Were None |
| | of | Rings | |
| | Two | | |
| | Citie | | |
| | s | | |
+---------------+-------+----------+----------------+
TABLE;

Expand Down Expand Up @@ -1416,8 +1418,8 @@ public function testColumnMaxWidthsHeaders()
| Publication | Very long header with a lot of |
| | information |
+-------------+--------------------------------+
| 1954 | The Lord of the Rings, by J.R. |
| | R. Tolkien |
| 1954 | The Lord of the Rings, by |
| | J.R.R. Tolkien |
+-------------+--------------------------------+
TABLE;
Expand Down Expand Up @@ -1577,22 +1579,22 @@ public function testWithColspanAndMaxWith()
| Lorem ipsum dolor sit amet, consectetur adipi |
| scing elit, sed do eiusmod tempor |
+-----------------+-----------------+-----------------+
| Lorem ipsum dolor sit amet, consectetur adipi |
| scing elit, sed do eiusmod tempor |
| Lorem ipsum dolor sit amet, consectetur |
| adipiscing elit, sed do eiusmod tempor |
+-----------------+-----------------+-----------------+
| Lorem ipsum dolor sit amet, co | hello world |
| nsectetur | |
+-----------------+-----------------+-----------------+
| hello world | Lorem ipsum dolor sit amet, co |
| | nsectetur adipiscing elit |
+-----------------+-----------------+-----------------+
| hello | world | Lorem ipsum dol |
| | | or sit amet, co |
| | | nsectetur |
| hello | world | Lorem ipsum |
| | | dolor sit amet, |
| | | consectetur |
+-----------------+-----------------+-----------------+
| Symfony | Test | Lorem ipsum dol |
| | | or sit amet, co |
| | | nsectetur |
| | | or sit amet, |
| | | consectetur |
+-----------------+-----------------+-----------------+
TABLE;
Expand All @@ -1614,8 +1616,9 @@ public function testWithHyperlinkAndMaxWidth()
$expected =
<<<TABLE
+----------------------+
| \033]8;;Lorem\033\\Lorem ipsum dolor si\033]8;;\033\\ |
| \033]8;;Lorem\033\\t amet, consectetur \033]8;;\033\\ |
| \033]8;;Lorem\033\\Lorem ipsum dolor\033]8;;\033\\ |
| \033]8;;Lorem\033\\sit amet,\033]8;;\033\\ |
| \033]8;;Lorem\033\\consectetur\033]8;;\033\\ |
| \033]8;;Lorem\033\\adipiscing elit, sed\033]8;;\033\\ |
| \033]8;;Lorem\033\\do eiusmod tempor\033]8;;\033\\ |
+----------------------+
Expand Down

0 comments on commit f4f7184

Please sign in to comment.