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')).']')