diff --git a/src/Adapter/AbstractAdapter.php b/src/Adapter/AbstractAdapter.php index 6d6a436..e982b63 100644 --- a/src/Adapter/AbstractAdapter.php +++ b/src/Adapter/AbstractAdapter.php @@ -11,6 +11,7 @@ use Zend\Console\Charset; use Zend\Console\Exception; +use Zend\Stdlib\StringUtils; /** * Common console adapter codebase @@ -73,8 +74,6 @@ public function writeText($text, $color = null, $bgColor = null) /** * Write a single line of text to console and advance cursor to the next line. - * If the text length matches console window width no newline character will be added, - * which prevents double empty lines. * * @param string $text * @param null|int $color @@ -82,21 +81,7 @@ public function writeText($text, $color = null, $bgColor = null) */ public function writeLine($text = "", $color = null, $bgColor = null) { - $width = $this->getStringWidth($text); - - // Remove newline characters from the end of string - $text = trim($text, "\r\n"); - - // Replace newline characters with spaces - $text = str_replace("\n", " ", $text); - - // Write the line but refuse to add EOL if the text fits the window - if ($width % $this->getWidth() === 0) { - $this->write($text, $color, $bgColor); - } else { - $this->write($text, $color, $bgColor); - $this->write(PHP_EOL); - } + $this->write($text . PHP_EOL, $color, $bgColor); } /** @@ -224,7 +209,7 @@ public function writeBox( } } elseif ($fillStyle) { - $fillChar = $this->stringTrim($fillStyle, 1); + $fillChar = StringUtils::getWrapper()->substr($fillStyle, 0, 1); } else { $fillChar = ' '; } @@ -483,56 +468,6 @@ public function clearScreen() return $this->clear(); } - /** - * Helper function that return string length as rendered in console. - * - * @static - * @param $string - * @return int - */ - protected function getStringWidth($string) - { - $width = strlen($string); - - if (!$this->isUtf8()) { - return $width; - } - - if (static::$hasMBString === null) { - static::$hasMBString = extension_loaded( 'mbstring' ); - } - - $width = (static::$hasMBString) - ? mb_strlen($string, 'UTF-8' ) - : strlen(utf8_decode($string)); - - return $width; - } - - /** - * Trim a string in an encoding-safe way - * - * @param mixed $string - * @param mixed $length - * @return int - */ - protected function stringTrim($string, $length) - { - if ($this->isUtf8()) { - if (static::$hasMBString === null) { - static::$hasMBString = extension_loaded('mbstring'); - } - - if (static::$hasMBString) { - return mb_strcut($string, 0, $length, 'UTF-8'); - } - - return substr(utf8_decode($string), 0, $length); - } - - return substr($string, 0, $length); - } - /** * Read a single line from the console input * diff --git a/src/Adapter/Posix.php b/src/Adapter/Posix.php index 3044a63..7e5c505 100644 --- a/src/Adapter/Posix.php +++ b/src/Adapter/Posix.php @@ -92,6 +92,24 @@ class Posix extends AbstractAdapter */ protected $lastTTYMode = null; + /** + * Write a single line of text to console and advance cursor to the next line. + * + * This override works around a bug in some terminals that cause the background color + * to fill the next line after EOL. To remedy this, we are sending the colored string with + * appropriate color reset sequences before sending EOL character. + * + * @link https://github.com/zendframework/zf2/issues/4167 + * @param string $text + * @param null|int $color + * @param null|int $bgColor + */ + public function writeLine($text = "", $color = null, $bgColor = null) + { + $this->write($text, $color, $bgColor); + $this->write(PHP_EOL); + } + /** * Determine and return current console width. * diff --git a/test/Adapter/AbstractAdapterTest.php b/test/Adapter/AbstractAdapterTest.php index b5cc02e..06e0946 100644 --- a/test/Adapter/AbstractAdapterTest.php +++ b/test/Adapter/AbstractAdapterTest.php @@ -54,11 +54,11 @@ public function testWriteLine() ob_start(); $this->adapter->writeLine("foo\nbar"); - $this->assertEquals("foo bar" . PHP_EOL, ob_get_clean()); + $this->assertEquals("foo\nbar" . PHP_EOL, ob_get_clean()); ob_start(); $this->adapter->writeLine("\rfoo\r"); - $this->assertEquals("foo" . PHP_EOL, ob_get_clean()); + $this->assertEquals("\rfoo\r" . PHP_EOL, ob_get_clean()); } /** @@ -71,57 +71,14 @@ public function testWriteLineOverflowAndWidthMatch() $this->adapter->setTestWidth(80); ob_start(); - $line = str_repeat('#',80); + $line = str_repeat('#', 80); $this->adapter->writeLine($line); - $this->assertEquals($line, ob_get_clean(), 'No newline because text matches console window width'); + $this->assertEquals($line . PHP_EOL, ob_get_clean()); ob_start(); $line2 = $line . '#'; $this->adapter->writeLine($line2); - $this->assertEquals($line . '#' . PHP_EOL, ob_get_clean()); - - ob_start(); - $line3 = $line . $line; - $this->adapter->writeLine($line3); - $this->assertEquals($line3, ob_get_clean(), 'No newline because text matches console window width'); - - - // make sure console is reported as utf8 compatible - $this->adapter->setTestUtf8(true); - - ob_start(); - $line = str_repeat('ź',80); - $this->adapter->writeLine($line); - $this->assertEquals($line, ob_get_clean(), 'No newline because text matches console window width'); - - ob_start(); - $line2 = $line . 'ź'; - $this->adapter->writeLine($line2); - $this->assertEquals($line . 'ź' . PHP_EOL, ob_get_clean()); - - ob_start(); - $line3 = $line . $line; - $this->adapter->writeLine($line3); - $this->assertEquals($line3, ob_get_clean(), 'No newline because text matches console window width'); - - - // attempt to test utf8 string on a non-utf8 console (which should result in utf8 decoding) - $this->adapter->setTestUtf8(false); - - ob_start(); - $line = str_repeat('ź',80); - $this->adapter->writeLine($line); - $this->assertEquals($line, ob_get_clean(), 'No newline because text matches console window width'); - - ob_start(); - $line2 = $line . 'ź'; - $this->adapter->writeLine($line2); - $this->assertEquals($line . 'ź' . PHP_EOL, ob_get_clean()); - - ob_start(); - $line3 = $line . $line; - $this->adapter->writeLine($line3); - $this->assertEquals($line3, ob_get_clean(), 'No newline because text matches console window width'); + $this->assertEquals($line2 . PHP_EOL, ob_get_clean()); } public function testReadLine()