Skip to content

Commit

Permalink
Cleaner way of customizing spinner frames and progress bars
Browse files Browse the repository at this point in the history
  • Loading branch information
freost committed Nov 2, 2024
1 parent 19ce882 commit 15ec057
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 14 deletions.
9 changes: 4 additions & 5 deletions src/mako/cli/output/components/Spinner.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
use function posix_getpid;
use function posix_getppid;
use function posix_kill;
use function sprintf;
use function usleep;

/**
Expand Down Expand Up @@ -51,7 +50,7 @@ protected function canFork(): bool
/**
* Draws the spinner.
*/
protected function spinner(string $message, string $template): void
protected function spinner(string $message): void
{
$i = 0;

Expand All @@ -62,7 +61,7 @@ protected function spinner(string $message, string $template): void
$timeBetweenRedraw = $this->frames->getTimeBetweenRedraw();

while (true) {
$this->output->write("\r" . sprintf($template, $frames[$i++ % $frameCount]) . " {$message}");
$this->output->write("\r" . $frames[$i++ % $frameCount] . " {$message}");

if (posix_kill(posix_getpid(), 0) === false) {
break;
Expand All @@ -79,7 +78,7 @@ protected function spinner(string $message, string $template): void
/**
* Draws the spinner.
*/
public function spin(string $message, callable $callback, string $template = '%s'): mixed
public function spin(string $message, callable $callback): mixed
{
$result = null;

Expand Down Expand Up @@ -110,7 +109,7 @@ public function spin(string $message, callable $callback, string $template = '%s
else {
// We're in the child process so we'll display the spinner

$this->spinner($message, $template);
$this->spinner($message);
}

$this->output->getCursor()->restore();
Expand Down
15 changes: 13 additions & 2 deletions src/mako/cli/output/components/progress/ProgressBar.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

namespace mako\cli\output\components\progress;

use function sprintf;

/**
* Progress bar.
*/
Expand All @@ -22,19 +24,28 @@ class ProgressBar
*/
protected const string FILLED = '';

/**
* Constructor.
*/
public function __construct(
protected string $emptyTemplate = '%s',
protected string $filledTemplate = '%s'
) {
}

/**
* Returns the empty progress bar character.
*/
public function getEmpty(): string
{
return static::EMPTY;
return sprintf($this->emptyTemplate, static::EMPTY);
}

/**
* Returns the filled progress bar character.
*/
public function getFilled(): string
{
return static::FILLED;
return sprintf($this->filledTemplate, static::FILLED);
}
}
13 changes: 12 additions & 1 deletion src/mako/cli/output/components/spinner/Frames.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

namespace mako\cli\output\components\spinner;

use function array_map;
use function sprintf;

/**
* Frames.
*/
Expand All @@ -22,12 +25,20 @@ class Frames
*/
protected const array FRAMES = ['', '', '', '', '', '', '', '', '', ''];

/**
* Constructor.
*/
public function __construct(
protected string $template = '%s'
) {
}

/**
* Returns the spinner frames.
*/
public function getFrames(): array
{
return static::FRAMES;
return array_map(fn ($frame) => sprintf($this->template, $frame), static::FRAMES);
}

/**
Expand Down
15 changes: 9 additions & 6 deletions src/mako/reactor/traits/CommandHelperTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use mako\cli\output\components\Countdown;
use mako\cli\output\components\OrderedList;
use mako\cli\output\components\Progress;
use mako\cli\output\components\progress\ProgressBar;
use mako\cli\output\components\ProgressIterator;
use mako\cli\output\components\Spinner;
use mako\cli\output\components\spinner\Frames;
Expand Down Expand Up @@ -115,14 +116,15 @@ protected function progressBar(int $items, float $minTimeBetweenRedraw = 0.1, ?s
/**
* Draws a progress bar and returns a progress instance.
*/
protected function progress(int $itemCount, string $description = '', int $width = 50, float $minTimeBetweenRedraw = 0.1): Progress
protected function progress(int $itemCount, string $description = '', int $width = 50, float $minTimeBetweenRedraw = 0.1, ProgressBar $progressBar = new ProgressBar): Progress
{
$progressBar = new Progress(
$this->output,
$itemCount,
$description,
$width,
$minTimeBetweenRedraw
$minTimeBetweenRedraw,
$progressBar
);

$progressBar->draw();
Expand All @@ -133,23 +135,24 @@ protected function progress(int $itemCount, string $description = '', int $width
/**
* Returns a progress iterator instance.
*/
protected function progressIterator(array|(Countable&Traversable) $items, string $description = '', int $width = 50, float $minTimeBetweenRedraw = 0.1): ProgressIterator
protected function progressIterator(array|(Countable&Traversable) $items, string $description = '', int $width = 50, float $minTimeBetweenRedraw = 0.1, ProgressBar $progressBar = new ProgressBar): ProgressIterator
{
return new ProgressIterator(
$this->output,
$items,
$description,
$width,
$minTimeBetweenRedraw
$minTimeBetweenRedraw,
$progressBar
);
}

/**
* Draws a spinner while executing the callback.
*/
protected function spinner(string $message, callable $callback, string $template = '%s', Frames $frames = new Frames): void
protected function spinner(string $message, callable $callback, Frames $frames = new Frames): void
{
(new Spinner($this->output, $frames))->spin($message, $callback, $template);
(new Spinner($this->output, $frames))->spin($message, $callback);
}

/**
Expand Down
40 changes: 40 additions & 0 deletions tests/unit/cli/output/components/progress/ProgressBarTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

/**
* @copyright Frederic G. Østby
* @license http://www.makoframework.com/license
*/

namespace mako\tests\unit\cli\output\components\progress;

use mako\cli\output\components\progress\ProgressBar;
use mako\tests\TestCase;
use PHPUnit\Framework\Attributes\Group;

#[Group('unit')]
class ProgressBarTest extends TestCase
{
/**
*
*/
public function testWithDefaultTemplate(): void
{
$progressBar = new ProgressBar;

$this->assertSame('', $progressBar->getEmpty());

$this->assertSame('', $progressBar->getFilled());
}

/**
*
*/
public function testWithCustomTemplate(): void
{
$progressBar = new ProgressBar('x%sx', 'y%sy');

$this->assertSame('x─x', $progressBar->getEmpty());

$this->assertSame('y█y', $progressBar->getFilled());
}
}
36 changes: 36 additions & 0 deletions tests/unit/cli/output/components/spinner/FramesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

/**
* @copyright Frederic G. Østby
* @license http://www.makoframework.com/license
*/

namespace mako\tests\unit\cli\output\components\progress;

use mako\cli\output\components\spinner\Frames;
use mako\tests\TestCase;
use PHPUnit\Framework\Attributes\Group;

#[Group('unit')]
class FramesTest extends TestCase
{
/**
*
*/
public function testWithDefaultTemplate(): void
{
$frames = new Frames;

$this->assertSame(['', '', '', '', '', '', '', '', '', ''], $frames->getFrames());
}

/**
*
*/
public function testWithCustomTemplate(): void
{
$frames = new Frames('x%sx');

$this->assertSame(['x⠋x', 'x⠙x', 'x⠹x', 'x⠸x', 'x⠼x', 'x⠴x', 'x⠦x', 'x⠧x', 'x⠇x', 'x⠏x'], $frames->getFrames());
}
}

0 comments on commit 15ec057

Please sign in to comment.