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

Commit d6855d4

Browse filesBrowse files
committed
bug #32763 [Console] Get dimensions from stty on windows if possible (rtek)
This PR was merged into the 3.4 branch. Discussion ---------- [Console] Get dimensions from stty on windows if possible | Q | A | ------------- | --- | Branch? | 4.3 | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | | License | MIT | Doc PR | `Console\Terminal` is modified to extract width/height settings to from `stty` on windows if possible. Previously such values were extracted from `mode CON`. If another terminal is in use (eg, gitbash) then the incorrect values would be applied. Commits ------- 5265080 [Console] Get dimensions from stty on windows if possible
2 parents ac7df04 + 5265080 commit d6855d4
Copy full SHA for d6855d4

File tree

4 files changed

+77
-34
lines changed
Filter options

4 files changed

+77
-34
lines changed

‎src/Symfony/Component/Console/Helper/QuestionHelper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Helper/QuestionHelper.php
+3-18Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Symfony\Component\Console\Output\OutputInterface;
2222
use Symfony\Component\Console\Question\ChoiceQuestion;
2323
use Symfony\Component\Console\Question\Question;
24+
use Symfony\Component\Console\Terminal;
2425

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

160-
if (null === $autocomplete || !$this->hasSttyAvailable()) {
161+
if (null === $autocomplete || !Terminal::hasSttyAvailable()) {
161162
$ret = false;
162163
if ($question->isHidden()) {
163164
try {
@@ -409,7 +410,7 @@ private function getHiddenResponse(OutputInterface $output, $inputStream)
409410
return $value;
410411
}
411412

412-
if ($this->hasSttyAvailable()) {
413+
if (Terminal::hasSttyAvailable()) {
413414
$sttyMode = shell_exec('stty -g');
414415

415416
shell_exec('stty -echo');
@@ -495,20 +496,4 @@ private function getShell()
495496

496497
return self::$shell;
497498
}
498-
499-
/**
500-
* Returns whether Stty is available or not.
501-
*
502-
* @return bool
503-
*/
504-
private function hasSttyAvailable()
505-
{
506-
if (null !== self::$stty) {
507-
return self::$stty;
508-
}
509-
510-
exec('stty 2>&1', $output, $exitcode);
511-
512-
return self::$stty = 0 === $exitcode;
513-
}
514499
}

‎src/Symfony/Component/Console/Terminal.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Terminal.php
+27-1Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class Terminal
1515
{
1616
private static $width;
1717
private static $height;
18+
private static $stty;
1819

1920
/**
2021
* Gets the terminal width.
@@ -54,6 +55,22 @@ public function getHeight()
5455
return self::$height ?: 50;
5556
}
5657

58+
/**
59+
* @internal
60+
*
61+
* @return bool
62+
*/
63+
public static function hasSttyAvailable()
64+
{
65+
if (null !== self::$stty) {
66+
return self::$stty;
67+
}
68+
69+
exec('stty 2>&1', $output, $exitcode);
70+
71+
return self::$stty = 0 === $exitcode;
72+
}
73+
5774
private static function initDimensions()
5875
{
5976
if ('\\' === \DIRECTORY_SEPARATOR) {
@@ -62,12 +79,21 @@ private static function initDimensions()
6279
// or [w, h] from "wxh"
6380
self::$width = (int) $matches[1];
6481
self::$height = isset($matches[4]) ? (int) $matches[4] : (int) $matches[2];
82+
} elseif (self::hasSttyAvailable()) {
83+
self::initDimensionsUsingStty();
6584
} elseif (null !== $dimensions = self::getConsoleMode()) {
6685
// extract [w, h] from "wxh"
6786
self::$width = (int) $dimensions[0];
6887
self::$height = (int) $dimensions[1];
6988
}
70-
} elseif ($sttyString = self::getSttyColumns()) {
89+
} else {
90+
self::initDimensionsUsingStty();
91+
}
92+
}
93+
94+
private static function initDimensionsUsingStty()
95+
{
96+
if ($sttyString = self::getSttyColumns()) {
7197
if (preg_match('/rows.(\d+);.columns.(\d+);/i', $sttyString, $matches)) {
7298
// extract [w, h] from "rows h; columns w;"
7399
self::$width = (int) $matches[2];

‎src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php
+9-15Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\Console\Question\ChoiceQuestion;
2020
use Symfony\Component\Console\Question\ConfirmationQuestion;
2121
use Symfony\Component\Console\Question\Question;
22+
use Symfony\Component\Console\Terminal;
2223

2324
/**
2425
* @group tty
@@ -167,7 +168,7 @@ public function testAsk()
167168

168169
public function testAskWithAutocomplete()
169170
{
170-
if (!$this->hasSttyAvailable()) {
171+
if (!Terminal::hasSttyAvailable()) {
171172
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
172173
}
173174

@@ -200,7 +201,7 @@ public function testAskWithAutocomplete()
200201

201202
public function testAskWithAutocompleteWithNonSequentialKeys()
202203
{
203-
if (!$this->hasSttyAvailable()) {
204+
if (!Terminal::hasSttyAvailable()) {
204205
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
205206
}
206207

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

220221
public function testAskWithAutocompleteWithExactMatch()
221222
{
222-
if (!$this->hasSttyAvailable()) {
223+
if (!Terminal::hasSttyAvailable()) {
223224
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
224225
}
225226

@@ -255,7 +256,7 @@ public function getInputs()
255256
*/
256257
public function testAskWithAutocompleteWithMultiByteCharacter($character)
257258
{
258-
if (!$this->hasSttyAvailable()) {
259+
if (!Terminal::hasSttyAvailable()) {
259260
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
260261
}
261262

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

280281
public function testAutocompleteWithTrailingBackslash()
281282
{
282-
if (!$this->hasSttyAvailable()) {
283+
if (!Terminal::hasSttyAvailable()) {
283284
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
284285
}
285286

@@ -672,7 +673,7 @@ public function testLegacyAsk()
672673
*/
673674
public function testLegacyAskWithAutocomplete()
674675
{
675-
if (!$this->hasSttyAvailable()) {
676+
if (!Terminal::hasSttyAvailable()) {
676677
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
677678
}
678679

@@ -709,7 +710,7 @@ public function testLegacyAskWithAutocomplete()
709710
*/
710711
public function testLegacyAskWithAutocompleteWithNonSequentialKeys()
711712
{
712-
if (!$this->hasSttyAvailable()) {
713+
if (!Terminal::hasSttyAvailable()) {
713714
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
714715
}
715716

@@ -977,7 +978,7 @@ public function testEmptyChoices()
977978

978979
public function testTraversableAutocomplete()
979980
{
980-
if (!$this->hasSttyAvailable()) {
981+
if (!Terminal::hasSttyAvailable()) {
981982
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
982983
}
983984

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

10631064
return $mock;
10641065
}
1065-
1066-
private function hasSttyAvailable()
1067-
{
1068-
exec('stty 2>&1', $output, $exitcode);
1069-
1070-
return 0 === $exitcode;
1071-
}
10721066
}
10731067

10741068
class AutocompleteValues implements \IteratorAggregate

‎src/Symfony/Component/Console/Tests/TerminalTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Console/Tests/TerminalTest.php
+38Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,31 @@ class TerminalTest extends TestCase
1818
{
1919
private $colSize;
2020
private $lineSize;
21+
private $ansiCon;
2122

2223
protected function setUp()
2324
{
2425
$this->colSize = getenv('COLUMNS');
2526
$this->lineSize = getenv('LINES');
27+
$this->ansiCon = getenv('ANSICON');
28+
$this->resetStatics();
2629
}
2730

2831
protected function tearDown()
2932
{
3033
putenv($this->colSize ? 'COLUMNS='.$this->colSize : 'COLUMNS');
3134
putenv($this->lineSize ? 'LINES' : 'LINES='.$this->lineSize);
35+
putenv($this->ansiCon ? 'ANSICON='.$this->ansiCon : 'ANSICON');
36+
$this->resetStatics();
37+
}
38+
39+
private function resetStatics()
40+
{
41+
foreach (['height', 'width', 'stty'] as $name) {
42+
$property = new \ReflectionProperty(Terminal::class, $name);
43+
$property->setAccessible(true);
44+
$property->setValue(null);
45+
}
3246
}
3347

3448
public function test()
@@ -56,4 +70,28 @@ public function test_zero_values()
5670
$this->assertSame(0, $terminal->getWidth());
5771
$this->assertSame(0, $terminal->getHeight());
5872
}
73+
74+
public function testSttyOnWindows()
75+
{
76+
if ('\\' !== \DIRECTORY_SEPARATOR) {
77+
$this->markTestSkipped('Must be on windows');
78+
}
79+
80+
$sttyString = exec('(stty -a | grep columns) 2>&1', $output, $exitcode);
81+
if (0 !== $exitcode) {
82+
$this->markTestSkipped('Must have stty support');
83+
}
84+
85+
$matches = [];
86+
if (0 === preg_match('/columns.(\d+)/i', $sttyString, $matches)) {
87+
$this->fail('Could not determine existing stty columns');
88+
}
89+
90+
putenv('COLUMNS');
91+
putenv('LINES');
92+
putenv('ANSICON');
93+
94+
$terminal = new Terminal();
95+
$this->assertSame((int) $matches[1], $terminal->getWidth());
96+
}
5997
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.