8000 [Console] fix restoring stty mode on CTRL+C · symfony/symfony@2bc6cfc · GitHub
[go: up one dir, main page]

Skip to content

Commit 2bc6cfc

Browse files
[Console] fix restoring stty mode on CTRL+C
1 parent 6cdfd71 commit 2bc6cfc

File tree

3 files changed

+49
-6
lines changed

3 files changed

+49
-6
lines changed

src/Symfony/Component/Console/Application.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,7 @@ protected function doRunCommand(Command $command, InputInterface $input, OutputI
957957
$event = new ConsoleSignalEvent($command, $input, $output, $signal);
958958

959959
$this->signalRegistry->register($signal, function ($signal, $hasNext) use ($event) {
960+
Terminal::restoreSttyMode();
960961
$this->dispatcher->dispatch($event, ConsoleEvents::SIGNAL);
961962

962963
// No more handlers, we try to simulate PHP default behavior

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

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu
247247
$matches = $autocomplete($ret);
248248
$numMatches = \count($matches);
249249

250-
$sttyMode = shell_exec('stty -g');
250+
$sttyMode = Terminal::backupSttyMode();
251251

252252
// Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead)
253253
shell_exec('stty -icanon -echo');
@@ -257,11 +257,17 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu
257257

258258
// Read a keypress
259259
while (!feof($inputStream)) {
260+
do {
261+
// Give signal handlers a chance to run
262+
$r = [$inputStream];
263+
$w = [];
264+
} while (0 === @stream_select($r, $w, $w, 0, 100));
265+
260266
$c = fread($inputStream, 1);
261267

262268
// as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false.
263269
if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) {
264-
shell_exec(sprintf('stty %s', $sttyMode));
270+
Terminal::restoreSttyMode($sttyMode);
265271
throw new MissingInputException('Aborted.');
266272
} elseif ("\177" === $c) { // Backspace Character
267273
if (0 === $numMatches && 0 !== $i) {
@@ -365,8 +371,7 @@ function ($match) use ($ret) {
365371
}
366372
}
367373

368-
// Reset stty so it behaves normally again
369-
shell_exec(sprintf('stty %s', $sttyMode));
374+
Terminal::restoreSttyMode($sttyMode);
370375

371376
return $fullChoice;
372377
}
@@ -418,7 +423,7 @@ private function getHiddenResponse(OutputInterface $output, $inputStream, bool $
418423
}
419424

420425
if (self::$stty && Terminal::hasSttyAvailable()) {
421-
$sttyMode = shell_exec('stty -g');
426+
$sttyMode = Terminal::backupSttyMode();
422427
shell_exec('stty -echo');
423428
} elseif ($this->isInteractiveInput($inputStream)) {
424429
throw new RuntimeException('Unable to hide the response.');
@@ -427,7 +432,7 @@ private function getHiddenResponse(OutputInterface $output, $inputStream, bool $
427432
$value = fgets($inputStream, 4096);
428433

429434
if (self::$stty && Terminal::hasSttyAvailable()) {
430-
shell_exec(sprintf('stty %s', $sttyMode));
435+
Terminal::restoreSttyMode($sttyMode);
431436
}
432437

433438
if (false === $value) {

src/Symfony/Component/Console/Terminal.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class Terminal
1616
private static $width;
1717
private static $height;
1818
private static $stty;
19+
private static $sttyMode;
20+
private static $sttyLevel = 0;
1921

2022
/**
2123
* Gets the terminal width.
@@ -76,6 +78,41 @@ public static function hasSttyAvailable()
7678
return self::$stty = 0 === $exitcode;
7779
}
7880

81+
/**
82+
* @internal
83+
*/
84+
public static function backupSttyMode(): string
85+
{
86+
$sttyMode = shell_exec('stty -g');
87+
88+
if (!self::$sttyLevel++) {
89+
self::$sttyMode = $sttyMode;
90+
}
91+
92+
return $sttyMode;
93+
}
94+
95+
/**
96+
* @internal
97+
*/
98+
public static function restoreSttymode(string $sttyMode = null): void
99+
{
100+
if (null === $sttyMode) {
101+
$sttyMode = self::$sttyMode;
102+
self::$sttyLevel = 0;
103+
} elseif (0 < self::$sttyLevel) {
104+
--self::$sttyLevel;
105+
}
106+
107+
if (!self::$sttyLevel) {
108+
self::$sttyMode = null;
109+
}
110+
111+
if (null !== $sttyMode) {
112+
shell_exec('stty '.$sttyMode);
113+
}
114+
}
115+
79116
private static function initDimensions()
80117
{
81118
if ('\\' === \DIRECTORY_SEPARATOR) {

0 commit comments

Comments
 (0)
0