Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
2c6f07d
Add logo support for commands
kodie Nov 25, 2024
6a7f7d6
Update readme copy for command logo example
kodie Nov 26, 2024
b50f502
Make logo property logo for command to avoid any conflicts
kodie Nov 26, 2024
04cfefd
Fix logo checking and writing
kodie Nov 26, 2024
3843419
Use the app's logo in a command's help screen if its the default command
kodie Nov 26, 2024
79e459a
Make all written text built-in styles so that their styles can be cus…
kodie Nov 25, 2024
ef091d0
Put back Interactor Writer method definitions
kodie Nov 25, 2024
7f7466f
Put back eol and table method definitions for Interactor
kodie Nov 25, 2024
a4ebc07
Put this blank line back? I'm not sure how that happened
kodie Nov 25, 2024
229d58c
Remove un-needed space
kodie Nov 25, 2024
5f7fb39
Hopefully fix issue with test
kodie Nov 25, 2024
4463acb
Put factory color functions back
kodie Nov 26, 2024
1365912
Prevent users from making factory functions invisible
kodie Nov 26, 2024
44c1bc1
Shorten a couple lines
kodie Nov 26, 2024
0453b1b
Update invisible_built_in_style expected exception message
kodie Nov 26, 2024
5c2681e
Add new method definitions for Writer and Interactor classes
kodie Nov 26, 2024
929aa8c
Make logo a built-in style
kodie Nov 26, 2024
5017764
Make help_description into help_description_even/odd and make help_it…
kodie Nov 26, 2024
47ef57b
Fix indentation
kodie Nov 26, 2024
07a58fa
Add support for custom help screens
kodie Nov 26, 2024
7737fe6
Fix identation
kodie Nov 26, 2024
1f0832a
Hopefully fix issues with tests
kodie Nov 26, 2024
be41352
Tests don't like variables starting with underscores in the application
kodie Nov 26, 2024
3321966
Add example to readme showing how you can get colors working in a cus…
kodie Nov 26, 2024
4b3084e
Just pass the colorizer as the help parameter in the custom help read…
kodie Nov 26, 2024
e46c51b
Rename custom_help to help
kodie Nov 26, 2024
dc2cbe8
Add support for 256 colors
kodie Nov 25, 2024
4cd771f
Add documentation about default command functionality
kodie Nov 25, 2024
0d5deae
Use 256 colors in test_custom_style test
kodie Nov 25, 2024
0a5c8ad
Add Color::bg256 and Color::fg256
kodie Nov 26, 2024
0bceee7
Add periods to bg256 and fg256 descriptions
kodie Nov 26, 2024
8bd27e1
Add mising A to fg256 example in readme
kodie Nov 26, 2024
cbb5476
Add return types for bg256 and fg256 functions
kodie Nov 26, 2024
50bfd67
Make bg256 and fg256 functions static
kodie Nov 26, 2024
a5358f4
Use PHP comments in Default command example in readme instead of Bash…
kodie Nov 26, 2024
0d62301
Make all written text built-in styles so that their styles can be cus…
kodie Nov 25, 2024
b53faa7
Put back eol and table method definitions for Interactor
kodie Nov 25, 2024
00a7636
Put this blank line back? I'm not sure how that happened
kodie Nov 25, 2024
765b71d
Remove un-needed space
kodie Nov 25, 2024
00cefbd
Hopefully fix issue with test
kodie Nov 25, 2024
df68b6c
Prevent users from making factory functions invisible
kodie Nov 26, 2024
641f690
Shorten a couple lines
kodie Nov 26, 2024
d02e462
Add new method definitions for Writer and Interactor classes
kodie Nov 26, 2024
559a457
Make help_description into help_description_even/odd and make help_it…
kodie Nov 26, 2024
e051346
Add support for custom help screens
kodie Nov 26, 2024
f6fe5bc
Fix identation
kodie Nov 26, 2024
7988eb7
Add example to readme showing how you can get colors working in a cus…
kodie Nov 26, 2024
a64b36c
Add logo support for commands
kodie Nov 25, 2024
7452e46
Make logo property logo for command to avoid any conflicts
kodie Nov 26, 2024
602d975
Fix logo checking and writing
kodie Nov 26, 2024
757349f
Remove duplicate test_custom_help that happened during rebase somehow
kodie Nov 26, 2024
cbec8dc
Return this from command logo function - got changed during rebase so…
kodie Nov 26, 2024
32bcfdc
Remove merge conflict indicators from Interactor that happened during…
kodie Nov 26, 2024
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
62 changes: 60 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,18 +170,23 @@ class InitCommand extends Ahc\Cli\Input\Command
{
parent::__construct('init', 'Init something');

$help = '<cyan>Custom help screen</end>';
$writer = new Ahc\Cli\Output\Writer();

$this
->argument('<arrg>', 'The Arrg')
->argument('[arg2]', 'The Arg2')
->option('-a --apple', 'The Apple')
->option('-b --ball', 'The ball')
->help($writer->colorizer()->colors($help))
// Usage examples:
->usage(
// append details or explanation of given example with ` ## ` so they will be uniformly aligned when shown
'<bold> init</end> <comment>--apple applet --ball ballon <arggg></end> ## details 1<eol/>' .
// $0 will be interpolated to actual command name
'<bold> $0</end> <comment>-a applet -b ballon <arggg> [arg2]</end> ## details 2<eol/>'
);
)
->logo('Ascii art logo of your command');
}

// This method is auto called before `self::execute()` and receives `Interactor $io` instance
Expand Down Expand Up @@ -243,6 +248,9 @@ $app->add(new OtherCommand, 'o');
// Set logo
$app->logo('Ascii art logo of your app');

// Custom help screen
$app->help('Custom help screen (if omitted one will be generated)');

$app->handle($_SERVER['argv']); // if argv[1] is `i` or `init` it executes InitCommand
```

Expand All @@ -267,6 +275,21 @@ $app->add((new ConfigListCommand)->inGroup('Config'));
...
```

#### Default command

By default, running your CLI app without any arguments will show the help screen. However you can set the default action to run one of your commands either by setting the third parameter of the `add` function to `true` or by using the `defaultCommand` function.

```php
$app->add(new InitCommand, 'i', true);

// Alternatively
$app->command('init', 'Init something', 'i');
$app->defaultCommand('init');

// Retrieve the name of the default command
$default_command = $app->getDefaultCommand();
```

#### Exception handler

Set a custom exception handler as callback. The callback receives exception & exit code. The callback may rethrow exception or may exit the program or just log exception and do nothing else.
Expand Down Expand Up @@ -443,13 +466,48 @@ echo $color->ok('This is ok msg');
```php
Ahc\Cli\Output\Color::style('mystyle', [
'bg' => Ahc\Cli\Output\Color::CYAN,
'fg' => Ahc\Cli\Output\Color::WHITE,
'fg' => Ahc\Cli\Output\Color::fg256(57), // 256 colors can be used as well
'bold' => 1, // You can experiment with 0, 1, 2, 3 ... as well
]);

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_even
- help_description_odd
- help_example
- help_footer
- help_group
- help_header
- help_item_even
- help_item_odd
- help_summary
- help_text
- info
- logo
- 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
43 changes: 40 additions & 3 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class Application
/** @var string Ascii art logo */
protected string $logo = '';

/** @var string Custom help screen */
protected string $help = '';

/** @var string Name of default command */
protected string $default = '__default__';

/** @var null|Interactor */
Expand Down Expand Up @@ -344,16 +348,49 @@ protected function aliasesFor(Command $command): array
}

/**
* Show help of all commands.
* Sets or gets the custom help screen contents.
*
* @param string|null $help
*
* @return string|self
*/
public function help(?string $help = null): mixed
{
if (func_num_args() === 0) {
return $this->help;
}

$this->help = $help;

return $this;
}

/**
* Show custom help screen if one is set, otherwise shows the default one.
*/
public function showHelp(): mixed
{
if ($help = $this->help()) {
$writer = $this->io()->writer();
$writer->write($help, true);

return ($this->onExit)();
}

return $this->showDefaultHelp();
}

/**
* Shows command help then aborts.
*/
public function showDefaultHelp(): mixed
{
$writer = $this->io()->writer();
$header = "{$this->name}, version {$this->version}";
$footer = 'Run `<command> --help` for specific help';

if ($this->logo) {
$writer->write($this->logo, true);
if ($logo = $this->logo()) {
$writer->logo($logo, true);
}

$this->outputHelper()->showCommandsHelp($this->commands(), $header, $footer);
Expand Down
25 changes: 15 additions & 10 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 @@ -197,20 +197,25 @@ protected function showHelp(string $for, array $items, string $header = '', stri
$group = $lastGroup = null;

$withDefault = $for === 'Options' || $for === 'Arguments';
foreach ($this->sortItems($items, $padLen, $for) as $item) {
foreach (array_values($this->sortItems($items, $padLen, $for)) as $idx => $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);
if ($idx % 2 == 0) {
$this->writer->help_item_even(' ' . str_pad($name, $padLen + $space));
$this->writer->help_description_even($desc, true);
} else {
$this->writer->help_item_odd(' ' . str_pad($name, $padLen + $space));
$this->writer->help_description_odd($desc, true);
}
}

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

Expand All @@ -224,7 +229,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 +246,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
29 changes: 22 additions & 7 deletions src/IO/Interactor.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
*
* @link https://github.com/adhocore/cli
*
* @method Writer answer($text, $eol = false)
* @method Writer bgBlack($text, $eol = false)
* @method Writer bgBlue($text, $eol = false)
* @method Writer bgCyan($text, $eol = false)
Expand Down Expand Up @@ -127,6 +128,7 @@
* @method Writer boldYellowBgPurple($text, $eol = false)
* @method Writer boldYellowBgRed($text, $eol = false)
* @method Writer boldYellowBgWhite($text, $eol = false)
* @method Writer choice($text, $eol = false)
* @method Writer colors($text)
* @method Writer comment($text, $eol = false)
* @method Writer cyan($text, $eol = false)
Expand All @@ -147,7 +149,18 @@
* @method Writer greenBgRed($text, $eol = false)
* @method Writer greenBgWhite($text, $eol = false)
* @method Writer greenBgYellow($text, $eol = false)
* @method Writer help_category($text, $eol = false)
* @method Writer help_description_even($text, $eol = false)
* @method Writer help_description_odd($text, $eol = false)
* @method Writer help_example($text, $eol = false)
* @method Writer help_footer($text, $eol = false)
* @method Writer help_group($text, $eol = false)
* @method Writer help_header($text, $eol = false)
* @method Writer help_item($text, $eol = false)
* @method Writer help_summary($text, $eol = false)
* @method Writer help_text($text, $eol = false)
* @method Writer info($text, $eol = false)
* @method Writer logo($text, $eol = false)
* @method Writer ok($text, $eol = false)
* @method Writer purple($text, $eol = false)
* @method Writer purpleBgBlack($text, $eol = false)
Expand All @@ -157,6 +170,7 @@
* @method Writer purpleBgRed($text, $eol = false)
* @method Writer purpleBgWhite($text, $eol = false)
* @method Writer purpleBgYellow($text, $eol = false)
* @method Writer question($text, $eol = false)
* @method Writer red($text, $eol = false)
* @method Writer redBgBlack($text, $eol = false)
* @method Writer redBgBlue($text, $eol = false)
Expand All @@ -166,6 +180,7 @@
* @method Writer redBgWhite($text, $eol = false)
* @method Writer redBgYellow($text, $eol = false)
* @method Writer table(array $rows, array $styles = [])
* @method Writer version($text, $eol = false)
* @method Writer warn($text, $eol = false)
* @method Writer white($text, $eol = false)
* @method Writer yellow($text, $eol = false)
Expand Down Expand Up @@ -241,7 +256,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 +277,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 +315,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 +325,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 +366,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 +384,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
Loading