Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Console] allow multiline responses to console questions #37683

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
Aug 12, 2020
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
2 changes: 2 additions & 0 deletions src/Symfony/Component/Console/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ CHANGELOG
-----

* Added `SingleCommandApplication::setAutoExit()` to allow testing via `CommandTester`
* added support for multiline responses to questions through `Question::setMultiline()`
and `Question::isMultiline()`

5.1.0
-----
Expand Down
24 changes: 23 additions & 1 deletion src/Symfony/Component/Console/Helper/QuestionHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ private function doAsk(OutputInterface $output, Question $question)
}

if (false === $ret) {
$ret = fgets($inputStream, 4096);
$ret = $this->readInput($inputStream, $question);
if (false === $ret) {
throw new MissingInputException('Aborted.');
}
Expand Down Expand Up @@ -502,4 +502,26 @@ private function isInteractiveInput($inputStream): bool

return self::$stdinIsInteractive = 1 !== $status;
}

/**
* Reads one or more lines of input and returns what is read.
*
* @param resource $inputStream The handler resource
* @param Question $question The question being asked
*
* @return string|bool The input received, false in case input could not be read
*/
private function readInput($inputStream, Question $question)
{
if (!$question->isMultiline()) {
return fgets($inputStream, 4096);
}

$ret = '';
while (false !== ($char = fgetc($inputStream))) {
$ret .= $char;
}

return $ret;
}
}
13 changes: 13 additions & 0 deletions src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ protected function writePrompt(OutputInterface $output, Question $question)
$text = OutputFormatter::escapeTrailingBackslash($question->getQuestion());
$default = $question->getDefault();

if ($question->isMultiline()) {
$text .= sprintf(' (press %s to continue)', $this->getEofShortcut());
}

switch (true) {
case null === $default:
$text = sprintf(' <info>%s</info>:', $text);
Expand Down Expand Up @@ -93,4 +97,13 @@ protected function writeError(OutputInterface $output, \Exception $error)

parent::writeError($output, $error);
}

private function getEofShortcut(): string
{
if (false !== strpos(PHP_OS, 'WIN')) {
return '<comment>Ctrl+Z</comment> then <comment>Enter</comment>';
}

return '<comment>Ctrl+D</comment>';
}
}
21 changes: 21 additions & 0 deletions src/Symfony/Component/Console/Question/Question.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class Question
private $default;
private $normalizer;
private $trimmable = true;
private $multiline = false;

/**
* @param string $question The question to ask to the user
Expand Down Expand Up @@ -61,6 +62,26 @@ public function getDefault()
return $this->default;
}

/**
* Returns whether the user response accepts newline characters.
*/
public function isMultiline(): bool
{
return $this->multiline;
}

/**
* Sets whether the user response should accept newline characters.
*
* @return $this
*/
public function setMultiline(bool $multiline): self
{
$this->multiline = $multiline;

return $this;
}

/**
* Returns whether the user response must be hidden.
*
Expand Down
34 changes: 34 additions & 0 deletions src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,40 @@ public function testAskHiddenResponseTrimmed()
$this->assertEquals(' 8AM', $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream(' 8AM')), $this->createOutputInterface(), $question));
}

public function testAskMultilineResponseWithEOF()
{
$essay = <<<'EOD'
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque pretium lectus quis suscipit porttitor. Sed pretium bibendum vestibulum.

Etiam accumsan, justo vitae imperdiet aliquet, neque est sagittis mauris, sed interdum massa leo id leo.

Aliquam rhoncus, libero ac blandit convallis, est sapien hendrerit nulla, vitae aliquet tellus orci a odio. Aliquam gravida ante sit amet massa lacinia, ut condimentum purus venenatis.

Vivamus et erat dictum, euismod neque in, laoreet odio. Aenean vitae tellus at leo vestibulum auctor id eget urna.
EOD;

$response = $this->getInputStream($essay);

$dialog = new QuestionHelper();

$question = new Question('Write an essay');
$question->setMultiline(true);

$this->assertEquals($essay, $dialog->ask($this->createStreamableInputInterfaceMock($response), $this->createOutputInterface(), $question));
}

public function testAskMultilineResponseWithSingleNewline()
{
$response = $this->getInputStream("\n");

$dialog = new QuestionHelper();

$question = new Question('Write an essay');
$question->setMultiline(true);

$this->assertEquals('', $dialog->ask($this->createStreamableInputInterfaceMock($response), $this->createOutputInterface(), $question));
}

/**
* @dataProvider getAskConfirmationData
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,22 @@ private function assertOutputContains($expected, StreamOutput $output, $normaliz

$this->assertStringContainsString($expected, $stream);
}

public function testAskMultilineQuestionIncludesHelpText()
{
$expected = 'Write an essay (press Ctrl+D to continue)';

if (false !== strpos(PHP_OS, 'WIN')) {
$expected = 'Write an essay (press Ctrl+Z then Enter to continue)';
}

$question = new Question('Write an essay');
$question->setMultiline(true);

$helper = new SymfonyQuestionHelper();
$input = $this->createStreamableInputInterfaceMock($this->getInputStream('\\'));
$helper->ask($input, $output = $this->createOutputInterface(), $question);

$this->assertOutputContains($expected, $output);
}
}
14 changes: 14 additions & 0 deletions src/Symfony/Component/Console/Tests/Question/QuestionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -297,4 +297,18 @@ public function testGetNormalizerDefault()
{
self::assertNull($this->question->getNormalizer());
}

/**
* @dataProvider providerTrueFalse
*/
public function testSetMultiline(bool $multiline)
{
self::assertSame($this->question, $this->question->setMultiline($multiline));
self::assertSame($multiline, $this->question->isMultiline());
}

public function testIsMultilineDefault()
{
self::assertFalse($this->question->isMultiline());
}
}