diff --git a/packages/publications/src/Commands/Helpers/InputStreamHandler.php b/packages/publications/src/Commands/Helpers/InputStreamHandler.php
index 9d7396457c2..ea3e138b717 100644
--- a/packages/publications/src/Commands/Helpers/InputStreamHandler.php
+++ b/packages/publications/src/Commands/Helpers/InputStreamHandler.php
@@ -8,6 +8,7 @@
use function explode;
use function fgets;
use Hyde\Hyde;
+use function str_contains;
use function trim;
/**
@@ -20,6 +21,7 @@
class InputStreamHandler
{
public const TERMINATION_SEQUENCE = '<<<';
+ public const END_OF_TRANSMISSION = "\x04";
private static ?array $mockedStreamBuffer = null;
@@ -49,7 +51,7 @@ protected function getLinesFromInputStream(): array
protected function shouldTerminate(string $line): bool
{
- return $line === self::TERMINATION_SEQUENCE;
+ return $line === self::TERMINATION_SEQUENCE || str_contains($line, self::END_OF_TRANSMISSION);
}
/** @codeCoverageIgnore Allows for mocking of the standard input stream */
@@ -59,7 +61,7 @@ protected function readInputStream(): string
return array_shift(self::$mockedStreamBuffer) ?? '';
}
- return fgets(STDIN);
+ return fgets(STDIN) ?: self::END_OF_TRANSMISSION;
}
/** @internal Allows for mocking of the standard input stream */
@@ -67,4 +69,14 @@ public static function mockInput(string $input): void
{
self::$mockedStreamBuffer = explode("\n", $input);
}
+
+ public static function terminationMessage(): string
+ {
+ return sprintf('Terminate with %s or press %s to finish', self::TERMINATION_SEQUENCE, self::getShortcut());
+ }
+
+ protected static function getShortcut(): string
+ {
+ return 'Ctrl+D'.(PHP_OS_FAMILY === 'Windows' ? ' then Enter' : '');
+ }
}
diff --git a/packages/publications/src/Commands/MakePublicationCommand.php b/packages/publications/src/Commands/MakePublicationCommand.php
index b7e9b042484..a4eecc81cd7 100644
--- a/packages/publications/src/Commands/MakePublicationCommand.php
+++ b/packages/publications/src/Commands/MakePublicationCommand.php
@@ -128,14 +128,14 @@ protected function captureFieldInput(PublicationFieldDefinition $field): ?Public
protected function captureTextFieldInput(PublicationFieldDefinition $field): PublicationFieldValue
{
- $this->infoComment("Enter lines for field [$field->name] (terminate with '<<<')>");
+ $this->infoComment(sprintf("Enter lines for field [$field->name] (%s)", InputStreamHandler::terminationMessage()));
return new PublicationFieldValue(PublicationFieldTypes::Text, implode("\n", InputStreamHandler::call()));
}
protected function captureArrayFieldInput(PublicationFieldDefinition $field): PublicationFieldValue
{
- $this->infoComment("Enter values for field [$field->name]");
+ $this->infoComment(sprintf("Enter values for field [$field->name] (%s)", InputStreamHandler::terminationMessage()));
return new PublicationFieldValue(PublicationFieldTypes::Array, InputStreamHandler::call());
}
diff --git a/packages/publications/src/Commands/MakePublicationTagCommand.php b/packages/publications/src/Commands/MakePublicationTagCommand.php
index 1ae0985b1d5..2f4f208abd8 100644
--- a/packages/publications/src/Commands/MakePublicationTagCommand.php
+++ b/packages/publications/src/Commands/MakePublicationTagCommand.php
@@ -72,7 +72,7 @@ protected function validateTagName(): void
protected function collectTags(): void
{
- $this->info('Enter the tag values: (end with an empty line)');
+ $this->info(sprintf('Enter the tag values: (%s)', InputStreamHandler::terminationMessage()));
$this->tags = [$this->tagName => InputStreamHandler::call()];
}
diff --git a/packages/publications/tests/Feature/InputStreamHandlerTest.php b/packages/publications/tests/Feature/InputStreamHandlerTest.php
index 15d03482f4f..5701a5b77cb 100644
--- a/packages/publications/tests/Feature/InputStreamHandlerTest.php
+++ b/packages/publications/tests/Feature/InputStreamHandlerTest.php
@@ -36,6 +36,13 @@ public function testCanTerminateWithHereSequenceAfterCarriageReturns()
$this->assertSame(0, $this->makeCommand(['foo', 'bar', 'baz'])->handle());
}
+ public function testCanTerminateWithEndOfTransmissionSequence()
+ {
+ InputStreamHandler::mockInput("foo\nbar\nbaz\n\x04");
+
+ $this->assertSame(0, $this->makeCommand(['foo', 'bar', 'baz'])->handle());
+ }
+
public function testCanCollectMultipleInputLines()
{
InputStreamHandler::mockInput("foo\nbar\nbaz\n<<<");
@@ -57,6 +64,27 @@ public function testCanEnterMultipleUnixEndings()
$this->assertSame(0, $this->makeCommand(['foo', 'bar', 'baz'])->handle());
}
+ public function testTerminationMessage()
+ {
+ $message = 'Terminate with <<< or press Ctrl+D';
+ if (PHP_OS_FAMILY === 'Windows') {
+ $message .= ' then Enter';
+ }
+ $expected = "$message to finish";
+
+ $this->assertSame($expected, InputStreamHandler::terminationMessage());
+ }
+
+ public function testTerminationSequenceConstant()
+ {
+ $this->assertSame('<<<', InputStreamHandler::TERMINATION_SEQUENCE);
+ }
+
+ public function testEndOfTransmissionConstant()
+ {
+ $this->assertSame("\x04", InputStreamHandler::END_OF_TRANSMISSION);
+ }
+
protected function makeCommand(array $expected): TestCommand
{
$command = new TestCommand;
diff --git a/packages/publications/tests/Feature/MakePublicationTagCommandTest.php b/packages/publications/tests/Feature/MakePublicationTagCommandTest.php
index 200238d39f0..a50d69dc92c 100644
--- a/packages/publications/tests/Feature/MakePublicationTagCommandTest.php
+++ b/packages/publications/tests/Feature/MakePublicationTagCommandTest.php
@@ -28,7 +28,7 @@ public function testCanCreateNewPublicationTag()
$this->artisan('make:publicationTag')
->expectsQuestion('Tag name', 'foo')
- ->expectsOutput('Enter the tag values: (end with an empty line)')
+ ->expectsOutputToContain('Enter the tag values:')
->expectsOutput('Adding the following tags:')
->expectsOutput(' foo: foo, bar, baz')
->expectsOutput('Saving tag data to [file://'.str_replace('\\', '/', Hyde::path('tags.yml')).']')
@@ -53,7 +53,7 @@ public function testCanCreateNewPublicationTagWithTagNameArgument()
$this->artisan('make:publicationTag foo')
->expectsOutput('Using tag name [foo] from command line argument')
- ->expectsOutput('Enter the tag values: (end with an empty line)')
+ ->expectsOutputToContain('Enter the tag values:')
->expectsOutput('Adding the following tags:')
->expectsOutput(' foo: foo, bar, baz')
->expectsOutput('Saving tag data to [file://'.str_replace('\\', '/', Hyde::path('tags.yml')).']')