@@ -3,11 +3,13 @@ module cmd.command;
33import core.stdc.stdlib ;
44import std.algorithm ;
55import std.array ;
6+ import std.range : repeat;
67import std.stdio ;
78import std.string ;
8- import std.range : repeat;
99
10+ import cmd.ansi;
1011import cmd.argument;
12+ import cmd.document;
1113import cmd.flag;
1214import cmd.option;
1315import cmd.parsed_args;
@@ -214,10 +216,12 @@ public class Command {
214216 /**
215217 * Gets the usage string for this command.
216218 *
219+ * Params:
220+ * colors = Whether to use colors in the usage string.
217221 * Throws:
218222 * AssertionError if command chain is null or empty, or if first command is not a Program.
219223 */
220- public string usage () const {
224+ public string usage (bool colors = false ) const {
221225 assert (chain ! is null , " Command chain is not initialised" );
222226 assert (! chain.empty(), " Command chain is empty. The command should have at least itself in its chain." );
223227 Program program = cast (Program) chain[0 ];
@@ -226,75 +230,62 @@ public class Command {
226230 Appender! string sb;
227231 sb.put(program.name());
228232 if (program.versionOption() || program.helpOption())
229- sb.put(chain.length > 1 ? " [global options]" : " [options]" );
233+ sb.put(" "
234+ ~ " [" .brightBlack() ~ ((chain.length > 1 ? " global " : " " ) ~ " options" ).dim() ~ " ]" .brightBlack());
230235 if (chain.length > 1 )
231236 sb.put(" " ~ chain[1 .. $].map! (c => c.name()).array.join(" " ));
232237 if (! subcommands.empty())
233- sb.put(" < command> ..." );
238+ sb.put(" " ~ " < " .brightBlack() ~ " command" .dim() ~ " > " .brightBlack() ~ " " ~ " ..." .brightBlack() );
234239 else {
235240 if (! options.empty() || ! flags.empty())
236- sb.put(" " ~ (options.any! (o => o.required) ? " <options>" : " [options]" ));
241+ sb.put(" " ~ (options.any! (o => o.required)
242+ ? " <" .brightBlack() ~ " options" .dim() ~ " >" .brightBlack()
243+ : " [" .brightBlack() ~ " options" .dim() ~ " ]" .brightBlack()
244+ ));
237245 foreach (arg; arguments)
238- sb.put(" " ~ arg.formattedName());
246+ sb.put(" " ~ arg.formattedName(colors ));
239247 }
240- return sb.data;
248+ return colors ? sb.data : sb.data.stripAnsi() ;
241249 }
242250
243251 /* * Prinths help for the command. */
244252 public int printHelp () const {
245- writeln(" \x1b [1mUsage:\x1b [0m" );
246- writeln(" " ~ usage());
247-
248- if (description() ! is null ) {
249- writeln();
250- writeln(" \x1b [1mDescription:\x1b [0m" );
251- writeln(" " ~ description());
252- }
253-
254- size_t longest = 0 ;
255- foreach (cmd; subcommands)
256- longest = max(longest, cmd.name().length);
257-
258- foreach (arg; arguments)
259- longest = max(longest, arg.name.length);
260-
261- auto allOpts = cast (Flag[]) (flags ~ cast (Flag[]) options);
262- foreach (opt; allOpts)
263- longest = max(longest, opt.paddedName().length);
253+ auto doc = new Document ();
254+ doc.add(" Usage:" .bold(), usage(true ));
264255
265256 if (subcommands ! is null ) {
266- writeln( );
267- writeln( " \x1b [1mCommands: \x1b [0m " );
257+ auto s = new Section( " Commands: " .bold() );
258+ doc.add(s );
268259
269260 foreach (cmd; (cast (Command[]) subcommands).dup .sort! ((a, b) {
270261 return a.name() < b.name();
271- }))
272- writeln(" " ~ cmd.name() ~ ' ' .repeat(longest - cmd.name().length + 2 ).array ~ " \x1b [2m"
273- ~ cmd.description() ~ " \x1b [0m" );
262+ })) s.add(cmd.name(), cmd.description());
274263 }
275264
276265 if (arguments ! is null ) {
277- writeln( );
278- writeln( " \x1b [1mArguments: \x1b [0m " );
266+ auto s = new Section( " Arguments: " .bold() );
267+ doc.add(s );
279268
280269 foreach (arg; arguments)
281- writeln(" " ~ arg.name ~ ' ' .repeat(longest - arg.name.length + 2 ).array ~ " \x1b [2m"
282- ~ arg.description ~ " \x1b [0m" );
270+ s.add(arg.name, arg.description);
283271 }
284272
285273 if (! flags.empty() || ! options.empty()) {
286- writeln( );
287- writeln( " \x1b [1mOptions: \x1b [0m " );
274+ auto s = new Section( " Options: " .bold() );
275+ doc.add(s );
288276
289- foreach (opt; allOpts .sort! ((a, b) {
277+ foreach (opt; ( cast (Flag[]) (flags ~ cast (Flag[]) options)) .sort! ((a, b) {
290278 auto nameA = a.longName ! is null ? a.longName : a.shortName;
291279 auto nameB = b.longName ! is null ? b.longName : b.shortName;
292280 return nameA < nameB;
293- }))
294- writeln(" " ~ opt.paddedName() ~ ' ' .repeat(longest - opt.paddedName().length + 2 ).array ~ " \x1b [2m"
295- ~ opt.description ~ " \x1b [0m" );
281+ })) {
282+ if (Option o = cast (Option) opt)
283+ s.add(o.paddedName(true ), opt.description);
284+ else s.add(opt.paddedName(), opt.description);
285+ }
296286 }
297287
288+ doc.print();
298289 return 0 ;
299290 }
300291
0 commit comments