Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,38 @@ Ahc\Cli\Output\Color::style('mystyle', [
echo $color->mystyle('My text');
```

#### Built-in styles

There are a number of pre-defined built-in styles that allows you granular customization to different output conditions such as help and prompts:

- answer
- choice
- comment
- error
- help_category
- help_description
- help_example
- help_footer
- help_group
- help_header
- help_item
- help_summary
- help_text
- info
- ok
- question
- version
- warn

Overriding a built-in style works the same way as defining a new style:

```php
Ahc\Cli\Output\Color::style('error', [
'fg' => Ahc\Cli\Output\Color::RED,
'bold' => 1,
]);
```

### Cursor

Move cursor around, erase line up or down, clear screen.
Expand Down
18 changes: 9 additions & 9 deletions src/Helper/OutputHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,13 @@ public function showCommandsHelp(array $commands, string $header = '', string $f
protected function showHelp(string $for, array $items, string $header = '', string $footer = ''): void
{
if ($header) {
$this->writer->bold($header, true);
$this->writer->help_header($header, true);
}

$this->writer->eol()->boldGreen($for . ':', true);
$this->writer->eol()->help_category($for . ':', true);

if (empty($items)) {
$this->writer->bold(' (n/a)', true);
$this->writer->help_text(' (n/a)', true);

return;
}
Expand All @@ -200,17 +200,17 @@ protected function showHelp(string $for, array $items, string $header = '', stri
foreach ($this->sortItems($items, $padLen, $for) as $item) {
$name = $this->getName($item);
if ($for === 'Commands' && $lastGroup !== $group = $item->group()) {
$this->writer->boldYellow($group ?: '*', true);
$this->writer->help_group($group ?: '*', true);
$lastGroup = $group;
}
$desc = str_replace(["\r\n", "\n"], str_pad("\n", $padLen + $space + 3), $item->desc($withDefault));

$this->writer->bold(' ' . str_pad($name, $padLen + $space));
$this->writer->comment($desc, true);
$this->writer->help_item(' ' . str_pad($name, $padLen + $space));
$this->writer->help_description($desc, true);
}

if ($footer) {
$this->writer->eol()->yellow($footer, true);
$this->writer->eol()->help_footer($footer, true);
}
}

Expand All @@ -224,7 +224,7 @@ public function showUsage(string $usage): self
$usage = str_replace('$0', $_SERVER['argv'][0] ?? '[cmd]', $usage);

if (!str_contains($usage, ' ## ')) {
$this->writer->eol()->boldGreen('Usage Examples:', true)->colors($usage)->eol();
$this->writer->eol()->help_category('Usage Examples:', true)->colors($usage)->eol();

return $this;
}
Expand All @@ -241,7 +241,7 @@ public function showUsage(string $usage): self
return str_pad('# ', $maxlen - array_shift($lines), ' ', STR_PAD_LEFT);
}, $usage);

$this->writer->eol()->boldGreen('Usage Examples:', true)->colors($usage)->eol();
$this->writer->eol()->help_category('Usage Examples:', true)->colors($usage)->eol();

return $this;
}
Expand Down
14 changes: 7 additions & 7 deletions src/IO/Interactor.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ public function confirm(string $text, string $default = 'y'): bool
*/
public function choice(string $text, array $choices, $default = null, bool $case = false): mixed
{
$this->writer->yellow($text);
$this->writer->question($text);

$this->listOptions($choices, $default, false);

Expand All @@ -262,7 +262,7 @@ public function choice(string $text, array $choices, $default = null, bool $case
*/
public function choices(string $text, array $choices, $default = null, bool $case = false): mixed
{
$this->writer->yellow($text);
$this->writer->question($text);

$this->listOptions($choices, $default, true);

Expand Down Expand Up @@ -300,7 +300,7 @@ public function prompt(string $text, $default = null, ?callable $fn = null, int
$hidden = func_get_args()[4] ?? false;
$readFn = ['read', 'readHidden'][(int) $hidden];

$this->writer->yellow($text)->comment(null !== $default ? " [$default]: " : ': ');
$this->writer->question($text)->answer(null !== $default ? " [$default]: " : ': ');

try {
$input = $this->reader->{$readFn}($default, $fn);
Expand All @@ -310,7 +310,7 @@ public function prompt(string $text, $default = null, ?callable $fn = null, int
}

if ($retry > 0 && $input === '') {
$this->writer->bgRed($error, true);
$this->writer->error($error, true);

return $this->prompt($text, $default, $fn, $retry - 1, $hidden);
}
Expand Down Expand Up @@ -351,12 +351,12 @@ protected function listOptions(array $choices, $default = null, bool $multi = fa
$maxLen = max(array_map('strlen', array_keys($choices)));

foreach ($choices as $choice => $desc) {
$this->writer->eol()->cyan(str_pad(" [$choice]", $maxLen + 6))->comment($desc);
$this->writer->eol()->choice(str_pad(" [$choice]", $maxLen + 6))->answer($desc);
}

$label = $multi ? 'Choices (comma separated)' : 'Choice';

$this->writer->eol()->yellow($label);
$this->writer->eol()->question($label);

return $this->promptOptions(array_keys($choices), $default);
}
Expand All @@ -369,7 +369,7 @@ protected function promptOptions(array $choices, mixed $default): self
$options = '';

foreach ($choices as $choice) {
$style = in_array($choice, (array) $default) ? 'boldCyan' : 'cyan';
$style = in_array($choice, (array) $default) ? 'boldChoice' : 'choice';
$options .= "/<$style>$choice</end>";
}

Expand Down
8 changes: 4 additions & 4 deletions src/Input/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -298,9 +298,9 @@ public function showHelp(): mixed
$io = $this->io();
$helper = new OutputHelper($io->writer());

$io->bold("Command {$this->_name}, version {$this->_version}", true)->eol();
$io->comment($this->_desc, true)->eol();
$io->bold('Usage: ')->yellow("{$this->_name} [OPTIONS...] [ARGUMENTS...]", true);
$io->help_header("Command {$this->_name}, version {$this->_version}", true)->eol();
$io->help_summary($this->_desc, true)->eol();
$io->help_text('Usage: ')->help_example("{$this->_name} [OPTIONS...] [ARGUMENTS...]", true);

$helper
->showArgumentsHelp($this->allArguments())
Expand All @@ -318,7 +318,7 @@ public function showHelp(): mixed
*/
public function showVersion(): mixed
{
$this->writer()->bold($this->_version, true);
$this->writer()->version($this->_version, true);

return $this->emit('_exit', 0);
}
Expand Down
71 changes: 25 additions & 46 deletions src/Output/Color.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,47 +53,26 @@ class Color
protected string $format = "\033[:mod:;:fg:;:bg:m:txt:\033[0m";

/** @var array Custom styles */
protected static array $styles = [];

/**
* Returns a line formatted as comment.
*/
public function comment(string $text, array $style = []): string
{
return $this->line($text, ['mod' => 2] + $style);
}

/**
* Returns a line formatted as comment.
*/
public function error(string $text, array $style = []): string
{
return $this->line($text, ['fg' => static::RED] + $style);
}

/**
* Returns a line formatted as ok msg.
*/
public function ok(string $text, array $style = []): string
{
return $this->line($text, ['fg' => static::GREEN] + $style);
}

/**
* Returns a line formatted as warning.
*/
public function warn(string $text, array $style = []): string
{
return $this->line($text, ['fg' => static::YELLOW] + $style);
}

/**
* Returns a line formatted as info.
*/
public function info(string $text, array $style = []): string
{
return $this->line($text, ['fg' => static::BLUE] + $style);
}
protected static array $styles = [
'answer' => ['fg' => 37, 'mod' => 2],
'choice' => ['fg' => 36],
'comment' => ['fg' => 37, 'mod' => 2],
'error' => ['fg' => 31],
'help_category' => ['fg' => 32, 'mod' => 1],
'help_description' => ['fg' => 37, 'mod' => 2],
'help_example' => ['fg' => 33],
'help_footer' => ['fg' => 33],
'help_group' => ['fg' => 33, 'mod' => 1],
'help_header' => ['fg' => 37, 'mod' => 1],
'help_item' => ['fg' => 37, 'mod' => 1],
'help_summary' => ['fg' => 37, 'mod' => 2],
'help_text' => ['fg' => 37, 'mod' => 1],
'info' => ['fg' => 34],
'ok' => ['fg' => 32],
'question' => ['fg' => 33],
'version' => ['fg' => 37, 'mod' => 1],
'warn' => ['fg' => 33],
];

/**
* Returns a formatted/colored line.
Expand Down Expand Up @@ -157,10 +136,6 @@ public static function style(string $name, array $style): void
throw new InvalidArgumentException('Trying to set empty or invalid style');
}

if (isset(static::$styles[$name]) || method_exists(static::class, $name)) {
throw new InvalidArgumentException('Trying to define existing style');
}

static::$styles[$name] = $style;
}

Expand All @@ -181,7 +156,7 @@ public function __call(string $name, array $arguments): string
[$name, $text, $style] = $this->parseCall($name, $arguments);

if (isset(static::$styles[$name])) {
return $this->line($text, $style + static::$styles[$name]);
return $this->line($text, static::$styles[$name] + $style);
}

if (defined($color = static::class . '::' . strtoupper($name))) {
Expand Down Expand Up @@ -212,6 +187,10 @@ protected function parseCall(string $name, array $arguments): array
}
}

if (isset(static::$styles[strtolower($name)])) {
$name = strtolower($name);
}

if (!preg_match_all('/([b|B|f|F]g)?([A-Z][a-z]+)([^A-Z])?/', $name, $matches)) {
return [lcfirst($name) ?: 'line', $text, $style];
}
Expand Down
11 changes: 4 additions & 7 deletions tests/Output/ColorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,11 @@ public function test_comment()

public function test_custom_style()
{
Color::style('alert', ['bg' => Color::YELLOW, 'fg' => Color::RED, 'bold' => 1]);
Color::style('alert', ['bg' => Color::YELLOW, 'fg' => Color::RED]);

$this->assertSame("\033[1;31;43malert\033[0m", (new Color)->alert('alert'));

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Trying to define existing style');

Color::style('alert', ['bg' => Color::BLACK]);
$this->assertSame("\033[0;31;43malert\033[0m", (new Color)->alert('alert'));
$this->assertSame("\033[1;31;43malert\033[0m", (new Color)->boldAlert('alert'));
$this->assertSame("\033[1;31;43malert\033[0m", (new Color)->alertBold('alert'));
}

public function test_invalid_custom_style()
Expand Down
Loading