From 0372f051e90ece2044ab99b89803008cfc605e93 Mon Sep 17 00:00:00 2001 From: Ben Wiederhake Date: Sat, 23 Oct 2021 13:22:06 +0200 Subject: [PATCH] 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. --- Userland/Libraries/LibCore/ArgsParser.cpp | 83 +++++++++++++++++++++++ Userland/Libraries/LibCore/ArgsParser.h | 2 + 2 files changed, 85 insertions(+) diff --git a/Userland/Libraries/LibCore/ArgsParser.cpp b/Userland/Libraries/LibCore/ArgsParser.cpp index 139eba3439..31ef98803d 100644 --- a/Userland/Libraries/LibCore/ArgsParser.cpp +++ b/Userland/Libraries/LibCore/ArgsParser.cpp @@ -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); diff --git a/Userland/Libraries/LibCore/ArgsParser.h b/Userland/Libraries/LibCore/ArgsParser.h index b9ae39a8a4..465e155c08 100644 --- a/Userland/Libraries/LibCore/ArgsParser.h +++ b/Userland/Libraries/LibCore/ArgsParser.h @@ -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&&);