LibCore: Enable emitting markdown from ArgsParser

ArgsParser will now automatically look for an environment variable
'ARGSPARSER_EMIT_MARKDOWN', and if it is set to exactly the string "1"
(i.e. mere presence or values like "ON" or "yes" are not enough), then
ArgsParser will emit a Markdown-formatted help message, instead of the
regular help message designed for consumption through a terminal.
This commit is contained in:
Ben Wiederhake 2021-10-23 13:22:06 +02:00 committed by Linus Groh
parent d2f9fee4ab
commit 0372f051e9
Notes: sideshowbarker 2024-07-18 01:38:39 +09:00
2 changed files with 85 additions and 0 deletions

View file

@ -173,6 +173,16 @@ bool ArgsParser::parse(int argc, char* const* argv, FailureBehavior failure_beha
}
void ArgsParser::print_usage(FILE* file, const char* argv0)
{
char const* env_preference = getenv("ARGSPARSER_EMIT_MARKDOWN");
if (env_preference != nullptr && env_preference[0] == '1' && env_preference[1] == 0) {
print_usage_markdown(file, argv0);
} else {
print_usage_terminal(file, argv0);
}
}
void ArgsParser::print_usage_terminal(FILE* file, const char* argv0)
{
out(file, "Usage:\n\t\033[1m{}\033[0m", argv0);
@ -243,6 +253,79 @@ void ArgsParser::print_usage(FILE* file, const char* argv0)
}
}
void ArgsParser::print_usage_markdown(FILE* file, const char* argv0)
{
outln(file, "## Name\n\n{}", argv0);
out(file, "\n## Synopsis\n\n```sh\n$ {}", argv0);
for (auto& opt : m_options) {
if (opt.long_name != nullptr && (!strcmp(opt.long_name, "help") || !strcmp(opt.long_name, "version")))
continue;
if (opt.requires_argument)
out(file, " [{} {}]", opt.name_for_display(), opt.value_name);
else
out(file, " [{}]", opt.name_for_display());
}
for (auto& arg : m_positional_args) {
bool required = arg.min_values > 0;
bool repeated = arg.max_values > 1;
if (required && repeated)
out(file, " <{}...>", arg.name);
else if (required && !repeated)
out(file, " <{}>", arg.name);
else if (!required && repeated)
out(file, " [{}...]", arg.name);
else if (!required && !repeated)
out(file, " [{}]", arg.name);
}
outln(file, "\n```");
if (m_general_help != nullptr && m_general_help[0] != '\0') {
outln(file, "\n## Description\n\n{}", m_general_help);
}
if (!m_options.is_empty())
outln(file, "\n## Options:\n");
for (auto& opt : m_options) {
auto print_argument = [&]() {
if (opt.value_name != nullptr) {
if (opt.requires_argument)
out(file, " {}", opt.value_name);
else
out(file, " [{}]", opt.value_name);
}
};
out(file, "* ");
if (opt.short_name != '\0') {
out(file, "`-{}", opt.short_name);
print_argument();
out(file, "`");
}
if (opt.short_name != '\0' && opt.long_name != nullptr)
out(file, ", ");
if (opt.long_name != nullptr) {
out(file, "`--{}", opt.long_name);
print_argument();
out(file, "`");
}
if (opt.help_string != nullptr)
out(file, ": {}", opt.help_string);
outln(file);
}
if (!m_positional_args.is_empty())
outln(file, "\n## Arguments:\n");
for (auto& arg : m_positional_args) {
out(file, "* `{}`", arg.name);
if (arg.help_string != nullptr)
out(file, ": {}", arg.help_string);
outln(file);
}
}
void ArgsParser::print_version(FILE* file)
{
outln(file, Core::Version::SERENITY_VERSION);

View file

@ -58,6 +58,8 @@ public:
void set_general_help(const char* help_string) { m_general_help = help_string; };
void set_stop_on_first_non_option(bool stop_on_first_non_option) { m_stop_on_first_non_option = stop_on_first_non_option; }
void print_usage(FILE*, const char* argv0);
void print_usage_terminal(FILE*, const char* argv0);
void print_usage_markdown(FILE*, const char* argv0);
void print_version(FILE*);
void add_option(Option&&);