symfony icon indicating copy to clipboard operation
symfony copied to clipboard

[Console] ProgressIndicator fails to clear properly when used in sections

Open mfonda opened this issue 1 year ago • 7 comments

Symfony version(s) affected

symfony/console v6.4.4

Description

Multiple ProgressIndicator work as expected for the first handful of advance() calls, but eventually begin to eat up all previous console output.

Run the script below to observe. Progress indicators will update as expected, but after a few iterations, all previous output already in the console window will disappear line by line.

How to reproduce

$section1 = $output->section();
$section2 = $output->section();
$progress1 = new ProgressIndicator($section1);
$progress2 = new ProgressIndicator($section2);
$progress1->start('Indicator 1');
$progress2->start('Indicator 2');
$i = 0;
while (++$i < 100) {
    $progress1->advance();
    $progress2->advance();
    usleep(50000);
}

Possible Solution

The problem appears to be how ProgressIndicator::overwrite() handles clearing the line.

Currently, it does the following:

$this->output->write("\x0D\x1B[2K");

This doesn't seem to be correct when used in a section. Changing it to the following fixes the bug:

use Symfony\Component\Console\Output\ConsoleSectionOutput;
...
if ($this->output instanceof ConsoleSectionOutput) {
    $this->output->clear(1);
} else {
    $this->output->write("\x0D\x1B[2K");
}

Additional Context

No response

mfonda avatar Mar 12 '24 20:03 mfonda

Hello,

Thank you for spotting this issue and posting this message.

I was able to reproduce the issue, and even worst, it happens without sections too. The output is a bit different, but the problem is related on how the ProgressIndicator clear the lines:

$progress3 = new ProgressIndicator($output);
$progress4 = new ProgressIndicator($output);
$progress3->start('Indicator 3');
$progress4->start('Indicator 4');
$i = 0;
while (++$i < 100) {
    $progress4->advance();
    $progress3->advance();
    usleep(50000);
}

$progress3->finish('Finished');
$progress4->finish('Finished');

It only shows the output for the Indicator 4 and writes Finished twice at the end.

NeilPeyssard avatar Mar 13 '24 13:03 NeilPeyssard

I'm not really sure how to fix this issue but I've been thinking about a possible solution:

// Each time we call the advance method:
    // Retrieve the position of the old indicator
    // Remove the line / the old indicator
    // Move cursor at last position
    // Write the updated indicator

In this way, it would be possible to write new entries between each modification of the indicator, and it would always be displayed in the last position.

And since the updated indicator would always be in last position, if we use two indicators at the same time, they should not conflict with each other.

NeilPeyssard avatar Mar 13 '24 15:03 NeilPeyssard

Hey, thanks for your report! There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

carsonbot avatar Sep 14 '24 13:09 carsonbot

Friendly reminder that this issue exists. If I don't hear anything I'll close this.

carsonbot avatar Sep 28 '24 13:09 carsonbot

@NeilPeyssard up for a PR?

chalasr avatar Sep 30 '24 15:09 chalasr

Hey, thanks for your report! There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

carsonbot avatar Mar 31 '25 13:03 carsonbot

I've experienced the issue as well. No workaround so far.

bytehead avatar Mar 31 '25 13:03 bytehead

Hey, thanks for your report! There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

carsonbot avatar Oct 01 '25 13:10 carsonbot

It's still relevant and no workaround so far.

bytehead avatar Oct 01 '25 13:10 bytehead