Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[Console] Get dimensions from stty on windows if possible #32763

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
[Console] Get dimensions from stty on windows if possible
  • Loading branch information
rtek authored and chalasr committed Sep 13, 2019
commit 52650803bf950556d0465e20fbea6dc14886cbc8
21 changes: 3 additions & 18 deletions 21 src/Symfony/Component/Console/Helper/QuestionHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Terminal;

/**
* The QuestionHelper class provides helpers to interact with the user.
Expand Down Expand Up @@ -157,7 +158,7 @@ private function doAsk(OutputInterface $output, Question $question)
$inputStream = $this->inputStream ?: STDIN;
$autocomplete = $question->getAutocompleterValues();

if (null === $autocomplete || !$this->hasSttyAvailable()) {
if (null === $autocomplete || !Terminal::hasSttyAvailable()) {
$ret = false;
if ($question->isHidden()) {
try {
Expand Down Expand Up @@ -409,7 +410,7 @@ private function getHiddenResponse(OutputInterface $output, $inputStream)
return $value;
}

if ($this->hasSttyAvailable()) {
if (Terminal::hasSttyAvailable()) {
$sttyMode = shell_exec('stty -g');

shell_exec('stty -echo');
Expand Down Expand Up @@ -495,20 +496,4 @@ private function getShell()

return self::$shell;
}

/**
* Returns whether Stty is available or not.
*
* @return bool
*/
private function hasSttyAvailable()
{
if (null !== self::$stty) {
return self::$stty;
}

exec('stty 2>&1', $output, $exitcode);

return self::$stty = 0 === $exitcode;
}
}
28 changes: 27 additions & 1 deletion 28 src/Symfony/Component/Console/Terminal.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class Terminal
{
private static $width;
private static $height;
private static $stty;

/**
* Gets the terminal width.
Expand Down Expand Up @@ -54,6 +55,22 @@ public function getHeight()
return self::$height ?: 50;
}

/**
* @internal
*
* @return bool
*/
chalasr marked this conversation as resolved.
Show resolved Hide resolved
public static function hasSttyAvailable()
{
if (null !== self::$stty) {
return self::$stty;
}

exec('stty 2>&1', $output, $exitcode);

return self::$stty = 0 === $exitcode;
}

private static function initDimensions()
{
if ('\\' === \DIRECTORY_SEPARATOR) {
Expand All @@ -62,12 +79,21 @@ private static function initDimensions()
// or [w, h] from "wxh"
self::$width = (int) $matches[1];
self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
} elseif (self::hasSttyAvailable()) {
self::initDimensionsUsingStty();
} elseif (null !== $dimensions = self::getConsoleMode()) {
// extract [w, h] from "wxh"
self::$width = (int) $dimensions[0];
self::$height = (int) $dimensions[1];
}
} elseif ($sttyString = self::getSttyColumns()) {
} else {
self::initDimensionsUsingStty();
}
}

private static function initDimensionsUsingStty()
{
if ($sttyString = self::getSttyColumns()) {
if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
// extract [w, h] from "rows h; columns w;"
self::$width = (int) $matches[2];
Expand Down
24 changes: 9 additions & 15 deletions 24 src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Symfony\Component\Console\Question\ChoiceQuestion;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Terminal;

/**
* @group tty
Expand Down Expand Up @@ -167,7 +168,7 @@ public function testAsk()

public function testAskWithAutocomplete()
{
if (!$this->hasSttyAvailable()) {
if (!Terminal::hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}

Expand Down Expand Up @@ -200,7 +201,7 @@ public function testAskWithAutocomplete()

public function testAskWithAutocompleteWithNonSequentialKeys()
{
if (!$this->hasSttyAvailable()) {
if (!Terminal::hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}

Expand All @@ -219,7 +220,7 @@ public function testAskWithAutocompleteWithNonSequentialKeys()

public function testAskWithAutocompleteWithExactMatch()
{
if (!$this->hasSttyAvailable()) {
if (!Terminal::hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}

Expand Down Expand Up @@ -255,7 +256,7 @@ public function getInputs()
*/
public function testAskWithAutocompleteWithMultiByteCharacter($character)
{
if (!$this->hasSttyAvailable()) {
if (!Terminal::hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}

Expand All @@ -279,7 +280,7 @@ public function testAskWithAutocompleteWithMultiByteCharacter($character)

public function testAutocompleteWithTrailingBackslash()
{
if (!$this->hasSttyAvailable()) {
if (!Terminal::hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}

Expand Down Expand Up @@ -672,7 +673,7 @@ public function testLegacyAsk()
*/
public function testLegacyAskWithAutocomplete()
{
if (!$this->hasSttyAvailable()) {
if (!Terminal::hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}

Expand Down Expand Up @@ -709,7 +710,7 @@ public function testLegacyAskWithAutocomplete()
*/
public function testLegacyAskWithAutocompleteWithNonSequentialKeys()
{
if (!$this->hasSttyAvailable()) {
if (!Terminal::hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}

Expand Down Expand Up @@ -977,7 +978,7 @@ public function testEmptyChoices()

public function testTraversableAutocomplete()
{
if (!$this->hasSttyAvailable()) {
if (!Terminal::hasSttyAvailable()) {
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
}

Expand Down Expand Up @@ -1062,13 +1063,6 @@ protected function createInputInterfaceMock($interactive = true)

return $mock;
}

private function hasSttyAvailable()
{
exec('stty 2>&1', $output, $exitcode);
fabpot marked this conversation as resolved.
Show resolved Hide resolved

return 0 === $exitcode;
}
}

class AutocompleteValues implements \IteratorAggregate
Expand Down
38 changes: 38 additions & 0 deletions 38 src/Symfony/Component/Console/Tests/TerminalTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,31 @@ class TerminalTest extends TestCase
{
private $colSize;
private $lineSize;
private $ansiCon;

protected function setUp()
{
$this->colSize = getenv('COLUMNS');
$this->lineSize = getenv('LINES');
$this->ansiCon = getenv('ANSICON');
$this->resetStatics();
}

protected function tearDown()
{
putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS');
putenv($this->lineSize ? 'LINES' : 'LINES='.$this->lineSize);
putenv($this->ansiCon ? 'ANSICON='.$this->ansiCon : 'ANSICON');
$this->resetStatics();
}

private function resetStatics()
{
foreach (['height', 'width', 'stty'] as $name) {
$property = new \ReflectionProperty(Terminal::class, $name);
$property->setAccessible(true);
$property->setValue(null);
}
}

public function test()
Expand Down Expand Up @@ -56,4 +70,28 @@ public function test_zero_values()
$this->assertSame(0, $terminal->getWidth());
$this->assertSame(0, $terminal->getHeight());
}

public function testSttyOnWindows()
{
if ('\\' !== \DIRECTORY_SEPARATOR) {
$this->markTestSkipped('Must be on windows');
}

$sttyString = exec('(stty -a | grep columns) 2>&1', $output, $exitcode);
if (0 !== $exitcode) {
$this->markTestSkipped('Must have stty support');
}

$matches = [];
if (0 === preg_match('/columns.(\d+)/i', $sttyString, $matches)) {
$this->fail('Could not determine existing stty columns');
}

putenv('COLUMNS');
putenv('LINES');
putenv('ANSICON');

$terminal = new Terminal();
$this->assertSame((int) $matches[1], $terminal->getWidth());
}
}
Morty Proxy This is a proxified and sanitized view of the page, visit original site.