From a9ef72b0134144eb20b4eb2901ecd7b2f27fa09d Mon Sep 17 00:00:00 2001 From: Len Woodward Date: Tue, 11 Jun 2024 02:21:51 -0700 Subject: [PATCH 1/4] reference output object using static instead of self --- src/Concerns/FakesInputOutput.php | 2 +- src/Prompt.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Concerns/FakesInputOutput.php b/src/Concerns/FakesInputOutput.php index e136db1d..c5d94c52 100644 --- a/src/Concerns/FakesInputOutput.php +++ b/src/Concerns/FakesInputOutput.php @@ -35,7 +35,7 @@ public static function fake(array $keys = []): void static::$terminal = $mock; - self::setOutput(new BufferedConsoleOutput()); + static::setOutput(new BufferedConsoleOutput()); } /** diff --git a/src/Prompt.php b/src/Prompt.php index 1d0709c9..bbc0d7dc 100644 --- a/src/Prompt.php +++ b/src/Prompt.php @@ -179,7 +179,7 @@ protected function capturePreviousNewLines(): void */ public static function setOutput(OutputInterface $output): void { - self::$output = $output; + static::$output = $output; } /** @@ -187,7 +187,7 @@ public static function setOutput(OutputInterface $output): void */ protected static function output(): OutputInterface { - return self::$output ??= new ConsoleOutput(); + return static::$output ??= new ConsoleOutput(); } /** From 2fb5ae18c9f6cf53cd68588ad0a1e7b7074697a4 Mon Sep 17 00:00:00 2001 From: Len Woodward Date: Tue, 11 Jun 2024 02:24:14 -0700 Subject: [PATCH 2/4] extract looping mechanism in prompt --- src/Prompt.php | 31 +++++++++++++++++++++++++++++-- src/Support/Nothing.php | 14 ++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 src/Support/Nothing.php diff --git a/src/Prompt.php b/src/Prompt.php index bbc0d7dc..cf416995 100644 --- a/src/Prompt.php +++ b/src/Prompt.php @@ -5,6 +5,7 @@ use Closure; use Laravel\Prompts\Exceptions\FormRevertedException; use Laravel\Prompts\Output\ConsoleOutput; +use Laravel\Prompts\Support\Nothing; use RuntimeException; use Symfony\Component\Console\Output\OutputInterface; use Throwable; @@ -122,7 +123,7 @@ public function prompt(): mixed $this->hideCursor(); $this->render(); - while (($key = static::terminal()->read()) !== null) { + $result = $this->runLoop(function (string $key): mixed { $continue = $this->handleKeyPress($key); $this->render(); @@ -142,12 +143,38 @@ public function prompt(): mixed return $this->value(); } - } + + // `null` is a valid return value for this loop + // so we'll return an instance of Nothing to + // indicate that the loop should continue. + return new Nothing; + }); + + return $result; } finally { $this->clearListeners(); } } + public function runLoop(callable $callable): mixed + { + while(($key = static::terminal()->read()) !== null) { + $result = $callable($key); + + if (! $this->is_nothing($result)) { + return $result; + } + } + } + + /** + * Check if the provided item is an instance of Nothing. + */ + public function is_nothing(mixed $item): bool + { + return is_object($item) && is_a($item, Nothing::class); + } + /** * Register a callback to be invoked when a user cancels a prompt. */ diff --git a/src/Support/Nothing.php b/src/Support/Nothing.php new file mode 100644 index 00000000..8601ba7e --- /dev/null +++ b/src/Support/Nothing.php @@ -0,0 +1,14 @@ + Date: Tue, 11 Jun 2024 02:26:47 -0700 Subject: [PATCH 3/4] extract keypress looping mechanism in FakesInputOutput --- src/Concerns/FakesInputOutput.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Concerns/FakesInputOutput.php b/src/Concerns/FakesInputOutput.php index c5d94c52..685ca50e 100644 --- a/src/Concerns/FakesInputOutput.php +++ b/src/Concerns/FakesInputOutput.php @@ -2,6 +2,7 @@ namespace Laravel\Prompts\Concerns; +use Closure; use Laravel\Prompts\Output\BufferedConsoleOutput; use Laravel\Prompts\Terminal; use PHPUnit\Framework\Assert; @@ -29,15 +30,22 @@ public static function fake(array $keys = []): void $mock->shouldReceive('lines')->byDefault()->andReturn(24); $mock->shouldReceive('initDimensions')->byDefault(); - foreach ($keys as $key) { + static::fakeKeyPresses($keys, function (string $key) use ($mock) { $mock->shouldReceive('read')->once()->andReturn($key); - } + }); static::$terminal = $mock; static::setOutput(new BufferedConsoleOutput()); } + public static function fakeKeyPresses(array $keys, Closure $closure): void + { + foreach ($keys as $key) { + $closure($key); + } + } + /** * Assert that the output contains the given string. */ From f0fb42782daefc790d798d55bc8df17c936e07ae Mon Sep 17 00:00:00 2001 From: Len Woodward Date: Tue, 11 Jun 2024 03:07:44 -0700 Subject: [PATCH 4/4] add docblock with type --- src/Concerns/FakesInputOutput.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Concerns/FakesInputOutput.php b/src/Concerns/FakesInputOutput.php index 685ca50e..19a697e5 100644 --- a/src/Concerns/FakesInputOutput.php +++ b/src/Concerns/FakesInputOutput.php @@ -39,6 +39,11 @@ public static function fake(array $keys = []): void static::setOutput(new BufferedConsoleOutput()); } + /** + * Implementation of the looping mechanism for simulating key presses. + * + * @param array $keys + */ public static function fakeKeyPresses(array $keys, Closure $closure): void { foreach ($keys as $key) {