From b030c24263b3a9b951287bd23e3dff4295dda5a5 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Fri, 6 Nov 2015 19:48:00 +0100 Subject: [PATCH 1/5] [Console] ProgressBar - adjust to the window width (static) --- src/Symfony/Component/Console/Application.php | 103 ++---------- .../Component/Console/Helper/ProgressBar.php | 77 ++++++--- .../Terminal/TerminalDimensionsProvider.php | 152 ++++++++++++++++++ .../Console/Tests/Helper/ProgressBarTest.php | 80 +++++---- .../TerminalDimensionsProviderTest.php | 38 +++++ 5 files changed, 307 insertions(+), 143 deletions(-) create mode 100644 src/Symfony/Component/Console/Terminal/TerminalDimensionsProvider.php create mode 100644 src/Symfony/Component/Console/Tests/Terminal/TerminalDimensionsProviderTest.php diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 9bbdb96233..8f9ff366b3 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -36,6 +36,7 @@ use Symfony\Component\Console\Event\ConsoleExceptionEvent; use Symfony\Component\Console\Event\ConsoleTerminateEvent; use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Console\Terminal\TerminalDimensionsProvider; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -65,20 +66,24 @@ class Application private $definition; private $helperSet; private $dispatcher; - private $terminalDimensions; private $defaultCommand; private $singleCommand; /** - * Constructor. - * - * @param string $name The name of the application - * @param string $version The version of the application + * @var TerminalDimensionsProvider */ - public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN') + private $terminalDimensionsProvider; + + /** + * @param string $name The name of the application + * @param string $version The version of the application + * @param TerminalDimensionsProvider $terminalDimensionsProvider + */ + public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN', TerminalDimensionsProvider $terminalDimensionsProvider = null) { $this->name = $name; $this->version = $version; + $this->terminalDimensionsProvider = $terminalDimensionsProvider ?: new TerminalDimensionsProvider(); $this->defaultCommand = 'list'; $this->helperSet = $this->getDefaultHelperSet(); $this->definition = $this->getDefaultInputDefinition(); @@ -692,9 +697,7 @@ class Application */ protected function getTerminalWidth() { - $dimensions = $this->getTerminalDimensions(); - - return $dimensions[0]; + return $this->terminalDimensionsProvider->getTerminalWidth(); } /** @@ -704,9 +707,7 @@ class Application */ protected function getTerminalHeight() { - $dimensions = $this->getTerminalDimensions(); - - return $dimensions[1]; + return $this->terminalDimensionsProvider->getTerminalWidth(); } /** @@ -716,33 +717,7 @@ class Application */ public function getTerminalDimensions() { - if ($this->terminalDimensions) { - return $this->terminalDimensions; - } - - if ('\\' === DIRECTORY_SEPARATOR) { - // extract [w, H] from "wxh (WxH)" - if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) { - return array((int) $matches[1], (int) $matches[2]); - } - // extract [w, h] from "wxh" - if (preg_match('/^(\d+)x(\d+)$/', $this->getConsoleMode(), $matches)) { - return array((int) $matches[1], (int) $matches[2]); - } - } - - if ($sttyString = $this->getSttyColumns()) { - // extract [w, h] from "rows h; columns w;" - if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) { - return array((int) $matches[2], (int) $matches[1]); - } - // extract [w, h] from "; h rows; w columns" - if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) { - return array((int) $matches[2], (int) $matches[1]); - } - } - - return array(null, null); + return $this->terminalDimensionsProvider->getTerminalDimensions(); } /** @@ -757,7 +732,7 @@ class Application */ public function setTerminalDimensions($width, $height) { - $this->terminalDimensions = array($width, $height); + $this->terminalDimensionsProvider->setTerminalDimensions($width, $height); return $this; } @@ -927,54 +902,6 @@ class Application )); } - /** - * Runs and parses stty -a if it's available, suppressing any error output. - * - * @return string - */ - private function getSttyColumns() - { - if (!function_exists('proc_open')) { - return; - } - - $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')); - $process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); - if (is_resource($process)) { - $info = stream_get_contents($pipes[1]); - fclose($pipes[1]); - fclose($pipes[2]); - proc_close($process); - - return $info; - } - } - - /** - * Runs and parses mode CON if it's available, suppressing any error output. - * - * @return string x or null if it could not be parsed - */ - private function getConsoleMode() - { - if (!function_exists('proc_open')) { - return; - } - - $descriptorspec = array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')); - $process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); - if (is_resource($process)) { - $info = stream_get_contents($pipes[1]); - fclose($pipes[1]); - fclose($pipes[2]); - proc_close($process); - - if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) { - return $matches[2].'x'.$matches[1]; - } - } - } - /** * Returns abbreviated suggestions in string format. * diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php index 3c067145e0..e6c9ad03e4 100644 --- a/src/Symfony/Component/Console/Helper/ProgressBar.php +++ b/src/Symfony/Component/Console/Helper/ProgressBar.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Exception\LogicException; +use Symfony\Component\Console\Terminal\TerminalDimensionsProvider; /** * The ProgressBar provides helpers to display progress output. @@ -49,12 +50,16 @@ class ProgressBar private static $formats; /** - * Constructor. - * - * @param OutputInterface $output An OutputInterface instance - * @param int $max Maximum steps (0 if unknown) + * @var TerminalDimensionsProvider */ - public function __construct(OutputInterface $output, $max = 0) + private $terminalDimensionsProvider; + + /** + * @param OutputInterface $output An OutputInterface instance + * @param int $max Maximum steps (0 if unknown) + * @param TerminalDimensionsProvider $terminalDimensionsProvider + */ + public function __construct(OutputInterface $output, $max = 0, TerminalDimensionsProvider $terminalDimensionsProvider = null) { if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); @@ -62,6 +67,7 @@ class ProgressBar $this->output = $output; $this->setMaxSteps($max); + $this->terminalDimensionsProvider = $terminalDimensionsProvider ?: new TerminalDimensionsProvider(); if (!$this->output->isDecorated()) { // disable overwrite when output does not support ANSI codes. @@ -217,7 +223,7 @@ class ProgressBar */ public function setBarWidth($size) { - $this->barWidth = (int) $size; + $this->barWidth = max(1, (int) $size); } /** @@ -412,21 +418,9 @@ class ProgressBar $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); } - $this->overwrite(preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) { - if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) { - $text = call_user_func($formatter, $this, $this->output); - } elseif (isset($this->messages[$matches[1]])) { - $text = $this->messages[$matches[1]]; - } else { - return $matches[0]; - } - - if (isset($matches[2])) { - $text = sprintf('%'.$matches[2], $text); - } - - return $text; - }, $this->format)); + $line = $this->buildLine(); + $line = $this->adjustLineWidthToTerminalWidth($line); + $this->overwrite($line); } /** @@ -592,4 +586,45 @@ class ProgressBar 'debug_nomax' => ' %current% [%bar%] %elapsed:6s% %memory:6s%', ); } + + /** + * @return string + */ + private function buildLine() + { + return preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) { + if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) { + $text = call_user_func($formatter, $this, $this->output); + } elseif (isset($this->messages[$matches[1]])) { + $text = $this->messages[$matches[1]]; + } else { + return $matches[0]; + } + + if (isset($matches[2])) { + $text = sprintf('%'.$matches[2], $text); + } + + return $text; + }, $this->format); + } + + /** + * @param string $line + * + * @return bool + */ + private function adjustLineWidthToTerminalWidth($line) + { + $lineLength = Helper::strlenWithoutDecoration($this->output->getFormatter(), $line); + $terminalWidth = $this->terminalDimensionsProvider->getTerminalWidth(); + if ($lineLength > $terminalWidth) { + $newBarWidth = $this->barWidth - $lineLength + $terminalWidth; + $this->setBarWidth($newBarWidth); + + return $this->buildLine(); + } + + return $line; + } } diff --git a/src/Symfony/Component/Console/Terminal/TerminalDimensionsProvider.php b/src/Symfony/Component/Console/Terminal/TerminalDimensionsProvider.php new file mode 100644 index 0000000000..06d478a2ae --- /dev/null +++ b/src/Symfony/Component/Console/Terminal/TerminalDimensionsProvider.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Terminal; + +class TerminalDimensionsProvider +{ + /** + * @var int[] + */ + private $terminalDimensions = array(); + + /** + * Tries to figure out the terminal dimensions based on the current environment. + * + * @return int[] Array containing width and height + */ + public function getTerminalDimensions() + { + if ($this->terminalDimensions) { + return $this->terminalDimensions; + } + + if ($this->isWindowsEnvironment()) { + // extract [w, H] from "wxh (WxH)" + if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) { + return array((int) $matches[1], (int) $matches[2]); + } + // extract [w, h] from "wxh" + if (preg_match('/^(\d+)x(\d+)$/', $this->getConsoleMode(), $matches)) { + return array((int) $matches[1], (int) $matches[2]); + } + } + + if ($sttyString = $this->getSttyColumns()) { + // extract [w, h] from "rows h; columns w;" + if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) { + return array((int) $matches[2], (int) $matches[1]); + } + // extract [w, h] from "; h rows; w columns" + if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) { + return array((int) $matches[2], (int) $matches[1]); + } + } + + return array(null, null); + } + + /** + * Tries to figure out the terminal width in which this application runs. + * + * @return int|null + */ + public function getTerminalWidth() + { + return $this->getTerminalDimensions()[0]; + } + + /** + * Tries to figure out the terminal height in which this application runs. + * + * @return int|null + */ + public function getTerminalHeight() + { + return $this->getTerminalDimensions()[1]; + } + + /** + * Sets terminal dimensions. + * + * Can be useful to force terminal dimensions for functional tests. + * + * @param int $width + * @param int $height + */ + public function setTerminalDimensions($width, $height) + { + $this->terminalDimensions = array($width, $height); + } + + /** + * Runs and parses mode CON if it's available, suppressing any error output. + * + * @return string x or null if it could not be parsed + */ + private function getConsoleMode() + { + if (!function_exists('proc_open')) { + return; + } + + $descriptorspec = array( + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w'), + ); + $process = proc_open('mode CON', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); + if (is_resource($process)) { + $info = stream_get_contents($pipes[1]); + fclose($pipes[1]); + fclose($pipes[2]); + proc_close($process); + + if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) { + return $matches[2].'x'.$matches[1]; + } + } + } + + /** + * Runs and parses stty -a if it's available, suppressing any error output. + * + * @return string + */ + private function getSttyColumns() + { + if (!function_exists('proc_open')) { + return; + } + + $descriptorspec = array( + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w'), + ); + + $process = proc_open('stty -a | grep columns', $descriptorspec, $pipes, null, null, array('suppress_errors' => true)); + if (is_resource($process)) { + $info = stream_get_contents($pipes[1]); + fclose($pipes[1]); + fclose($pipes[2]); + proc_close($process); + + return $info; + } + } + + /** + * @return bool + */ + private function isWindowsEnvironment() + { + return '\\' === DIRECTORY_SEPARATOR; + } +} diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php index 261908b542..4488b001b2 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Console\Tests\Helper; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Output\StreamOutput; +use Symfony\Component\Console\Terminal\TerminalDimensionsProvider; /** * @group time-sensitive @@ -22,7 +23,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase { public function testMultipleStart() { - $bar = new ProgressBar($output = $this->getOutputStream()); + $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->advance(); $bar->start(); @@ -38,7 +39,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testAdvance() { - $bar = new ProgressBar($output = $this->getOutputStream()); + $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->advance(); @@ -52,7 +53,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testAdvanceWithStep() { - $bar = new ProgressBar($output = $this->getOutputStream()); + $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->advance(5); @@ -66,7 +67,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testAdvanceMultipleTimes() { - $bar = new ProgressBar($output = $this->getOutputStream()); + $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->advance(3); $bar->advance(2); @@ -82,7 +83,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testAdvanceOverMax() { - $bar = new ProgressBar($output = $this->getOutputStream(), 10); + $bar = new ProgressBar($output = $this->getOutputStream(), 10, $this->createTerminalDimensionsProvider()); $bar->setProgress(9); $bar->advance(); $bar->advance(); @@ -105,7 +106,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase ; // max in construct, no format - $bar = new ProgressBar($output = $this->getOutputStream(), 10); + $bar = new ProgressBar($output = $this->getOutputStream(), 10, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->advance(10); $bar->finish(); @@ -114,7 +115,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, stream_get_contents($output->getStream())); // max in start, no format - $bar = new ProgressBar($output = $this->getOutputStream()); + $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); $bar->start(10); $bar->advance(10); $bar->finish(); @@ -123,7 +124,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, stream_get_contents($output->getStream())); // max in construct, explicit format before - $bar = new ProgressBar($output = $this->getOutputStream(), 10); + $bar = new ProgressBar($output = $this->getOutputStream(), 10, $this->createTerminalDimensionsProvider()); $bar->setFormat('normal'); $bar->start(); $bar->advance(10); @@ -133,7 +134,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, stream_get_contents($output->getStream())); // max in start, explicit format before - $bar = new ProgressBar($output = $this->getOutputStream()); + $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); $bar->setFormat('normal'); $bar->start(10); $bar->advance(10); @@ -145,7 +146,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testCustomizations() { - $bar = new ProgressBar($output = $this->getOutputStream(), 10); + $bar = new ProgressBar($output = $this->getOutputStream(), 10, $this->createTerminalDimensionsProvider()); $bar->setBarWidth(10); $bar->setBarCharacter('_'); $bar->setEmptyBarCharacter(' '); @@ -164,7 +165,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testDisplayWithoutStart() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); $bar->display(); rewind($output->getStream()); @@ -176,7 +177,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testDisplayWithQuietVerbosity() { - $bar = new ProgressBar($output = $this->getOutputStream(true, StreamOutput::VERBOSITY_QUIET), 50); + $bar = new ProgressBar($output = $this->getOutputStream(true, StreamOutput::VERBOSITY_QUIET), 50, $this->createTerminalDimensionsProvider()); $bar->display(); rewind($output->getStream()); @@ -188,7 +189,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testFinishWithoutStart() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); $bar->finish(); rewind($output->getStream()); @@ -200,7 +201,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testPercent() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->display(); $bar->advance(); @@ -218,7 +219,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testOverwriteWithShorterLine() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); $bar->setFormat(' %current%/%max% [%bar%] %percent:3s%%'); $bar->start(); $bar->display(); @@ -240,7 +241,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testStartWithMax() { - $bar = new ProgressBar($output = $this->getOutputStream()); + $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); $bar->setFormat('%current%/%max% [%bar%]'); $bar->start(50); $bar->advance(); @@ -255,7 +256,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testSetCurrentProgress() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->display(); $bar->advance(); @@ -288,7 +289,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase */ public function testRegressProgress() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->setProgress(15); $bar->setProgress(10); @@ -329,7 +330,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testMultiByteSupport() { - $bar = new ProgressBar($output = $this->getOutputStream()); + $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->setBarCharacter('■'); $bar->advance(3); @@ -344,7 +345,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testClear() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50); + $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->setProgress(25); $bar->clear(); @@ -360,7 +361,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testPercentNotHundredBeforeComplete() { - $bar = new ProgressBar($output = $this->getOutputStream(), 200); + $bar = new ProgressBar($output = $this->getOutputStream(), 200, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->display(); $bar->advance(199); @@ -378,7 +379,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testNonDecoratedOutput() { - $bar = new ProgressBar($output = $this->getOutputStream(false), 200); + $bar = new ProgressBar($output = $this->getOutputStream(false), 200, $this->createTerminalDimensionsProvider()); $bar->start(); for ($i = 0; $i < 200; ++$i) { @@ -406,7 +407,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testNonDecoratedOutputWithClear() { - $bar = new ProgressBar($output = $this->getOutputStream(false), 50); + $bar = new ProgressBar($output = $this->getOutputStream(false), 50, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->setProgress(25); $bar->clear(); @@ -424,7 +425,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testNonDecoratedOutputWithoutMax() { - $bar = new ProgressBar($output = $this->getOutputStream(false)); + $bar = new ProgressBar($output = $this->getOutputStream(false), 0, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->advance(); @@ -439,10 +440,10 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testParallelBars() { $output = $this->getOutputStream(); - $bar1 = new ProgressBar($output, 2); - $bar2 = new ProgressBar($output, 3); + $bar1 = new ProgressBar($output, 2, $this->createTerminalDimensionsProvider()); + $bar2 = new ProgressBar($output, 3, $this->createTerminalDimensionsProvider()); $bar2->setProgressCharacter('#'); - $bar3 = new ProgressBar($output); + $bar3 = new ProgressBar($output, 0, $this->createTerminalDimensionsProvider()); $bar1->start(); $output->write("\n"); @@ -499,7 +500,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase { $output = $this->getOutputStream(); - $bar = new ProgressBar($output); + $bar = new ProgressBar($output, 0, $this->createTerminalDimensionsProvider()); $bar->start(); $bar->advance(); $bar->advance(); @@ -522,7 +523,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase ProgressBar::setPlaceholderFormatterDefinition('remaining_steps', function (ProgressBar $bar) { return $bar->getMaxSteps() - $bar->getProgress(); }); - $bar = new ProgressBar($output = $this->getOutputStream(), 3); + $bar = new ProgressBar($output = $this->getOutputStream(), 3, $this->createTerminalDimensionsProvider()); $bar->setFormat(' %remaining_steps% [%bar%]'); $bar->start(); @@ -540,7 +541,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testMultilineFormat() { - $bar = new ProgressBar($output = $this->getOutputStream(), 3); + $bar = new ProgressBar($output = $this->getOutputStream(), 3, $this->createTerminalDimensionsProvider()); $bar->setFormat("%bar%\nfoobar"); $bar->start(); @@ -560,7 +561,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testAnsiColorsAndEmojis() { - $bar = new ProgressBar($output = $this->getOutputStream(), 15); + $bar = new ProgressBar($output = $this->getOutputStream(), 15, $this->createTerminalDimensionsProvider()); ProgressBar::setPlaceholderFormatterDefinition('memory', function (ProgressBar $bar) { static $i = 0; $mem = 100000 * $i; @@ -603,7 +604,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testSetFormat() { - $bar = new ProgressBar($output = $this->getOutputStream()); + $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); $bar->setFormat('normal'); $bar->start(); rewind($output->getStream()); @@ -612,7 +613,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase stream_get_contents($output->getStream()) ); - $bar = new ProgressBar($output = $this->getOutputStream(), 10); + $bar = new ProgressBar($output = $this->getOutputStream(), 10, $this->createTerminalDimensionsProvider()); $bar->setFormat('normal'); $bar->start(); rewind($output->getStream()); @@ -627,7 +628,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase */ public function testFormatsWithoutMax($format) { - $bar = new ProgressBar($output = $this->getOutputStream()); + $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); $bar->setFormat($format); $bar->start(); @@ -661,4 +662,15 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase return "\x0D\x1B[2K".($count ? str_repeat("\x1B[1A\x1B[2K", $count) : '').$expected; } + + /** + * @return TerminalDimensionsProvider + */ + private function createTerminalDimensionsProvider() + { + $terminalDimensionsProvider = new TerminalDimensionsProvider(); + $terminalDimensionsProvider->setTerminalDimensions(800, 5); + + return $terminalDimensionsProvider; + } } diff --git a/src/Symfony/Component/Console/Tests/Terminal/TerminalDimensionsProviderTest.php b/src/Symfony/Component/Console/Tests/Terminal/TerminalDimensionsProviderTest.php new file mode 100644 index 0000000000..0dbd656bfa --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Terminal/TerminalDimensionsProviderTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Terminal; + +use PHPUnit_Framework_TestCase; +use Symfony\Component\Console\Terminal\TerminalDimensionsProvider; +use Symfony\Component\Console\Terminal\TerminalDimensionsProviderInterface; + +class TerminalDimensionsProviderTest extends PHPUnit_Framework_TestCase +{ + /** + * @var TerminalDimensionsProviderInterface + */ + private $terminalDimensionsProvider; + + protected function setUp() + { + $this->terminalDimensionsProvider = new TerminalDimensionsProvider(); + } + + public function testGetTerminalDimensions() + { + $dimensions = $this->terminalDimensionsProvider->getTerminalDimensions(); + $this->assertCount(2, $dimensions); + + $this->terminalDimensionsProvider->setTerminalDimensions(100, 50); + $this->assertSame(array(100, 50), $this->terminalDimensionsProvider->getTerminalDimensions()); + } +} From 8f206c86d7492fa51bc34a732ff70e8aed771e1c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 9 Jun 2016 13:42:05 +0200 Subject: [PATCH 2/5] fixed CS, simplified code --- src/Symfony/Component/Console/Application.php | 25 ++-- .../Component/Console/Helper/ProgressBar.php | 33 +++-- ...nalDimensionsProvider.php => Terminal.php} | 125 ++++++++++-------- .../Console/Tests/Helper/ProgressBarTest.php | 98 +++++++------- .../TerminalDimensionsProviderTest.php | 38 ------ .../Component/Console/Tests/TerminalTest.php | 29 ++++ 6 files changed, 182 insertions(+), 166 deletions(-) rename src/Symfony/Component/Console/{Terminal/TerminalDimensionsProvider.php => Terminal.php} (58%) delete mode 100644 src/Symfony/Component/Console/Tests/Terminal/TerminalDimensionsProviderTest.php create mode 100644 src/Symfony/Component/Console/Tests/TerminalTest.php diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 8f9ff366b3..1e515b8495 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -36,7 +36,7 @@ use Symfony\Component\Console\Event\ConsoleExceptionEvent; use Symfony\Component\Console\Event\ConsoleTerminateEvent; use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\Console\Exception\LogicException; -use Symfony\Component\Console\Terminal\TerminalDimensionsProvider; +use Symfony\Component\Console\Terminal; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** @@ -66,24 +66,19 @@ class Application private $definition; private $helperSet; private $dispatcher; + private $terminal; private $defaultCommand; private $singleCommand; /** - * @var TerminalDimensionsProvider + * @param string $name The name of the application + * @param string $version The version of the application */ - private $terminalDimensionsProvider; - - /** - * @param string $name The name of the application - * @param string $version The version of the application - * @param TerminalDimensionsProvider $terminalDimensionsProvider - */ - public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN', TerminalDimensionsProvider $terminalDimensionsProvider = null) + public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN') { $this->name = $name; $this->version = $version; - $this->terminalDimensionsProvider = $terminalDimensionsProvider ?: new TerminalDimensionsProvider(); + $this->terminal = new Terminal(); $this->defaultCommand = 'list'; $this->helperSet = $this->getDefaultHelperSet(); $this->definition = $this->getDefaultInputDefinition(); @@ -697,7 +692,7 @@ class Application */ protected function getTerminalWidth() { - return $this->terminalDimensionsProvider->getTerminalWidth(); + return $this->terminal->getWidth(); } /** @@ -707,7 +702,7 @@ class Application */ protected function getTerminalHeight() { - return $this->terminalDimensionsProvider->getTerminalWidth(); + return $this->terminal->getHeight(); } /** @@ -717,7 +712,7 @@ class Application */ public function getTerminalDimensions() { - return $this->terminalDimensionsProvider->getTerminalDimensions(); + return $this->terminal->getDimensions(); } /** @@ -732,7 +727,7 @@ class Application */ public function setTerminalDimensions($width, $height) { - $this->terminalDimensionsProvider->setTerminalDimensions($width, $height); + $this->terminal->setDimensions($width, $height); return $this; } diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php index e6c9ad03e4..e0dce47a49 100644 --- a/src/Symfony/Component/Console/Helper/ProgressBar.php +++ b/src/Symfony/Component/Console/Helper/ProgressBar.php @@ -14,7 +14,7 @@ namespace Symfony\Component\Console\Helper; use Symfony\Component\Console\Output\ConsoleOutputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Exception\LogicException; -use Symfony\Component\Console\Terminal\TerminalDimensionsProvider; +use Symfony\Component\Console\Terminal; /** * The ProgressBar provides helpers to display progress output. @@ -45,21 +45,16 @@ class ProgressBar private $formatLineCount; private $messages = array(); private $overwrite = true; + private $terminal; private static $formatters; private static $formats; /** - * @var TerminalDimensionsProvider + * @param OutputInterface $output An OutputInterface instance + * @param int $max Maximum steps (0 if unknown) */ - private $terminalDimensionsProvider; - - /** - * @param OutputInterface $output An OutputInterface instance - * @param int $max Maximum steps (0 if unknown) - * @param TerminalDimensionsProvider $terminalDimensionsProvider - */ - public function __construct(OutputInterface $output, $max = 0, TerminalDimensionsProvider $terminalDimensionsProvider = null) + public function __construct(OutputInterface $output, $max = 0) { if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); @@ -67,7 +62,7 @@ class ProgressBar $this->output = $output; $this->setMaxSteps($max); - $this->terminalDimensionsProvider = $terminalDimensionsProvider ?: new TerminalDimensionsProvider(); + $this->terminal = new Terminal(); if (!$this->output->isDecorated()) { // disable overwrite when output does not support ANSI codes. @@ -443,6 +438,20 @@ class ProgressBar $this->overwrite(''); } + /** + * Gets the terminal. + * + * Can be useful to force terminal dimensions for functional tests. + * + * @return Terminal + * + * @internal + */ + public function getTerminal() + { + return $this->terminal; + } + /** * Sets the progress bar format. * @@ -617,7 +626,7 @@ class ProgressBar private function adjustLineWidthToTerminalWidth($line) { $lineLength = Helper::strlenWithoutDecoration($this->output->getFormatter(), $line); - $terminalWidth = $this->terminalDimensionsProvider->getTerminalWidth(); + $terminalWidth = $this->terminal->getWidth(); if ($lineLength > $terminalWidth) { $newBarWidth = $this->barWidth - $lineLength + $terminalWidth; $this->setBarWidth($newBarWidth); diff --git a/src/Symfony/Component/Console/Terminal/TerminalDimensionsProvider.php b/src/Symfony/Component/Console/Terminal.php similarity index 58% rename from src/Symfony/Component/Console/Terminal/TerminalDimensionsProvider.php rename to src/Symfony/Component/Console/Terminal.php index 06d478a2ae..625a491018 100644 --- a/src/Symfony/Component/Console/Terminal/TerminalDimensionsProvider.php +++ b/src/Symfony/Component/Console/Terminal.php @@ -9,59 +9,35 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Console\Terminal; +namespace Symfony\Component\Console; -class TerminalDimensionsProvider +class Terminal { - /** - * @var int[] - */ - private $terminalDimensions = array(); - - /** - * Tries to figure out the terminal dimensions based on the current environment. - * - * @return int[] Array containing width and height - */ - public function getTerminalDimensions() - { - if ($this->terminalDimensions) { - return $this->terminalDimensions; - } - - if ($this->isWindowsEnvironment()) { - // extract [w, H] from "wxh (WxH)" - if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) { - return array((int) $matches[1], (int) $matches[2]); - } - // extract [w, h] from "wxh" - if (preg_match('/^(\d+)x(\d+)$/', $this->getConsoleMode(), $matches)) { - return array((int) $matches[1], (int) $matches[2]); - } - } - - if ($sttyString = $this->getSttyColumns()) { - // extract [w, h] from "rows h; columns w;" - if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) { - return array((int) $matches[2], (int) $matches[1]); - } - // extract [w, h] from "; h rows; w columns" - if (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) { - return array((int) $matches[2], (int) $matches[1]); - } - } - - return array(null, null); - } + private $width; + private $height; /** * Tries to figure out the terminal width in which this application runs. * * @return int|null */ - public function getTerminalWidth() + public function getWidth() { - return $this->getTerminalDimensions()[0]; + if (null === $this->width) { + $this->initDimensions(); + } + + return $this->width; + } + + /** + * Sets the terminal width. + * + * @param int + */ + public function setWidth($width) + { + $this->width = $width; } /** @@ -69,28 +45,67 @@ class TerminalDimensionsProvider * * @return int|null */ - public function getTerminalHeight() + public function getHeight() { - return $this->getTerminalDimensions()[1]; + if (null === $this->height) { + $this->initDimensions(); + } + + return $this->height; } /** - * Sets terminal dimensions. + * Sets the terminal height. * - * Can be useful to force terminal dimensions for functional tests. - * - * @param int $width - * @param int $height + * @param int */ - public function setTerminalDimensions($width, $height) + public function setHeight($height) { - $this->terminalDimensions = array($width, $height); + $this->height = $height; + } + + private function initDimensions() + { + if (null !== $this->width && null !== $this->height) { + return; + } + + $width = $height = null; + if ($this->isWindowsEnvironment()) { + if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) { + // extract [w, H] from "wxh (WxH)" + $width = (int) $matches[1]; + $height = (int) $matches[2]; + } elseif (null != $dimensions = $this->getConsoleMode()) { + // extract [w, h] from "wxh" + $width = $dimensions[0]; + $height = $dimensions[1]; + } + } elseif ($sttyString = $this->getSttyColumns()) { + if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) { + // extract [w, h] from "rows h; columns w;" + $width = (int) $matches[1]; + $height = (int) $matches[2]; + } elseif (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) { + // extract [w, h] from "; h rows; w columns" + $width = (int) $matches[2]; + $heighth = (int) $matches[1]; + } + } + + if (null === $this->width) { + $this->width = $width; + } + + if (null === $this->height) { + $this->height = $height; + } } /** * Runs and parses mode CON if it's available, suppressing any error output. * - * @return string x or null if it could not be parsed + * @return array|null An array composed of the width and the height or null if it could not be parsed */ private function getConsoleMode() { @@ -110,7 +125,7 @@ class TerminalDimensionsProvider proc_close($process); if (preg_match('/--------+\r?\n.+?(\d+)\r?\n.+?(\d+)\r?\n/', $info, $matches)) { - return $matches[2].'x'.$matches[1]; + return array((int) $matches[2], (int) $matches[1]); } } } diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php index 4488b001b2..bf7bb54d93 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php @@ -14,7 +14,7 @@ namespace Symfony\Component\Console\Tests\Helper; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Output\StreamOutput; -use Symfony\Component\Console\Terminal\TerminalDimensionsProvider; +use Symfony\Component\Console\Terminal; /** * @group time-sensitive @@ -23,7 +23,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase { public function testMultipleStart() { - $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream()); $bar->start(); $bar->advance(); $bar->start(); @@ -39,7 +39,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testAdvance() { - $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream()); $bar->start(); $bar->advance(); @@ -53,7 +53,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testAdvanceWithStep() { - $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream()); $bar->start(); $bar->advance(5); @@ -67,7 +67,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testAdvanceMultipleTimes() { - $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream()); $bar->start(); $bar->advance(3); $bar->advance(2); @@ -83,7 +83,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testAdvanceOverMax() { - $bar = new ProgressBar($output = $this->getOutputStream(), 10, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 10); $bar->setProgress(9); $bar->advance(); $bar->advance(); @@ -106,7 +106,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase ; // max in construct, no format - $bar = new ProgressBar($output = $this->getOutputStream(), 10, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 10); $bar->start(); $bar->advance(10); $bar->finish(); @@ -115,7 +115,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, stream_get_contents($output->getStream())); // max in start, no format - $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream()); $bar->start(10); $bar->advance(10); $bar->finish(); @@ -124,7 +124,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, stream_get_contents($output->getStream())); // max in construct, explicit format before - $bar = new ProgressBar($output = $this->getOutputStream(), 10, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 10); $bar->setFormat('normal'); $bar->start(); $bar->advance(10); @@ -134,7 +134,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase $this->assertEquals($expected, stream_get_contents($output->getStream())); // max in start, explicit format before - $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream()); $bar->setFormat('normal'); $bar->start(10); $bar->advance(10); @@ -146,7 +146,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testCustomizations() { - $bar = new ProgressBar($output = $this->getOutputStream(), 10, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 10); $bar->setBarWidth(10); $bar->setBarCharacter('_'); $bar->setEmptyBarCharacter(' '); @@ -165,7 +165,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testDisplayWithoutStart() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 50); $bar->display(); rewind($output->getStream()); @@ -177,7 +177,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testDisplayWithQuietVerbosity() { - $bar = new ProgressBar($output = $this->getOutputStream(true, StreamOutput::VERBOSITY_QUIET), 50, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(true, StreamOutput::VERBOSITY_QUIET), 50); $bar->display(); rewind($output->getStream()); @@ -189,7 +189,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testFinishWithoutStart() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 50); $bar->finish(); rewind($output->getStream()); @@ -201,7 +201,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testPercent() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 50); $bar->start(); $bar->display(); $bar->advance(); @@ -219,7 +219,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testOverwriteWithShorterLine() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 50); $bar->setFormat(' %current%/%max% [%bar%] %percent:3s%%'); $bar->start(); $bar->display(); @@ -241,7 +241,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testStartWithMax() { - $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream()); $bar->setFormat('%current%/%max% [%bar%]'); $bar->start(50); $bar->advance(); @@ -256,7 +256,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testSetCurrentProgress() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 50); $bar->start(); $bar->display(); $bar->advance(); @@ -289,7 +289,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase */ public function testRegressProgress() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 50); $bar->start(); $bar->setProgress(15); $bar->setProgress(10); @@ -330,7 +330,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testMultiByteSupport() { - $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream()); $bar->start(); $bar->setBarCharacter('■'); $bar->advance(3); @@ -345,7 +345,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testClear() { - $bar = new ProgressBar($output = $this->getOutputStream(), 50, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 50); $bar->start(); $bar->setProgress(25); $bar->clear(); @@ -361,7 +361,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testPercentNotHundredBeforeComplete() { - $bar = new ProgressBar($output = $this->getOutputStream(), 200, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 200); $bar->start(); $bar->display(); $bar->advance(199); @@ -379,7 +379,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testNonDecoratedOutput() { - $bar = new ProgressBar($output = $this->getOutputStream(false), 200, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(false), 200); $bar->start(); for ($i = 0; $i < 200; ++$i) { @@ -407,7 +407,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testNonDecoratedOutputWithClear() { - $bar = new ProgressBar($output = $this->getOutputStream(false), 50, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(false), 50); $bar->start(); $bar->setProgress(25); $bar->clear(); @@ -425,7 +425,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testNonDecoratedOutputWithoutMax() { - $bar = new ProgressBar($output = $this->getOutputStream(false), 0, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(false)); $bar->start(); $bar->advance(); @@ -440,10 +440,10 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testParallelBars() { $output = $this->getOutputStream(); - $bar1 = new ProgressBar($output, 2, $this->createTerminalDimensionsProvider()); - $bar2 = new ProgressBar($output, 3, $this->createTerminalDimensionsProvider()); + $bar1 = new ProgressBar($output, 2); + $bar2 = new ProgressBar($output, 3); $bar2->setProgressCharacter('#'); - $bar3 = new ProgressBar($output, 0, $this->createTerminalDimensionsProvider()); + $bar3 = new ProgressBar($output); $bar1->start(); $output->write("\n"); @@ -500,7 +500,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase { $output = $this->getOutputStream(); - $bar = new ProgressBar($output, 0, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output); $bar->start(); $bar->advance(); $bar->advance(); @@ -518,12 +518,29 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase ); } + public function testWithSmallScreen() + { + $output = $this->getOutputStream(); + + $bar = new ProgressBar($output); + $bar->getTerminal()->setDimensions(12, 50); + $bar->start(); + $bar->advance(); + + rewind($output->getStream()); + $this->assertEquals( + $this->generateOutput(' 0 [>---]'). + $this->generateOutput(' 1 [->--]'), + stream_get_contents($output->getStream()) + ); + } + public function testAddingPlaceholderFormatter() { ProgressBar::setPlaceholderFormatterDefinition('remaining_steps', function (ProgressBar $bar) { return $bar->getMaxSteps() - $bar->getProgress(); }); - $bar = new ProgressBar($output = $this->getOutputStream(), 3, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 3); $bar->setFormat(' %remaining_steps% [%bar%]'); $bar->start(); @@ -541,7 +558,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testMultilineFormat() { - $bar = new ProgressBar($output = $this->getOutputStream(), 3, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 3); $bar->setFormat("%bar%\nfoobar"); $bar->start(); @@ -561,7 +578,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testAnsiColorsAndEmojis() { - $bar = new ProgressBar($output = $this->getOutputStream(), 15, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 15); ProgressBar::setPlaceholderFormatterDefinition('memory', function (ProgressBar $bar) { static $i = 0; $mem = 100000 * $i; @@ -604,7 +621,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testSetFormat() { - $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream()); $bar->setFormat('normal'); $bar->start(); rewind($output->getStream()); @@ -613,7 +630,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase stream_get_contents($output->getStream()) ); - $bar = new ProgressBar($output = $this->getOutputStream(), 10, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream(), 10); $bar->setFormat('normal'); $bar->start(); rewind($output->getStream()); @@ -628,7 +645,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase */ public function testFormatsWithoutMax($format) { - $bar = new ProgressBar($output = $this->getOutputStream(), 0, $this->createTerminalDimensionsProvider()); + $bar = new ProgressBar($output = $this->getOutputStream()); $bar->setFormat($format); $bar->start(); @@ -662,15 +679,4 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase return "\x0D\x1B[2K".($count ? str_repeat("\x1B[1A\x1B[2K", $count) : '').$expected; } - - /** - * @return TerminalDimensionsProvider - */ - private function createTerminalDimensionsProvider() - { - $terminalDimensionsProvider = new TerminalDimensionsProvider(); - $terminalDimensionsProvider->setTerminalDimensions(800, 5); - - return $terminalDimensionsProvider; - } } diff --git a/src/Symfony/Component/Console/Tests/Terminal/TerminalDimensionsProviderTest.php b/src/Symfony/Component/Console/Tests/Terminal/TerminalDimensionsProviderTest.php deleted file mode 100644 index 0dbd656bfa..0000000000 --- a/src/Symfony/Component/Console/Tests/Terminal/TerminalDimensionsProviderTest.php +++ /dev/null @@ -1,38 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Console\Tests\Terminal; - -use PHPUnit_Framework_TestCase; -use Symfony\Component\Console\Terminal\TerminalDimensionsProvider; -use Symfony\Component\Console\Terminal\TerminalDimensionsProviderInterface; - -class TerminalDimensionsProviderTest extends PHPUnit_Framework_TestCase -{ - /** - * @var TerminalDimensionsProviderInterface - */ - private $terminalDimensionsProvider; - - protected function setUp() - { - $this->terminalDimensionsProvider = new TerminalDimensionsProvider(); - } - - public function testGetTerminalDimensions() - { - $dimensions = $this->terminalDimensionsProvider->getTerminalDimensions(); - $this->assertCount(2, $dimensions); - - $this->terminalDimensionsProvider->setTerminalDimensions(100, 50); - $this->assertSame(array(100, 50), $this->terminalDimensionsProvider->getTerminalDimensions()); - } -} diff --git a/src/Symfony/Component/Console/Tests/TerminalTest.php b/src/Symfony/Component/Console/Tests/TerminalTest.php new file mode 100644 index 0000000000..959a82295f --- /dev/null +++ b/src/Symfony/Component/Console/Tests/TerminalTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests; + +use Symfony\Component\Console\Terminal; + +class TerminalTest extends \PHPUnit_Framework_TestCase +{ + public function testGetDimensions() + { + $terminal = new Terminal(); + $dimensions = $terminal->getDimensions(); + $this->assertCount(2, $dimensions); + + $terminal->setDimensions(100, 50); + $this->assertSame(array(100, 50), $terminal->getDimensions()); + $this->assertSame(100, $terminal->getWidth()); + $this->assertSame(50, $terminal->getHeight()); + } +} From a5896356431d58e626d8ec1b9a319c7520c199c3 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 9 Jun 2016 17:22:51 +0200 Subject: [PATCH 3/5] deprecated some Console Application methods --- src/Symfony/Component/Console/Application.php | 33 +++++++++++++++++-- .../Component/Console/Style/SymfonyStyle.php | 12 ++----- src/Symfony/Component/Console/Terminal.php | 4 +-- .../Console/Tests/ApplicationTest.php | 33 ++++++++----------- .../Console/Tests/Helper/ProgressBarTest.php | 2 +- .../Component/Console/Tests/TerminalTest.php | 9 ++--- 6 files changed, 52 insertions(+), 41 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 1e515b8495..afea03640d 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -625,7 +625,7 @@ class Application $len = $this->stringWidth($title); - $width = $this->getTerminalWidth() ? $this->getTerminalWidth() - 1 : PHP_INT_MAX; + $width = $this->terminal->getWidth() ? $this->terminal->getWidth() - 1 : PHP_INT_MAX; // HHVM only accepts 32 bits integer in str_split, even when PHP_INT_MAX is a 64 bit integer: https://github.com/facebook/hhvm/issues/1327 if (defined('HHVM_VERSION') && $width > 1 << 31) { $width = 1 << 31; @@ -685,13 +685,27 @@ class Application } } + /** + * Returns the current terminal. + * + * @return Terminal + */ + public function getTerminal() + { + return $this->terminal; + } + /** * Tries to figure out the terminal width in which this application runs. * * @return int|null + * + * @deprecated since version 3.2, to be removed in 4.0. Use the getTerminal() method instead. */ protected function getTerminalWidth() { + @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Use getTerminal() instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); + return $this->terminal->getWidth(); } @@ -699,9 +713,13 @@ class Application * Tries to figure out the terminal height in which this application runs. * * @return int|null + * + * @deprecated since version 3.2, to be removed in 4.0. Use the getTerminal() method instead. */ protected function getTerminalHeight() { + @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Use getTerminal() instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); + return $this->terminal->getHeight(); } @@ -709,10 +727,14 @@ class Application * Tries to figure out the terminal dimensions based on the current environment. * * @return array Array containing width and height + * + * @deprecated since version 3.2, to be removed in 4.0. Use the getTerminal() method instead. */ public function getTerminalDimensions() { - return $this->terminal->getDimensions(); + @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Use getTerminal() instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); + + return array($this->terminal->getWidth(), $this->terminal->getHeight()); } /** @@ -724,10 +746,15 @@ class Application * @param int $height The height * * @return Application The current application + * + * @deprecated since version 3.2, to be removed in 4.0. Use the getTerminal() method instead. */ public function setTerminalDimensions($width, $height) { - $this->terminal->setDimensions($width, $height); + @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Use getTerminal() instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); + + $this->terminal->setWidth($width); + $this->terminal->setHeight($height); return $this; } diff --git a/src/Symfony/Component/Console/Style/SymfonyStyle.php b/src/Symfony/Component/Console/Style/SymfonyStyle.php index 53a7951e01..8c572833c5 100644 --- a/src/Symfony/Component/Console/Style/SymfonyStyle.php +++ b/src/Symfony/Component/Console/Style/SymfonyStyle.php @@ -25,6 +25,7 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\ConfirmationQuestion; use Symfony\Component\Console\Question\Question; +use Symfony\Component\Console\Terminal; /** * Output decorator helpers for the Symfony Style Guide. @@ -50,7 +51,8 @@ class SymfonyStyle extends OutputStyle $this->input = $input; $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter()); // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. - $this->lineLength = min($this->getTerminalWidth() - (int) (DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH); + $width = (new Terminal())->getWidth() ?: self::MAX_LINE_LENGTH; + $this->lineLength = min($width - (int) (DIRECTORY_SEPARATOR === '\\'), self::MAX_LINE_LENGTH); parent::__construct($output); } @@ -401,14 +403,6 @@ class SymfonyStyle extends OutputStyle return $this->progressBar; } - private function getTerminalWidth() - { - $application = new Application(); - $dimensions = $application->getTerminalDimensions(); - - return $dimensions[0] ?: self::MAX_LINE_LENGTH; - } - private function autoPrependBlock() { $chars = substr(str_replace(PHP_EOL, "\n", $this->bufferedOutput->fetch()), -2); diff --git a/src/Symfony/Component/Console/Terminal.php b/src/Symfony/Component/Console/Terminal.php index 625a491018..8aec95bf70 100644 --- a/src/Symfony/Component/Console/Terminal.php +++ b/src/Symfony/Component/Console/Terminal.php @@ -17,7 +17,7 @@ class Terminal private $height; /** - * Tries to figure out the terminal width in which this application runs. + * Gets the terminal width. * * @return int|null */ @@ -41,7 +41,7 @@ class Terminal } /** - * Tries to figure out the terminal height in which this application runs. + * Gets the terminal height. * * @return int|null */ diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index ee21ad23dc..ac3549f00a 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -476,11 +476,9 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase public function testSetCatchExceptions() { - $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application = new Application(); $application->setAutoExit(false); - $application->expects($this->any()) - ->method('getTerminalWidth') - ->will($this->returnValue(120)); + $application->getTerminal()->setWidth(120); $tester = new ApplicationTester($application); $application->setCatchExceptions(true); @@ -514,11 +512,9 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase public function testRenderException() { - $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application = new Application(); $application->setAutoExit(false); - $application->expects($this->any()) - ->method('getTerminalWidth') - ->will($this->returnValue(120)); + $application->getTerminal()->setWidth(120); $tester = new ApplicationTester($application); $tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); @@ -546,11 +542,9 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $tester->run(array('command' => 'foo3:bar'), array('decorated' => true, 'capture_stderr_separately' => true)); $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception3decorated.txt', $tester->getErrorOutput(true), '->renderException() renders a pretty exceptions with previous exceptions'); - $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application = new Application(); $application->setAutoExit(false); - $application->expects($this->any()) - ->method('getTerminalWidth') - ->will($this->returnValue(32)); + $application->getTerminal()->setWidth(32); $tester = new ApplicationTester($application); $tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); @@ -559,11 +553,9 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase public function testRenderExceptionWithDoubleWidthCharacters() { - $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application = new Application(); $application->setAutoExit(false); - $application->expects($this->any()) - ->method('getTerminalWidth') - ->will($this->returnValue(120)); + $application->getTerminal()->setWidth(120); $application->register('foo')->setCode(function () { throw new \Exception('エラーメッセージ'); }); @@ -575,11 +567,9 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $tester->run(array('command' => 'foo'), array('decorated' => true, 'capture_stderr_separately' => true)); $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth1decorated.txt', $tester->getErrorOutput(true), '->renderException() renders a pretty exceptions with previous exceptions'); - $application = $this->getMock('Symfony\Component\Console\Application', array('getTerminalWidth')); + $application = new Application(); $application->setAutoExit(false); - $application->expects($this->any()) - ->method('getTerminalWidth') - ->will($this->returnValue(32)); + $application->getTerminal()->setWidth(32); $application->register('foo')->setCode(function () { throw new \Exception('コマンドの実行中にエラーが発生しました。'); }); @@ -1023,6 +1013,9 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $this->assertEquals('some test value', $extraValue); } + /** + * @group legacy + */ public function testTerminalDimensions() { $application = new Application(); diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php index bf7bb54d93..d78221efb7 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php @@ -523,7 +523,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase $output = $this->getOutputStream(); $bar = new ProgressBar($output); - $bar->getTerminal()->setDimensions(12, 50); + $bar->getTerminal()->setWidth(12); $bar->start(); $bar->advance(); diff --git a/src/Symfony/Component/Console/Tests/TerminalTest.php b/src/Symfony/Component/Console/Tests/TerminalTest.php index 959a82295f..edbb8a079c 100644 --- a/src/Symfony/Component/Console/Tests/TerminalTest.php +++ b/src/Symfony/Component/Console/Tests/TerminalTest.php @@ -15,14 +15,11 @@ use Symfony\Component\Console\Terminal; class TerminalTest extends \PHPUnit_Framework_TestCase { - public function testGetDimensions() + public function test() { $terminal = new Terminal(); - $dimensions = $terminal->getDimensions(); - $this->assertCount(2, $dimensions); - - $terminal->setDimensions(100, 50); - $this->assertSame(array(100, 50), $terminal->getDimensions()); + $terminal->setWidth(100); + $terminal->setHeight(50); $this->assertSame(100, $terminal->getWidth()); $this->assertSame(50, $terminal->getHeight()); } From bf7a5c58a99c46b8493c23d276692b7d86a57ef1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 9 Jun 2016 17:57:23 +0200 Subject: [PATCH 4/5] fixed logic --- src/Symfony/Component/Console/Application.php | 1 - .../Component/Console/Helper/ProgressBar.php | 29 +++++++------------ .../Component/Console/Style/SymfonyStyle.php | 1 - src/Symfony/Component/Console/Terminal.php | 4 +-- .../Console/Tests/Helper/ProgressBarTest.php | 1 - 5 files changed, 12 insertions(+), 24 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index afea03640d..313ba3f50e 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -36,7 +36,6 @@ use Symfony\Component\Console\Event\ConsoleExceptionEvent; use Symfony\Component\Console\Event\ConsoleTerminateEvent; use Symfony\Component\Console\Exception\CommandNotFoundException; use Symfony\Component\Console\Exception\LogicException; -use Symfony\Component\Console\Terminal; use Symfony\Component\EventDispatcher\EventDispatcherInterface; /** diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php index e0dce47a49..305094c99e 100644 --- a/src/Symfony/Component/Console/Helper/ProgressBar.php +++ b/src/Symfony/Component/Console/Helper/ProgressBar.php @@ -413,9 +413,7 @@ class ProgressBar $this->setRealFormat($this->internalFormat ?: $this->determineBestFormat()); } - $line = $this->buildLine(); - $line = $this->adjustLineWidthToTerminalWidth($line); - $this->overwrite($line); + $this->overwrite($this->buildLine()); } /** @@ -601,7 +599,8 @@ class ProgressBar */ private function buildLine() { - return preg_replace_callback("{%([a-z\-_]+)(?:\:([^%]+))?%}i", function ($matches) { + $regex = "{%([a-z\-_]+)(?:\:([^%]+))?%}i"; + $callback = function ($matches) { if ($formatter = $this::getPlaceholderFormatterDefinition($matches[1])) { $text = call_user_func($formatter, $this, $this->output); } elseif (isset($this->messages[$matches[1]])) { @@ -615,25 +614,17 @@ class ProgressBar } return $text; - }, $this->format); - } + }; + $line = preg_replace_callback($regex, $callback, $this->format); - /** - * @param string $line - * - * @return bool - */ - private function adjustLineWidthToTerminalWidth($line) - { $lineLength = Helper::strlenWithoutDecoration($this->output->getFormatter(), $line); $terminalWidth = $this->terminal->getWidth(); - if ($lineLength > $terminalWidth) { - $newBarWidth = $this->barWidth - $lineLength + $terminalWidth; - $this->setBarWidth($newBarWidth); - - return $this->buildLine(); + if ($lineLength <= $terminalWidth) { + return $line; } - return $line; + $this->setBarWidth($this->barWidth - $lineLength + $terminalWidth); + + return preg_replace_callback($regex, $callback, $this->format); } } diff --git a/src/Symfony/Component/Console/Style/SymfonyStyle.php b/src/Symfony/Component/Console/Style/SymfonyStyle.php index 8c572833c5..c89ad1667f 100644 --- a/src/Symfony/Component/Console/Style/SymfonyStyle.php +++ b/src/Symfony/Component/Console/Style/SymfonyStyle.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Console\Style; -use Symfony\Component\Console\Application; use Symfony\Component\Console\Exception\RuntimeException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\Helper; diff --git a/src/Symfony/Component/Console/Terminal.php b/src/Symfony/Component/Console/Terminal.php index 8aec95bf70..ef2d8e44b8 100644 --- a/src/Symfony/Component/Console/Terminal.php +++ b/src/Symfony/Component/Console/Terminal.php @@ -33,7 +33,7 @@ class Terminal /** * Sets the terminal width. * - * @param int + * @param int $width */ public function setWidth($width) { @@ -57,7 +57,7 @@ class Terminal /** * Sets the terminal height. * - * @param int + * @param int $height */ public function setHeight($height) { diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php index d78221efb7..e0a7fa889a 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php @@ -14,7 +14,6 @@ namespace Symfony\Component\Console\Tests\Helper; use Symfony\Component\Console\Helper\ProgressBar; use Symfony\Component\Console\Helper\Helper; use Symfony\Component\Console\Output\StreamOutput; -use Symfony\Component\Console\Terminal; /** * @group time-sensitive From 2f812470052c7145451f5f12523d6cc744787a8a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 10 Jun 2016 08:21:21 +0200 Subject: [PATCH 5/5] switched to use COLUMNS and LINES env vars to change terminal dimensions --- src/Symfony/Component/Console/Application.php | 30 ++---- .../Component/Console/Helper/ProgressBar.php | 14 --- src/Symfony/Component/Console/Terminal.php | 96 +++++++------------ .../Console/Tests/ApplicationTest.php | 12 ++- .../Console/Tests/Helper/ProgressBarTest.php | 34 +++++-- .../Component/Console/Tests/TerminalTest.php | 10 +- 6 files changed, 84 insertions(+), 112 deletions(-) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 313ba3f50e..71f0d9a950 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -684,26 +684,16 @@ class Application } } - /** - * Returns the current terminal. - * - * @return Terminal - */ - public function getTerminal() - { - return $this->terminal; - } - /** * Tries to figure out the terminal width in which this application runs. * * @return int|null * - * @deprecated since version 3.2, to be removed in 4.0. Use the getTerminal() method instead. + * @deprecated since version 3.2, to be removed in 4.0. Create a Terminal instance instead. */ protected function getTerminalWidth() { - @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Use getTerminal() instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); + @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Create a Terminal instance instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); return $this->terminal->getWidth(); } @@ -713,11 +703,11 @@ class Application * * @return int|null * - * @deprecated since version 3.2, to be removed in 4.0. Use the getTerminal() method instead. + * @deprecated since version 3.2, to be removed in 4.0. Create a Terminal instance instead. */ protected function getTerminalHeight() { - @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Use getTerminal() instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); + @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Create a Terminal instance instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); return $this->terminal->getHeight(); } @@ -727,11 +717,11 @@ class Application * * @return array Array containing width and height * - * @deprecated since version 3.2, to be removed in 4.0. Use the getTerminal() method instead. + * @deprecated since version 3.2, to be removed in 4.0. Create a Terminal instance instead. */ public function getTerminalDimensions() { - @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Use getTerminal() instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); + @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Create a Terminal instance instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); return array($this->terminal->getWidth(), $this->terminal->getHeight()); } @@ -746,14 +736,14 @@ class Application * * @return Application The current application * - * @deprecated since version 3.2, to be removed in 4.0. Use the getTerminal() method instead. + * @deprecated since version 3.2, to be removed in 4.0. Set the COLUMNS and LINES env vars instead. */ public function setTerminalDimensions($width, $height) { - @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Use getTerminal() instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); + @trigger_error(sprintf('%s is deprecated as of 3.2 and will be removed in 4.0. Set the COLUMNS and LINES env vars instead.', __METHOD__, ArgumentResolverInterface::class), E_USER_DEPRECATED); - $this->terminal->setWidth($width); - $this->terminal->setHeight($height); + putenv('COLUMNS='.$width); + putenv('LINES='.$height); return $this; } diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php index 305094c99e..896cbf5eff 100644 --- a/src/Symfony/Component/Console/Helper/ProgressBar.php +++ b/src/Symfony/Component/Console/Helper/ProgressBar.php @@ -436,20 +436,6 @@ class ProgressBar $this->overwrite(''); } - /** - * Gets the terminal. - * - * Can be useful to force terminal dimensions for functional tests. - * - * @return Terminal - * - * @internal - */ - public function getTerminal() - { - return $this->terminal; - } - /** * Sets the progress bar format. * diff --git a/src/Symfony/Component/Console/Terminal.php b/src/Symfony/Component/Console/Terminal.php index ef2d8e44b8..4a6c30b8a0 100644 --- a/src/Symfony/Component/Console/Terminal.php +++ b/src/Symfony/Component/Console/Terminal.php @@ -13,8 +13,8 @@ namespace Symfony\Component\Console; class Terminal { - private $width; - private $height; + private static $width; + private static $height; /** * Gets the terminal width. @@ -23,21 +23,15 @@ class Terminal */ public function getWidth() { - if (null === $this->width) { - $this->initDimensions(); + if ($width = trim(getenv('COLUMNS'))) { + return (int) $width; } - return $this->width; - } + if (null === self::$width) { + self::initDimensions(); + } - /** - * Sets the terminal width. - * - * @param int $width - */ - public function setWidth($width) - { - $this->width = $width; + return self::$width; } /** @@ -47,59 +41,41 @@ class Terminal */ public function getHeight() { - if (null === $this->height) { - $this->initDimensions(); + if ($height = trim(getenv('LINES'))) { + return (int) $height; } - return $this->height; - } - - /** - * Sets the terminal height. - * - * @param int $height - */ - public function setHeight($height) - { - $this->height = $height; - } - - private function initDimensions() - { - if (null !== $this->width && null !== $this->height) { - return; + if (null === self::$height) { + self::initDimensions(); } - $width = $height = null; - if ($this->isWindowsEnvironment()) { - if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) { + return self::$height; + } + + private static function initDimensions() + { + if ('\\' === DIRECTORY_SEPARATOR) { + if (preg_match('/^(\d+)x(\d+)(?: \((\d+)x(\d+)\))?$/', trim(getenv('ANSICON')), $matches)) { // extract [w, H] from "wxh (WxH)" - $width = (int) $matches[1]; - $height = (int) $matches[2]; - } elseif (null != $dimensions = $this->getConsoleMode()) { + // or [w, h] from "wxh" + self::$width = (int) $matches[1]; + self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2]; + } elseif (null != $dimensions = self::getConsoleMode()) { // extract [w, h] from "wxh" - $width = $dimensions[0]; - $height = $dimensions[1]; + self::$width = (int) $dimensions[0]; + self::$height = (int) $dimensions[1]; } - } elseif ($sttyString = $this->getSttyColumns()) { + } elseif ($sttyString = self::getSttyColumns()) { if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) { // extract [w, h] from "rows h; columns w;" - $width = (int) $matches[1]; - $height = (int) $matches[2]; + self::$width = (int) $matches[2]; + self::$height = (int) $matches[1]; } elseif (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) { // extract [w, h] from "; h rows; w columns" - $width = (int) $matches[2]; - $heighth = (int) $matches[1]; + self::$width = (int) $matches[2]; + self::$height = (int) $matches[1]; } } - - if (null === $this->width) { - $this->width = $width; - } - - if (null === $this->height) { - $this->height = $height; - } } /** @@ -107,7 +83,7 @@ class Terminal * * @return array|null An array composed of the width and the height or null if it could not be parsed */ - private function getConsoleMode() + private static function getConsoleMode() { if (!function_exists('proc_open')) { return; @@ -135,7 +111,7 @@ class Terminal * * @return string */ - private function getSttyColumns() + private static function getSttyColumns() { if (!function_exists('proc_open')) { return; @@ -156,12 +132,4 @@ class Terminal return $info; } } - - /** - * @return bool - */ - private function isWindowsEnvironment() - { - return '\\' === DIRECTORY_SEPARATOR; - } } diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index ac3549f00a..60ab13dacc 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -478,7 +478,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase { $application = new Application(); $application->setAutoExit(false); - $application->getTerminal()->setWidth(120); + putenv('COLUMNS=120'); $tester = new ApplicationTester($application); $application->setCatchExceptions(true); @@ -514,7 +514,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase { $application = new Application(); $application->setAutoExit(false); - $application->getTerminal()->setWidth(120); + putenv('COLUMNS=120'); $tester = new ApplicationTester($application); $tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); @@ -544,18 +544,19 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $application = new Application(); $application->setAutoExit(false); - $application->getTerminal()->setWidth(32); + putenv('COLUMNS=32'); $tester = new ApplicationTester($application); $tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception4.txt', $tester->getErrorOutput(true), '->renderException() wraps messages when they are bigger than the terminal'); + putenv('COLUMNS=120'); } public function testRenderExceptionWithDoubleWidthCharacters() { $application = new Application(); $application->setAutoExit(false); - $application->getTerminal()->setWidth(120); + putenv('COLUMNS=120'); $application->register('foo')->setCode(function () { throw new \Exception('エラーメッセージ'); }); @@ -569,13 +570,14 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase $application = new Application(); $application->setAutoExit(false); - $application->getTerminal()->setWidth(32); + putenv('COLUMNS=32'); $application->register('foo')->setCode(function () { throw new \Exception('コマンドの実行中にエラーが発生しました。'); }); $tester = new ApplicationTester($application); $tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); $this->assertStringEqualsFile(self::$fixturesPath.'/application_renderexception_doublewidth2.txt', $tester->getErrorOutput(true), '->renderException() wraps messages when they are bigger than the terminal'); + putenv('COLUMNS=120'); } public function testRun() diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php index e0a7fa889a..96bfc6e4b4 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php @@ -522,9 +522,10 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase $output = $this->getOutputStream(); $bar = new ProgressBar($output); - $bar->getTerminal()->setWidth(12); + putenv('COLUMNS=12'); $bar->start(); $bar->advance(); + putenv('COLUMNS=120'); rewind($output->getStream()); $this->assertEquals( @@ -577,6 +578,8 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase public function testAnsiColorsAndEmojis() { + putenv('COLUMNS=156'); + $bar = new ProgressBar($output = $this->getOutputStream(), 15); ProgressBar::setPlaceholderFormatterDefinition('memory', function (ProgressBar $bar) { static $i = 0; @@ -592,10 +595,6 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase $bar->setMessage('Starting the demo... fingers crossed', 'title'); $bar->start(); - $bar->setMessage('Looks good to me...', 'title'); - $bar->advance(4); - $bar->setMessage('Thanks, bye', 'title'); - $bar->finish(); rewind($output->getStream()); $this->assertEquals( @@ -603,12 +602,32 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase " \033[44;37m Starting the demo... fingers crossed \033[0m\n". ' 0/15 '.$progress.str_repeat($empty, 26)." 0%\n". " \xf0\x9f\x8f\x81 < 1 sec \033[44;37m 0 B \033[0m" - ). + ), + stream_get_contents($output->getStream()) + ); + ftruncate($output->getStream(), 0); + rewind($output->getStream()); + + $bar->setMessage('Looks good to me...', 'title'); + $bar->advance(4); + + rewind($output->getStream()); + $this->assertEquals( $this->generateOutput( " \033[44;37m Looks good to me... \033[0m\n". ' 4/15 '.str_repeat($done, 7).$progress.str_repeat($empty, 19)." 26%\n". " \xf0\x9f\x8f\x81 < 1 sec \033[41;37m 97 KiB \033[0m" - ). + ), + stream_get_contents($output->getStream()) + ); + ftruncate($output->getStream(), 0); + rewind($output->getStream()); + + $bar->setMessage('Thanks, bye', 'title'); + $bar->finish(); + + rewind($output->getStream()); + $this->assertEquals( $this->generateOutput( " \033[44;37m Thanks, bye \033[0m\n". ' 15/15 '.str_repeat($done, 28)." 100%\n". @@ -616,6 +635,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase ), stream_get_contents($output->getStream()) ); + putenv('COLUMNS=120'); } public function testSetFormat() diff --git a/src/Symfony/Component/Console/Tests/TerminalTest.php b/src/Symfony/Component/Console/Tests/TerminalTest.php index edbb8a079c..f13102244e 100644 --- a/src/Symfony/Component/Console/Tests/TerminalTest.php +++ b/src/Symfony/Component/Console/Tests/TerminalTest.php @@ -17,10 +17,16 @@ class TerminalTest extends \PHPUnit_Framework_TestCase { public function test() { + putenv('COLUMNS=100'); + putenv('LINES=50'); $terminal = new Terminal(); - $terminal->setWidth(100); - $terminal->setHeight(50); $this->assertSame(100, $terminal->getWidth()); $this->assertSame(50, $terminal->getHeight()); + + putenv('COLUMNS=120'); + putenv('LINES=60'); + $terminal = new Terminal(); + $this->assertSame(120, $terminal->getWidth()); + $this->assertSame(60, $terminal->getHeight()); } }