Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
100.00% |
38 / 38 |
|
100.00% |
48 / 48 |
|
13.33% |
8 / 60 |
|
100.00% |
5 / 5 |
CRAP | |
100.00% |
1 / 1 |
| Help | |
100.00% |
38 / 38 |
|
100.00% |
48 / 48 |
|
13.33% |
8 / 60 |
|
100.00% |
5 / 5 |
337.07 | |
100.00% |
1 / 1 |
| __construct | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| show | |
100.00% |
10 / 10 |
|
100.00% |
15 / 15 |
|
8.33% |
2 / 24 |
|
100.00% |
1 / 1 |
33.73 | |||
| showArguments | |
100.00% |
8 / 8 |
|
100.00% |
11 / 11 |
|
28.57% |
2 / 7 |
|
100.00% |
1 / 1 |
14.11 | |||
| showOptions | |
100.00% |
18 / 18 |
|
100.00% |
20 / 20 |
|
7.41% |
2 / 27 |
|
100.00% |
1 / 1 |
73.30 | |||
| showFor | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| 1 | <?php |
| 2 | |
| 3 | declare(strict_types=1); |
| 4 | |
| 5 | namespace Celema\Console; |
| 6 | |
| 7 | /** |
| 8 | * Renders a command's help screen from its attributes. |
| 9 | * |
| 10 | * Used by the Runner for `help <command>`; commands that intercept a |
| 11 | * `--help` flag themselves can render the same screen via `showFor()`. |
| 12 | * |
| 13 | * @api |
| 14 | */ |
| 15 | final class Help |
| 16 | { |
| 17 | public function __construct( |
| 18 | private readonly Io $io, |
| 19 | ) {} |
| 20 | |
| 21 | /** |
| 22 | * @param list<Opt> $opts |
| 23 | * @param list<Arg> $arguments |
| 24 | */ |
| 25 | public function show(Command $meta, array $opts = [], array $arguments = []): void |
| 26 | { |
| 27 | $script = $_SERVER['argv'][0] ?? ''; |
| 28 | |
| 29 | if ($meta->description !== '') { |
| 30 | $this->io->echo("<yellow>Description:</yellow>\n {$meta->description}\n\n"); |
| 31 | } |
| 32 | |
| 33 | $usage = "<yellow>Usage:</yellow>\n php {$script} {$meta->full()}"; |
| 34 | |
| 35 | foreach ($arguments as $argument) { |
| 36 | // Escaped: the <name> notation must not parse as markup. |
| 37 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 38 | $usage .= $argument->optional ? " [{$name}]" : " {$name}"; |
| 39 | } |
| 40 | |
| 41 | $this->io->echo($usage . ($opts === [] ? "\n" : " [options]\n")); |
| 42 | $this->showArguments($arguments); |
| 43 | $this->showOptions($opts); |
| 44 | } |
| 45 | |
| 46 | /** @param list<Arg> $arguments */ |
| 47 | private function showArguments(array $arguments): void |
| 48 | { |
| 49 | if ($arguments === []) { |
| 50 | return; |
| 51 | } |
| 52 | |
| 53 | $this->io->echo("\n<yellow>Arguments:</yellow>\n"); |
| 54 | |
| 55 | foreach ($arguments as $argument) { |
| 56 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 57 | $this->io->echo(" <green>{$name}</green>\n"); |
| 58 | |
| 59 | if ($argument->description !== '') { |
| 60 | $this->io->echo($this->io->indent($argument->description, 8, 80) . "\n"); |
| 61 | } |
| 62 | } |
| 63 | } |
| 64 | |
| 65 | /** @param list<Opt> $opts */ |
| 66 | private function showOptions(array $opts): void |
| 67 | { |
| 68 | if ($opts === []) { |
| 69 | return; |
| 70 | } |
| 71 | |
| 72 | $this->io->echo("\n<yellow>Options:</yellow>\n"); |
| 73 | |
| 74 | foreach ($opts as $opt) { |
| 75 | $suffix = match (true) { |
| 76 | $opt->value === '' => '', |
| 77 | $opt->optionalValue => "[=<{$opt->value}>]", |
| 78 | default => "=<{$opt->value}>", |
| 79 | }; |
| 80 | |
| 81 | $option = $opt->short === '' |
| 82 | ? $opt->long . $suffix |
| 83 | : "{$opt->short}{$suffix}, {$opt->long}{$suffix}"; |
| 84 | |
| 85 | $description = $opt->default === '' |
| 86 | ? $opt->description |
| 87 | : "{$opt->description} [default: {$opt->default}]"; |
| 88 | |
| 89 | $this->io->echo(' <green>' . $this->io->escape($option) . "</green>\n"); |
| 90 | |
| 91 | if ($description !== '') { |
| 92 | $this->io->echo($this->io->indent($description, 8, 80) . "\n"); |
| 93 | } |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | /** |
| 98 | * Renders help for a command instance or class from its attributes. |
| 99 | * |
| 100 | * @param class-string|object $command |
| 101 | */ |
| 102 | public function showFor(object|string $command): void |
| 103 | { |
| 104 | $this->show(Command::of($command), Opt::of($command), Arg::of($command)); |
| 105 | } |
| 106 | } |
Below are the source code lines that represent each code branch as identified by Xdebug. Please note a branch is not
necessarily coterminous with a line, a line may contain multiple branches and therefore show up more than once.
Please also be aware that some branches may be implicit rather than explicit, e.g. an if statement
always has an else as part of its logical flow even if you didn't write one.
| 18 | private readonly Io $io, |
| 19 | ) {} |
| 25 | public function show(Command $meta, array $opts = [], array $arguments = []): void |
| 26 | { |
| 27 | $script = $_SERVER['argv'][0] ?? ''; |
| 28 | |
| 29 | if ($meta->description !== '') { |
| 30 | $this->io->echo("<yellow>Description:</yellow>\n {$meta->description}\n\n"); |
| 31 | } |
| 32 | |
| 33 | $usage = "<yellow>Usage:</yellow>\n php {$script} {$meta->full()}"; |
| 33 | $usage = "<yellow>Usage:</yellow>\n php {$script} {$meta->full()}"; |
| 34 | |
| 35 | foreach ($arguments as $argument) { |
| 35 | foreach ($arguments as $argument) { |
| 37 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 37 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 37 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 37 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 38 | $usage .= $argument->optional ? " [{$name}]" : " {$name}"; |
| 38 | $usage .= $argument->optional ? " [{$name}]" : " {$name}"; |
| 38 | $usage .= $argument->optional ? " [{$name}]" : " {$name}"; |
| 35 | foreach ($arguments as $argument) { |
| 36 | // Escaped: the <name> notation must not parse as markup. |
| 37 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 38 | $usage .= $argument->optional ? " [{$name}]" : " {$name}"; |
| 35 | foreach ($arguments as $argument) { |
| 36 | // Escaped: the <name> notation must not parse as markup. |
| 37 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 38 | $usage .= $argument->optional ? " [{$name}]" : " {$name}"; |
| 39 | } |
| 40 | |
| 41 | $this->io->echo($usage . ($opts === [] ? "\n" : " [options]\n")); |
| 41 | $this->io->echo($usage . ($opts === [] ? "\n" : " [options]\n")); |
| 41 | $this->io->echo($usage . ($opts === [] ? "\n" : " [options]\n")); |
| 41 | $this->io->echo($usage . ($opts === [] ? "\n" : " [options]\n")); |
| 42 | $this->showArguments($arguments); |
| 43 | $this->showOptions($opts); |
| 44 | } |
| 47 | private function showArguments(array $arguments): void |
| 48 | { |
| 49 | if ($arguments === []) { |
| 50 | return; |
| 53 | $this->io->echo("\n<yellow>Arguments:</yellow>\n"); |
| 54 | |
| 55 | foreach ($arguments as $argument) { |
| 55 | foreach ($arguments as $argument) { |
| 56 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 56 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 56 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 56 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 57 | $this->io->echo(" <green>{$name}</green>\n"); |
| 58 | |
| 59 | if ($argument->description !== '') { |
| 55 | foreach ($arguments as $argument) { |
| 56 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 57 | $this->io->echo(" <green>{$name}</green>\n"); |
| 58 | |
| 59 | if ($argument->description !== '') { |
| 60 | $this->io->echo($this->io->indent($argument->description, 8, 80) . "\n"); |
| 55 | foreach ($arguments as $argument) { |
| 55 | foreach ($arguments as $argument) { |
| 56 | $name = $this->io->escape("<{$argument->name}>") . ($argument->variadic ? '...' : ''); |
| 57 | $this->io->echo(" <green>{$name}</green>\n"); |
| 58 | |
| 59 | if ($argument->description !== '') { |
| 60 | $this->io->echo($this->io->indent($argument->description, 8, 80) . "\n"); |
| 61 | } |
| 62 | } |
| 63 | } |
| 102 | public function showFor(object|string $command): void |
| 103 | { |
| 104 | $this->show(Command::of($command), Opt::of($command), Arg::of($command)); |
| 105 | } |
| 66 | private function showOptions(array $opts): void |
| 67 | { |
| 68 | if ($opts === []) { |
| 69 | return; |
| 72 | $this->io->echo("\n<yellow>Options:</yellow>\n"); |
| 73 | |
| 74 | foreach ($opts as $opt) { |
| 74 | foreach ($opts as $opt) { |
| 76 | $opt->value === '' => '', |
| 77 | $opt->optionalValue => "[=<{$opt->value}>]", |
| 77 | $opt->optionalValue => "[=<{$opt->value}>]", |
| 76 | $opt->value === '' => '', |
| 77 | $opt->optionalValue => "[=<{$opt->value}>]", |
| 78 | default => "=<{$opt->value}>", |
| 75 | $suffix = match (true) { |
| 76 | $opt->value === '' => '', |
| 77 | $opt->optionalValue => "[=<{$opt->value}>]", |
| 78 | default => "=<{$opt->value}>", |
| 79 | }; |
| 80 | |
| 81 | $option = $opt->short === '' |
| 82 | ? $opt->long . $suffix |
| 81 | $option = $opt->short === '' |
| 82 | ? $opt->long . $suffix |
| 83 | : "{$opt->short}{$suffix}, {$opt->long}{$suffix}"; |
| 81 | $option = $opt->short === '' |
| 82 | ? $opt->long . $suffix |
| 83 | : "{$opt->short}{$suffix}, {$opt->long}{$suffix}"; |
| 84 | |
| 85 | $description = $opt->default === '' |
| 86 | ? $opt->description |
| 85 | $description = $opt->default === '' |
| 86 | ? $opt->description |
| 87 | : "{$opt->description} [default: {$opt->default}]"; |
| 85 | $description = $opt->default === '' |
| 86 | ? $opt->description |
| 87 | : "{$opt->description} [default: {$opt->default}]"; |
| 88 | |
| 89 | $this->io->echo(' <green>' . $this->io->escape($option) . "</green>\n"); |
| 90 | |
| 91 | if ($description !== '') { |
| 74 | foreach ($opts as $opt) { |
| 75 | $suffix = match (true) { |
| 76 | $opt->value === '' => '', |
| 77 | $opt->optionalValue => "[=<{$opt->value}>]", |
| 78 | default => "=<{$opt->value}>", |
| 79 | }; |
| 80 | |
| 81 | $option = $opt->short === '' |
| 82 | ? $opt->long . $suffix |
| 83 | : "{$opt->short}{$suffix}, {$opt->long}{$suffix}"; |
| 84 | |
| 85 | $description = $opt->default === '' |
| 86 | ? $opt->description |
| 87 | : "{$opt->description} [default: {$opt->default}]"; |
| 88 | |
| 89 | $this->io->echo(' <green>' . $this->io->escape($option) . "</green>\n"); |
| 90 | |
| 91 | if ($description !== '') { |
| 92 | $this->io->echo($this->io->indent($description, 8, 80) . "\n"); |
| 74 | foreach ($opts as $opt) { |
| 74 | foreach ($opts as $opt) { |
| 75 | $suffix = match (true) { |
| 76 | $opt->value === '' => '', |
| 77 | $opt->optionalValue => "[=<{$opt->value}>]", |
| 78 | default => "=<{$opt->value}>", |
| 79 | }; |
| 80 | |
| 81 | $option = $opt->short === '' |
| 82 | ? $opt->long . $suffix |
| 83 | : "{$opt->short}{$suffix}, {$opt->long}{$suffix}"; |
| 84 | |
| 85 | $description = $opt->default === '' |
| 86 | ? $opt->description |
| 87 | : "{$opt->description} [default: {$opt->default}]"; |
| 88 | |
| 89 | $this->io->echo(' <green>' . $this->io->escape($option) . "</green>\n"); |
| 90 | |
| 91 | if ($description !== '') { |
| 92 | $this->io->echo($this->io->indent($description, 8, 80) . "\n"); |
| 93 | } |
| 94 | } |
| 95 | } |