Skip to content

Commit 628e3b7

Browse files
committed
Merge branch 'cli-documentation'
2 parents c9913a0 + 2605c56 commit 628e3b7

File tree

5 files changed

+138
-48
lines changed

5 files changed

+138
-48
lines changed

src/Cli/Catalog/CliOptionVisibility.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ final class CliOptionVisibility extends Enumeration
1717

1818
public const HELP = 2;
1919

20-
public const COMPLETION = 4;
20+
public const MARKDOWN = 4;
2121

22-
public const ALL = CliOptionVisibility::SYNOPSIS | CliOptionVisibility::HELP | CliOptionVisibility::COMPLETION;
22+
public const MAN_PAGE = 8;
23+
24+
public const COMPLETION = 16;
25+
26+
public const ALL = CliOptionVisibility::SYNOPSIS | CliOptionVisibility::HELP | CliOptionVisibility::MARKDOWN | CliOptionVisibility::MAN_PAGE | CliOptionVisibility::COMPLETION;
2327
}

src/Cli/CliApplication.php

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Lkrms\Facade\Console;
1616
use Lkrms\Facade\Sys;
1717
use Lkrms\Utility\Convert;
18+
use Lkrms\Utility\Pcre;
1819
use LogicException;
1920

2021
/**
@@ -223,7 +224,7 @@ private function getUsage(string $name, $node, bool $terse = false): ?string
223224
foreach ($node as $childName => $childNode) {
224225
if ($command = $this->getNodeCommand(trim("$name $childName"), $childNode)) {
225226
if ($terse) {
226-
$synopses[] = $command->getSynopsis(false, $width);
227+
$synopses[] = $command->getSynopsis(false, $width, true);
227228
} else {
228229
$synopses[] = "__{$childName}__ - " . $command->description();
229230
}
@@ -308,7 +309,7 @@ public function buildHelp(array $sections): string
308309
EOF;
309310
}
310311

311-
return rtrim($usage);
312+
return Pcre::replace('/^\s+$/m', '', rtrim($usage));
312313
}
313314

314315
/**
@@ -382,12 +383,14 @@ public function run(): int
382383
$name .= ($name === '' ? '' : ' ') . $arg;
383384
}
384385

385-
if ($args === ['_md']) {
386-
return $this->generateHelp($name, $node, CliHelpType::MARKDOWN);
386+
if (($args[0] ?? null) === '_md') {
387+
array_shift($args);
388+
return $this->generateHelp($name, $node, CliHelpType::MARKDOWN, ...$args);
387389
}
388390

389-
if ($args === ['_man']) {
390-
return $this->generateHelp($name, $node, CliHelpType::MAN_PAGE);
391+
if (($args[0] ?? null) === '_man') {
392+
array_shift($args);
393+
return $this->generateHelp($name, $node, CliHelpType::MAN_PAGE, ...$args);
391394
}
392395

393396
$command = $this->getNodeCommand($name, $node);
@@ -424,7 +427,7 @@ public function runAndExit()
424427
* @param array<string,class-string<CliCommand>|mixed[]>|class-string<CliCommand> $node
425428
* @param CliHelpType::* $type
426429
*/
427-
private function generateHelp(string $name, $node, int $type): int
430+
private function generateHelp(string $name, $node, int $type, string ...$args): int
428431
{
429432
$this->HelpType = $type;
430433

@@ -435,6 +438,13 @@ private function generateHelp(string $name, $node, int $type): int
435438

436439
case CliHelpType::MAN_PAGE:
437440
$formats = TagFormats::getManPageFormats();
441+
printf(
442+
"%% %s(%d) %s | %s\n\n",
443+
strtoupper(str_replace(' ', '-', trim($this->getProgramName() . " $name"))),
444+
(int) ($args[0] ?? '1'),
445+
$args[1] ?? Composer::getRootPackageVersion(true, true),
446+
$args[2] ?? (Composer::getRootPackageName() . ' Documentation'),
447+
);
438448
break;
439449

440450
default:

src/Cli/CliCommand.php

Lines changed: 101 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -358,46 +358,73 @@ final protected function getOption(string $name): ?CliOption
358358
/**
359359
* @inheritDoc
360360
*/
361-
final public function getSynopsis(bool $withMarkup = true, ?int $width = 80): string
361+
final public function getSynopsis(bool $withMarkup = true, ?int $width = 80, bool $collapse = false): string
362362
{
363363
$pre = '';
364364
$b = '';
365365
$n = "\n ";
366+
366367
if ($withMarkup) {
367-
if ($this->App->getHelpType() === CliHelpType::MAN_PAGE) {
368-
$pre = '| ';
369-
$b = '`';
370-
$n = "\n{$pre} ";
371-
} else {
372-
$b = '__';
373-
$n = " \\\n\ \ \ \ ";
368+
$b = '__';
369+
$n = " \\\n\ \ \ \ ";
370+
371+
switch ($this->App->getHelpType()) {
372+
case CliHelpType::MARKDOWN:
373+
$b = '`';
374+
break;
375+
376+
case CliHelpType::MAN_PAGE:
377+
$pre = '| ';
378+
$b = '`';
379+
$n = "\n{$pre} ";
380+
break;
374381
}
375382
}
376383

377384
$synopsis = Convert::sparseToString(' ', [
378385
$b . $this->getNameWithProgram() . $b,
379-
$this->getOptionsSynopsis($withMarkup, true),
386+
$this->getOptionsSynopsis($withMarkup, true, $collapsed),
380387
]);
381388

382389
if ($width !== null) {
383-
return $pre . str_replace(
390+
$wrapped = $pre . str_replace(
384391
"\n", $n, $this
385392
->getLoopbackFormatter()
386393
->formatTags($synopsis, false, [$width, $width - 4], !$withMarkup)
387394
);
395+
396+
if (!$collapse || strpos($wrapped, "\n") === false) {
397+
return $wrapped;
398+
}
399+
400+
$synopsis = Convert::sparseToString(' ', [
401+
$b . $this->getNameWithProgram() . $b,
402+
$collapsed,
403+
]);
388404
}
389405

390406
return $pre . $this
391407
->getLoopbackFormatter()
392408
->formatTags($synopsis, false, null, !$withMarkup);
393409
}
394410

395-
private function getOptionsSynopsis(bool $withMarkup = true, bool $withEscapes = false): string
411+
private function getOptionsSynopsis(bool $withMarkup = true, bool $withEscapes = false, ?string &$collapsed = null): string
396412
{
397413
$withEscapes = $withEscapes && !$withMarkup;
398-
$b = $withMarkup ? '__' : '';
414+
415+
$b = '';
399416
$esc = ($withMarkup || $withEscapes) ? '\\' : '';
400417

418+
if ($withMarkup) {
419+
$b = '__';
420+
switch ($this->App->getHelpType()) {
421+
case CliHelpType::MARKDOWN:
422+
case CliHelpType::MAN_PAGE:
423+
$b = '`';
424+
break;
425+
}
426+
}
427+
401428
// Produce this:
402429
//
403430
// [-ny] [--exclude PATTERN] [--verbose] --from SOURCE DEST
@@ -414,12 +441,17 @@ private function getOptionsSynopsis(bool $withMarkup = true, bool $withEscapes =
414441
$required = [];
415442
$positional = [];
416443

444+
$count = 0;
417445
foreach ($this->getOptions() as $option) {
418446
if (!($option->Visibility & CliOptionVisibility::SYNOPSIS)) {
419447
continue;
420448
}
421449

422450
if ($option->IsFlag) {
451+
$count++;
452+
if ($option->MultipleAllowed) {
453+
$count++;
454+
}
423455
if ($option->Short !== null) {
424456
$shortFlag[] = $option->Short;
425457
continue;
@@ -441,10 +473,13 @@ private function getOptionsSynopsis(bool $withMarkup = true, bool $withEscapes =
441473
continue;
442474
}
443475

476+
$count++;
477+
444478
$prefix = '';
445479
$suffix = '';
446480
$ellipsis = '';
447481
if ($option->MultipleAllowed) {
482+
$count++;
448483
if ($option->Delimiter) {
449484
$valueName .= "{$option->Delimiter}...";
450485
} elseif ($option->ValueRequired) {
@@ -476,42 +511,61 @@ private function getOptionsSynopsis(bool $withMarkup = true, bool $withEscapes =
476511
}
477512
}
478513

514+
$collapsed = implode(' ', array_filter([
515+
$count > 1 ? "{$esc}[<option>]..." : '',
516+
$count === 1 ? "{$esc}[<option>]" : '',
517+
$positional ? "{$esc}[{$b}--{$b}] " . implode(' ', $positional) : '',
518+
]));
519+
479520
return implode(' ', array_filter([
480521
$shortFlag ? "{$esc}[{$b}-" . implode('', $shortFlag) . "{$b}]" : '',
481522
$optional ? implode(' ', $optional) : '',
482523
$required ? implode(' ', $required) : '',
483-
$positional ? implode(' ', $positional) : '',
524+
$positional ? "{$esc}[{$b}--{$b}] " . implode(' ', $positional) : '',
484525
]));
485526
}
486527

487528
final public function getHelp(bool $withMarkup = true, ?int $width = 80): string
488529
{
489-
$b = $withMarkup ? '__' : '';
490-
$em = $withMarkup ? '_' : '';
491-
$esc = $withMarkup ? '\\' : '';
492-
493-
$indent = '';
494-
$beforeDescription = "\n\n";
495-
$beforeList = "\n\n";
496-
497-
switch ($this->App->getHelpType()) {
498-
case CliHelpType::TTY:
499-
$indent = ' ';
500-
$beforeDescription = "\n" . $indent;
501-
$beforeList = "\n";
502-
break;
530+
$b = '';
531+
$em = '';
532+
$esc = '';
533+
$indent = ' ';
534+
$beforeSynopsis = '';
535+
$beforeDescription = "\n" . $indent;
536+
$visibility = CliOptionVisibility::HELP;
537+
$collapse = false;
503538

504-
case CliHelpType::MAN_PAGE:
505-
$indent = ' ';
506-
$beforeDescription .= ': ';
507-
break;
539+
if ($withMarkup) {
540+
$b = '__';
541+
$em = '_';
542+
$esc = '\\';
543+
544+
switch ($this->App->getHelpType()) {
545+
case CliHelpType::MARKDOWN:
546+
$b = '`';
547+
$indent = ' ';
548+
$beforeSynopsis = '- ';
549+
$beforeDescription = "\n\n" . $indent;
550+
$visibility = CliOptionVisibility::MARKDOWN;
551+
$collapse = true;
552+
break;
553+
554+
case CliHelpType::MAN_PAGE:
555+
$b = '`';
556+
$indent = ' ';
557+
$beforeDescription = "\n\n: ";
558+
$visibility = CliOptionVisibility::MAN_PAGE;
559+
$collapse = true;
560+
break;
561+
}
508562
}
509563

510564
$formatter = $this->getLoopbackFormatter();
511565

512566
$options = [];
513567
foreach ($this->getOptions() as $option) {
514-
if (!($option->Visibility & CliOptionVisibility::HELP)) {
568+
if (!($option->Visibility & $visibility)) {
515569
continue;
516570
}
517571

@@ -595,6 +649,11 @@ final public function getHelp(bool $withMarkup = true, ?int $width = 80): string
595649
$synopsis = $line;
596650
}
597651

652+
if ($valueName !== null) {
653+
$valueName = $formatter->removeTags($valueName);
654+
$valueName = strtolower(Convert::splitWords($valueName, null, ' '));
655+
}
656+
598657
$lines = [];
599658
if ($option->Description !== null &&
600659
($description = trim($option->Description)) !== '') {
@@ -603,18 +662,21 @@ final public function getHelp(bool $withMarkup = true, ?int $width = 80): string
603662

604663
if ($allowed) {
605664
foreach ($allowed as &$value) {
606-
$value = sprintf("%s-{$esc} %s", $indent, $value);
665+
$value = sprintf('%s- %s', $indent, $value);
607666
}
608-
$lines[] = "{$indent}{$valueName} can be:"
609-
. $beforeList
610-
. implode("\n", $allowed);
667+
$lines[] = sprintf(
668+
"%sThe %s can be:\n\n%s",
669+
$indent,
670+
$valueName,
671+
implode("\n", $allowed)
672+
);
611673
}
612674

613675
if (!$option->IsFlag &&
614676
$option->DefaultValue !== null &&
615677
$option->DefaultValue !== []) {
616678
foreach ((array) $option->DefaultValue as $value) {
617-
$default[] = sprintf("{$em}%s{$em}", $formatter->escapeTags((string) $value));
679+
$default[] = $em . $formatter->escapeTags((string) $value) . $em;
618680
}
619681
$lines[] = sprintf(
620682
"%sThe default %s is:{$esc} %s",
@@ -624,7 +686,7 @@ final public function getHelp(bool $withMarkup = true, ?int $width = 80): string
624686
);
625687
}
626688

627-
$options[] = $synopsis
689+
$options[] = $beforeSynopsis . $synopsis
628690
. ($lines ? $beforeDescription . ltrim(implode("\n\n", $lines)) : '');
629691
}
630692

@@ -638,7 +700,7 @@ final public function getHelp(bool $withMarkup = true, ?int $width = 80): string
638700

639701
$sections = [
640702
'NAME' => $name . ' - ' . $this->description(),
641-
'SYNOPSIS' => $this->getSynopsis($withMarkup, $width),
703+
'SYNOPSIS' => $this->getSynopsis($withMarkup, $width, $collapse),
642704
'DESCRIPTION' => $this->prepareUsage($this->getLongDescription(), $formatter, $width),
643705
'OPTIONS' => implode("\n\n", $options),
644706
] + $sections;

src/Console/Support/ConsoleManPageFormat.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ public function apply(?string $text, array $attributes = []): string
3535
if ($tag === '##') {
3636
$before = '# ';
3737
$after = '';
38+
} elseif ($tag === '_') {
39+
$before = '';
40+
$after = '';
41+
} elseif ($this->Before === '`') {
42+
$before = '**`';
43+
$after = '`**';
3844
} elseif ($this->Before === '```') {
3945
$before = $tag . ($attributes[Attribute::INFO_STRING] ?? '') . "\n";
4046
$after = "\n" . $tag;

src/Console/Support/ConsoleMarkdownFormat.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Lkrms\Console\Catalog\ConsoleAttribute as Attribute;
66
use Lkrms\Console\Contract\IConsoleFormat;
7+
use Lkrms\Console\ConsoleFormatter;
78

89
/**
910
* Applies Markdown formatting to console output
@@ -35,6 +36,13 @@ public function apply(?string $text, array $attributes = []): string
3536
if ($tag === '##') {
3637
$before = '## ';
3738
$after = '';
39+
} elseif ($tag === '_' || $tag === '*') {
40+
$before = '`';
41+
$after = '`';
42+
$text = ConsoleFormatter::removeTags($text);
43+
} elseif ($this->Before === '`') {
44+
$before = '**`';
45+
$after = '`**';
3846
} elseif ($this->Before === '```') {
3947
$before = $tag . ($attributes[Attribute::INFO_STRING] ?? '') . "\n";
4048
$after = "\n" . $tag;

0 commit comments

Comments
 (0)