2

I've search high and low and can't find this. What is the CLI11 method to print out the help. I want to be able to show the user the help when they've entered incorrect info.

Also, does CLI11 throw an exception when no option are given? If not, how do you tell how many options have been given?

rici
  • 234,347
  • 28
  • 237
  • 341
rtcdude
  • 41
  • 3
  • What is cli11?? – Alan Birtles Jul 10 '21 at 05:50
  • @Alan: Apparently it's an argument parsing library. I added a link, straight from a web search. – rici Jul 10 '21 at 16:43
  • CLI11 is a command line parsing package. And yes, I already l know about that page about using CLI11, not what CLI11 method is used to progmatically output the help text for the tool you are building. You can use the -h, --help command line options to output the help text on your tool. But I what to progmatically output that text from inside my tool. – rtcdude Jul 11 '21 at 07:06
  • @rtcdude: i guessed that you knew that page I added the link as a courtesy to other readers of the question who might not have been familiar with it, such as the person who asked about it. – rici Jul 11 '21 at 20:50

2 Answers2

4

Too long, didn't read

// App::help() returns a std::string
std::cerr << app::help() << std::flush;

Not detailed enough, more information please

How App::exit(...) leads to help text being emitted

Here's the member function App::exit from CLI/App.hpp.

We can see that a std::ostream object out is used in conjunction with App::help() and App::help("", AppFormatMode::All),

    int exit(const Error &e, std::ostream &out = std::cout, std::ostream &err = std::cerr) const {

        /// Avoid printing anything if this is a CLI::RuntimeError
        if(e.get_name() == "RuntimeError")
            return e.get_exit_code();

        if(e.get_name() == "CallForHelp") {
            out << help();
            return e.get_exit_code();
        }

        if(e.get_name() == "CallForAllHelp") {
            out << help("", AppFormatMode::All);
            return e.get_exit_code();
        }

        if(e.get_name() == "CallForVersion") {
            out << e.what() << std::endl;
            return e.get_exit_code();
        }

        if(e.get_exit_code() != static_cast<int>(ExitCodes::Success)) {
            if(failure_message_)
                err << failure_message_(this, e) << std::flush;
        }

        return e.get_exit_code();
    }

App::help(...) itself

App::help(...) itself has the following prototype:

std::string help(std::string prev = "", AppFormatMode mode = AppFormatMode::Normal) const

Demonstration usage

We can therefore use App::help (Compiler Explorer demo short url, demo full url):

// C++ Standard Library
#include <iostream>
#include <string>

// 3rd party libraries
#include "CLI/CLI.hpp"


int main() {
    CLI::App app{"Demonstration app"};

    // Assigning to string for demonstrative purposes
    const std::string help_text = app.help();
    std::cerr << help_text << std::flush;

    return 0;
}

yielding:

Demonstration app
Usage: [OPTIONS]

Options:
  -h,--help                   Print this help message and exit

Subcommands

This also works for subcommands (Compiler Explorer demo short url, demo full url):

    CLI::App* app_sub_command = app.add_subcommand("usage", "This is a subcommand");
    std::cerr << app_sub_command->help() << std::flush;

which yields:

This is a subcommand
Usage: usage [OPTIONS]

Options:
  -h,--help                   Print this help message and exit

When was this introduced?

The function signature of App::help came to be on commit 952f291, in April of 2018.

DWD
  • 422
  • 5
  • 16
2

I will answer my own question so that it may help someone else in the future.

I ran across a code snippet on the net that hinted at a solution and lead me to an answer. In short, there is no CLI11 method to directly print out the help text. However, there are two ways to print the help text programmatically.

try/catch block

This the CLI11 native method. After you have set up all your option definitions, define a try/catch block as in:

CLIx::App app( argc,
               argv );
         .
         .
         .
try
    {
    app.parse( argc,
               argv);
    }
catch( const CLI::CallForHelp &e )
    {
    exit( app.exit( e ) );
    }

The line "exit( app.exit( e ) );" calls the app parser method "exit" which prints the help text and returns an errorcode to exit the program. Then when you want help text printed, simply do a throw:

throw CLI::CallForHelp();

This exception is never described in any if the documentation, and is only discovered by crawling through CLI11's source.

sort of directly, slightly clumsy

The previous method assumes you want to exit the program after printing the help text. In my case that wouldn't work since I have users entering commands with options at an interactive prompt as part of my program. Instead, you can call CLI11's exit method directly with a fake exception:

app.exit( CLI::CallForHelp() );

Kind of goofy, but gets the job done.

Again, nowhere is this documented anywhere and is only discover by going through the CLI11 code.

Lastly, despite this little wart, I highly recommend CLI11. It's easy to use and quite powerful.

rtcdude
  • 41
  • 3