/home/mip/mip/public/img/credit/datatables/Themes.tar
Contracts/Scrolling.php 0000644 00000000314 15152100566 0011150 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Contracts;
interface Scrolling
{
/**
* The number of lines to reserve outside of the scrollable area.
*/
public function reservedLines(): int;
}
Default/SuggestPromptRenderer.php 0000644 00000010102 15152100566 0013146 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\SuggestPrompt;
use Laravel\Prompts\Themes\Contracts\Scrolling;
class SuggestPromptRenderer extends Renderer implements Scrolling
{
use Concerns\DrawsBoxes;
use Concerns\DrawsScrollbars;
/**
* Render the suggest prompt.
*/
public function __invoke(SuggestPrompt $prompt): string
{
$maxWidth = $prompt->terminal()->cols() - 6;
return match ($prompt->state) {
'submit' => $this
->box(
$this->dim($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->truncate($prompt->value(), $maxWidth),
),
'cancel' => $this
->box(
$this->dim($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->strikethrough($this->dim($this->truncate($prompt->value() ?: $prompt->placeholder, $maxWidth))),
color: 'red',
)
->error($prompt->cancelMessage),
'error' => $this
->box(
$this->truncate($prompt->label, $prompt->terminal()->cols() - 6),
$this->valueWithCursorAndArrow($prompt, $maxWidth),
$this->renderOptions($prompt),
color: 'yellow',
)
->warning($this->truncate($prompt->error, $prompt->terminal()->cols() - 5)),
default => $this
->box(
$this->cyan($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->valueWithCursorAndArrow($prompt, $maxWidth),
$this->renderOptions($prompt),
)
->when(
$prompt->hint,
fn () => $this->hint($prompt->hint),
fn () => $this->newLine() // Space for errors
)
->spaceForDropdown($prompt),
};
}
/**
* Render the value with the cursor and an arrow.
*/
protected function valueWithCursorAndArrow(SuggestPrompt $prompt, int $maxWidth): string
{
if ($prompt->highlighted !== null || $prompt->value() !== '' || count($prompt->matches()) === 0) {
return $prompt->valueWithCursor($maxWidth);
}
return preg_replace(
'/\s$/',
$this->cyan('⌄'),
$this->pad($prompt->valueWithCursor($maxWidth - 1).' ', min($this->longest($prompt->matches(), padding: 2), $maxWidth))
);
}
/**
* Render a spacer to prevent jumping when the suggestions are displayed.
*/
protected function spaceForDropdown(SuggestPrompt $prompt): self
{
if ($prompt->value() === '' && $prompt->highlighted === null) {
$this->newLine(min(
count($prompt->matches()),
$prompt->scroll,
$prompt->terminal()->lines() - 7
) + 1);
}
return $this;
}
/**
* Render the options.
*/
protected function renderOptions(SuggestPrompt $prompt): string
{
if (empty($prompt->matches()) || ($prompt->value() === '' && $prompt->highlighted === null)) {
return '';
}
return $this->scrollbar(
collect($prompt->visible())
->map(fn ($label) => $this->truncate($label, $prompt->terminal()->cols() - 10))
->map(fn ($label, $key) => $prompt->highlighted === $key
? "{$this->cyan('›')} {$label} "
: " {$this->dim($label)} "
),
$prompt->firstVisible,
$prompt->scroll,
count($prompt->matches()),
min($this->longest($prompt->matches(), padding: 4), $prompt->terminal()->cols() - 6),
$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;
}
}
Default/ProgressRenderer.php 0000644 00000004035 15152100566 0012137 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\Progress;
class ProgressRenderer extends Renderer
{
use Concerns\DrawsBoxes;
/**
* The character to use for the progress bar.
*/
protected string $barCharacter = '█';
/**
* Render the progress bar.
*
* @param Progress<int|iterable<mixed>> $progress
*/
public function __invoke(Progress $progress): string
{
$filled = str_repeat($this->barCharacter, (int) ceil($progress->percentage() * min($this->minWidth, $progress->terminal()->cols() - 6)));
return match ($progress->state) {
'submit' => $this
->box(
$this->dim($this->truncate($progress->label, $progress->terminal()->cols() - 6)),
$this->dim($filled),
info: $progress->progress.'/'.$progress->total,
),
'error' => $this
->box(
$this->truncate($progress->label, $progress->terminal()->cols() - 6),
$this->dim($filled),
color: 'red',
info: $progress->progress.'/'.$progress->total,
),
'cancel' => $this
->box(
$this->truncate($progress->label, $progress->terminal()->cols() - 6),
$this->dim($filled),
color: 'red',
info: $progress->progress.'/'.$progress->total,
)
->error($progress->cancelMessage),
default => $this
->box(
$this->cyan($this->truncate($progress->label, $progress->terminal()->cols() - 6)),
$this->dim($filled),
info: $progress->progress.'/'.$progress->total,
)
->when(
$progress->hint,
fn () => $this->hint($progress->hint),
fn () => $this->newLine() // Space for errors
)
};
}
}
Default/NoteRenderer.php 0000644 00000002734 15152100566 0011244 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\Note;
class NoteRenderer extends Renderer
{
/**
* Render the note.
*/
public function __invoke(Note $note): string
{
$lines = collect(explode(PHP_EOL, $note->message));
switch ($note->type) {
case 'intro':
case 'outro':
$lines = $lines->map(fn ($line) => " {$line} ");
$longest = $lines->map(fn ($line) => strlen($line))->max();
$lines
->each(function ($line) use ($longest) {
$line = str_pad($line, $longest, ' ');
$this->line(" {$this->bgCyan($this->black($line))}");
});
return $this;
case 'warning':
$lines->each(fn ($line) => $this->line($this->yellow(" {$line}")));
return $this;
case 'error':
$lines->each(fn ($line) => $this->line($this->red(" {$line}")));
return $this;
case 'alert':
$lines->each(fn ($line) => $this->line(" {$this->bgRed($this->white(" {$line} "))}"));
return $this;
case 'info':
$lines->each(fn ($line) => $this->line($this->green(" {$line}")));
return $this;
default:
$lines->each(fn ($line) => $this->line(" {$line}"));
return $this;
}
}
}
Default/ConfirmPromptRenderer.php 0000644 00000004572 15152100566 0013140 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\ConfirmPrompt;
class ConfirmPromptRenderer extends Renderer
{
use Concerns\DrawsBoxes;
/**
* Render the confirm prompt.
*/
public function __invoke(ConfirmPrompt $prompt): string
{
return match ($prompt->state) {
'submit' => $this
->box(
$this->dim($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->truncate($prompt->label(), $prompt->terminal()->cols() - 6)
),
'cancel' => $this
->box(
$this->truncate($prompt->label, $prompt->terminal()->cols() - 6),
$this->renderOptions($prompt),
color: 'red'
)
->error($prompt->cancelMessage),
'error' => $this
->box(
$this->truncate($prompt->label, $prompt->terminal()->cols() - 6),
$this->renderOptions($prompt),
color: 'yellow',
)
->warning($this->truncate($prompt->error, $prompt->terminal()->cols() - 5)),
default => $this
->box(
$this->cyan($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->renderOptions($prompt),
)
->when(
$prompt->hint,
fn () => $this->hint($prompt->hint),
fn () => $this->newLine() // Space for errors
),
};
}
/**
* Render the confirm prompt options.
*/
protected function renderOptions(ConfirmPrompt $prompt): string
{
$length = (int) floor(($prompt->terminal()->cols() - 14) / 2);
$yes = $this->truncate($prompt->yes, $length);
$no = $this->truncate($prompt->no, $length);
if ($prompt->state === 'cancel') {
return $this->dim($prompt->confirmed
? "● {$this->strikethrough($yes)} / ○ {$this->strikethrough($no)}"
: "○ {$this->strikethrough($yes)} / ● {$this->strikethrough($no)}");
}
return $prompt->confirmed
? "{$this->green('●')} {$yes} {$this->dim('/ ○ '.$no)}"
: "{$this->dim('○ '.$yes.' /')} {$this->green('●')} {$no}";
}
}
Default/TextareaPromptRenderer.php 0000644 00000005057 15152100566 0013317 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\TextareaPrompt;
use Laravel\Prompts\Themes\Contracts\Scrolling;
class TextareaPromptRenderer extends Renderer implements Scrolling
{
use Concerns\DrawsBoxes;
use Concerns\DrawsScrollbars;
/**
* Render the textarea prompt.
*/
public function __invoke(TextareaPrompt $prompt): string
{
$prompt->width = $prompt->terminal()->cols() - 8;
return match ($prompt->state) {
'submit' => $this
->box(
$this->dim($this->truncate($prompt->label, $prompt->width)),
collect($prompt->lines())->implode(PHP_EOL),
),
'cancel' => $this
->box(
$this->truncate($prompt->label, $prompt->width),
collect($prompt->lines())->map(fn ($line) => $this->strikethrough($this->dim($line)))->implode(PHP_EOL),
color: 'red',
)
->error($prompt->cancelMessage),
'error' => $this
->box(
$this->truncate($prompt->label, $prompt->width),
$this->renderText($prompt),
color: 'yellow',
info: 'Ctrl+D to submit'
)
->warning($this->truncate($prompt->error, $prompt->terminal()->cols() - 5)),
default => $this
->box(
$this->cyan($this->truncate($prompt->label, $prompt->width)),
$this->renderText($prompt),
info: 'Ctrl+D to submit'
)
->when(
$prompt->hint,
fn () => $this->hint($prompt->hint),
fn () => $this->newLine() // Space for errors
)
};
}
/**
* Render the text in the prompt.
*/
protected function renderText(TextareaPrompt $prompt): string
{
$visible = collect($prompt->visible());
while ($visible->count() < $prompt->scroll) {
$visible->push('');
}
$longest = $this->longest($prompt->lines()) + 2;
return $this->scrollbar(
$visible,
$prompt->firstVisible,
$prompt->scroll,
count($prompt->lines()),
min($longest, $prompt->width + 2),
)->implode(PHP_EOL);
}
/**
* The number of lines to reserve outside of the scrollable area.
*/
public function reservedLines(): int
{
return 5;
}
}
Default/SpinnerRenderer.php 0000644 00000001646 15152100566 0011756 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\Spinner;
class SpinnerRenderer extends Renderer
{
/**
* The frames of the spinner.
*
* @var array<string>
*/
protected array $frames = ['⠂', '⠒', '⠐', '⠰', '⠠', '⠤', '⠄', '⠆'];
/**
* The frame to render when the spinner is static.
*/
protected string $staticFrame = '⠶';
/**
* The interval between frames.
*/
protected int $interval = 75;
/**
* Render the spinner.
*/
public function __invoke(Spinner $spinner): string
{
if ($spinner->static) {
return $this->line(" {$this->cyan($this->staticFrame)} {$spinner->message}");
}
$spinner->interval = $this->interval;
$frame = $this->frames[$spinner->count % count($this->frames)];
return $this->line(" {$this->cyan($frame)} {$spinner->message}");
}
}
Default/MultiSelectPromptRenderer.php 0000644 00000010735 15152100566 0013773 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\MultiSelectPrompt;
use Laravel\Prompts\Themes\Contracts\Scrolling;
class MultiSelectPromptRenderer extends Renderer implements Scrolling
{
use Concerns\DrawsBoxes;
use Concerns\DrawsScrollbars;
/**
* Render the multiselect prompt.
*/
public function __invoke(MultiSelectPrompt $prompt): string
{
return match ($prompt->state) {
'submit' => $this
->box(
$this->dim($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->renderSelectedOptions($prompt)
),
'cancel' => $this
->box(
$this->truncate($prompt->label, $prompt->terminal()->cols() - 6),
$this->renderOptions($prompt),
color: 'red',
)
->error($prompt->cancelMessage),
'error' => $this
->box(
$this->truncate($prompt->label, $prompt->terminal()->cols() - 6),
$this->renderOptions($prompt),
color: 'yellow',
info: count($prompt->options) > $prompt->scroll ? (count($prompt->value()).' selected') : '',
)
->warning($this->truncate($prompt->error, $prompt->terminal()->cols() - 5)),
default => $this
->box(
$this->cyan($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->renderOptions($prompt),
info: count($prompt->options) > $prompt->scroll ? (count($prompt->value()).' selected') : '',
)
->when(
$prompt->hint,
fn () => $this->hint($prompt->hint),
fn () => $this->newLine() // Space for errors
),
};
}
/**
* Render the options.
*/
protected function renderOptions(MultiSelectPrompt $prompt): string
{
return $this->scrollbar(
collect($prompt->visible())
->map(fn ($label) => $this->truncate($label, $prompt->terminal()->cols() - 12))
->map(function ($label, $key) use ($prompt) {
$index = array_search($key, array_keys($prompt->options));
$active = $index === $prompt->highlighted;
if (array_is_list($prompt->options)) {
$value = $prompt->options[$index];
} else {
$value = array_keys($prompt->options)[$index];
}
$selected = in_array($value, $prompt->value());
if ($prompt->state === 'cancel') {
return $this->dim(match (true) {
$active && $selected => "› ◼ {$this->strikethrough($label)} ",
$active => "› ◻ {$this->strikethrough($label)} ",
$selected => " ◼ {$this->strikethrough($label)} ",
default => " ◻ {$this->strikethrough($label)} ",
});
}
return match (true) {
$active && $selected => "{$this->cyan('› ◼')} {$label} ",
$active => "{$this->cyan('›')} ◻ {$label} ",
$selected => " {$this->cyan('◼')} {$this->dim($label)} ",
default => " {$this->dim('◻')} {$this->dim($label)} ",
};
})
->values(),
$prompt->firstVisible,
$prompt->scroll,
count($prompt->options),
min($this->longest($prompt->options, padding: 6), $prompt->terminal()->cols() - 6),
$prompt->state === 'cancel' ? 'dim' : 'cyan'
)->implode(PHP_EOL);
}
/**
* Render the selected options.
*/
protected function renderSelectedOptions(MultiSelectPrompt $prompt): string
{
if (count($prompt->labels()) === 0) {
return $this->gray('None');
}
return implode("\n", array_map(
fn ($label) => $this->truncate($label, $prompt->terminal()->cols() - 6),
$prompt->labels()
));
}
/**
* The number of lines to reserve outside of the scrollable area.
*/
public function reservedLines(): int
{
return 5;
}
}
Default/Concerns/DrawsBoxes.php 0000644 00000003506 15152100566 0012501 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default\Concerns;
use Laravel\Prompts\Prompt;
trait DrawsBoxes
{
use InteractsWithStrings;
protected int $minWidth = 60;
/**
* Draw a box.
*
* @return $this
*/
protected function box(
string $title,
string $body,
string $footer = '',
string $color = 'gray',
string $info = '',
): self {
$this->minWidth = min($this->minWidth, Prompt::terminal()->cols() - 6);
$bodyLines = collect(explode(PHP_EOL, $body));
$footerLines = collect(explode(PHP_EOL, $footer))->filter();
$width = $this->longest(
$bodyLines
->merge($footerLines)
->push($title)
->toArray()
);
$titleLength = mb_strwidth($this->stripEscapeSequences($title));
$titleLabel = $titleLength > 0 ? " {$title} " : '';
$topBorder = str_repeat('─', $width - $titleLength + ($titleLength > 0 ? 0 : 2));
$this->line("{$this->{$color}(' ┌')}{$titleLabel}{$this->{$color}($topBorder.'┐')}");
$bodyLines->each(function ($line) use ($width, $color) {
$this->line("{$this->{$color}(' │')} {$this->pad($line, $width)} {$this->{$color}('│')}");
});
if ($footerLines->isNotEmpty()) {
$this->line($this->{$color}(' ├'.str_repeat('─', $width + 2).'┤'));
$footerLines->each(function ($line) use ($width, $color) {
$this->line("{$this->{$color}(' │')} {$this->pad($line, $width)} {$this->{$color}('│')}");
});
}
$this->line($this->{$color}(' └'.str_repeat(
'─', $info ? ($width - mb_strwidth($this->stripEscapeSequences($info))) : ($width + 2)
).($info ? " {$info} " : '').'┘'));
return $this;
}
}
Default/Concerns/InteractsWithStrings.php 0000644 00000002436 15152100566 0014563 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default\Concerns;
trait InteractsWithStrings
{
/**
* Get the length of the longest line.
*
* @param array<string> $lines
*/
protected function longest(array $lines, int $padding = 0): int
{
return max(
$this->minWidth,
collect($lines)
->map(fn ($line) => mb_strwidth($this->stripEscapeSequences($line)) + $padding)
->max()
);
}
/**
* Pad text ignoring ANSI escape sequences.
*/
protected function pad(string $text, int $length, string $char = ' '): string
{
$rightPadding = str_repeat($char, max(0, $length - mb_strwidth($this->stripEscapeSequences($text))));
return "{$text}{$rightPadding}";
}
/**
* Strip ANSI escape sequences from the given text.
*/
protected function stripEscapeSequences(string $text): string
{
// Strip ANSI escape sequences.
$text = preg_replace("/\e[^m]*m/", '', $text);
// Strip Symfony named style tags.
$text = preg_replace("/<(info|comment|question|error)>(.*?)<\/\\1>/", '$2', $text);
// Strip Symfony inline style tags.
return preg_replace("/<(?:(?:[fb]g|options)=[a-z,;]+)+>(.*?)<\/>/i", '$1', $text);
}
}
Default/Concerns/DrawsScrollbars.php 0000644 00000003005 15152100566 0013521 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default\Concerns;
use Illuminate\Support\Collection;
trait DrawsScrollbars
{
/**
* Render a scrollbar beside the visible items.
*
* @param \Illuminate\Support\Collection<int, string> $visible
* @return \Illuminate\Support\Collection<int, string>
*/
protected function scrollbar(Collection $visible, int $firstVisible, int $height, int $total, int $width, string $color = 'cyan'): Collection
{
if ($height >= $total) {
return $visible;
}
$scrollPosition = $this->scrollPosition($firstVisible, $height, $total);
return $visible
->values()
->map(fn ($line) => $this->pad($line, $width))
->map(fn ($line, $index) => match ($index) {
$scrollPosition => preg_replace('/.$/', $this->{$color}('┃'), $line),
default => preg_replace('/.$/', $this->gray('│'), $line),
});
}
/**
* Return the position where the scrollbar "handle" should be rendered.
*/
protected function scrollPosition(int $firstVisible, int $height, int $total): int
{
if ($firstVisible === 0) {
return 0;
}
$maxPosition = $total - $height;
if ($firstVisible === $maxPosition) {
return $height - 1;
}
if ($height <= 2) {
return -1;
}
$percent = $firstVisible / $maxPosition;
return (int) round($percent * ($height - 3)) + 1;
}
}
Default/TableRenderer.php 0000644 00000002466 15152100566 0011370 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\Output\BufferedConsoleOutput;
use Laravel\Prompts\Table;
use Symfony\Component\Console\Helper\Table as SymfonyTable;
use Symfony\Component\Console\Helper\TableStyle;
class TableRenderer extends Renderer
{
/**
* Render the table.
*/
public function __invoke(Table $table): string
{
$tableStyle = (new TableStyle())
->setHorizontalBorderChars('─')
->setVerticalBorderChars('│', '│')
->setCellHeaderFormat($this->dim('<fg=default>%s</>'))
->setCellRowFormat('<fg=default>%s</>');
if (empty($table->headers)) {
$tableStyle->setCrossingChars('┼', '', '', '', '┤', '┘</>', '┴', '└', '├', '<fg=gray>┌', '┬', '┐');
} else {
$tableStyle->setCrossingChars('┼', '<fg=gray>┌', '┬', '┐', '┤', '┘</>', '┴', '└', '├');
}
$buffered = new BufferedConsoleOutput();
(new SymfonyTable($buffered))
->setHeaders($table->headers)
->setRows($table->rows)
->setStyle($tableStyle)
->render();
collect(explode(PHP_EOL, trim($buffered->content(), PHP_EOL)))
->each(fn ($line) => $this->line(' '.$line));
return $this;
}
}
Default/MultiSearchPromptRenderer.php 0000644 00000013643 15152100566 0013762 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\MultiSearchPrompt;
use Laravel\Prompts\Themes\Contracts\Scrolling;
class MultiSearchPromptRenderer extends Renderer implements Scrolling
{
use Concerns\DrawsBoxes;
use Concerns\DrawsScrollbars;
/**
* Render the suggest prompt.
*/
public function __invoke(MultiSearchPrompt $prompt): string
{
$maxWidth = $prompt->terminal()->cols() - 6;
return match ($prompt->state) {
'submit' => $this
->box(
$this->dim($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->renderSelectedOptions($prompt),
),
'cancel' => $this
->box(
$this->dim($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->strikethrough($this->dim($this->truncate($prompt->searchValue() ?: $prompt->placeholder, $maxWidth))),
color: 'red',
)
->error($prompt->cancelMessage),
'error' => $this
->box(
$this->truncate($prompt->label, $prompt->terminal()->cols() - 6),
$prompt->valueWithCursor($maxWidth),
$this->renderOptions($prompt),
color: 'yellow',
info: $this->getInfoText($prompt),
)
->warning($this->truncate($prompt->error, $prompt->terminal()->cols() - 5)),
'searching' => $this
->box(
$this->cyan($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->valueWithCursorAndSearchIcon($prompt, $maxWidth),
$this->renderOptions($prompt),
info: $this->getInfoText($prompt),
)
->hint($prompt->hint),
default => $this
->box(
$this->cyan($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$prompt->valueWithCursor($maxWidth),
$this->renderOptions($prompt),
info: $this->getInfoText($prompt),
)
->when(
$prompt->hint,
fn () => $this->hint($prompt->hint),
fn () => $this->newLine() // Space for errors
)
->spaceForDropdown($prompt)
};
}
/**
* Render the value with the cursor and a search icon.
*/
protected function valueWithCursorAndSearchIcon(MultiSearchPrompt $prompt, int $maxWidth): string
{
return preg_replace(
'/\s$/',
$this->cyan('…'),
$this->pad($prompt->valueWithCursor($maxWidth - 1).' ', min($this->longest($prompt->matches(), padding: 2), $maxWidth))
);
}
/**
* Render a spacer to prevent jumping when the suggestions are displayed.
*/
protected function spaceForDropdown(MultiSearchPrompt $prompt): self
{
if ($prompt->searchValue() !== '') {
return $this;
}
$this->newLine(max(
0,
min($prompt->scroll, $prompt->terminal()->lines() - 7) - count($prompt->matches()),
));
if ($prompt->matches() === []) {
$this->newLine();
}
return $this;
}
/**
* Render the options.
*/
protected function renderOptions(MultiSearchPrompt $prompt): string
{
if ($prompt->searchValue() !== '' && empty($prompt->matches())) {
return $this->gray(' '.($prompt->state === 'searching' ? 'Searching...' : 'No results.'));
}
return $this->scrollbar(
collect($prompt->visible())
->map(fn ($label) => $this->truncate($label, $prompt->terminal()->cols() - 12))
->map(function ($label, $key) use ($prompt) {
$index = array_search($key, array_keys($prompt->matches()));
$active = $index === $prompt->highlighted;
$selected = $prompt->isList()
? in_array($label, $prompt->value())
: in_array($key, $prompt->value());
return match (true) {
$active && $selected => "{$this->cyan('› ◼')} {$label} ",
$active => "{$this->cyan('›')} ◻ {$label} ",
$selected => " {$this->cyan('◼')} {$this->dim($label)} ",
default => " {$this->dim('◻')} {$this->dim($label)} ",
};
}),
$prompt->firstVisible,
$prompt->scroll,
count($prompt->matches()),
min($this->longest($prompt->matches(), padding: 4), $prompt->terminal()->cols() - 6)
)->implode(PHP_EOL);
}
/**
* Render the selected options.
*/
protected function renderSelectedOptions(MultiSearchPrompt $prompt): string
{
if (count($prompt->labels()) === 0) {
return $this->gray('None');
}
return implode("\n", array_map(
fn ($label) => $this->truncate($label, $prompt->terminal()->cols() - 6),
$prompt->labels()
));
}
/**
* Render the info text.
*/
protected function getInfoText(MultiSearchPrompt $prompt): string
{
$info = count($prompt->value()).' selected';
$hiddenCount = count($prompt->value()) - collect($prompt->matches())
->filter(fn ($label, $key) => in_array($prompt->isList() ? $label : $key, $prompt->value()))
->count();
if ($hiddenCount > 0) {
$info .= " ($hiddenCount hidden)";
}
return $info;
}
/**
* The number of lines to reserve outside of the scrollable area.
*/
public function reservedLines(): int
{
return 7;
}
}
Default/TextPromptRenderer.php 0000644 00000003330 15152100566 0012456 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\TextPrompt;
class TextPromptRenderer extends Renderer
{
use Concerns\DrawsBoxes;
/**
* Render the text prompt.
*/
public function __invoke(TextPrompt $prompt): string
{
$maxWidth = $prompt->terminal()->cols() - 6;
return match ($prompt->state) {
'submit' => $this
->box(
$this->dim($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->truncate($prompt->value(), $maxWidth),
),
'cancel' => $this
->box(
$this->truncate($prompt->label, $prompt->terminal()->cols() - 6),
$this->strikethrough($this->dim($this->truncate($prompt->value() ?: $prompt->placeholder, $maxWidth))),
color: 'red',
)
->error($prompt->cancelMessage),
'error' => $this
->box(
$this->truncate($prompt->label, $prompt->terminal()->cols() - 6),
$prompt->valueWithCursor($maxWidth),
color: 'yellow',
)
->warning($this->truncate($prompt->error, $prompt->terminal()->cols() - 5)),
default => $this
->box(
$this->cyan($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$prompt->valueWithCursor($maxWidth),
)
->when(
$prompt->hint,
fn () => $this->hint($prompt->hint),
fn () => $this->newLine() // Space for errors
)
};
}
}
Default/SelectPromptRenderer.php 0000644 00000006246 15152100566 0012762 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\SelectPrompt;
use Laravel\Prompts\Themes\Contracts\Scrolling;
class SelectPromptRenderer extends Renderer implements Scrolling
{
use Concerns\DrawsBoxes;
use Concerns\DrawsScrollbars;
/**
* Render the select prompt.
*/
public function __invoke(SelectPrompt $prompt): string
{
$maxWidth = $prompt->terminal()->cols() - 6;
return match ($prompt->state) {
'submit' => $this
->box(
$this->dim($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->truncate($prompt->label(), $maxWidth),
),
'cancel' => $this
->box(
$this->truncate($prompt->label, $prompt->terminal()->cols() - 6),
$this->renderOptions($prompt),
color: 'red',
)
->error($prompt->cancelMessage),
'error' => $this
->box(
$this->truncate($prompt->label, $prompt->terminal()->cols() - 6),
$this->renderOptions($prompt),
color: 'yellow',
)
->warning($this->truncate($prompt->error, $prompt->terminal()->cols() - 5)),
default => $this
->box(
$this->cyan($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->renderOptions($prompt),
)
->when(
$prompt->hint,
fn () => $this->hint($prompt->hint),
fn () => $this->newLine() // Space for errors
),
};
}
/**
* Render the options.
*/
protected function renderOptions(SelectPrompt $prompt): string
{
return $this->scrollbar(
collect($prompt->visible())
->map(fn ($label) => $this->truncate($label, $prompt->terminal()->cols() - 12))
->map(function ($label, $key) use ($prompt) {
$index = array_search($key, array_keys($prompt->options));
if ($prompt->state === 'cancel') {
return $this->dim($prompt->highlighted === $index
? "› ● {$this->strikethrough($label)} "
: " ○ {$this->strikethrough($label)} "
);
}
return $prompt->highlighted === $index
? "{$this->cyan('›')} {$this->cyan('●')} {$label} "
: " {$this->dim('○')} {$this->dim($label)} ";
})
->values(),
$prompt->firstVisible,
$prompt->scroll,
count($prompt->options),
min($this->longest($prompt->options, padding: 6), $prompt->terminal()->cols() - 6),
$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;
}
}
Default/PasswordPromptRenderer.php 0000644 00000003307 15152100566 0013340 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\PasswordPrompt;
class PasswordPromptRenderer extends Renderer
{
use Concerns\DrawsBoxes;
/**
* Render the password prompt.
*/
public function __invoke(PasswordPrompt $prompt): string
{
$maxWidth = $prompt->terminal()->cols() - 6;
return match ($prompt->state) {
'submit' => $this
->box(
$this->dim($prompt->label),
$this->truncate($prompt->masked(), $maxWidth),
),
'cancel' => $this
->box(
$this->truncate($prompt->label, $prompt->terminal()->cols() - 6),
$this->strikethrough($this->dim($this->truncate($prompt->masked() ?: $prompt->placeholder, $maxWidth))),
color: 'red',
)
->error($prompt->cancelMessage),
'error' => $this
->box(
$this->dim($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$prompt->maskedWithCursor($maxWidth),
color: 'yellow',
)
->warning($this->truncate($prompt->error, $prompt->terminal()->cols() - 5)),
default => $this
->box(
$this->cyan($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$prompt->maskedWithCursor($maxWidth),
)
->when(
$prompt->hint,
fn () => $this->hint($prompt->hint),
fn () => $this->newLine() // Space for errors
),
};
}
}
Default/SearchPromptRenderer.php 0000644 00000010655 15152100566 0012747 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\SearchPrompt;
use Laravel\Prompts\Themes\Contracts\Scrolling;
class SearchPromptRenderer extends Renderer implements Scrolling
{
use Concerns\DrawsBoxes;
use Concerns\DrawsScrollbars;
/**
* Render the suggest prompt.
*/
public function __invoke(SearchPrompt $prompt): string
{
$maxWidth = $prompt->terminal()->cols() - 6;
return match ($prompt->state) {
'submit' => $this
->box(
$this->dim($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->truncate($prompt->label(), $maxWidth),
),
'cancel' => $this
->box(
$this->dim($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->strikethrough($this->dim($this->truncate($prompt->searchValue() ?: $prompt->placeholder, $maxWidth))),
color: 'red',
)
->error($prompt->cancelMessage),
'error' => $this
->box(
$this->truncate($prompt->label, $prompt->terminal()->cols() - 6),
$prompt->valueWithCursor($maxWidth),
$this->renderOptions($prompt),
color: 'yellow',
)
->warning($this->truncate($prompt->error, $prompt->terminal()->cols() - 5)),
'searching' => $this
->box(
$this->cyan($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$this->valueWithCursorAndSearchIcon($prompt, $maxWidth),
$this->renderOptions($prompt),
)
->hint($prompt->hint),
default => $this
->box(
$this->cyan($this->truncate($prompt->label, $prompt->terminal()->cols() - 6)),
$prompt->valueWithCursor($maxWidth),
$this->renderOptions($prompt),
)
->when(
$prompt->hint,
fn () => $this->hint($prompt->hint),
fn () => $this->newLine() // Space for errors
)
->spaceForDropdown($prompt)
};
}
/**
* Render the value with the cursor and a search icon.
*/
protected function valueWithCursorAndSearchIcon(SearchPrompt $prompt, int $maxWidth): string
{
return preg_replace(
'/\s$/',
$this->cyan('…'),
$this->pad($prompt->valueWithCursor($maxWidth - 1).' ', min($this->longest($prompt->matches(), padding: 2), $maxWidth))
);
}
/**
* Render a spacer to prevent jumping when the suggestions are displayed.
*/
protected function spaceForDropdown(SearchPrompt $prompt): self
{
if ($prompt->searchValue() !== '') {
return $this;
}
$this->newLine(max(
0,
min($prompt->scroll, $prompt->terminal()->lines() - 7) - count($prompt->matches()),
));
if ($prompt->matches() === []) {
$this->newLine();
}
return $this;
}
/**
* Render the options.
*/
protected function renderOptions(SearchPrompt $prompt): string
{
if ($prompt->searchValue() !== '' && empty($prompt->matches())) {
return $this->gray(' '.($prompt->state === 'searching' ? 'Searching...' : 'No results.'));
}
return $this->scrollbar(
collect($prompt->visible())
->map(fn ($label) => $this->truncate($label, $prompt->terminal()->cols() - 10))
->map(function ($label, $key) use ($prompt) {
$index = array_search($key, array_keys($prompt->matches()));
return $prompt->highlighted === $index
? "{$this->cyan('›')} {$label} "
: " {$this->dim($label)} ";
})
->values(),
$prompt->firstVisible,
$prompt->scroll,
count($prompt->matches()),
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;
}
}
Default/PausePromptRenderer.php 0000644 00000001171 15152100566 0012610 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\PausePrompt;
class PausePromptRenderer extends Renderer
{
use Concerns\DrawsBoxes;
/**
* Render the pause prompt.
*/
public function __invoke(PausePrompt $prompt): string
{
match ($prompt->state) {
'submit' => collect(explode(PHP_EOL, $prompt->message))
->each(fn ($line) => $this->line($this->gray(" {$line}"))),
default => collect(explode(PHP_EOL, $prompt->message))
->each(fn ($line) => $this->line($this->green(" {$line}")))
};
return $this;
}
}
Default/Renderer.php 0000644 00000004145 15152100566 0010414 0 ustar 00 <?php
namespace Laravel\Prompts\Themes\Default;
use Laravel\Prompts\Concerns\Colors;
use Laravel\Prompts\Concerns\Truncation;
use Laravel\Prompts\Prompt;
abstract class Renderer
{
use Colors;
use Truncation;
/**
* The output to be rendered.
*/
protected string $output = '';
/**
* Create a new renderer instance.
*/
public function __construct(protected Prompt $prompt)
{
//
}
/**
* Render a line of output.
*/
protected function line(string $message): self
{
$this->output .= $message.PHP_EOL;
return $this;
}
/**
* Render a new line.
*/
protected function newLine(int $count = 1): self
{
$this->output .= str_repeat(PHP_EOL, $count);
return $this;
}
/**
* Render a warning message.
*/
protected function warning(string $message): self
{
return $this->line($this->yellow(" ⚠ {$message}"));
}
/**
* Render an error message.
*/
protected function error(string $message): self
{
return $this->line($this->red(" ⚠ {$message}"));
}
/**
* Render an hint message.
*/
protected function hint(string $message): self
{
if ($message === '') {
return $this;
}
$message = $this->truncate($message, $this->prompt->terminal()->cols() - 6);
return $this->line($this->gray(" {$message}"));
}
/**
* Apply the callback if the given "value" is truthy.
*
* @return $this
*/
protected function when(mixed $value, callable $callback, ?callable $default = null): self
{
if ($value) {
$callback($this);
} elseif ($default) {
$default($this);
}
return $this;
}
/**
* Render the output with a blank line above and below.
*/
public function __toString()
{
return str_repeat(PHP_EOL, max(2 - $this->prompt->newLinesWritten(), 0))
.$this->output
.(in_array($this->prompt->state, ['submit', 'cancel']) ? PHP_EOL : '');
}
}