From 4b200a6d195470bcbfc280d92222e8573644a8c0 Mon Sep 17 00:00:00 2001 From: Pavel Belikov Date: Tue, 14 Nov 2017 19:08:41 +0300 Subject: add more HelpParams for options --- args.hxx | 44 +++++++++++++++++++++++++++++++++------ test.cxx | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 6 deletions(-) diff --git a/args.hxx b/args.hxx index c595ab7..655ef12 100644 --- a/args.hxx +++ b/args.hxx @@ -571,6 +571,26 @@ namespace args /** Use short flags in program lines when possible */ bool proglinePreferShortFlags = false; + + /** Program line prefix + */ + std::string usageString; + + /** String shown in help before flags descriptions + */ + std::string optionsString = "OPTIONS:"; + + /** Display value name after all the long and short flags + */ + bool useValueNameOnce = false; + + /** Show value name + */ + bool showValueName = true; + + /** Add newline before flag description + */ + bool addNewlineBeforeDescription = false; }; /** Base class for all match types @@ -832,9 +852,11 @@ namespace args virtual std::vector> GetDescription(const HelpParams ¶ms, const unsigned indentLevel) const override { std::tuple description; - const std::string postfix = NumberOfArguments() == 0 ? std::string() : Name(); + const std::string postfix = !params.showValueName || NumberOfArguments() == 0 ? std::string() : Name(); std::string flags; - for (const auto &flag : matcher.GetFlagStrings()) + const auto flagStrings = matcher.GetFlagStrings(); + const bool useValueNameOnce = flagStrings.size() == 1 ? false : params.useValueNameOnce; + for (const auto &flag : flagStrings) { if (!flags.empty()) { @@ -843,12 +865,18 @@ namespace args flags += flag.isShort ? params.shortPrefix : params.longPrefix; flags += flag.str(); - if (!postfix.empty()) + if (!postfix.empty() && !useValueNameOnce) { flags += flag.isShort ? params.shortSeparator : params.longSeparator; flags += "[" + postfix + "]"; } } + + if (!postfix.empty() && useValueNameOnce) + { + flags += " [" + postfix + "]"; + } + std::get<0>(description) = std::move(flags); std::get<1>(description) = help; std::get<2>(description) = indentLevel; @@ -2236,7 +2264,7 @@ namespace args const bool hasarguments = command.HasPositional(); std::ostringstream prognameline; - prognameline << Prog(); + prognameline << helpParams.usageString << Prog(); for (const std::string &posname: command.GetProgramLine(helpParams)) { @@ -2268,7 +2296,11 @@ namespace args bool lastDescriptionIsNewline = false; - help_ << std::string(helpParams.progindent, ' ') << "OPTIONS:\n\n"; + if (!helpParams.optionsString.empty()) + { + help_ << std::string(helpParams.progindent, ' ') << helpParams.optionsString << "\n\n"; + } + for (const auto &desc: command.GetDescription(helpParams, 0)) { lastDescriptionIsNewline = std::get<0>(desc).empty() && std::get<1>(desc).empty(); @@ -2289,7 +2321,7 @@ namespace args auto infoit = std::begin(info); // groupindent is on both sides of this inequality, and therefore can be removed - if ((helpParams.flagindent + flagssize + helpParams.gutter) > helpParams.helpindent || infoit == std::end(info)) + if ((helpParams.flagindent + flagssize + helpParams.gutter) > helpParams.helpindent || infoit == std::end(info) || helpParams.addNewlineBeforeDescription) { help_ << '\n'; } else diff --git a/test.cxx b/test.cxx index 71f1fb7..2c4cd6e 100644 --- a/test.cxx +++ b/test.cxx @@ -964,6 +964,78 @@ TEST_CASE("Matcher validation works as expected", "[args]") REQUIRE_THROWS_AS(args::ValueFlag(parser, "", "", {}), args::UsageError); } +TEST_CASE("HelpParams work as expected", "[args]") +{ + args::ArgumentParser p("parser"); + args::ValueFlag f(p, "name", "description", {'f', "foo"}); + args::ValueFlag g(p, "name", "description", {'g'}); + p.Prog("prog"); + + REQUIRE(p.Help() == R"( prog {OPTIONS} + + parser + + OPTIONS: + + -f[name], --foo=[name] description + -g[name] description + +)"); + + p.helpParams.usageString = "usage: "; + p.helpParams.optionsString = "Options"; + p.helpParams.useValueNameOnce = true; + REQUIRE(p.Help() == R"( usage: prog {OPTIONS} + + parser + + Options + + -f, --foo [name] description + -g[name] description + +)"); + + p.helpParams.showValueName = false; + p.helpParams.optionsString = {}; + REQUIRE(p.Help() == R"( usage: prog {OPTIONS} + + parser + + -f, --foo description + -g description + +)"); + + p.helpParams.helpindent = 12; + p.helpParams.optionsString = "Options"; + REQUIRE(p.Help() == R"( usage: prog {OPTIONS} + + parser + + Options + + -f, --foo + description + -g description + +)"); + + p.helpParams.addNewlineBeforeDescription = true; + REQUIRE(p.Help() == R"( usage: prog {OPTIONS} + + parser + + Options + + -f, --foo + description + -g + description + +)"); +} + #undef ARGS_HXX #define ARGS_TESTNAMESPACE #define ARGS_NOEXCEPT -- cgit v1.2.1 From 01955238036ac546ba1e488546101f65d213f4dd Mon Sep 17 00:00:00 2001 From: Pavel Belikov Date: Tue, 14 Nov 2017 21:33:31 +0300 Subject: add leading whitespace support in Wrap --- args.hxx | 39 +++++++++++++++++++++++++-------------- test.cxx | 32 +++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 15 deletions(-) diff --git a/args.hxx b/args.hxx index 655ef12..a381435 100644 --- a/args.hxx +++ b/args.hxx @@ -114,37 +114,48 @@ namespace args std::istringstream stream(in); std::vector output; - std::ostringstream line; - std::string::size_type linesize = 0; + std::string line; + bool empty = true; + + for (char c : in) + { + if (!isspace(c)) + { + break; + } + line += c; + } + while (stream) { std::string item; stream >> item; auto itemsize = Glyphs(item); - if ((linesize + 1 + itemsize) > currentwidth) + if ((line.length() + 1 + itemsize) > currentwidth) { - if (linesize > 0) + if (!empty) { - output.push_back(line.str()); - line.str(std::string()); - linesize = 0; + output.push_back(line); + line.clear(); + empty = true; currentwidth = width; } } if (itemsize > 0) { - if (linesize) + if (!empty) { - ++linesize; - line << " "; + line += ' '; } - line << item; - linesize += itemsize; + + line += item; + empty = false; } } - if (linesize > 0) + + if (!empty) { - output.push_back(line.str()); + output.push_back(line); } return output; } diff --git a/test.cxx b/test.cxx index 2c4cd6e..991d98e 100644 --- a/test.cxx +++ b/test.cxx @@ -968,7 +968,7 @@ TEST_CASE("HelpParams work as expected", "[args]") { args::ArgumentParser p("parser"); args::ValueFlag f(p, "name", "description", {'f', "foo"}); - args::ValueFlag g(p, "name", "description", {'g'}); + args::ValueFlag g(p, "name", "description\n d1\n d2", {'g'}); p.Prog("prog"); REQUIRE(p.Help() == R"( prog {OPTIONS} @@ -979,6 +979,8 @@ TEST_CASE("HelpParams work as expected", "[args]") -f[name], --foo=[name] description -g[name] description + d1 + d2 )"); @@ -993,6 +995,8 @@ TEST_CASE("HelpParams work as expected", "[args]") -f, --foo [name] description -g[name] description + d1 + d2 )"); @@ -1004,6 +1008,8 @@ TEST_CASE("HelpParams work as expected", "[args]") -f, --foo description -g description + d1 + d2 )"); @@ -1018,6 +1024,8 @@ TEST_CASE("HelpParams work as expected", "[args]") -f, --foo description -g description + d1 + d2 )"); @@ -1032,8 +1040,30 @@ TEST_CASE("HelpParams work as expected", "[args]") description -g description + d1 + d2 )"); + + args::ValueFlag e(p, "name", "some reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaally loooooooooooooooooooooooooooong description", {'e'}); + REQUIRE(p.Help() == R"( usage: prog {OPTIONS} + + parser + + Options + + -f, --foo + description + -g + description + d1 + d2 + -e + some reaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaally + loooooooooooooooooooooooooooong description + +)"); + } #undef ARGS_HXX -- cgit v1.2.1 From 029dd296063c0810d40830567216c92b8cca0f79 Mon Sep 17 00:00:00 2001 From: Pavel Belikov Date: Tue, 14 Nov 2017 22:47:49 +0300 Subject: fix HelpParams::showValueNameOnce --- args.hxx | 13 +++++-------- test.cxx | 2 +- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/args.hxx b/args.hxx index a381435..7af24c4 100644 --- a/args.hxx +++ b/args.hxx @@ -867,27 +867,24 @@ namespace args std::string flags; const auto flagStrings = matcher.GetFlagStrings(); const bool useValueNameOnce = flagStrings.size() == 1 ? false : params.useValueNameOnce; - for (const auto &flag : flagStrings) + for (auto it = flagStrings.begin(); it != flagStrings.end(); ++it) { - if (!flags.empty()) + auto &flag = *it; + if (it != flagStrings.begin()) { flags += ", "; } flags += flag.isShort ? params.shortPrefix : params.longPrefix; flags += flag.str(); - if (!postfix.empty() && !useValueNameOnce) + + if (!postfix.empty() && (!useValueNameOnce || it + 1 == flagStrings.end())) { flags += flag.isShort ? params.shortSeparator : params.longSeparator; flags += "[" + postfix + "]"; } } - if (!postfix.empty() && useValueNameOnce) - { - flags += " [" + postfix + "]"; - } - std::get<0>(description) = std::move(flags); std::get<1>(description) = help; std::get<2>(description) = indentLevel; diff --git a/test.cxx b/test.cxx index 991d98e..1189f97 100644 --- a/test.cxx +++ b/test.cxx @@ -993,7 +993,7 @@ TEST_CASE("HelpParams work as expected", "[args]") Options - -f, --foo [name] description + -f, --foo=[name] description -g[name] description d1 d2 -- cgit v1.2.1