Skip to content

Commit

Permalink
[0.3.0] Remove circular dependency on illuminate/collections (#168)
Browse files Browse the repository at this point in the history
* Move illuminate/collections to a dev dependency only

* Remove internal use of collections

* try removing collections in tests

* wip

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

* wip

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

* Fix code styling

* wip

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

* wip

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

* wip

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

* Fix code styling

* wip

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

* wip

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

* wip

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>

* Fix collection dependency check

* Remove collections from data providers when not installed

* Fix code styling

* Refactor tests that didn't require collections

* Formatting

* Fix test

* Update .github/workflows/tests.yml

* wip

---------

Signed-off-by: Mior Muhammad Zaki <crynobone@gmail.com>
Co-authored-by: Dries Vints <dries@vints.be>
Co-authored-by: Mior Muhammad Zaki <crynobone@gmail.com>
Co-authored-by: crynobone <crynobone@users.noreply.github.com>
Co-authored-by: jessarcher <jessarcher@users.noreply.github.com>
  • Loading branch information
5 people authored Sep 25, 2024
1 parent 8499792 commit 5f99189
Show file tree
Hide file tree
Showing 27 changed files with 354 additions and 223 deletions.
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"
}
},
"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

0 comments on commit 5f99189

Please sign in to comment.