Skip to content

Feature Request: CLI usage/help generation #692

Description

@solly-skyral

Automated Usage Generation

Context

Hey, firstly just wanted to say thanks for the addition of the CLI parser. One feature that I've ended up hand-rolling in my own codebase but which I feel could be generally applicable is a generated Usage/Help function (directly from the named tuple read() types so renames are tracked etc) for printing the expected CLI arguments.

The library already has everything needed to generate this, so it seems like a natural addition.

Proposal

A usage function in rfl::cli, generated from the same struct
rfl::cli::read<T>() parses into:

template <class T, class... Ps>
std::string usage(const std::string& program_name, bool detailed = false);

Given:

enum class LogLevel { debug, info, warn };

struct Database {
  std::string host;
  int port;
};

struct Config {
  rfl::Positional<std::string> input_file;
  std::string host_name;
  bool verbose;
  std::vector<std::string> tags;
  rfl::Short<"p", int> port;
  Database database;
  std::optional<LogLevel> log_level;
};

rfl::cli::usage<Config>("my_binary") returns:

Usage: my_binary <input-file> --host-name=<value> --verbose[=<bool>] --tags=<v1,v2,...> -p|--port=<value> --database.host=<value> --database.port=<value> [--log-level=<debug|info|warn>]

The detailed flag could extend this to a full help form, taking into account any descriptions passed via rfl::Description. Given:

struct Config {
  rfl::Description<"Path to the input file", rfl::Positional<std::string>> input_file;
  rfl::Description<"Host to connect to", std::string> host_name;
  bool verbose;
  rfl::Description<"Port to connect on", rfl::Short<"p", int>> port;
  rfl::Description<"Minimum level to log", std::optional<LogLevel>> log_level;
};

rfl::cli::usage<Config>("my_binary", /*detailed=*/true) returns the usage line followed
by one line per argument, with the description where one was given:

Usage: my_binary <input-file> --host-name=<value> --verbose[=<bool>] -p|--port=<value> [--log-level=<debug|info|warn>]

Arguments:
  input-file: Path to the input file
  host-name: Host to connect to
  verbose:
  port: Port to connect on
  log-level: Minimum level to log

I'd be happy to put up a PR for this if it seems useful.

Note: The proposal only covers manual generation, there's potential to auto handle a --help/--usage in future but that's out of scope.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions