Skip to content
Open
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
6 changes: 5 additions & 1 deletion src/Command/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,11 @@ protected function writeLine(
string $message = "",
StreamName $streamName = StreamName::OUT
):void {
$this->write($message . PHP_EOL, $streamName);
if(!isset($this->stream)) {
return;
}

$this->stream->writeLine($message, $streamName);
}

protected function readLine(?string $default = null):string {
Expand Down
86 changes: 68 additions & 18 deletions src/Stream.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class Stream {

protected string $lastLineBuffer;
private bool $lastLineRepeats;
/** @var array<string, string> */
private array $lineBuffer;
public Cursor $cursor;

public function __construct(
Expand All @@ -39,6 +41,7 @@ public function __construct(
$this->setStream($in, $out, $error);
$this->lastLineBuffer = "";
$this->lastLineRepeats = false;
$this->lineBuffer = [];
}

public function setStream(string $in, string $out, string $error):void {
Expand Down Expand Up @@ -106,32 +109,47 @@ public function writeLine(
?Palette $foreground = null,
?Palette $background = null,
):void {
$line = $message . PHP_EOL;
$this->writeCompleteLine(
$message . PHP_EOL,
$streamName,
$foreground,
$background,
);
}

if($line === $this->lastLineBuffer) {
$this->write(
self::REPEAT_CHAR,
$streamName,
$foreground,
$background
);
$this->lastLineRepeats = true;
}
else {
if($this->lastLineRepeats) {
$this->write(PHP_EOL, $streamName);
public function writeBufferedLines(
string $message,
StreamName $streamName = StreamName::OUT,
?Palette $foreground = null,
?Palette $background = null,
):void {
$bufferKey = $streamName->value;
$this->lineBuffer[$bufferKey] ??= "";
$this->lineBuffer[$bufferKey] .= $message;

while(true) {
$newlinePos = strpos($this->lineBuffer[$bufferKey], "\n");
if($newlinePos === false) {
break;
}

$this->write(
$line = substr(
$this->lineBuffer[$bufferKey],
0,
$newlinePos + 1,
);
$remainingBufferOffset = $newlinePos + 1;
$this->lineBuffer[$bufferKey] = substr(
$this->lineBuffer[$bufferKey],
$remainingBufferOffset,
);
$this->writeCompleteLine(
$line,
$streamName,
$foreground,
$background
$background,
);
$this->lastLineRepeats = false;
}

$this->lastLineBuffer = $line;
}

public function setOutputPalette(
Expand Down Expand Up @@ -181,4 +199,36 @@ private function wrapInPalette(
. $message
. self::ANSI_RESET;
}

private function writeCompleteLine(
string $line,
StreamName $streamName,
?Palette $foreground = null,
?Palette $background = null,
):void {
if($line === $this->lastLineBuffer) {
$this->write(
self::REPEAT_CHAR,
$streamName,
$foreground,
$background
);
$this->lastLineRepeats = true;
}
else {
if($this->lastLineRepeats) {
$this->write(PHP_EOL, $streamName);
}

$this->write(
$line,
$streamName,
$foreground,
$background
);
$this->lastLineRepeats = false;
}

$this->lastLineBuffer = $line;
}
}
20 changes: 19 additions & 1 deletion test/phpunit/Command/CommandOutputTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public function testSetOutput():void {
StreamName::OUT->value => [],
StreamName::ERROR->value => [],
];
$stream->method("write")
$stream->method("writeLine")
->willReturnCallback(function(
string $message,
StreamName $streamName
Expand Down Expand Up @@ -60,6 +60,24 @@ public function outputPublic(string $message, ?Palette $colour = null):void {
$command->outputPublic("single green message", Palette::GREEN);
}

public function testWriteLineUsesStreamWriteLine():void {
$stream = $this->createMock(Stream::class);
$stream->expects(self::once())
->method("writeLine")
->with(
"line output",
StreamName::OUT
);

$command = new class extends TestCommand {
public function writeLinePublic(string $message):void {
$this->writeLine($message);
}
};
$command->setStream($stream);
$command->writeLinePublic("line output");
}

public function testSetAndResetOutputPalette():void {
$stream = $this->createMock(Stream::class);
$stream->expects(self::once())
Expand Down
36 changes: 36 additions & 0 deletions test/phpunit/StreamTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,42 @@ public function testRepeatingLineSuppressed():void {
self::assertSame(4, substr_count($fullStreamContents, Stream::REPEAT_CHAR));
}

public function testBufferedRepeatingLinesSuppressed():void {
$stream = new Stream(
"php://memory",
"php://memory",
"php://memory",
);
$out = $stream->getOutStream();

$stream->writeBufferedLines("repeat");
$stream->writeBufferedLines(" me\nrepeat me\n");
$stream->writeBufferedLines("repeat me\nunique\n");

$out->rewind();
self::assertSame(
"repeat me\n" . Stream::REPEAT_CHAR . Stream::REPEAT_CHAR . "\nunique\n",
$out->fread(1024)
);
}

public function testBufferedWritesHoldPartialLinesUntilNewline():void {
$stream = new Stream(
"php://memory",
"php://memory",
"php://memory",
);
$out = $stream->getOutStream();

$stream->writeBufferedLines("partial");
$out->rewind();
self::assertSame("", $out->fread(1024));

$stream->writeBufferedLines(" line\n");
$out->rewind();
self::assertSame("partial line\n", $out->fread(1024));
}

public function testWriteLineWithTemporaryPalette() {
$stream = new Stream(
"php://memory",
Expand Down
Loading