kaycxx-cli
C++ CLI library
Loading...
Searching...
No Matches
Subcommands

A command can own named subcommands. Each subcommand has its own description, flags, options, and positional parameters.

auto example = app{"example"};
auto debug = example.flag("debug", "Enable debug output");
auto help = example.flag("help", 'h', "Show help").action();
auto login = example.command("login", "Log in to an account");
auto account = login.option<std::string>("account", "NAME", "Account to use");
auto logout = example.command("logout", "Log out");

Only the description belongs to a subcommand. Version, author, email, bug-report address, copyright, and license are configured once on the application and used by every descendant's help and version output.

command() returns a lightweight, copyable handle to the application-owned definition. The handle is used to configure and nest the command and as the dispatch key for args::is_selected(). Keep the application alive while using its command or argument handles and parsed arguments.

Subcommands can own nested subcommands as well. The same rules then apply recursively, but most command-line interfaces only need one subcommand level.

Command Scopes

The parser starts at the application and changes scope whenever it reads a command name. The example definitions accept:

example --debug login --account work
example login --debug --account work
example login --help
example logout --help

Parent switches remain available after selecting descendant commands. A child switch cannot appear before selecting the command that owns it, so this form is rejected:

example --account work login

The --debug and --help flags belong to the application and are accepted at every command level. The --account option becomes available only after login is selected.

A command can have subcommands or positional parameters, but not both. Put positional parameters on the leaf command that consumes them. This keeps every non-switch argument unambiguous.

Selection and Dispatch

The library parses commands but does not execute callbacks. args::selected_command() returns the deepest command selected by the command line. args::is_selected() compares it with a specific command handle and is the normal way to dispatch application code.

auto arguments = example.parse(argc, argv);
if (arguments.get(help)) {
return arguments.selected_command().print_help();
}
arguments.validate();
if (arguments.is_selected(login)) {
if (arguments.has(account)) {
select_account(arguments.get(account));
}
perform_login();
} else if (arguments.is_selected(logout)) {
perform_logout();
}

The logout handle is useful even though that command has no arguments of its own: It identifies the selected command for dispatch.

The application itself is selected when no subcommand was provided. Because it has subcommands, validate() then reports Missing command. This validation is deliberately delayed so example --help can print the application's help first.

An unknown subcommand is rejected immediately by parse() with an Unknown command error. Only one command can be selected at each level.

Generated Help

Help lists only the direct subcommands of the command for which it is generated. It also uses the complete command path in the usage line.

For example --help, example.print_help() contains:

Usage: example [OPTION]... COMMAND
--debug Enable debug output
-h, --help Show help
Commands:
login Log in to an account
logout Log out

For example login --help, login.print_help() contains:

Usage: example login [OPTION]...
Log in to an account
--account <NAME> Account to use
--debug Enable debug output
-h, --help Show help

Parent switches are shown in descendant help output regardless of whether they are required or optional.