rtcdude
rtcdude

Reputation: 61

Method for printing CLI11 help_text

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?

Upvotes: 4

Views: 2036

Answers (3)

Alpha
Alpha

Reputation: 715

When I use app.parse(argc, argv) in my source code, ./myproj -h error:

terminate called after throwing an instance of 'CLI::CallForHelp'
  what():  This should be caught in your main function, see examples

When I use MACROS CLI11_PARSE in my source code, no error for ./myproj -h

CLI11_PARSE(app, argc, argv);

Upvotes: 0

DWD
DWD

Reputation: 452

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.

Upvotes: 6

rtcdude
rtcdude

Reputation: 61

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.

Upvotes: 2

Related Questions