Skip to content

Commit

Permalink
bug #48897 [Console] fix clear of section with question (maxbeckers)
Browse files Browse the repository at this point in the history
This PR was merged into the 6.2 branch.

Discussion
----------

[Console] fix clear of section with question

| Q             | A
| ------------- | ---
| Branch?       |  6.2
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #47411
| License       | MIT
| Doc PR        | n/a

This PR fixes the problems to clear a section with a question included.

Example Code:
```
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $section1 = $output->section();
        $io = new SymfonyStyle($input, $section1);

        $output->writeln("foo");

        $countdown = 3;
        while ($countdown > 0) {
            $section1->clear();
            $io->writeln('start ' . $countdown);
            $io->write('foo');
            $io->write(' and bar'.\PHP_EOL);
            $givenAnswer = $io->ask('Dummy question?');
            $section1->write('bar');
            $countdown--;
        }

        return self::SUCCESS;
    }
```

Output loop 1:
![Screenshot 2023-01-06 142630](https://user-images.githubusercontent.com/11738128/211021767-e4109951-0519-4763-bdd0-6504ee875b46.png)

Output loop 1:
![Screenshot 2023-01-06 142653](https://user-images.githubusercontent.com/11738128/211021793-db987c4a-1ac5-422d-a8b9-f6c3f4a23c7f.png)

There was already a fix #48089 to be merged in 6.1, but the problem was that there were some changes in 6.2, so it was not possible to merge it into 6.2.

So this fix is only working for 6.2, but perhaps we could find a solution as well for the older versions. But because of the changes of console it was not possible to find a solution working for all versions.

`@chalasr` this fix is still with the newline always `true`
https://github.com/symfony/symfony/blob/4cf9855debc26e4323429ac8d87f02df582e2893/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php#L181
A change of the newline to `$newline` would change the behavior. Maybe we could change that in symfony 7.

To make it easier to test is here a zip with 2 testcommands in the root and the changed vendors.
[test-48089.zip](https://github.com/symfony/symfony/files/10360423/test-48089.zip)

Commits
-------

f4c551805b [Console] fix clear of section with question
  • Loading branch information
chalasr committed Feb 19, 2023
2 parents 12b1042 + e65c925 commit fc0e346
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 1 deletion.
12 changes: 11 additions & 1 deletion Output/ConsoleSectionOutput.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ public function addContent(string $input, bool $newline = true): int
// re-add the line break (that has been removed in the above `explode()` for
// - every line that is not the last line
// - if $newline is required, also add it to the last line
if ($i < $count || $newline) {
// - if it's not new line, but input ending with `\PHP_EOL`
if ($i < $count || $newline || str_ends_with($input, \PHP_EOL)) {
$lineContent .= \PHP_EOL;
}

Expand Down Expand Up @@ -149,6 +150,15 @@ public function addContent(string $input, bool $newline = true): int
return $linesAdded;
}

/**
* @internal
*/
public function addNewLineOfInputSubmit()
{
$this->content[] = \PHP_EOL;
++$this->lines;
}

protected function doWrite(string $message, bool $newline)
{
if (!$this->isDecorated()) {
Expand Down
6 changes: 6 additions & 0 deletions Style/SymfonyStyle.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\TrimmedBufferOutput;
use Symfony\Component\Console\Question\ChoiceQuestion;
Expand Down Expand Up @@ -298,6 +299,11 @@ public function askQuestion(Question $question): mixed
$answer = $this->questionHelper->ask($this->input, $this, $question);

if ($this->input->isInteractive()) {
if ($this->output instanceof ConsoleSectionOutput) {
// add the new line of the `return` to submit the input to ConsoleSectionOutput, because ConsoleSectionOutput is holding all it's lines.
// this is relevant when a `ConsoleSectionOutput::clear` is called.
$this->output->addNewLineOfInputSubmit();
}
$this->newLine();
$this->bufferedOutput->write("\n");
}
Expand Down
42 changes: 42 additions & 0 deletions Tests/Style/SymfonyStyleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Formatter\OutputFormatter;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\Input;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\ConsoleSectionOutput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\Console\Tester\CommandTester;

Expand Down Expand Up @@ -181,4 +183,44 @@ public function testMemoryConsumption()

$this->assertSame(0, memory_get_usage() - $start);
}

public function testAskAndClearExpectFullSectionCleared()
{
$answer = 'Answer';
$inputStream = fopen('php://memory', 'r+');
fwrite($inputStream, $answer.\PHP_EOL);
rewind($inputStream);
$input = $this->createMock(Input::class);
$sections = [];
$output = new ConsoleSectionOutput(fopen('php://memory', 'r+', false), $sections, StreamOutput::VERBOSITY_NORMAL, true, new OutputFormatter());
$input
->method('isInteractive')
->willReturn(true);
$input
->method('getStream')
->willReturn($inputStream);

$style = new SymfonyStyle($input, $output);

$style->writeln('start');
$style->write('foo');
$style->writeln(' and bar');
$givenAnswer = $style->ask('Dummy question?');
$style->write('foo2'.\PHP_EOL);
$output->write('bar2');
$output->clear();

rewind($output->getStream());
$this->assertEquals($answer, $givenAnswer);
$this->assertEquals(
'start'.\PHP_EOL. // write start
'foo'.\PHP_EOL. // write foo
"\x1b[1A\x1b[0Jfoo and bar".\PHP_EOL. // complete line
\PHP_EOL.\PHP_EOL." \033[32mDummy question?\033[39m:".\PHP_EOL.' > '.\PHP_EOL.\PHP_EOL.\PHP_EOL. // question
'foo2'.\PHP_EOL.\PHP_EOL. // write foo2
'bar2'.\PHP_EOL. // write bar
"\033[12A\033[0J", // clear 12 lines (11 output lines and one from the answer input return)
stream_get_contents($output->getStream())
);
}
}

0 comments on commit fc0e346

Please sign in to comment.