diff --git a/src/Concerns/ReducesScrollingToFitTerminal.php b/src/Concerns/ReducesScrollingToFitTerminal.php new file mode 100644 index 00000000..bae85761 --- /dev/null +++ b/src/Concerns/ReducesScrollingToFitTerminal.php @@ -0,0 +1,18 @@ +getRenderer()) instanceof Scrolling ? $renderer->reservedLines() : 0; + + $this->scroll = min($this->scroll, $this->terminal()->lines() - $reservedLines); + } +} diff --git a/src/MultiSelectPrompt.php b/src/MultiSelectPrompt.php index 8c77184c..0d27d283 100644 --- a/src/MultiSelectPrompt.php +++ b/src/MultiSelectPrompt.php @@ -7,6 +7,8 @@ class MultiSelectPrompt extends Prompt { + use Concerns\ReducesScrollingToFitTerminal; + /** * The index of the highlighted option. */ @@ -57,6 +59,8 @@ public function __construct( $this->default = $default instanceof Collection ? $default->all() : $default; $this->values = $this->default; + $this->reduceScrollingToFitTerminal(); + $this->on('key', fn ($key) => match ($key) { Key::UP, Key::UP_ARROW, Key::LEFT, Key::LEFT_ARROW, Key::SHIFT_TAB, 'k', 'h' => $this->highlightPrevious(), Key::DOWN, Key::DOWN_ARROW, Key::RIGHT, Key::RIGHT_ARROW, Key::TAB, 'j', 'l' => $this->highlightNext(), diff --git a/src/SearchPrompt.php b/src/SearchPrompt.php index 80cc7e94..4e6b9b58 100644 --- a/src/SearchPrompt.php +++ b/src/SearchPrompt.php @@ -6,6 +6,7 @@ class SearchPrompt extends Prompt { + use Concerns\ReducesScrollingToFitTerminal; use Concerns\Truncation; use Concerns\TypedValue; @@ -41,6 +42,8 @@ public function __construct( ) { $this->trackTypedValue(submit: false); + $this->reduceScrollingToFitTerminal(); + $this->on('key', fn ($key) => match ($key) { Key::UP, Key::UP_ARROW, Key::SHIFT_TAB => $this->highlightPrevious(), Key::DOWN, Key::DOWN_ARROW, Key::TAB => $this->highlightNext(), diff --git a/src/SelectPrompt.php b/src/SelectPrompt.php index d8cb24d8..f2f09bd6 100644 --- a/src/SelectPrompt.php +++ b/src/SelectPrompt.php @@ -7,6 +7,8 @@ class SelectPrompt extends Prompt { + use Concerns\ReducesScrollingToFitTerminal; + /** * The index of the highlighted option. */ @@ -39,6 +41,8 @@ public function __construct( ) { $this->options = $options instanceof Collection ? $options->all() : $options; + $this->reduceScrollingToFitTerminal(); + if ($this->default) { if (array_is_list($this->options)) { $this->highlighted = array_search($this->default, $this->options) ?: 0; diff --git a/src/SuggestPrompt.php b/src/SuggestPrompt.php index 6e1f4237..b9b6d0fd 100644 --- a/src/SuggestPrompt.php +++ b/src/SuggestPrompt.php @@ -7,6 +7,7 @@ class SuggestPrompt extends Prompt { + use Concerns\ReducesScrollingToFitTerminal; use Concerns\Truncation; use Concerns\TypedValue; @@ -51,6 +52,8 @@ public function __construct( ) { $this->options = $options instanceof Collection ? $options->all() : $options; + $this->reduceScrollingToFitTerminal(); + $this->on('key', fn ($key) => match ($key) { Key::UP, Key::UP_ARROW, Key::SHIFT_TAB => $this->highlightPrevious(), Key::DOWN, Key::DOWN_ARROW, Key::TAB => $this->highlightNext(), diff --git a/src/Themes/Contracts/Scrolling.php b/src/Themes/Contracts/Scrolling.php new file mode 100644 index 00000000..1f697027 --- /dev/null +++ b/src/Themes/Contracts/Scrolling.php @@ -0,0 +1,11 @@ +scroll = min($prompt->scroll, $prompt->terminal()->lines() - 5); - return match ($prompt->state) { 'submit' => $this ->box( @@ -109,4 +108,12 @@ protected function renderSelectedOptions(MultiSelectPrompt $prompt): string $prompt->labels() )); } + + /** + * The number of lines to reserve outside of the scrollable area. + */ + public function reservedLines(): int + { + return 5; + } } diff --git a/src/Themes/Default/SearchPromptRenderer.php b/src/Themes/Default/SearchPromptRenderer.php index 7142fa57..f19450d9 100644 --- a/src/Themes/Default/SearchPromptRenderer.php +++ b/src/Themes/Default/SearchPromptRenderer.php @@ -3,8 +3,9 @@ namespace Laravel\Prompts\Themes\Default; use Laravel\Prompts\SearchPrompt; +use Laravel\Prompts\Themes\Contracts\Scrolling; -class SearchPromptRenderer extends Renderer +class SearchPromptRenderer extends Renderer implements Scrolling { use Concerns\DrawsBoxes; use Concerns\DrawsScrollbars; @@ -14,7 +15,6 @@ class SearchPromptRenderer extends Renderer */ public function __invoke(SearchPrompt $prompt): string { - $prompt->scroll = min($prompt->scroll, $prompt->terminal()->lines() - 7); $maxWidth = $prompt->terminal()->cols() - 6; return match ($prompt->state) { @@ -123,4 +123,12 @@ protected function renderOptions(SearchPrompt $prompt): string min($this->longest($prompt->matches(), padding: 4), $prompt->terminal()->cols() - 6) )->implode(PHP_EOL); } + + /** + * The number of lines to reserve outside of the scrollable area. + */ + public function reservedLines(): int + { + return 7; + } } diff --git a/src/Themes/Default/SelectPromptRenderer.php b/src/Themes/Default/SelectPromptRenderer.php index a7b73433..52c4824d 100644 --- a/src/Themes/Default/SelectPromptRenderer.php +++ b/src/Themes/Default/SelectPromptRenderer.php @@ -3,8 +3,9 @@ namespace Laravel\Prompts\Themes\Default; use Laravel\Prompts\SelectPrompt; +use Laravel\Prompts\Themes\Contracts\Scrolling; -class SelectPromptRenderer extends Renderer +class SelectPromptRenderer extends Renderer implements Scrolling { use Concerns\DrawsBoxes; use Concerns\DrawsScrollbars; @@ -14,7 +15,6 @@ class SelectPromptRenderer extends Renderer */ public function __invoke(SelectPrompt $prompt): string { - $prompt->scroll = min($prompt->scroll, $prompt->terminal()->lines() - 5); $maxWidth = $prompt->terminal()->cols() - 6; return match ($prompt->state) { @@ -83,4 +83,12 @@ protected function renderOptions(SelectPrompt $prompt): string $prompt->state === 'cancel' ? 'dim' : 'cyan' )->implode(PHP_EOL); } + + /** + * The number of lines to reserve outside of the scrollable area. + */ + public function reservedLines(): int + { + return 5; + } } diff --git a/src/Themes/Default/SuggestPromptRenderer.php b/src/Themes/Default/SuggestPromptRenderer.php index be04221e..5e4a6f2c 100644 --- a/src/Themes/Default/SuggestPromptRenderer.php +++ b/src/Themes/Default/SuggestPromptRenderer.php @@ -3,8 +3,9 @@ namespace Laravel\Prompts\Themes\Default; use Laravel\Prompts\SuggestPrompt; +use Laravel\Prompts\Themes\Contracts\Scrolling; -class SuggestPromptRenderer extends Renderer +class SuggestPromptRenderer extends Renderer implements Scrolling { use Concerns\DrawsBoxes; use Concerns\DrawsScrollbars; @@ -14,7 +15,6 @@ class SuggestPromptRenderer extends Renderer */ public function __invoke(SuggestPrompt $prompt): string { - $prompt->scroll = min($prompt->scroll, $prompt->terminal()->lines() - 7); $maxWidth = $prompt->terminal()->cols() - 6; return match ($prompt->state) { @@ -111,4 +111,12 @@ protected function renderOptions(SuggestPrompt $prompt): string $prompt->state === 'cancel' ? 'dim' : 'cyan' )->implode(PHP_EOL); } + + /** + * The number of lines to reserve outside of the scrollable area. + */ + public function reservedLines(): int + { + return 7; + } }