diff --git a/README.md b/README.md index 4976efc..26afffc 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/src/Helper/OutputHelper.php b/src/Helper/OutputHelper.php index 7cf9c5c..df518c8 100644 --- a/src/Helper/OutputHelper.php +++ b/src/Helper/OutputHelper.php @@ -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; } @@ -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); } } @@ -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; } @@ -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; } diff --git a/src/IO/Interactor.php b/src/IO/Interactor.php index 37c5a78..e711097 100644 --- a/src/IO/Interactor.php +++ b/src/IO/Interactor.php @@ -37,145 +37,6 @@ * @license MIT * * @link https://github.com/adhocore/cli - * - * @method Writer bgBlack($text, $eol = false) - * @method Writer bgBlue($text, $eol = false) - * @method Writer bgCyan($text, $eol = false) - * @method Writer bgGreen($text, $eol = false) - * @method Writer bgPurple($text, $eol = false) - * @method Writer bgRed($text, $eol = false) - * @method Writer bgWhite($text, $eol = false) - * @method Writer bgYellow($text, $eol = false) - * @method Writer black($text, $eol = false) - * @method Writer blackBgBlue($text, $eol = false) - * @method Writer blackBgCyan($text, $eol = false) - * @method Writer blackBgGreen($text, $eol = false) - * @method Writer blackBgPurple($text, $eol = false) - * @method Writer blackBgRed($text, $eol = false) - * @method Writer blackBgWhite($text, $eol = false) - * @method Writer blackBgYellow($text, $eol = false) - * @method Writer blue($text, $eol = false) - * @method Writer blueBgBlack($text, $eol = false) - * @method Writer blueBgCyan($text, $eol = false) - * @method Writer blueBgGreen($text, $eol = false) - * @method Writer blueBgPurple($text, $eol = false) - * @method Writer blueBgRed($text, $eol = false) - * @method Writer blueBgWhite($text, $eol = false) - * @method Writer blueBgYellow($text, $eol = false) - * @method Writer bold($text, $eol = false) - * @method Writer boldBlack($text, $eol = false) - * @method Writer boldBlackBgBlue($text, $eol = false) - * @method Writer boldBlackBgCyan($text, $eol = false) - * @method Writer boldBlackBgGreen($text, $eol = false) - * @method Writer boldBlackBgPurple($text, $eol = false) - * @method Writer boldBlackBgRed($text, $eol = false) - * @method Writer boldBlackBgWhite($text, $eol = false) - * @method Writer boldBlackBgYellow($text, $eol = false) - * @method Writer boldBlue($text, $eol = false) - * @method Writer boldBlueBgBlack($text, $eol = false) - * @method Writer boldBlueBgCyan($text, $eol = false) - * @method Writer boldBlueBgGreen($text, $eol = false) - * @method Writer boldBlueBgPurple($text, $eol = false) - * @method Writer boldBlueBgRed($text, $eol = false) - * @method Writer boldBlueBgWhite($text, $eol = false) - * @method Writer boldBlueBgYellow($text, $eol = false) - * @method Writer boldCyan($text, $eol = false) - * @method Writer boldCyanBgBlack($text, $eol = false) - * @method Writer boldCyanBgBlue($text, $eol = false) - * @method Writer boldCyanBgGreen($text, $eol = false) - * @method Writer boldCyanBgPurple($text, $eol = false) - * @method Writer boldCyanBgRed($text, $eol = false) - * @method Writer boldCyanBgWhite($text, $eol = false) - * @method Writer boldCyanBgYellow($text, $eol = false) - * @method Writer boldGreen($text, $eol = false) - * @method Writer boldGreenBgBlack($text, $eol = false) - * @method Writer boldGreenBgBlue($text, $eol = false) - * @method Writer boldGreenBgCyan($text, $eol = false) - * @method Writer boldGreenBgPurple($text, $eol = false) - * @method Writer boldGreenBgRed($text, $eol = false) - * @method Writer boldGreenBgWhite($text, $eol = false) - * @method Writer boldGreenBgYellow($text, $eol = false) - * @method Writer boldPurple($text, $eol = false) - * @method Writer boldPurpleBgBlack($text, $eol = false) - * @method Writer boldPurpleBgBlue($text, $eol = false) - * @method Writer boldPurpleBgCyan($text, $eol = false) - * @method Writer boldPurpleBgGreen($text, $eol = false) - * @method Writer boldPurpleBgRed($text, $eol = false) - * @method Writer boldPurpleBgWhite($text, $eol = false) - * @method Writer boldPurpleBgYellow($text, $eol = false) - * @method Writer boldRed($text, $eol = false) - * @method Writer boldRedBgBlack($text, $eol = false) - * @method Writer boldRedBgBlue($text, $eol = false) - * @method Writer boldRedBgCyan($text, $eol = false) - * @method Writer boldRedBgGreen($text, $eol = false) - * @method Writer boldRedBgPurple($text, $eol = false) - * @method Writer boldRedBgWhite($text, $eol = false) - * @method Writer boldRedBgYellow($text, $eol = false) - * @method Writer boldWhite($text, $eol = false) - * @method Writer boldWhiteBgBlack($text, $eol = false) - * @method Writer boldWhiteBgBlue($text, $eol = false) - * @method Writer boldWhiteBgCyan($text, $eol = false) - * @method Writer boldWhiteBgGreen($text, $eol = false) - * @method Writer boldWhiteBgPurple($text, $eol = false) - * @method Writer boldWhiteBgRed($text, $eol = false) - * @method Writer boldWhiteBgYellow($text, $eol = false) - * @method Writer boldYellow($text, $eol = false) - * @method Writer boldYellowBgBlack($text, $eol = false) - * @method Writer boldYellowBgBlue($text, $eol = false) - * @method Writer boldYellowBgCyan($text, $eol = false) - * @method Writer boldYellowBgGreen($text, $eol = false) - * @method Writer boldYellowBgPurple($text, $eol = false) - * @method Writer boldYellowBgRed($text, $eol = false) - * @method Writer boldYellowBgWhite($text, $eol = false) - * @method Writer colors($text) - * @method Writer comment($text, $eol = false) - * @method Writer cyan($text, $eol = false) - * @method Writer cyanBgBlack($text, $eol = false) - * @method Writer cyanBgBlue($text, $eol = false) - * @method Writer cyanBgGreen($text, $eol = false) - * @method Writer cyanBgPurple($text, $eol = false) - * @method Writer cyanBgRed($text, $eol = false) - * @method Writer cyanBgWhite($text, $eol = false) - * @method Writer cyanBgYellow($text, $eol = false) - * @method Writer eol(int $n = 1) - * @method Writer error($text, $eol = false) - * @method Writer green($text, $eol = false) - * @method Writer greenBgBlack($text, $eol = false) - * @method Writer greenBgBlue($text, $eol = false) - * @method Writer greenBgCyan($text, $eol = false) - * @method Writer greenBgPurple($text, $eol = false) - * @method Writer greenBgRed($text, $eol = false) - * @method Writer greenBgWhite($text, $eol = false) - * @method Writer greenBgYellow($text, $eol = false) - * @method Writer info($text, $eol = false) - * @method Writer ok($text, $eol = false) - * @method Writer purple($text, $eol = false) - * @method Writer purpleBgBlack($text, $eol = false) - * @method Writer purpleBgBlue($text, $eol = false) - * @method Writer purpleBgCyan($text, $eol = false) - * @method Writer purpleBgGreen($text, $eol = false) - * @method Writer purpleBgRed($text, $eol = false) - * @method Writer purpleBgWhite($text, $eol = false) - * @method Writer purpleBgYellow($text, $eol = false) - * @method Writer red($text, $eol = false) - * @method Writer redBgBlack($text, $eol = false) - * @method Writer redBgBlue($text, $eol = false) - * @method Writer redBgCyan($text, $eol = false) - * @method Writer redBgGreen($text, $eol = false) - * @method Writer redBgPurple($text, $eol = false) - * @method Writer redBgWhite($text, $eol = false) - * @method Writer redBgYellow($text, $eol = false) - * @method Writer table(array $rows, array $styles = []) - * @method Writer warn($text, $eol = false) - * @method Writer white($text, $eol = false) - * @method Writer yellow($text, $eol = false) - * @method Writer yellowBgBlack($text, $eol = false) - * @method Writer yellowBgBlue($text, $eol = false) - * @method Writer yellowBgCyan($text, $eol = false) - * @method Writer yellowBgGreen($text, $eol = false) - * @method Writer yellowBgPurple($text, $eol = false) - * @method Writer yellowBgRed($text, $eol = false) - * @method Writer yellowBgWhite($text, $eol = false) */ class Interactor { @@ -241,7 +102,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); @@ -262,7 +123,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); @@ -300,7 +161,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); @@ -310,7 +171,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); } @@ -351,12 +212,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); } @@ -369,7 +230,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"; } diff --git a/src/Input/Command.php b/src/Input/Command.php index 5b999ee..49dbfb4 100644 --- a/src/Input/Command.php +++ b/src/Input/Command.php @@ -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()) @@ -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); } diff --git a/src/Output/Color.php b/src/Output/Color.php index d2be69a..d9187bb 100644 --- a/src/Output/Color.php +++ b/src/Output/Color.php @@ -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. @@ -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; } @@ -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))) { @@ -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]; } diff --git a/tests/Output/ColorTest.php b/tests/Output/ColorTest.php index 607beda..9cfe381 100644 --- a/tests/Output/ColorTest.php +++ b/tests/Output/ColorTest.php @@ -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()