Skip to content

Commit

Permalink
[Command] fix emojis messing up the line width
Browse files Browse the repository at this point in the history
add tests + removed irrelevant method
  • Loading branch information
MarionLeHerisson authored and nicolas-grekas committed Mar 23, 2021
1 parent 9373481 commit 054f548
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 10 deletions.
25 changes: 18 additions & 7 deletions Helper/Helper.php
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion Helper/QuestionHelper.php
Expand Up @@ -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),
Expand Down
2 changes: 0 additions & 2 deletions Style/SymfonyStyle.php
Expand Up @@ -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) {
Expand Down
13 changes: 13 additions & 0 deletions Tests/Fixtures/Style/SymfonyStyle/command/command_21.php
@@ -0,0 +1,13 @@
<?php

use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

//Ensure texts with emojis don't make longer lines than expected
return function (InputInterface $input, OutputInterface $output) {
$output = new SymfonyStyle($input, $output);
$output->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 👩‍🌾👩‍🌾👩‍🌾👩‍🌾👩‍🌾');
};
7 changes: 7 additions & 0 deletions 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 👩‍🌾👩‍🌾👩‍🌾👩‍🌾👩‍🌾

0 comments on commit 054f548

Please sign in to comment.