Skip to content

Commit

Permalink
Merge pull request #82 from adhocore/81-progress-bar
Browse files Browse the repository at this point in the history
Add progress bar
  • Loading branch information
adhocore authored Mar 30, 2023
2 parents 2e46d00 + 48d5821 commit 9e60ddf
Show file tree
Hide file tree
Showing 10 changed files with 610 additions and 27 deletions.
59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,65 @@ echo $cursor->up(1)
. $cursor->moveTo(5, 8); // x, y
```

### Progress Bar

Easily add a progress bar to your output:

```php
$progress = new Ahc\Cli\Output\ProgressBar(100);
for ($i = 0; $i <= 100; $i++) {
$progress->current($i);

// Simulate something happening
usleep(80000);
}
```

You can also manually advance the bar:

```php
$progress = new Ahc\Cli\Output\ProgressBar(100);

// Do something

$progress->advance(); // Adds 1 to the current progress

// Do something

$progress->advance(10); // Adds 10 to the current progress

// Do something

$progress->advance(5, 'Still going.'); // Adds 5, displays a label
```

You can override the progress bar options to customize it to your liking:

```php
$progress = new Ahc\Cli\Output\ProgressBar(100);
$progress->option('pointer', '>>');
$progress->option('loader', '▩');

// You can set the progress fluently
$progress->option('pointer', '>>')->option('loader', '▩');

// You can also use an associative array to set many options in one time
$progress->option([
'pointer' => '>>',
'loader' => '▩'
]);

// Available options
+------------+------------------------------+---------------+
| Option | Description | Default value |
+------------+------------------------------+---------------+
| pointer | The progress bar head symbol | > |
| loader | The loader symbol | = |
| color | The color of progress bar | white |
| labelColor | The text color of the label | white |
+------------+------------------------------+---------------+
```

### Writer

Write anything in style.
Expand Down
4 changes: 3 additions & 1 deletion src/Helper/OutputHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use Ahc\Cli\Input\Parameter;
use Ahc\Cli\Output\Writer;
use Throwable;

use function array_map;
use function array_shift;
use function asort;
Expand All @@ -44,6 +45,7 @@
use function trim;
use function uasort;
use function var_export;

use const STR_PAD_LEFT;

/**
Expand Down Expand Up @@ -102,7 +104,7 @@ public function printTrace(Throwable $e): void
$this->writer->colors($traceStr);
}

protected function stringifyArgs(array $args): string
public function stringifyArgs(array $args): string
{
$holder = [];

Expand Down
34 changes: 8 additions & 26 deletions src/Helper/Shell.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace Ahc\Cli\Helper;

use Ahc\Cli\Exception\RuntimeException;

use function fclose;
use function function_exists;
use function fwrite;
Expand All @@ -23,7 +24,6 @@
use function proc_terminate;
use function stream_get_contents;
use function stream_set_blocking;
use const DIRECTORY_SEPARATOR;

/**
* A thin proc_open wrapper to execute shell commands.
Expand Down Expand Up @@ -109,7 +109,7 @@ public function __construct(protected string $command, protected ?string $input

protected function prepareDescriptors(?array $stdin = null, ?array $stdout = null, ?array $stderr = null): array
{
$win = $this->isWindows();
$win = Terminal::isWindows();
if (!$stdin) {
$stdin = $win ? self::DEFAULT_STDIN_WIN : self::DEFAULT_STDIN_NIX;
}
Expand All @@ -127,16 +127,6 @@ protected function prepareDescriptors(?array $stdin = null, ?array $stdout = nul
];
}

protected function isWindows(): bool
{
// If PHP_OS is defined, use it - More reliable:
if (defined('PHP_OS')) {
return 'WIN' === strtoupper(substr(PHP_OS, 0, 3)); // May be 'WINNT' or 'WIN32' or 'Windows'
}

return '\\' === DIRECTORY_SEPARATOR; // Fallback - Less reliable (Windows 7...)
}

protected function setInput(): void
{
//Make sure the pipe is a stream resource before writing to it to avoid a warning
Expand Down Expand Up @@ -263,12 +253,9 @@ public function execute(bool $async = false, ?array $stdin = null, ?array $stdou

private function setOutputStreamNonBlocking(): bool
{
// Make sure the pipe is a stream resource before setting it to non-blocking to avoid a warning
if (!is_resource($this->pipes[self::STDOUT_DESCRIPTOR_KEY])) {
return false;
}
$isRes = is_resource($this->pipes[self::STDOUT_DESCRIPTOR_KEY]);

return stream_set_blocking($this->pipes[self::STDOUT_DESCRIPTOR_KEY], false);
return $isRes ? stream_set_blocking($this->pipes[self::STDOUT_DESCRIPTOR_KEY], false) : false;
}

public function getState(): string
Expand All @@ -278,21 +265,16 @@ public function getState(): string

public function getOutput(): string
{
// Make sure the pipe is a stream resource before reading it to avoid a warning
if (!is_resource($this->pipes[self::STDOUT_DESCRIPTOR_KEY])) {
return '';
}
$isRes = is_resource($this->pipes[self::STDOUT_DESCRIPTOR_KEY]);

return stream_get_contents($this->pipes[self::STDOUT_DESCRIPTOR_KEY]);
return $isRes ? stream_get_contents($this->pipes[self::STDOUT_DESCRIPTOR_KEY]) : '';
}

public function getErrorOutput(): string
{
if (!is_resource($this->pipes[self::STDERR_DESCRIPTOR_KEY])) {
return '';
}
$isRes = is_resource($this->pipes[self::STDERR_DESCRIPTOR_KEY]);

return stream_get_contents($this->pipes[self::STDERR_DESCRIPTOR_KEY]);
return $isRes ? stream_get_contents($this->pipes[self::STDERR_DESCRIPTOR_KEY]) : '';
}

public function getExitCode(): ?int
Expand Down
99 changes: 99 additions & 0 deletions src/Helper/Terminal.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

/*
* This file is part of the PHP-CLI package.
*
* (c) Jitendra Adhikari <[email protected]>
* <https://github.com/adhocore>
*
* Licensed under MIT license.
*/

namespace Ahc\Cli\Helper;

use function array_map;
use function array_search;
use function exec;
use function implode;
use function is_array;
use function preg_match_all;

/**
* A thin to find some information about the current terminal (width, height, ect...).
*
* @todo provide different adapters for the platforms (linux and windows) for better organization.
*
* @author Dimitri Sitchet Tomkeu <[email protected]>
* @license MIT
*
* @link https://github.com/adhocore/cli
*/
class Terminal
{
public static function isWindows(): bool
{
// If PHP_OS is defined, use it - More reliable:
if (defined('PHP_OS')) {
return str_starts_with(strtoupper(PHP_OS), 'WIN'); // May be 'WINNT' or 'WIN32' or 'Windows'
}

// @codeCoverageIgnoreStart
return '\\' === DIRECTORY_SEPARATOR; // Fallback - Less reliable (Windows 7...)
// @codeCoverageIgnoreEnd
}

/**
* Get the width of the terminal.
*/
public function width(): ?int
{
return $this->getDimension('width');
}

/**
* Get the height of the terminal.
*/
public function height(): ?int
{
return $this->getDimension('height');
}

/**
* Get specified terminal dimension.
*/
protected function getDimension(string $key): ?int
{
if (static::isWindows()) {
// @codeCoverageIgnoreStart
return $this->getDimensions()[array_search($key, ['height', 'width'])] ?? null;
// @codeCoverageIgnoreEnd
}

$type = ['width' => 'cols', 'height' => 'lines'][$key];
$result = exec("tput {$type} 2>/dev/null");

return $result === false ? null : (int) $result;
}

/**
* Get information about the dimensions of the Windows terminal.
*
* @codeCoverageIgnore
*
* @return int[]
*/
protected function getDimensions(): array
{
exec('mode CON', $output);

if (!is_array($output)) {
return [];
}

$output = implode("\n", $output);

preg_match_all('/.*:\s*(\d+)/', $output, $matches);

return array_map('intval', $matches[1] ?? []);
}
}
10 changes: 10 additions & 0 deletions src/Input/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@
use Ahc\Cli\Helper\InflectsString;
use Ahc\Cli\Helper\OutputHelper;
use Ahc\Cli\IO\Interactor;
use Ahc\Cli\Output\ProgressBar;
use Ahc\Cli\Output\Writer;
use Closure;

use function array_filter;
use function array_keys;
use function end;
Expand Down Expand Up @@ -382,4 +384,12 @@ protected function io(): Interactor
{
return $this->_app ? $this->_app->io() : new Interactor;
}

/**
* Get ProgressBar instance.
*/
protected function progress(int $total = null): ProgressBar
{
return new ProgressBar($total, $this->writer());
}
}
Loading

0 comments on commit 9e60ddf

Please sign in to comment.