8000 [Console] allow answer to be trimmed by adding a flag by Simperfit · Pull Request #31626 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[Console] allow answer to be trimmed by adding a flag #31626

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
Jul 8, 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
5 changes: 5 additions & 0 deletions src/Symfony/Component/Console/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

4.4.0
-----

* added `Question::setTrimmable` default to true to allow the answer to be trimmed or not
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove the or not


4.3.0
-----

Expand Down
26 changes: 17 additions & 9 deletions src/Symfony/Component/Console/Helper/QuestionHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public function ask(InputInterface $input, OutputInterface $output, Question $qu

$default = explode(',', $default);
foreach ($default as $k => $v) {
$v = trim($v);
$v = $question->isTrimmable() ? trim($v) : $v;
$default[$k] = isset($choices[$v]) ? $choices[$v] : $v;
}
}
Expand Down Expand Up @@ -121,7 +121,8 @@ private function doAsk(OutputInterface $output, Question $question)
$ret = false;
if ($question->isHidden()) {
try {
$ret = trim($this->getHiddenResponse($output, $inputStream));
$hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable());
$ret = $question->isTrimmable() ? trim($hiddenResponse) : $hiddenResponse;
} catch (RuntimeException $e) {
if (!$question->isHiddenFallback()) {
throw $e;
Expand All @@ -134,10 +135,13 @@ private function doAsk(OutputInterface $output, Question $question)
if (false === $ret) {
throw new RuntimeException('Aborted.');
}
$ret = trim($ret);
if ($question->isTrimmable()) {
$ret = trim($ret);
}
}
} else {
$ret = trim($this->autocomplete($output, $question, $inputStream, $autocomplete));
$autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete);
$ret = $question->isTrimmable() ? trim($autocomplete) : $autocomplete;
}

if ($output instanceof ConsoleSectionOutput) {
Expand Down Expand Up @@ -351,10 +355,11 @@ private function mostRecentlyEnteredValue($entered)
*
* @param OutputInterface $output An Output instance
* @param resource $inputStream The handler resource
* @param bool $trimmable Is the answer trimmable
*
* @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
*/
private function getHiddenResponse(OutputInterface $output, $inputStream): string
private function getHiddenResponse(OutputInterface $output, $inputStream, $trimmable = true): string
{
if ('\\' === \DIRECTORY_SEPARATOR) {
$exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
Expand All @@ -366,7 +371,8 @@ private function getHiddenResponse(OutputInterface $output, $inputStream): strin
$exe = $tmpExe;
}

$value = rtrim(shell_exec($exe));
$sExec = shell_exec($exe);
$value = $trimmable ? rtrim($sExec) : $sExec;
$output->writeln('');

if (isset($tmpExe)) {
Expand All @@ -386,8 +392,9 @@ private function getHiddenResponse(OutputInterface $output, $inputStream): strin
if (false === $value) {
throw new RuntimeException('Aborted.');
}

$value = trim($value);
if ($trimmable) {
$value = trim($value);
}
$output->writeln('');

return $value;
Expand All @@ -396,7 +403,8 @@ private function getHiddenResponse(OutputInterface $output, $inputStream): strin
if (false !== $shell = $this->getShell()) {
$readCmd = 'csh' === $shell ? 'set mypassword = $<' : 'read -r mypassword';
$command = sprintf("/usr/bin/env %s -c 'stty -echo; %s; stty echo; echo \$mypassword'", $shell, $readCmd);
$value = rtrim(shell_exec($command));
$sCommand = shell_exec($command);
$value = $trimmable ? rtrim($sCommand) : $sCommand;
$output->writeln('');

return $value;
Expand Down
16 changes: 16 additions & 0 deletions src/Symfony/Component/Console/Question/Question.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Question
private $validator;
private $default;
private $normalizer;
private $trimmable = true;

/**
* @param string $question The question to ask to the user
Expand Down Expand Up @@ -274,4 +275,19 @@ protected function isAssoc($array)
{
return (bool) \count(array_filter(array_keys($array), 'is_string'));
}

public function isTrimmable(): bool
{
return $this->trimmable;
}

/**
* @return $this
*/
public function setTrimmable(bool $trimmable): self
{
$this->trimmable = $trimmable;

return $this;
}
}
E30A 63 changes: 63 additions & 0 deletions src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,20 @@ public function testAsk()
$this->assertEquals('What time is it?', stream_get_contents($output->getStream()));
}

public function testAskNonTrimmed()
{
$dialog = new QuestionHelper();

$inputStream = $this->getInputStream(' 8AM ');

$question = new Question('What time is it?', '2PM');
$question->setTrimmable(false);
$this->assertEquals(' 8AM ', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $output = $this->createOutputInterface(), $question));

rewind($output->getStream());
$this->assertEquals('What time is it?', stream_get_contents($output->getStream()));
}

public function testAskWithAutocomplete()
{
if (!$this->hasSttyAvailable()) {
Expand Down Expand Up @@ -198,6 +212,40 @@ public function testAskWithAutocomplete()
$this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
}

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

// Acm<NEWLINE>
// Ac<BACKSPACE><BACKSPACE>s<TAB>Test<NEWLINE>
// <NEWLINE>
// <UP ARROW><UP ARROW><NEWLINE>
// <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
// <DOWN ARROW><NEWLINE>
// S<BACKSPACE><BACKSPACE><DOWN ARROW><DOWN ARROW><NEWLINE>
// F00<BACKSPACE><BACKSPACE>oo<TAB><NEWLINE>
$inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\n");

$dialog = new QuestionHelper();
$helperSet = new HelperSet([new FormatterHelper()]);
$dialog->setHelperSet($helperSet);

$question = new Question('Please select a bundle', 'FrameworkBundle');
$question->setAutocompleterValues(['AcmeDemoBundle ', 'AsseticBundle', ' SecurityBundle ', 'FooBundle']);
$question->setTrimmable(false);

$this->assertEquals('AcmeDemoBundle ', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('AsseticBundleTest', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('FrameworkBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals(' SecurityBundle ', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('FooBundleTest', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('AcmeDemoBundle ', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('AsseticBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
$this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
}

public function testAskWithAutocompleteCallback()
{
if (!$this->hasSttyAvailable()) {
Expand Down Expand Up @@ -373,6 +421,21 @@ public function testAskHiddenResponse()
$this->assertEquals('8AM', $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream("8AM\n")), $this->createOutputInterface(), $question));
}

public function testAskHiddenResponseTrimmed()
{
if ('\\' === \DIRECTORY_SEPARATOR) {
$this->markTestSkipped('This test is not supported on Windows');
}

$dialog = new QuestionHelper();

$question = new Question('What time is it?');
$question->setHidden(true);
$question->setTrimmable(false);

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

/**
* @dataProvider getAskConfirmationData
*/
Expand Down
0