diff --git a/Formatter/OutputFormatter.php b/Formatter/OutputFormatter.php
index 9cb631048..3e4897c33 100644
--- a/Formatter/OutputFormatter.php
+++ b/Formatter/OutputFormatter.php
@@ -13,6 +13,8 @@
use Symfony\Component\Console\Exception\InvalidArgumentException;
+use function Symfony\Component\String\b;
+
/**
* Formatter class for console output.
*
@@ -241,7 +243,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 && !str_ends_with($current, "\n")) {
@@ -265,4 +267,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);
+ }
}
diff --git a/Tests/Formatter/OutputFormatterTest.php b/Tests/Formatter/OutputFormatterTest.php
index 20669e6d3..610522a7e 100644
--- a/Tests/Formatter/OutputFormatterTest.php
+++ b/Tests/Formatter/OutputFormatterTest.php
@@ -358,10 +358,10 @@ 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('foobar 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 foo bar baz 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 foo bar baz 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 foo bar baz 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 foo bar baz 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 foo bar baz 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 foo bar baz 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 foo bar baz 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 ipsum dolor sit 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 ipsum dolor sit 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 ipsum dolor sit, amet et laudantium architecto', 18));
@@ -369,10 +369,12 @@ public function testFormatAndWrap()
$formatter = new OutputFormatter();
$this->assertSame("fo\nob\nar\nba\nz", $formatter->formatAndWrap('foobar baz', 2));
- $this->assertSame("pr\ne \nfo\no \nba\nr \nba\nz \npo\nst", $formatter->formatAndWrap('pre foo bar baz post', 2));
+ $this->assertSame("pr\ne \nfo\no\nba\nr\nba\nz \npo\nst", $formatter->formatAndWrap('pre foo bar baz post', 2));
$this->assertSame("pre\nfoo\nbar\nbaz\npos\nt", $formatter->formatAndWrap('pre foo bar baz post', 3));
- $this->assertSame("pre \nfoo \nbar \nbaz \npost", $formatter->formatAndWrap('pre foo bar baz post', 4));
- $this->assertSame("pre f\noo ba\nr baz\npost", $formatter->formatAndWrap('pre foo bar baz post', 5));
+ $this->assertSame("pre \nfoo\nbar\nbaz \npost", $formatter->formatAndWrap('pre foo bar baz post', 4));
+ $this->assertSame("pre f\noo\nbar\nbaz p\nost", $formatter->formatAndWrap('pre foo bar baz 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));
}
}
diff --git a/Tests/Helper/TableTest.php b/Tests/Helper/TableTest.php
index 5908c5b97..9cd5dcc5f 100644
--- a/Tests/Helper/TableTest.php
+++ b/Tests/Helper/TableTest.php
@@ -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'],
@@ -1378,12 +1378,14 @@ public function testColumnMaxWidths()
$expected =
<<