support for positional args
[pharext/pharext] / src / pharext / Cli / Args / Help.php
1 <?php
2
3 namespace pharext\Cli\Args;
4
5 use pharext\Cli\Args;
6
7 class Help
8 {
9 private $args;
10
11 function __construct($prog, Args $args) {
12 $this->prog = $prog;
13 $this->args = $args;
14 }
15
16 function __toString() {
17 $usage = "Usage:\n\n \$ ";
18 $usage .= $this->prog;
19
20 list($flags, $required, $optional, $positional) = $this->listSpec();
21 if ($flags) {
22 $usage .= $this->dumpFlags($flags);
23 }
24 if ($required) {
25 $usage .= $this->dumpRequired($required);
26 }
27 if ($optional) {
28 $usage .= $this->dumpOptional($optional);
29 }
30 if ($positional) {
31 $usage .= $this->dumpPositional($positional);
32 }
33
34 $help = $this->dumpHelp($positional);
35
36 return $usage . "\n\n" . $help . "\n";
37 }
38
39 function listSpec() {
40 $flags = [];
41 $required = [];
42 $optional = [];
43 $positional = [];
44 foreach ($this->args->getSpec() as $spec) {
45 if (is_numeric($spec[0])) {
46 $positional[] = $spec;
47 } elseif ($spec[3] & Args::REQARG) {
48 if ($spec[3] & Args::REQUIRED) {
49 $required[] = $spec;
50 } else {
51 $optional[] = $spec;
52 }
53 } else {
54 $flags[] = $spec;
55 }
56 }
57
58 return [$flags, $required, $optional, $positional]
59 + compact("flags", "required", "optional", "positional");
60 }
61
62 function dumpFlags(array $flags) {
63 return sprintf(" [-%s]", implode("", array_column($flags, 0)));
64 }
65
66 function dumpRequired(array $required) {
67 $dump = "";
68 foreach ($required as $req) {
69 $dump .= sprintf(" -%s <%s>", $req[0], $req[1]);
70 }
71 return $dump;
72 }
73
74 function dumpOptional(array $optional) {
75 return sprintf(" [-%s <arg>]", implode("|-", array_column($optional, 0)));
76 }
77
78 function dumpPositional(array $positional) {
79 $dump = " [--]";
80 foreach ($positional as $pos) {
81 if ($pos[3] & Args::MULTI) {
82 $multi = " ...";
83 } else {
84 $multi = "";
85 }
86 if ($pos[3] & Args::REQUIRED) {
87 $dump .= sprintf(" <%s%s>", $pos[1], $multi);
88 } else {
89 $dump .= sprintf(" [%s%s]", $pos[1], $multi);
90 }
91 }
92 return $dump;
93 }
94
95 function calcMaxLen() {
96 $spc = $this->args->getSpec();
97 $max = max(array_map("strlen", array_column($spc, 1)));
98 $max += $max % 8 + 2;
99 return $max;
100 }
101
102 function dumpHelp() {
103 $max = $this->calcMaxLen();
104 $parg = "";
105 $dump = "";
106 foreach ($this->args->getSpec() as $spec) {
107 $dump .= " ";
108 if (is_numeric($spec[0])) {
109 $dump .= sprintf("-- %s ", $spec[1]);
110 } elseif (isset($spec[0])) {
111 $dump .= sprintf("-%s|", $spec[0]);
112 }
113 if (!is_numeric($spec[0])) {
114 $dump .= sprintf("--%s ", $spec[1]);
115 }
116 if ($spec[3] & Args::REQARG) {
117 $dump .= "<arg> ";
118 } elseif ($spec[3] & Args::OPTARG) {
119 $dump .= "[<arg>]";
120 } else {
121 $dump .= " ";
122 }
123
124 $dump .= str_repeat(" ", $max-strlen($spec[1])+3*!isset($spec[0]));
125 $dump .= $spec[2];
126
127 if ($spec[3] & Args::REQUIRED) {
128 $dump .= " (REQUIRED)";
129 }
130 if ($spec[3] & Args::MULTI) {
131 $dump .= " (MULTIPLE)";
132 }
133 if (isset($spec[4])) {
134 $dump .= sprintf(" [%s]", $spec[4]);
135 }
136 $dump .= "\n";
137 }
138 return $dump;
139 }
140 }