Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[0.3.0] Remove circular dependency on illuminate/collections #168

Merged
merged 22 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
matrix:
php: [8.1, 8.2, 8.3]

name: PHP ${{ matrix.php }}
name: PHP ${{ matrix.php }} - With Collections

steps:
- name: Checkout code
Expand All @@ -45,3 +45,43 @@ jobs:

- name: Execute tests
run: vendor/bin/pest

without_collections:
runs-on: ubuntu-22.04

strategy:
fail-fast: true
matrix:
php: [8.1, 8.2, 8.3]

name: PHP ${{ matrix.php }} - Without Collections

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: dom, curl, libxml, mbstring, zip
ini-values: error_reporting=E_ALL
tools: composer:v2
coverage: none

- name: Remove collections
uses: nick-fields/retry@v3
with:
timeout_minutes: 5
max_attempts: 5
command: composer remove illuminate/collections --dev --no-interaction --no-update

- name: Install dependencies
uses: nick-fields/retry@v3
with:
timeout_minutes: 5
max_attempts: 5
command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress

- name: Execute tests
run: vendor/bin/pest
7 changes: 4 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@
"require": {
"php": "^8.1",
"ext-mbstring": "*",
"illuminate/collections": "^10.0|^11.0",
"composer-runtime-api": "^2.2",
"symfony/console": "^6.2|^7.0"
},
"require-dev": {
"phpstan/phpstan": "^1.11",
"pestphp/pest": "^2.3",
"mockery/mockery": "^1.5",
"phpstan/phpstan-mockery": "^1.1"
"phpstan/phpstan-mockery": "^1.1",
"illuminate/collections": "^10.0|^11.0"
},
"conflict": {
"illuminate/console": ">=10.17.0 <10.25.0",
Expand All @@ -42,7 +43,7 @@
},
"extra": {
"branch-alias": {
"dev-main": "0.2.x-dev"
"dev-main": "0.3.x-dev"
taylorotwell marked this conversation as resolved.
Show resolved Hide resolved
}
},
"prefer-stable": true,
Expand Down
10 changes: 9 additions & 1 deletion src/Key.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ class Key
*/
public static function oneOf(array $keys, string $match): ?string
{
return collect($keys)->flatten()->contains($match) ? $match : null;
foreach ($keys as $key) {
if (is_array($key) && static::oneOf($key, $match) !== null) {
return $match;
} elseif ($key === $match) {
return $match;
}
}

return null;
}
}
3 changes: 2 additions & 1 deletion src/MultiSearchPrompt.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Laravel\Prompts;

use Closure;
use Laravel\Prompts\Support\Utils;

class MultiSearchPrompt extends Prompt
{
Expand Down Expand Up @@ -140,7 +141,7 @@ public function visible(): array
*/
protected function toggleAll(): void
{
$allMatchesSelected = collect($this->matches)->every(fn ($label, $key) => $this->isList()
$allMatchesSelected = Utils::allMatch($this->matches, fn ($label, $key) => $this->isList()
? array_key_exists($label, $this->values)
: array_key_exists($key, $this->values));

Expand Down
7 changes: 4 additions & 3 deletions src/Support/Result.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@
*/
final class Result
{
public function __construct(
public readonly mixed $value,
) {}
public function __construct(public readonly mixed $value)
{
//
}

public static function from(mixed $value): self
{
Expand Down
53 changes: 53 additions & 0 deletions src/Support/Utils.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

namespace Laravel\Prompts\Support;

use Closure;

/**
* @internal
*/
class Utils
{
/**
* Determine if all items in an array match a truth test.
*
* @param array<array-key, mixed> $values
*/
public static function allMatch(array $values, Closure $callback): bool
{
foreach ($values as $key => $value) {
if (! $callback($value, $key)) {
return false;
}
}

return true;
}

/**
* Get the last item from an array or null if it doesn't exist.
*
* @param array<array-key, mixed> $array
*/
public static function last(array $array): mixed
{
return array_reverse($array)[0] ?? null;
}

/**
* Returns the key of the first element in the array that satisfies the callback.
*
* @param array<array-key, mixed> $array
*/
public static function search(array $array, Closure $callback): int|string|false
{
foreach ($array as $key => $value) {
if ($callback($value, $key)) {
return $key;
}
}

return false;
}
}
35 changes: 18 additions & 17 deletions src/TextareaPrompt.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Laravel\Prompts;

use Closure;
use Laravel\Prompts\Support\Utils;

class TextareaPrompt extends Prompt
{
Expand Down Expand Up @@ -113,10 +114,10 @@ protected function handleUpKey(): void
return;
}

$lines = collect($this->lines());
$lines = $this->lines();

// Line length + 1 for the newline character
$lineLengths = $lines->map(fn ($line, $index) => mb_strlen($line) + ($index === $lines->count() - 1 ? 0 : 1));
$lineLengths = array_map(fn ($line, $index) => mb_strlen($line) + ($index === count($lines) - 1 ? 0 : 1), $lines, range(0, count($lines) - 1));

$currentLineIndex = $this->currentLineIndex();

Expand All @@ -127,52 +128,52 @@ protected function handleUpKey(): void
return;
}

$currentLines = $lineLengths->slice(0, $currentLineIndex + 1);
$currentLines = array_slice($lineLengths, 0, $currentLineIndex + 1);

$currentColumn = $currentLines->last() - ($currentLines->sum() - $this->cursorPosition);
$currentColumn = Utils::last($currentLines) - (array_sum($currentLines) - $this->cursorPosition);

$destinationLineLength = ($lineLengths->get($currentLineIndex - 1) ?? $currentLines->first()) - 1;
$destinationLineLength = ($lineLengths[$currentLineIndex - 1] ?? $currentLines[0]) - 1;

$newColumn = min($destinationLineLength, $currentColumn);

$fullLines = $currentLines->slice(0, -2);
$fullLines = array_slice($currentLines, 0, -2);

$this->cursorPosition = $fullLines->sum() + $newColumn;
$this->cursorPosition = array_sum($fullLines) + $newColumn;
}

/**
* Handle the down key press.
*/
protected function handleDownKey(): void
{
$lines = collect($this->lines());
$lines = $this->lines();

// Line length + 1 for the newline character
$lineLengths = $lines->map(fn ($line, $index) => mb_strlen($line) + ($index === $lines->count() - 1 ? 0 : 1));
$lineLengths = array_map(fn ($line, $index) => mb_strlen($line) + ($index === count($lines) - 1 ? 0 : 1), $lines, range(0, count($lines) - 1));

$currentLineIndex = $this->currentLineIndex();

if ($currentLineIndex === $lines->count() - 1) {
if ($currentLineIndex === count($lines) - 1) {
// They're already at the last line, jump them to the last position
$this->cursorPosition = mb_strlen($lines->implode(PHP_EOL));
$this->cursorPosition = mb_strlen(implode(PHP_EOL, $lines));

return;
}

// Lines up to and including the current line
$currentLines = $lineLengths->slice(0, $currentLineIndex + 1);
$currentLines = array_slice($lineLengths, 0, $currentLineIndex + 1);

$currentColumn = $currentLines->last() - ($currentLines->sum() - $this->cursorPosition);
$currentColumn = Utils::last($currentLines) - (array_sum($currentLines) - $this->cursorPosition);

$destinationLineLength = $lineLengths->get($currentLineIndex + 1) ?? $currentLines->last();
$destinationLineLength = $lineLengths[$currentLineIndex + 1] ?? Utils::last($currentLines);

if ($currentLineIndex + 1 !== $lines->count() - 1) {
if ($currentLineIndex + 1 !== count($lines) - 1) {
$destinationLineLength--;
}

$newColumn = min(max(0, $destinationLineLength), $currentColumn);

$this->cursorPosition = $currentLines->sum() + $newColumn;
$this->cursorPosition = array_sum($currentLines) + $newColumn;
}

/**
Expand Down Expand Up @@ -207,7 +208,7 @@ protected function currentLineIndex(): int
{
$totalLineLength = 0;

return (int) collect($this->lines())->search(function ($line) use (&$totalLineLength) {
return (int) Utils::search($this->lines(), function ($line) use (&$totalLineLength) {
$totalLineLength += mb_strlen($line) + 1;

return $totalLineLength > $this->cursorPosition;
Expand Down
22 changes: 9 additions & 13 deletions src/Themes/Default/Concerns/DrawsBoxes.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,31 +24,27 @@ protected function box(
): 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()
);
$bodyLines = explode(PHP_EOL, $body);
$footerLines = array_filter(explode(PHP_EOL, $footer));

$width = $this->longest(array_merge($bodyLines, $footerLines, [$title]));

$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) {
foreach ($bodyLines as $line) {
$this->line("{$this->{$color}(' │')} {$this->pad($line, $width)} {$this->{$color}('│')}");
});
}

if ($footerLines->isNotEmpty()) {
if (count($footerLines) > 0) {
$this->line($this->{$color}(' ├'.str_repeat('─', $width + 2).'┤'));

$footerLines->each(function ($line) use ($width, $color) {
foreach ($footerLines as $line) {
$this->line("{$this->{$color}(' │')} {$this->pad($line, $width)} {$this->{$color}('│')}");
});
}
}

$this->line($this->{$color}(' └'.str_repeat(
Expand Down
23 changes: 13 additions & 10 deletions src/Themes/Default/Concerns/DrawsScrollbars.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,27 @@ trait DrawsScrollbars
/**
* Render a scrollbar beside the visible items.
*
* @param \Illuminate\Support\Collection<int, string> $visible
* @return \Illuminate\Support\Collection<int, string>
* @template T of array<int, string>|\Illuminate\Support\Collection<int, string>
*
* @param T $visible
* @return T
*/
protected function scrollbar(Collection $visible, int $firstVisible, int $height, int $total, int $width, string $color = 'cyan'): Collection
protected function scrollbar(array|Collection $visible, int $firstVisible, int $height, int $total, int $width, string $color = 'cyan'): array|Collection
{
if ($height >= $total) {
return $visible;
}

$scrollPosition = $this->scrollPosition($firstVisible, $height, $total);

return $visible // @phpstan-ignore return.type
->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),
});
$lines = $visible instanceof Collection ? $visible->all() : $visible;

$result = array_map(fn ($line, $index) => match ($index) {
$scrollPosition => preg_replace('/.$/', $this->{$color}('┃'), $this->pad($line, $width)) ?? '',
default => preg_replace('/.$/', $this->gray('│'), $this->pad($line, $width)) ?? '',
}, array_values($lines), range(0, count($lines) - 1));

return $visible instanceof Collection ? new Collection($result) : $result; // @phpstan-ignore return.type (https://github.com/phpstan/phpstan/issues/11663)
}

/**
Expand Down
4 changes: 1 addition & 3 deletions src/Themes/Default/Concerns/InteractsWithStrings.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ 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()
count($lines) > 0 ? max(array_map(fn ($line) => mb_strwidth($this->stripEscapeSequences($line)) + $padding, $lines)) : null
);
}

Expand Down
Loading
Loading