commit f329d651df3844b0df7a5c997c11004114d70c4f
parent 3cdb743888aa56c5e5301858e24973284a311946
Author: Dimitrije Dobrota <mail@dimitrijedobrota.com>
Date: Sat, 8 Jun 2024 22:58:50 +0200
Add groups to options for better --help
Diffstat:
M | args.hpp | | | 42 | ++++++++++++++++++++++++++++++++++-------- |
M | demo.cpp | | | 13 | +++++++++---- |
2 files changed, 43 insertions(+), 12 deletions(-)
diff --git a/args.hpp b/args.hpp
@@ -19,6 +19,7 @@ class Parser {
const char *arg;
const uint8_t options;
const char *message;
+ const int group;
};
enum Option {
@@ -47,11 +48,17 @@ class Parser {
Parser(argp_t *argp) : argp(argp) {
bool hidden = false;
- int key_last = 0;
+ int group = 0, key_last = 0;
for (int i = 0; true; i++) {
const auto &opt = argp->options[i];
- if (!opt.name && !opt.key) break;
+ if (!opt.name && !opt.key && !opt.message) break;
+
+ if (!opt.name && !opt.key) {
+ group = opt.group ? opt.group : group + 1;
+ help_entries.emplace_back(nullptr, opt.message, group);
+ continue;
+ }
if (!opt.key) {
if ((opt.options & ALIAS) == 0) {
@@ -84,7 +91,8 @@ class Parser {
if ((opt.options & ALIAS) == 0) {
if ((hidden = opt.options & Option::HIDDEN)) continue;
- help_entries.emplace_back(opt.arg, opt.message, arg_opt);
+ help_entries.emplace_back(opt.arg, opt.message, group,
+ arg_opt);
if (opt.name) help_entries.back().push(opt.name);
if (std::isprint(opt.key)) {
@@ -109,12 +117,11 @@ class Parser {
std::sort(begin(help_entries), end(help_entries));
- help_entries.emplace_back(nullptr, "Give this help list", false);
+ help_entries.emplace_back(nullptr, "Give this help list", -1);
help_entries.back().push("help");
help_entries.back().push('?');
- help_entries.emplace_back(nullptr, "Give a short usage message",
- false);
+ help_entries.emplace_back(nullptr, "Give a short usage message", -1);
help_entries.back().push("usage");
}
@@ -281,15 +288,25 @@ class Parser {
const char *arg;
const char *message;
+ int group;
bool opt;
- help_entry_t(const char *arg, const char *message, bool opt)
- : arg(arg), message(message), opt(opt) {}
+ help_entry_t(const char *arg, const char *message, int group,
+ bool opt = false)
+ : arg(arg), message(message), group(group), opt(opt) {}
void push(char sh) { opt_short.push_back(sh); }
void push(const char *lg) { opt_long.push_back(lg); }
bool operator<(const help_entry_t &rhs) const {
+ if (group && rhs.group) {
+ if (group < 0 && rhs.group < 0) return group < rhs.group;
+ if (group < 0 || rhs.group < 0) return rhs.group < 0;
+ return group < rhs.group;
+ }
+
+ if (group || rhs.group) return !group;
+
if (opt_long.empty() && rhs.opt_long.empty())
return opt_short.front() < rhs.opt_short.front();
@@ -331,9 +348,18 @@ class Parser {
if (!m1.empty()) std::cout << "\n" << m1;
std::cout << "\n\n";
+ bool first = true;
for (const auto &entry : help_entries) {
bool prev = false;
+ if (entry.opt_short.empty() && entry.opt_long.empty()) {
+ if (!first) std::cout << "\n";
+ if (entry.message) std::cout << " " << entry.message << ":\n";
+ continue;
+ }
+
+ first = false;
+
std::string message = " ";
for (const char c : entry.opt_short) {
if (!prev) prev = true;
diff --git a/demo.cpp b/demo.cpp
@@ -41,12 +41,17 @@ using enum Parser::Option;
// clang-format off
static const Parser::option_t options[] = {
- { "output", 'o', "file", ARG_OPTIONAL, "Output file, default stdout"},
- { 0, 'i', "file", 0, "Input file"},
- { "debug", 777, 0, 0, "Execute program in debugging mode"},
- { "hex", 'h', 0, 0, "Output in hex format"},
+ { 0, 'R', 0, 0, "random 0-group option"},
+ { 0, 0, 0, 0, "Program mode", 1},
+ { "hex", 'h', 0, 0, "Output in hex format"},
{"hexadecimal", 0, 0, ALIAS | HIDDEN},
{"relocatable", 'r', 0, 0, "Output in relocatable format"},
+ { 0, 0, 0, 0, "For developers", 4},
+ { "debug", 777, 0, 0, "Enable debugging mode"},
+ { 0, 0, 0, 0, "Input/output", 3},
+ { "output", 'o', "file", ARG_OPTIONAL, "Output file, default stdout"},
+ { 0, 'i', "file", 0, "Input file"},
+ { 0, 0, 0, 0, "Informational Options", -1},
{0},
};
// clang-format on