Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 8c0022b

Browse filesBrowse files
committed
[Console] fixed progress bar when using ANSI colors and Emojis
1 parent 38f7a6f commit 8c0022b
Copy full SHA for 8c0022b

File tree

Expand file treeCollapse file tree

4 files changed

+92
-41
lines changed
Filter options
Expand file treeCollapse file tree

4 files changed

+92
-41
lines changed

‎src/Symfony/Component/Console/Helper/Helper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Helper/Helper.php
+15Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Console\Helper;
1313

14+
use Symfony\Component\Console\Formatter\OutputFormatterInterface;
15+
1416
/**
1517
* Helper is the base class for all helper classes.
1618
*
@@ -103,4 +105,17 @@ public static function formatMemory($memory)
103105

104106
return sprintf('%d B', $memory);
105107
}
108+
109+
public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, $string)
110+
{
111+
$isDecorated = $formatter->isDecorated();
112+
$formatter->setDecorated(false);
113+
// remove <...> formatting
114+
$string = $formatter->format($string);
115+
// remove already formatted characters
116+
$string = preg_replace("/\033\[[^m]*m/", '', $string);
117+
$formatter->setDecorated($isDecorated);
118+
119+
return self::strlen($string);
120+
}
106121
}

‎src/Symfony/Component/Console/Helper/ProgressBar.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Helper/ProgressBar.php
+25-14Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -387,12 +387,15 @@ public function display()
387387
throw new \LogicException('You must start the progress bar before calling display().');
388388
}
389389

390+
// these 3 variables can be removed in favor of using $this in the closure when support for PHP 5.3 will be dropped.
390391
$self = $this;
391-
$this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self) {
392+
$output = $this->output;
393+
$messages = $this->messages;
394+
$this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) use ($self, $output, $messages) {
392395
if ($formatter = $self::getPlaceholderFormatterDefinition($matches[1])) {
393-
$text = call_user_func($formatter, $self);
394-
} elseif (isset($this->messages[$matches[1]])) {
395-
$text = $this->messages[$matches[1]];
396+
$text = call_user_func($formatter, $self, $output);
397+
} elseif (isset($messages[$matches[1]])) {
398+
$text = $messages[$matches[1]];
396399
} else {
397400
return $matches[0];
398401
}
@@ -424,23 +427,31 @@ public function clear()
424427
*/
425428
private function overwrite($message)
426429
{
427-
$length = Helper::strlen($message);
430+
$lines = explode("\n", $message);
428431

429-
// append whitespace to match the last line's length
430-
// FIXME: on each line!!!!!
431-
// FIXME: max of each line for lastMessagesLength or an array?
432-
if (null !== $this->lastMessagesLength && $this->lastMessagesLength > $length) {
433-
$message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
432+
// append whitespace to match the line's length
433+
if (null !== $this->lastMessagesLength) {
434+
foreach ($lines as $i => $line) {
435+
if ($this->lastMessagesLength > Helper::strlenWithoutDecoration($this->output->getFormatter(), $line)) {
436+
$lines[$i] = str_pad($line, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
437+
}
438+
}
434439
}
435440

436441
// move back to the beginning of the progress bar before redrawing it
437442
$this->output->write("\x0D");
438443
if ($this->formatLineCount) {
439444
$this->output->write(sprintf("\033[%dA", $this->formatLineCount));
440445
}
441-
$this->output->write($message);
446+
$this->output->write(implode("\n", $lines));
442447

443-
$this->lastMessagesLength = Helper::strlen($message);
448+
$this->lastMessagesLength = 0;
449+
foreach ($lines as $line) {
450+
$len = Helper::strlenWithoutDecoration($this->output->getFormatter(), $line);
451+
if ($len > $this->lastMessagesLength) {
452+
$this->lastMessagesLength = $len;
453+
}
454+
}
444455
}
445456

446457
private function determineBestFormat()
@@ -460,11 +471,11 @@ private function determineBestFormat()
460471
private static function initPlaceholderFormatters()
461472
{
462473
return array(
463-
'bar' => function (ProgressBar $bar) {
474+
'bar' => function (ProgressBar $bar, OutputInterface $output) {
464475
$completeBars = floor($bar->getMaxSteps() > 0 ? $bar->getProgressPercent() * $bar->getBarWidth() : $bar->getStep() % $bar->getBarWidth());
465-
$emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlen($bar->getProgressCharacter());
466476
$display = str_repeat($bar->getBarCharacter(), $completeBars);
467477
if ($completeBars < $bar->getBarWidth()) {
478+
$emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter());
468479
$display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars);
469480
}
470481

‎src/Symfony/Component/Console/Helper/TableHelper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Helper/TableHelper.php
+2-14Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ private function renderCell(array $row, $column, $cellFormat)
427427
$width += strlen($cell) - mb_strlen($cell, $encoding);
428428
}
429429

430-
$width += $this->strlen($cell) - $this->computeLengthWithoutDecoration($cell);
430+
$width += $this->strlen($cell) - self::strlenWithoutDecoration($this->output->getFormatter(), $cell);
431431

432432
$content = sprintf($this->cellRowContentFormat, $cell);
433433

@@ -486,7 +486,7 @@ private function getColumnWidth($column)
486486
*/
487487
private function getCellWidth(array $row, $column)
488488
{
489-
return isset($row[$column]) ? $this->computeLengthWithoutDecoration($row[$column]) : 0;
489+
return isset($row[$column]) ? self::strlenWithoutDecoration($this->output->getFormatter(), $row[$column]) : 0;
490490
}
491491

492492
/**
@@ -498,18 +498,6 @@ private function cleanup()
498498
$this->numberOfColumns = null;
499499
}
500500

501-
private function computeLengthWithoutDecoration($string)
502-
{
503-
$formatter = $this->output->getFormatter();
504-
$isDecorated = $formatter->isDecorated();
505-
$formatter->setDecorated(false);
506-
507-
$string = $formatter->format($string);
508-
$formatter->setDecorated($isDecorated);
509-
510-
return $this->strlen($string);
511-
}
512-
513501
/**
514502
* {@inheritDoc}
515503
*/

‎src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
+50-13Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Console\Tests\Helper;
1313

1414
use Symfony\Component\Console\Helper\ProgressBar;
15+
use Symfony\Component\Console\Helper\Helper;
1516
use Symfony\Component\Console\Output\StreamOutput;
1617

1718
class ProgressBarTest extends \PHPUnit_Framework_TestCase
@@ -206,7 +207,7 @@ public function testClear()
206207
$this->assertEquals(
207208
$this->generateOutput(' 0/50 [>---------------------------] 0%').
208209
$this->generateOutput(' 25/50 [==============>-------------] 50%').
209-
$this->generateOutput(''),
210+
$this->generateOutput(' '),
210211
stream_get_contents($output->getStream())
211212
);
212213
}
@@ -332,9 +333,53 @@ public function testMultilineFormat()
332333
rewind($output->getStream());
333334
$this->assertEquals(
334335
$this->generateOutput(">---------------------------\nfoobar").
335-
$this->generateOutput("=========>------------------\nfoobar").
336-
$this->generateOutput("\n").
337-
$this->generateOutput("============================\nfoobar"),
336+
$this->generateOutput("=========>------------------\nfoobar ").
337+
$this->generateOutput(" \n ").
338+
$this->generateOutput("============================\nfoobar "),
339+
stream_get_contents($output->getStream())
340+
);
341+
}
342+
343+
public function testAnsiColorsAndEmojis()
344+
{
345+
$bar = new ProgressBar($output = $this->getOutputStream(), 15);
346+
ProgressBar::setPlaceholderFormatterDefinition('memory', function (ProgressBar $bar) {
347+
static $i = 0;
348+
$mem = 100000 * $i;
349+
$colors = $i++ ? '41;37' : '44;37';
350+
351+
return "\033[".$colors."m ".Helper::formatMemory($mem)." \033[0m";
352+
});
353+
$bar->setFormat(" \033[44;37m %title:-37s% \033[0m\n %current%/%max% %bar% %percent:3s%%\n 🏁 %remaining:-10s% %memory:37s%");
354+
$bar->setBarCharacter($done = "\033[32m●\033[0m");
355+
$bar->setEmptyBarCharacter($empty = "\033[31m●\033[0m");
356+
$bar->setProgressCharacter($progress = "\033[32m➤ \033[0m");
357+
358+
$bar->setMessage('Starting the demo... fingers crossed', 'title');
359+
$bar->start();
360+
$bar->setMessage('Looks good to me...', 'title');
361+
$bar->advance(4);
362+
$bar->setMessage('Thanks, bye', 'title');
363+
$bar->finish();
364+
365+
rewind($output->getStream());
366+
367+
$this->assertEquals(
368+
$this->generateOutput(
369+
" \033[44;37m Starting the demo... fingers crossed \033[0m\n".
370+
" 0/15 ".$progress.str_repeat($empty, 26)." 0%\n".
371+
" 🏁 1 sec \033[44;37m 0 B \033[0m"
372+
).
373+
$this->generateOutput(
374+
" \033[44;37m Looks good to me... \033[0m\n".
375+
" 4/15 ".str_repeat($done, 7).$progress.str_repeat($empty, 19)." 26%\n".
376+
" 🏁 1 sec \033[41;37m 97 kB \033[0m"
377+
).
378+
$this->generateOutput(
379+
" \033[44;37m Thanks, bye \033[0m\n".
380+
" 15/15 ".str_repeat($done, 28)." 100%\n".
381+
" 🏁 1 sec \033[41;37m 195 kB \033[0m"
382+
),
338383
stream_get_contents($output->getStream())
339384
);
340385
}
@@ -346,16 +391,8 @@ protected function getOutputStream($decorated = true)
346391

347392
protected function generateOutput($expected)
348393
{
349-
$expectedout = $expected;
350-
351-
if (null !== $this->lastMessagesLength) {
352-
$expectedout = str_pad($expected, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT);
353-
}
354-
355-
$this->lastMessagesLength = strlen($expectedout);
356-
357394
$count = substr_count($expected, "\n");
358395

359-
return "\x0D".($count ? sprintf("\033[%dA", $count) : '').$expectedout;
396+
return "\x0D".($count ? sprintf("\033[%dA", $count) : '').$expected;
360397
}
361398
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.