8000 [Console] Get dimensions from stty on windows if possible · symfony/symfony@5265080 · GitHub
[go: up one dir, main page]

Skip to content

Commit 5265080

Browse files
rtekchalasr
authored andcommitted
[Console] Get dimensions from stty on windows if possible
1 parent ac7df04 commit 5265080

File tree

4 files changed

+77
-34
lines changed

4 files changed

+77
-34
lines changed

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

Lines 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

Lines 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

Lines 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 EED3 \IteratorAggregate

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

Lines 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