p-ranav / argparse

Argument Parser for Modern C++
MIT License
2.67k stars 244 forks source link

Subcommand help should be displayed instead of main help when required parameter is missing #283

Closed nmoreaud closed 1 year ago

nmoreaud commented 1 year ago

Hello,

With this example:

    argparse::ArgumentParser program("git");

    // git add subparser
    argparse::ArgumentParser add_command("add");
    add_command.add_description("Add file contents to the index");
    add_command.add_argument("files")
        .help("Files to add content from. Fileglobs (e.g.  *.c) can be given to add all matching files.")
        .remaining();

    // git commit subparser
    argparse::ArgumentParser clone_command("clone");
    clone_command.add_description("Clone repository");
    clone_command.add_argument("url");

    program.add_subparser(add_command);
    program.add_subparser(clone_command);

If I don't provide a clone url, the program prints:

./program clone
1 argument(s) expected. 0 provided.
Usage: git [-h] {add,clone}

Optional arguments:
  -h, --help    shows help message and exits 
  -v, --version prints version information and exits 

Subcommands:
  add           Add file contents to the index
  clone         Clone repository

I would expect to see:

./program clone
1 argument(s) expected. 0 provided.
Usage: clone [-h] url

Clone repository

Positional arguments:
  url          

Optional arguments:
  -h, --help    shows help message and exits 
  -v, --version prints version information and exits

What do you think about it? It behaves the same for required parameters, etc.

nmoreaud commented 1 year ago

Ok so in fact it works, because is_subcommand_used is set. Ex:

    try {
        program.parse_args(m_argc, m_argv);
    } catch (const std::runtime_error& err) {
        std::cerr << err.what() << std::endl;
        if (program.is_subcommand_used("clone")) {
            std::cerr << clone_command;
        } else {
            std::cerr << program;
        }
        return 1;
    }

It would be convenient to have access directly to used subcommand without having to test every subcommand name ; and to have access to more fields (ex m_program_name could have a getter).

shubhampaul commented 7 months ago

Unfortunately, this doesn't work with 'required' arguments. I think it would be necessary to have contextual help when required arguments are missing, currently it just prints what is required.