diff --git a/Helper/Helper.php b/Helper/Helper.php index f82dd286f..acec994db 100644 --- a/Helper/Helper.php +++ b/Helper/Helper.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Formatter\OutputFormatterInterface; +use Symfony\Component\String\UnicodeString; /** * Helper is the base class for all helper classes. @@ -45,7 +46,11 @@ public function getHelperSet() */ public static function strlen(?string $string) { - $string = (string) $string; + $string ?? $string = ''; + + if (preg_match('//u', $string)) { + return (new UnicodeString($string))->width(false); + } if (false === $encoding = mb_detect_encoding($string, null, true)) { return \strlen($string); @@ -59,9 +64,9 @@ public static function strlen(?string $string) * * @return string The string subset */ - public static function substr(string $string, int $from, int $length = null) + public static function substr(?string $string, int $from, int $length = null) { - $string = (string) $string; + $string ?? $string = ''; if (false === $encoding = mb_detect_encoding($string, null, true)) { return substr($string, $from, $length); @@ -116,17 +121,23 @@ public static function formatMemory(int $memory) return sprintf('%d B', $memory); } - public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string) + public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, ?string $string) { - return self::strlen(self::removeDecoration($formatter, $string)); + $string = self::removeDecoration($formatter, $string); + + if (preg_match('//u', $string)) { + return (new UnicodeString($string))->width(true); + } + + return self::strlen($string); } - public static function removeDecoration(OutputFormatterInterface $formatter, $string) + public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string) { $isDecorated = $formatter->isDecorated(); $formatter->setDecorated(false); // remove <...> formatting - $string = $formatter->format($string); + $string = $formatter->format($string ?? ''); // remove already formatted characters $string = preg_replace("/\033\[[^m]*m/", '', $string); $formatter->setDecorated($isDecorated); diff --git a/Helper/QuestionHelper.php b/Helper/QuestionHelper.php index c0fb5461f..5bf8186b8 100644 --- a/Helper/QuestionHelper.php +++ b/Helper/QuestionHelper.php @@ -311,7 +311,7 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu $remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)))); $output->write($remainingCharacters); $fullChoice .= $remainingCharacters; - $i = self::strlen($fullChoice); + $i = (false === $encoding = mb_detect_encoding($fullChoice, null, true)) ? \strlen($fullChoice) : mb_strlen($fullChoice, $encoding); $matches = array_filter( $autocomplete($ret), diff --git a/Style/SymfonyStyle.php b/Style/SymfonyStyle.php index 187bceed2..075fe6621 100644 --- a/Style/SymfonyStyle.php +++ b/Style/SymfonyStyle.php @@ -501,8 +501,6 @@ private function createBlock(iterable $messages, string $type = null, string $st } $line = $prefix.$line; - $decorationLength = Helper::strlen($line) - Helper::strlenWithoutDecoration($this->getFormatter(), $line); - $messageLineLength = min($this->lineLength - $prefixLength - $indentLength + $decorationLength, $this->lineLength); $line .= str_repeat(' ', max($this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line), 0)); if ($style) { diff --git a/Tests/Fixtures/Style/SymfonyStyle/command/command_21.php b/Tests/Fixtures/Style/SymfonyStyle/command/command_21.php new file mode 100644 index 000000000..8460e7ece --- /dev/null +++ b/Tests/Fixtures/Style/SymfonyStyle/command/command_21.php @@ -0,0 +1,13 @@ +success('Lorem ipsum dolor sit amet'); + $output->success('Lorem ipsum dolor sit amet with one emoji πŸŽ‰'); + $output->success('Lorem ipsum dolor sit amet with so many of them πŸ‘©β€πŸŒΎπŸ‘©β€πŸŒΎπŸ‘©β€πŸŒΎπŸ‘©β€πŸŒΎπŸ‘©β€πŸŒΎ'); +}; diff --git a/Tests/Fixtures/Style/SymfonyStyle/output/output_21.txt b/Tests/Fixtures/Style/SymfonyStyle/output/output_21.txt new file mode 100644 index 000000000..aee3c4a89 --- /dev/null +++ b/Tests/Fixtures/Style/SymfonyStyle/output/output_21.txt @@ -0,0 +1,7 @@ + + [OK] Lorem ipsum dolor sit amet + + [OK] Lorem ipsum dolor sit amet with one emoji πŸŽ‰ + + [OK] Lorem ipsum dolor sit amet with so many of them πŸ‘©β€πŸŒΎπŸ‘©β€πŸŒΎπŸ‘©β€πŸŒΎπŸ‘©β€πŸŒΎπŸ‘©β€πŸŒΎ +