diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index dc710e8cc9205..b876bc971dad4 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -1278,7 +1278,7 @@ private function splitStringByWidth(string $string, int $width): array foreach (preg_split('//u', $m[0]) as $char) { // test if $char could be appended to current line - if (mb_strwidth($line.$char, 'utf8') <= $width) { + if (Helper::width($line.$char) <= $width) { $line .= $char; continue; } diff --git a/src/Symfony/Component/Console/Helper/Helper.php b/src/Symfony/Component/Console/Helper/Helper.php index 05be647870781..5999537d71d93 100644 --- a/src/Symfony/Component/Console/Helper/Helper.php +++ b/src/Symfony/Component/Console/Helper/Helper.php @@ -48,7 +48,9 @@ public static function width(?string $string): int $string ??= ''; if (preg_match('//u', $string)) { - return (new UnicodeString($string))->width(false); + $string = preg_replace('/[\p{Cc}\x7F]++/u', '', $string, -1, $count); + + return (new UnicodeString($string))->width(false) + $count; } if (false === $encoding = mb_detect_encoding($string, null, true)) { diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 1f026dc504adb..809c659283d4b 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -564,10 +564,7 @@ private function renderCell(array $row, int $column, string $cellFormat): string } // str_pad won't work properly with multi-byte strings, we need to fix the padding - if (false !== $encoding = mb_detect_encoding($cell, null, true)) { - $width += \strlen($cell) - mb_strwidth($cell, $encoding); - } - + $width += \strlen($cell) - Helper::width($cell) - substr_count($cell, "\0"); $style = $this->getColumnStyle($column); if ($cell instanceof TableSeparator) { diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php index 608d23c210bef..3a6b2b724ebc3 100644 --- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php @@ -1294,9 +1294,9 @@ public static function renderSetTitle() 'footer', 'default', <<<'TABLE' -+---------------+---- Multiline ++---------------+--- Multiline header -here -+------------------+ +here +------------------+ | ISBN | Title | Author | +---------------+--------------------------+------------------+ | 99921-58-10-7 | Divine Comedy | Dante Alighieri | @@ -2078,4 +2078,36 @@ public function testGithubIssue52101HorizontalFalse() $this->getOutputContent($output) ); } + + public function testGithubIssue60038WidthOfCellWithEmoji() + { + $table = (new Table($output = $this->getOutputStream())) + ->setHeaderTitle('Test Title') + ->setHeaders(['Title', 'Author']) + ->setRows([ + ["🎭 💫 ☯"." Divine Comedy", "Dante Alighieri"], + // the snowflake (e2 9d 84 ef b8 8f) has a variant selector + ["👑 ❄️ 🗡"." Game of Thrones", "George R.R. Martin"], + // the snowflake in text style (e2 9d 84 ef b8 8e) has a variant selector + ["❄︎❄︎❄︎ snowflake in text style ❄︎❄︎❄︎", ""], + ["And a very long line to show difference in previous lines", ""], + ]) + ; + $table->render(); + + $this->assertSame(<<