8000 [Console] allow answer to be trimmed by adding a flag · symfony/symfony@39a3bb9 · GitHub
[go: up one dir, main page]

Skip to content

Commit 39a3bb9

Browse files
committed
[Console] allow answer to be trimmed by adding a flag
1 parent 5dba412 commit 39a3bb9

File tree

4 files changed

+107
-9
lines changed

4 files changed

+107
-9
lines changed

src/Symfony/Component/Console/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
4.4.0
5+
-----
6+
7+
* added `Question::trimmable` default to true to allow the anwser to be trimmed or not
8+
49
4.3.0
510
-----
611

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

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public function ask(InputInterface $input, OutputInterface $output, Question $qu
6464

6565
$default = explode(',', $default);
6666
foreach ($default as $k => $v) {
67-
$v = trim($v);
67+
$v = $question->isTrimmable() ? trim($v) : $v;
6868
$default[$k] = isset($choices[$v]) ? $choices[$v] : $v;
6969
}
7070
}
@@ -121,7 +121,8 @@ private function doAsk(OutputInterface $output, Question $question)
121121
$ret = false;
122122
if ($question->isHidden()) {
123123
try {
124-
$ret = trim($this->getHiddenResponse($output, $inputStream));
124+
$hiddenResponse = $this->getHiddenResponse($output, $inputStream, $question->isTrimmable());
125+
$ret = $question->isTrimmable() ? trim($hiddenResponse) : $hiddenResponse;
125126
} catch (RuntimeException $e) {
126127
if (!$question->isHiddenFallback()) {
127128
throw $e;
@@ -134,10 +135,13 @@ private function doAsk(OutputInterface $output, Question $question)
134135
if (false === $ret) {
135136
throw new RuntimeException('Aborted.');
136137
}
137-
$ret = trim($ret);
138+
if ($question->isTrimmable()) {
139+
$ret = trim($ret);
140+
}
138141
}
139142
} else {
140-
$ret = trim($this->autocomplete($output, $question, $inputStream, $autocomplete));
143+
$autocomplete = $this->autocomplete($output, $question, $inputStream, $autocomplete);
144+
$ret = $question->isTrimmable() ? trim($autocomplete) : $autocomplete;
141145
}
142146

143147
if ($output instanceof ConsoleSectionOutput) {
@@ -351,10 +355,11 @@ private function mostRecentlyEnteredValue($entered)
351355
*
352356
* @param OutputInt 67E6 erface $output An Output instance
353357
* @param resource $inputStream The handler resource
358+
* @param bool $trimmable Is the answer trimmable
354359
*
355360
* @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden
356361
*/
357-
private function getHiddenResponse(OutputInterface $output, $inputStream): string
362+
private function getHiddenResponse(OutputInterface $output, $inputStream, $trimmable = true): string
358363
{
359364
if ('\\' === \DIRECTORY_SEPARATOR) {
360365
$exe = __DIR__.'/../Resources/bin/hiddeninput.exe';
@@ -366,7 +371,8 @@ private function getHiddenResponse(OutputInterface $output, $inputStream): strin
366371
$exe = $tmpExe;
367372
}
368373

369-
$value = rtrim(shell_exec($exe));
374+
$sExec = shell_exec($exe);
375+
$value = $trimmable ? rtrim($sExec) : $sExec;
370376
$output->writeln('');
371377

372378
if (isset($tmpExe)) {
@@ -386,8 +392,9 @@ private function getHiddenResponse(OutputInterface $output, $inputStream): strin
386392
if (false === $value) {
387393
throw new RuntimeException('Aborted.');
388394
}
389-
390-
$value = trim($value);
395+
if ($trimmable) {
396+
$value = trim($value);
397+
}
391398
$output->writeln('');
392399

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

402410
return $value;

src/Symfony/Component/Console/Question/Question.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class Question
2929
private $validator;
3030
private $default;
3131
private $normalizer;
32+
private $trimmable = true;
3233

3334
/**
3435
* @param string $question The question to ask to the user
@@ -274,4 +275,24 @@ protected function isAssoc($array)
274275
{
275276
return (bool) \count(array_filter(array_keys($array), 'is_string'));
276277
}
278+
279+
/**
280+
* @return bool
281+
*/
282+
public function isTrimmable(): bool
283+
{
284+
return $this->trimmable;
285+
}
286+
287+
/**
288+
* @param bool $isTrimmable
289+
*
290+
* return $this
291+
*/
292+
public function setTrimmable(bool $trimmable): Question
293+
{
294+
$this->trimmable = $trimmable;
295+
296+
return $this;
297+
}
277298
}

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

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,20 @@ public function testAsk()
165165
$this->assertEquals('What time is it?', stream_get_contents($output->getStream()));
166166
}
167167

168+
public function testAskNonTrimmed()
169+
{
170+
$dialog = new QuestionHelper();
171+
172+
$inputStream = $this->getInputStream(' 8AM ');
173+
174+
$question = new Question('What time is it?', '2PM');
175+
$question->setTrimmable(false);
176+
$this->assertEquals(' 8AM ', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $output = $this->createOutputInterface(), $question));
177+
178+
rewind($output->getStream());
179+
$this->assertEquals('What time is it?', stream_get_contents($output->getStream()));
180+
}
181+
168182
public function testAskWithAutocomplete()
169183
{
170184
if (!$this->hasSttyAvailable()) {
@@ -198,6 +212,41 @@ public function testAskWithAutocomplete()
198212
$this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
199213
}
200214

215+
public function testAskWithAutocompleteTrimmable()
216+
{
217+
if (!$this->hasSttyAvailable()) {
218 F42D +
$this->markTestSkipped('`stty` is required to test autocomplete functionality');
219+
}
220+
221+
// Acm<NEWLINE>
222+
// Ac<BACKSPACE><BACKSPACE>s<TAB>Test<NEWLINE>
223+
// <NEWLINE>
224+
// <UP ARROW><UP ARROW><NEWLINE>
225+
// <UP ARROW><UP ARROW><UP ARROW><UP ARROW><UP ARROW><TAB>Test<NEWLINE>
226+
// <DOWN ARROW><NEWLINE>
227+
// S<BACKSPACE><BACKSPACE><DOWN ARROW><DOWN ARROW><NEWLINE>
228+
// F00<BACKSPACE><BACKSPACE>oo<TAB><NEWLINE>
229+
$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");
230+
231+
$dialog = new QuestionHelper();
232+
$helperSet = new HelperSet([new FormatterHelper()]);
233+
$dialog->setHelperSet($helperSet);
234+
235+
$question = new Question('Please select a bundle', 'FrameworkBundle');
236+
$question->setAutocompleterValues(['AcmeDemoBundle ', 'AsseticBundle', 'SecurityBundle', 'FooBundle']);
237+
$question->setTrimmable(false);
238+
239+
$this->assertEquals('AcmeDemoBundle ', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
240+
$this->assertEquals('AsseticBundleTest', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
241+
$this->assertEquals('FrameworkBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
242+
$this->assertEquals('SecurityBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
243+
$this->assertEquals('FooBundleTest', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
244+
$this->assertEquals('AcmeDemoBundle ', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
245+
$this->assertEquals('AsseticBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
246+
$this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question));
247+
}
248+
249+
201250
public function testAskWithAutocompleteCallback()
202251
{
203252
if (!$this->hasSttyAvailable()) {
@@ -373,6 +422,21 @@ public function testAskHiddenResponse()
373422
$this->assertEquals('8AM', $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream("8AM\n")), $this->createOutputInterface(), $question));
374423
}
375424

425+
public function testAskHiddenResponseTrimmed()
426+
{
427+
if ('\\' === \DIRECTORY_SEPARATOR) {
428+
$this->markTestSkipped('This test is not supported on Windows');
429+
}
430+
431+
$dialog = new QuestionHelper();
432+
433+
$question = new Question('What time is it?');
434+
$question->setHidden(true);
435+
$question->setTrimmable(false);
436+
437+
$this->assertEquals(' 8AM', $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream(' 8AM')), $this->createOutputInterface(), $question));
438+
}
439+
376440
/**
377441
* @dataProvider getAskConfirmationData
378442
*/

0 commit comments

Comments
 (0)
0