switched to use COLUMNS and LINES env vars to change terminal dimensions

This commit is contained in:
Fabien Potencier 2016-06-10 08:21:21 +02:00
parent bf7a5c58a9
commit 2f81247005
6 changed files with 84 additions and 112 deletions

View File

@ -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. * Tries to figure out the terminal width in which this application runs.
* *
* @return int|null * @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() 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(); return $this->terminal->getWidth();
} }
@ -713,11 +703,11 @@ class Application
* *
* @return int|null * @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() 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(); return $this->terminal->getHeight();
} }
@ -727,11 +717,11 @@ class Application
* *
* @return array Array containing width and height * @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() 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()); return array($this->terminal->getWidth(), $this->terminal->getHeight());
} }
@ -746,14 +736,14 @@ class Application
* *
* @return Application The current 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) 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); putenv('COLUMNS='.$width);
$this->terminal->setHeight($height); putenv('LINES='.$height);
return $this; return $this;
} }

View File

@ -436,20 +436,6 @@ class ProgressBar
$this->overwrite(''); $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. * Sets the progress bar format.
* *

View File

@ -13,8 +13,8 @@ namespace Symfony\Component\Console;
class Terminal class Terminal
{ {
private $width; private static $width;
private $height; private static $height;
/** /**
* Gets the terminal width. * Gets the terminal width.
@ -23,21 +23,15 @@ class Terminal
*/ */
public function getWidth() public function getWidth()
{ {
if (null === $this->width) { if ($width = trim(getenv('COLUMNS'))) {
$this->initDimensions(); return (int) $width;
} }
return $this->width; if (null === self::$width) {
} self::initDimensions();
}
/** return self::$width;
* Sets the terminal width.
*
* @param int $width
*/
public function setWidth($width)
{
$this->width = $width;
} }
/** /**
@ -47,59 +41,41 @@ class Terminal
*/ */
public function getHeight() public function getHeight()
{ {
if (null === $this->height) { if ($height = trim(getenv('LINES'))) {
$this->initDimensions(); return (int) $height;
} }
return $this->height; if (null === self::$height) {
} self::initDimensions();
/**
* 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;
} }
$width = $height = null; return self::$height;
if ($this->isWindowsEnvironment()) { }
if (preg_match('/^(\d+)x\d+ \(\d+x(\d+)\)$/', trim(getenv('ANSICON')), $matches)) {
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)" // extract [w, H] from "wxh (WxH)"
$width = (int) $matches[1]; // or [w, h] from "wxh"
$height = (int) $matches[2]; self::$width = (int) $matches[1];
} elseif (null != $dimensions = $this->getConsoleMode()) { self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
} elseif (null != $dimensions = self::getConsoleMode()) {
// extract [w, h] from "wxh" // extract [w, h] from "wxh"
$width = $dimensions[0]; self::$width = (int) $dimensions[0];
$height = $dimensions[1]; self::$height = (int) $dimensions[1];
} }
} elseif ($sttyString = $this->getSttyColumns()) { } elseif ($sttyString = self::getSttyColumns()) {
if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) { if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
// extract [w, h] from "rows h; columns w;" // extract [w, h] from "rows h; columns w;"
$width = (int) $matches[1]; self::$width = (int) $matches[2];
$height = (int) $matches[2]; self::$height = (int) $matches[1];
} elseif (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) { } elseif (preg_match('/;.(\d+).rows;.(\d+).columns/i', $sttyString, $matches)) {
// extract [w, h] from "; h rows; w columns" // extract [w, h] from "; h rows; w columns"
$width = (int) $matches[2]; self::$width = (int) $matches[2];
$heighth = (int) $matches[1]; 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 * @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')) { if (!function_exists('proc_open')) {
return; return;
@ -135,7 +111,7 @@ class Terminal
* *
* @return string * @return string
*/ */
private function getSttyColumns() private static function getSttyColumns()
{ {
if (!function_exists('proc_open')) { if (!function_exists('proc_open')) {
return; return;
@ -156,12 +132,4 @@ class Terminal
return $info; return $info;
} }
} }
/**
* @return bool
*/
private function isWindowsEnvironment()
{
return '\\' === DIRECTORY_SEPARATOR;
}
} }

View File

@ -478,7 +478,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
{ {
$application = new Application(); $application = new Application();
$application->setAutoExit(false); $application->setAutoExit(false);
$application->getTerminal()->setWidth(120); putenv('COLUMNS=120');
$tester = new ApplicationTester($application); $tester = new ApplicationTester($application);
$application->setCatchExceptions(true); $application->setCatchExceptions(true);
@ -514,7 +514,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
{ {
$application = new Application(); $application = new Application();
$application->setAutoExit(false); $application->setAutoExit(false);
$application->getTerminal()->setWidth(120); putenv('COLUMNS=120');
$tester = new ApplicationTester($application); $tester = new ApplicationTester($application);
$tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); $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 = new Application();
$application->setAutoExit(false); $application->setAutoExit(false);
$application->getTerminal()->setWidth(32); putenv('COLUMNS=32');
$tester = new ApplicationTester($application); $tester = new ApplicationTester($application);
$tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); $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'); $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() public function testRenderExceptionWithDoubleWidthCharacters()
{ {
$application = new Application(); $application = new Application();
$application->setAutoExit(false); $application->setAutoExit(false);
$application->getTerminal()->setWidth(120); putenv('COLUMNS=120');
$application->register('foo')->setCode(function () { $application->register('foo')->setCode(function () {
throw new \Exception('エラーメッセージ'); throw new \Exception('エラーメッセージ');
}); });
@ -569,13 +570,14 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
$application = new Application(); $application = new Application();
$application->setAutoExit(false); $application->setAutoExit(false);
$application->getTerminal()->setWidth(32); putenv('COLUMNS=32');
$application->register('foo')->setCode(function () { $application->register('foo')->setCode(function () {
throw new \Exception('コマンドの実行中にエラーが発生しました。'); throw new \Exception('コマンドの実行中にエラーが発生しました。');
}); });
$tester = new ApplicationTester($application); $tester = new ApplicationTester($application);
$tester->run(array('command' => 'foo'), array('decorated' => false, 'capture_stderr_separately' => true)); $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'); $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() public function testRun()

View File

@ -522,9 +522,10 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase
$output = $this->getOutputStream(); $output = $this->getOutputStream();
$bar = new ProgressBar($output); $bar = new ProgressBar($output);
$bar->getTerminal()->setWidth(12); putenv('COLUMNS=12');
$bar->start(); $bar->start();
$bar->advance(); $bar->advance();
putenv('COLUMNS=120');
rewind($output->getStream()); rewind($output->getStream());
$this->assertEquals( $this->assertEquals(
@ -577,6 +578,8 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase
public function testAnsiColorsAndEmojis() public function testAnsiColorsAndEmojis()
{ {
putenv('COLUMNS=156');
$bar = new ProgressBar($output = $this->getOutputStream(), 15); $bar = new ProgressBar($output = $this->getOutputStream(), 15);
ProgressBar::setPlaceholderFormatterDefinition('memory', function (ProgressBar $bar) { ProgressBar::setPlaceholderFormatterDefinition('memory', function (ProgressBar $bar) {
static $i = 0; static $i = 0;
@ -592,10 +595,6 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase
$bar->setMessage('Starting the demo... fingers crossed', 'title'); $bar->setMessage('Starting the demo... fingers crossed', 'title');
$bar->start(); $bar->start();
$bar->setMessage('Looks good to me...', 'title');
$bar->advance(4);
$bar->setMessage('Thanks, bye', 'title');
$bar->finish();
rewind($output->getStream()); rewind($output->getStream());
$this->assertEquals( $this->assertEquals(
@ -603,12 +602,32 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase
" \033[44;37m Starting the demo... fingers crossed \033[0m\n". " \033[44;37m Starting the demo... fingers crossed \033[0m\n".
' 0/15 '.$progress.str_repeat($empty, 26)." 0%\n". ' 0/15 '.$progress.str_repeat($empty, 26)." 0%\n".
" \xf0\x9f\x8f\x81 < 1 sec \033[44;37m 0 B \033[0m" " \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( $this->generateOutput(
" \033[44;37m Looks good to me... \033[0m\n". " \033[44;37m Looks good to me... \033[0m\n".
' 4/15 '.str_repeat($done, 7).$progress.str_repeat($empty, 19)." 26%\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" " \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( $this->generateOutput(
" \033[44;37m Thanks, bye \033[0m\n". " \033[44;37m Thanks, bye \033[0m\n".
' 15/15 '.str_repeat($done, 28)." 100%\n". ' 15/15 '.str_repeat($done, 28)." 100%\n".
@ -616,6 +635,7 @@ class ProgressBarTest extends \PHPUnit_Framework_TestCase
), ),
stream_get_contents($output->getStream()) stream_get_contents($output->getStream())
); );
putenv('COLUMNS=120');
} }
public function testSetFormat() public function testSetFormat()

View File

@ -17,10 +17,16 @@ class TerminalTest extends \PHPUnit_Framework_TestCase
{ {
public function test() public function test()
{ {
putenv('COLUMNS=100');
putenv('LINES=50');
$terminal = new Terminal(); $terminal = new Terminal();
$terminal->setWidth(100);
$terminal->setHeight(50);
$this->assertSame(100, $terminal->getWidth()); $this->assertSame(100, $terminal->getWidth());
$this->assertSame(50, $terminal->getHeight()); $this->assertSame(50, $terminal->getHeight());
putenv('COLUMNS=120');
putenv('LINES=60');
$terminal = new Terminal();
$this->assertSame(120, $terminal->getWidth());
$this->assertSame(60, $terminal->getHeight());
} }
} }