From 192bef8d1434231237e8eb1bd6e49a7374556ffe Mon Sep 17 00:00:00 2001 From: mark_story Date: Wed, 9 Apr 2014 23:11:25 -0400 Subject: [PATCH] Implement ConsoleIo::overwrite(). --- src/Console/ConsoleIo.php | 45 ++++++++++++++++++++++-- tests/TestCase/Console/ConsoleIoTest.php | 30 ++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/Console/ConsoleIo.php b/src/Console/ConsoleIo.php index 4452cdec323..5fe941c6b56 100644 --- a/src/Console/ConsoleIo.php +++ b/src/Console/ConsoleIo.php @@ -75,6 +75,14 @@ class ConsoleIo { */ protected $_level = ConsoleIo::NORMAL; +/** + * The number of bytes last written to the output stream + * used when overwriting the previous message. + * + * @var integer + */ + protected $_lastWritten = 0; + /** * Constructor * @@ -140,13 +148,46 @@ public function quiet($message, $newlines = 1) { * @return integer|boolean Returns the number of bytes returned from writing to stdout. * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::out */ - public function out($message = null, $newlines = 1, $level = Shell::NORMAL) { + public function out($message = null, $newlines = 1, $level = ConsoleIo::NORMAL) { if ($level <= $this->_level) { - return $this->_out->write($message, $newlines); + $this->_lastWritten = $this->_out->write($message, $newlines); + return $this->_lastWritten; } return true; } +/** + * Overwrite some already output text. + * + * Useful for building progress bars, or when you want to replace + * text already output to the screen with new text. + * + * **Warning** You cannot overwrite text that contains newlines. + * + * @param array|string $message The message to output. + * @param integer $newlines Number of newlines to append. + * @param integer $size The number of bytes to overwrite. Defaults to the + * length of the last message output. + * @return integer|boolean Returns the number of bytes returned from writing to stdout. + */ + public function overwrite($message, $newlines = 1, $size = null) { + $size = $size ?: $this->_lastWritten; + + // Output backspaces. + $this->out(str_repeat("\x08", $size), 0); + + $newBytes = $this->out($message, 0); + + // Fill any remaining bytes with spaces. + $fill = $size - $newBytes; + if ($fill > 0) { + $this->out(str_repeat(' ', $fill), 0); + } + if ($newlines) { + $this->out($this->nl($newlines), 0); + } + } + /** * Outputs a single or multiple error messages to stderr. If no parameters * are passed outputs just a newline. diff --git a/tests/TestCase/Console/ConsoleIoTest.php b/tests/TestCase/Console/ConsoleIoTest.php index 77e2568a944..2d9e3160c43 100644 --- a/tests/TestCase/Console/ConsoleIoTest.php +++ b/tests/TestCase/Console/ConsoleIoTest.php @@ -280,4 +280,34 @@ public function testHr() { $this->io->hr(2); } +/** + * Test overwriting. + * + * @return void + */ + public function testOverwrite() { + $number = strlen('Some text I want to overwrite'); + + $this->out->expects($this->at(0)) + ->method('write') + ->with('Some text I want to overwrite', 0) + ->will($this->returnValue($number)); + + $this->out->expects($this->at(1)) + ->method('write') + ->with(str_repeat("\x08", $number), 0); + + $this->out->expects($this->at(2)) + ->method('write') + ->with('Less text', 0) + ->will($this->returnValue(9)); + + $this->out->expects($this->at(3)) + ->method('write') + ->with(str_repeat(' ', $number - 9), 0); + + $this->io->out('Some text I want to overwrite', 0); + $this->io->overwrite('Less text'); + } + }