From 0046b1116b980928b9869647835c8a12fb44bc26 Mon Sep 17 00:00:00 2001 From: Peter Kruithof Date: Fri, 8 Mar 2013 11:24:33 +0100 Subject: [PATCH 1/5] Overwrite no longer clears the line first, fixing blinking issues --- .../Console/Helper/ProgressHelper.php | 21 ++++++++-------- .../Tests/Helper/ProgressHelperTest.php | 25 +++++++++++++++++-- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/ProgressHelper.php b/src/Symfony/Component/Console/Helper/ProgressHelper.php index 25736af634e23..ed5c918902d26 100644 --- a/src/Symfony/Component/Console/Helper/ProgressHelper.php +++ b/src/Symfony/Component/Console/Helper/ProgressHelper.php @@ -384,21 +384,22 @@ private function humaneTime($secs) * Overwrites a previous message to the output. * * @param OutputInterface $output An Output instance - * @param string|array $messages The message as an array of lines or a single string + * @param string $messages The message */ - private function overwrite(OutputInterface $output, $messages) + private function overwrite(OutputInterface $output, $message) { + $length = strlen($message); + + // append whitespace to match the last line's length + if (($this->lastMessagesLength !== null) && ($this->lastMessagesLength > $length)) { + $message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT); + } + // carriage return $output->write("\x0D"); - if ($this->lastMessagesLength!==null) { - // clear the line with the length of the last message - $output->write(str_repeat("\x20", $this->lastMessagesLength)); - // carriage return - $output->write("\x0D"); - } - $output->write($messages); + $output->write($message); - $this->lastMessagesLength=strlen($messages); + $this->lastMessagesLength = strlen($message); } /** diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php index b5560263f6a07..15ab100d3f231 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php @@ -74,6 +74,27 @@ public function testPercent() $this->assertEquals($this->generateOutput(' 0/50 [>---------------------------] 0%').$this->generateOutput(' 1/50 [>---------------------------] 2%').$this->generateOutput(' 2/50 [=>--------------------------] 4%'), stream_get_contents($output->getStream())); } + public function testOverwriteWithShorterLine() + { + $progress = new ProgressHelper(); + $progress->setFormat(' %current%/%max% [%bar%] %percent%%'); + $progress->start($output = $this->getOutputStream(), 50); + $progress->display(); + $progress->advance(); + + // set shorter format + $progress->setFormat(' %current%/%max% [%bar%]'); + $progress->advance(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/50 [>---------------------------] 0%') . + $this->generateOutput(' 1/50 [>---------------------------] 2%') . + $this->generateOutput(' 2/50 [=>--------------------------] '), + stream_get_contents($output->getStream()) + ); + } + protected function getOutputStream() { return new StreamOutput(fopen('php://memory', 'r+', false)); @@ -86,10 +107,10 @@ protected function generateOutput($expected) $expectedout = $expected; if ($this->lastMessagesLength !== null) { - $expectedout = str_repeat("\x20", $this->lastMessagesLength)."\x0D".$expected; + $expectedout = str_pad($expected, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT); } - $this->lastMessagesLength = strlen($expected); + $this->lastMessagesLength = strlen($expectedout); return "\x0D".$expectedout; } From 2b537652a5caf44851bd554d54e9ce00320402a5 Mon Sep 17 00:00:00 2001 From: Peter Kruithof Date: Fri, 8 Mar 2013 11:40:29 +0100 Subject: [PATCH 2/5] added setCurrent method --- .../Console/Helper/ProgressHelper.php | 30 ++++++++++++++ .../Tests/Helper/ProgressHelperTest.php | 41 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/src/Symfony/Component/Console/Helper/ProgressHelper.php b/src/Symfony/Component/Console/Helper/ProgressHelper.php index ed5c918902d26..8a89d8975c22a 100644 --- a/src/Symfony/Component/Console/Helper/ProgressHelper.php +++ b/src/Symfony/Component/Console/Helper/ProgressHelper.php @@ -236,6 +236,36 @@ public function advance($step = 1, $redraw = false) } } + /** + * Sets the current progress. + * + * @param integer $current The current progress + * @param Boolean $redraw Whether to redraw or not + * + * @throws \LogicException + */ + public function setCurrent($current, $redraw = false) + { + if (null === $this->startTime) { + throw new \LogicException('You must start the progress bar before calling setCurrent().'); + } + + $current = (int) $current; + + if ($current < $this->current) { + throw new \LogicException('You can\'t regress the progress bar'); + } + + if ($this->current === 0) { + $redraw = true; + } + + $this->current = $current; + if ($redraw || $this->current % $this->redrawFreq === 0) { + $this->display(); + } + } + /** * Outputs the current progress string. * diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php index 15ab100d3f231..0cd1d6fefe0ed 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php @@ -95,6 +95,47 @@ public function testOverwriteWithShorterLine() ); } + public function testSetCurrentProgress() + { + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream(), 50); + $progress->display(); + $progress->advance(); + $progress->setCurrent(15); + $progress->setCurrent(25); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0/50 [>---------------------------] 0%') . + $this->generateOutput(' 1/50 [>---------------------------] 2%') . + $this->generateOutput(' 15/50 [========>-------------------] 30%') . + $this->generateOutput(' 25/50 [==============>-------------] 50%'), + stream_get_contents($output->getStream()) + ); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage You must start the progress bar + */ + public function testSetCurrentBeforeStarting() + { + $progress = new ProgressHelper(); + $progress->setCurrent(15); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage You can't regress the progress bar + */ + public function testRegressProgress() + { + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream(), 50); + $progress->setCurrent(15); + $progress->setCurrent(10); + } + protected function getOutputStream() { return new StreamOutput(fopen('php://memory', 'r+', false)); From 1febffd842dc4ce50a6292e7aafc75f63fe7e6e9 Mon Sep 17 00:00:00 2001 From: Peter Kruithof Date: Fri, 8 Mar 2013 11:42:01 +0100 Subject: [PATCH 3/5] CS fix --- src/Symfony/Component/Console/Helper/ProgressHelper.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/ProgressHelper.php b/src/Symfony/Component/Console/Helper/ProgressHelper.php index 8a89d8975c22a..87910c688b48c 100644 --- a/src/Symfony/Component/Console/Helper/ProgressHelper.php +++ b/src/Symfony/Component/Console/Helper/ProgressHelper.php @@ -177,8 +177,8 @@ public function setRedrawFrequency($freq) /** * Starts the progress output. * - * @param OutputInterface $output An Output instance - * @param integer $max Maximum steps + * @param OutputInterface $output An Output instance + * @param integer $max Maximum steps */ public function start(OutputInterface $output, $max = null) { From de3527283ef6401e22f65dc671ef6cbb73d2cf4b Mon Sep 17 00:00:00 2001 From: Peter Kruithof Date: Fri, 8 Mar 2013 14:52:38 +0100 Subject: [PATCH 4/5] Added multi-byte support (optional) --- .../Console/Helper/ProgressHelper.php | 27 ++++++++++++++++--- .../Tests/Helper/ProgressHelperTest.php | 15 +++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/ProgressHelper.php b/src/Symfony/Component/Console/Helper/ProgressHelper.php index 87910c688b48c..5f145bb4094cd 100644 --- a/src/Symfony/Component/Console/Helper/ProgressHelper.php +++ b/src/Symfony/Component/Console/Helper/ProgressHelper.php @@ -319,7 +319,7 @@ private function initialize() } if ($this->max > 0) { - $this->widths['max'] = strlen($this->max); + $this->widths['max'] = $this->getLength($this->max); $this->widths['current'] = $this->widths['max']; } else { $this->barCharOriginal = $this->barChar; @@ -355,7 +355,7 @@ private function generate($finish = false) } } - $emptyBars = $this->barWidth - $completeBars - strlen($this->progressChar); + $emptyBars = $this->barWidth - $completeBars - $this->getLength($this->progressChar); $bar = str_repeat($this->barChar, $completeBars); if ($completeBars < $this->barWidth) { $bar .= $this->progressChar; @@ -418,7 +418,7 @@ private function humaneTime($secs) */ private function overwrite(OutputInterface $output, $message) { - $length = strlen($message); + $length = $this->getLength($message); // append whitespace to match the last line's length if (($this->lastMessagesLength !== null) && ($this->lastMessagesLength > $length)) { @@ -429,7 +429,26 @@ private function overwrite(OutputInterface $output, $message) $output->write("\x0D"); $output->write($message); - $this->lastMessagesLength = strlen($message); + $this->lastMessagesLength = $this->getLength($message); + } + + /** + * Wrapper arround strlen: uses multi-byte function if available + * + * @param string $string + * @return integer + */ + private function getLength($string) + { + if (!function_exists('mb_strlen')) { + return strlen($string); + } + + if (false === $encoding = mb_detect_encoding($string)) { + return strlen($string); + } + + return mb_strlen($string, $encoding); } /** diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php index 0cd1d6fefe0ed..6fc75744c03b7 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php @@ -136,6 +136,21 @@ public function testRegressProgress() $progress->setCurrent(10); } + public function testMultiByteSupport() + { + if (!function_exists('mb_strlen') || (false === $encoding = mb_detect_encoding('■'))) { + $this->markTestIncomplete('The mbstring extension is needed for multi-byte support'); + } + + $progress = new ProgressHelper(); + $progress->start($output = $this->getOutputStream()); + $progress->setBarCharacter('■'); + $progress->advance(3); + + rewind($output->getStream()); + $this->assertEquals($this->generateOutput(' 3 [■■■>------------------------]'), stream_get_contents($output->getStream())); + } + protected function getOutputStream() { return new StreamOutput(fopen('php://memory', 'r+', false)); From 6a87c772ddedea1eac7f51121463c257ade9e9ff Mon Sep 17 00:00:00 2001 From: Peter Kruithof Date: Sun, 10 Mar 2013 18:13:13 +0100 Subject: [PATCH 5/5] changed incomplete to skipped test when mbstring is not available --- .../Component/Console/Tests/Helper/ProgressHelperTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php index 6fc75744c03b7..abb8d0b681566 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressHelperTest.php @@ -139,7 +139,7 @@ public function testRegressProgress() public function testMultiByteSupport() { if (!function_exists('mb_strlen') || (false === $encoding = mb_detect_encoding('■'))) { - $this->markTestIncomplete('The mbstring extension is needed for multi-byte support'); + $this->markTestSkipped('The mbstring extension is needed for multi-byte support'); } $progress = new ProgressHelper();