p-ranav/structopt

Ambiguous help, short name duplicates

rysson opened this issue · 4 comments

I seems that first character of long-name is used in a short-name.

In case:

struct Options
{
  // oositional flags
  // ./main [--bar] [--baz]
  std::optional<bool> bar = false;
  std::optional<bool> baz = false;
};
STRUCTOPT(Options, bar, baz);

Help prints:

USAGE: my_app [FLAGS] [OPTIONS] 

FLAGS:
    -b, --bar
    -b, --baz

OPTIONS:
    -h, --help <help>
    -v, --version <version>

There are -b twice. Ii can be confusing, specially with many another options between duplicates.

BTW, it's possible (or is planned) to set flag name (short name)?

Maybe something like

std::optional<bool> baz = false;
...
STRUCTOPT(Options, bar, structopt::short(baz, "z"));

I've been wondering for awhile how to solve this - being able to provide short names, help descriptions etc.

Using it as part of the STRUCTOPT macro makes sense. Thanks for the suggestion!

I like this idea. Custom help strings can be added to individual arguments this way too.

I would like to +1 this idea. Any idea if it will get implemented?

You should check out my fork of visit_struct : https://github.com/sixprime/visit_struct.

I added the capability of adding metadata to any struct member being visited. This can technically allow things such as :

struct my_type {
  int a = 666;
  float b = 42.0f;
  std::string c;
};

struct arg_opt {
    std::optional<std::string> help;
    int priority = 0;
};

struct arg_special {
    bool is_valid = false;
};

VISITABLE_STRUCT_METADATA(my_type,
  METADATA(a, arg_opt { .help = "help message for A", .priority = 1 }),
  METADATA(b, arg_opt { .help = "help message for B", .priority = 2 }),
  METADATA(c, arg_special { .is_valid = true }));

struct debug_printer {
  template <typename T>
    void operator()(const char* name, const T& value, const arg_opt& ao) {
        std::cerr << name << ": " << value << " [ desc=" << ao.help.value_or("<none>")
            << ", priority=" << ao.priority << "]" << std::endl;
    }

    template <typename T, typename M>
    void operator()(const char* name, const T& value, const M& /*metadata*/) {
        std::cerr << name << ": " << value << std::endl;
    }
};

void debug_print(const my_type & my_struct) {
  visit_struct::for_each(my_struct, debug_printer{});
}

Now, in theory, this can open the door to custom help messages, argument groups, custom short names, etc. And there could be many other improvements as well.

Only major difference is that I really wanted to use designated initializers, and that's only available for C++20 and above.