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

Skip to content

Commit 997de0a

Browse files
Amoifrnicolas-grekas
authored andcommitted
[Console] Make ConsoleSectionOutput::overwrite() atomic
1 parent 7bbcaf3 commit 997de0a

2 files changed

Lines changed: 40 additions & 3 deletions

File tree

Output/ConsoleSectionOutput.php

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,31 @@ public function clear(?int $lines = null)
8888
*/
8989
public function overwrite(string|iterable $message)
9090
{
91-
$this->clear();
92-
$this->writeln($message);
91+
if (!$this->content || !$this->isDecorated()) {
92+
$this->writeln($message);
93+
94+
return;
95+
}
96+
97+
// Replace own content and write everything in a single cursor-up + erase
98+
// pass, to avoid the flicker (and the line-eating artifacts on some
99+
// terminals) caused by calling clear() then writeln() back-to-back.
100+
$linesCleared = $this->lines;
101+
$this->content = [];
102+
$this->lines = 0;
103+
104+
if (!is_iterable($message)) {
105+
$message = [$message];
106+
}
107+
108+
foreach ($message as $line) {
109+
$this->addContent($line, true);
110+
}
111+
112+
$erasedContent = $this->popStreamContentUntilCurrentSection($this->maxHeight ? min($this->maxHeight, $linesCleared) : $linesCleared);
113+
114+
parent::doWrite($this->getVisibleContent(), false);
115+
parent::doWrite($erasedContent, false);
93116
}
94117

95118
public function getContent(): string

Tests/Output/ConsoleSectionOutputTest.php

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,20 @@ public function testOverwriteMultipleLines()
200200
$this->assertEquals('Foo'.\PHP_EOL.'Bar'.\PHP_EOL.'Baz'.\PHP_EOL.\sprintf("\x1b[%dA", 3)."\x1b[0J".'Bar'.\PHP_EOL, stream_get_contents($output->getStream()));
201201
}
202202

203+
public function testOverwriteWithMaxHeightOverflow()
204+
{
205+
$sections = [];
206+
$output = new ConsoleSectionOutput($this->stream, $sections, OutputInterface::VERBOSITY_NORMAL, true, new OutputFormatter());
207+
$output->setMaxHeight(2);
208+
209+
$output->writeln(['One', 'Two']);
210+
// overwrite with more lines than the max height: only the last lines stay visible
211+
$output->overwrite('A'.\PHP_EOL.'B'.\PHP_EOL.'C');
212+
213+
rewind($output->getStream());
214+
$this->assertEquals('One'.\PHP_EOL.'Two'.\PHP_EOL."\x1b[2A\x1b[0J".'B'.\PHP_EOL.'C'.\PHP_EOL, stream_get_contents($output->getStream()));
215+
}
216+
203217
public function testAddingMultipleSections()
204218
{
205219
$sections = [];
@@ -223,7 +237,7 @@ public function testMultipleSectionsOutput()
223237
$output2->overwrite('Foobar');
224238

225239
rewind($output->getStream());
226-
$this->assertEquals('Foo'.\PHP_EOL.'Bar'.\PHP_EOL."\x1b[2A\x1b[0JBar".\PHP_EOL."\x1b[1A\x1b[0JBaz".\PHP_EOL.'Bar'.\PHP_EOL."\x1b[1A\x1b[0JFoobar".\PHP_EOL, stream_get_contents($output->getStream()));
240+
$this->assertEquals('Foo'.\PHP_EOL.'Bar'.\PHP_EOL."\x1b[2A\x1b[0JBaz".\PHP_EOL.'Bar'.\PHP_EOL."\x1b[1A\x1b[0JFoobar".\PHP_EOL, stream_get_contents($output->getStream()));
227241
}
228242

229243
public function testMultipleSectionsOutputWithoutNewline()

0 commit comments

Comments
 (0)