From 4b02649e9fee72a66f17a1b96e90ef4f4e053aeb Mon Sep 17 00:00:00 2001 From: Pavel Belikov Date: Sat, 18 Nov 2017 15:27:23 +0300 Subject: add choices and default strings to argument description --- args.hxx | 207 +++++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 162 insertions(+), 45 deletions(-) (limited to 'args.hxx') diff --git a/args.hxx b/args.hxx index ed9325b..223525b 100644 --- a/args.hxx +++ b/args.hxx @@ -635,6 +635,21 @@ namespace args */ std::string valueClose = "]"; + /** Add choices to argument description + */ + bool addChoices = false; + + /** The prefix for choices + */ + std::string choiceString = "\nOne of: "; + + /** Add default values to argument description + */ + bool addDefault = false; + + /** The prefix for default values + */ + std::string defaultString = "\nDefault: "; }; /** Base class for all match types @@ -771,17 +786,63 @@ namespace args protected: const std::string name; bool kickout = false; + std::string defaultString; + bool defaultStringManual = false; + std::string choicesString; + bool choicesStringManual = false; + + virtual std::string GetDefaultString(const HelpParams&) const { return {}; } + + virtual std::string GetChoicesString(const HelpParams&) const { return {}; } + + virtual std::string GetNameString(const HelpParams&) const { return Name(); } + + void AddDescriptionPostfix(std::string &dest, const bool isManual, const std::string &manual, bool isGenerated, const std::string &generated, const std::string &str) const + { + if (isManual && !manual.empty()) + { + dest += str; + dest += manual; + } + else if (!isManual && isGenerated && !generated.empty()) + { + dest += str; + dest += generated; + } + } public: NamedBase(const std::string &name_, const std::string &help_, Options options_ = {}) : Base(help_, options_), name(name_) {} virtual ~NamedBase() {} - virtual std::vector> GetDescription(const HelpParams &, const unsigned indentLevel) const override + /** Sets default value string that will be added to argument description. + * Use empty string to disable it for this argument. + */ + void HelpDefault(const std::string &str) + { + defaultStringManual = true; + defaultString = str; + } + + /** Sets choices string that will be added to argument description. + * Use empty string to disable it for this argument. + */ + void HelpChoices(const std::string &str) + { + choicesStringManual = true; + choicesString = str; + } + + virtual std::vector> GetDescription(const HelpParams ¶ms, const unsigned indentLevel) const override { std::tuple description; - std::get<0>(description) = Name(); + std::get<0>(description) = GetNameString(params); std::get<1>(description) = help; std::get<2>(description) = indentLevel; + + AddDescriptionPostfix(std::get<1>(description), choicesStringManual, choicesString, params.addChoices, GetChoicesString(params), params.choiceString); + AddDescriptionPostfix(std::get<1>(description), defaultStringManual, defaultString, params.addDefault, GetDefaultString(params), params.defaultString); + return { std::move(description) }; } @@ -825,6 +886,30 @@ namespace args } }; + namespace detail + { + template + struct IsConvertableToString : std::false_type {}; + + template + struct IsConvertableToString() << std::declval(), int())> : std::true_type {}; + + template + typename std::enable_if::value, std::string>::type + ToString(const T &value) + { + std::ostringstream s; + s << value; + return s.str(); + } + template + typename std::enable_if::value, std::string>::type + ToString(const T &) + { + return {}; + } + } + /** Base class for all flag options */ class FlagBase : public NamedBase @@ -832,6 +917,33 @@ namespace args protected: const Matcher matcher; + virtual std::string GetNameString(const HelpParams ¶ms) const override + { + const std::string postfix = !params.showValueName || NumberOfArguments() == 0 ? std::string() : Name(); + std::string flags; + const auto flagStrings = matcher.GetFlagStrings(); + const bool useValueNameOnce = flagStrings.size() == 1 ? false : params.useValueNameOnce; + for (auto it = flagStrings.begin(); it != flagStrings.end(); ++it) + { + auto &flag = *it; + if (it != flagStrings.begin()) + { + flags += ", "; + } + + flags += flag.isShort ? params.shortPrefix : params.longPrefix; + flags += flag.str(); + + if (!postfix.empty() && (!useValueNameOnce || it + 1 == flagStrings.end())) + { + flags += flag.isShort ? params.shortSeparator : params.longSeparator; + flags += params.valueOpen + postfix + params.valueClose; + } + } + + return flags; + } + public: FlagBase(const std::string &name_, const std::string &help_, Matcher &&matcher_, const bool extraError_ = false) : NamedBase(name_, help_, extraError_ ? Options::Single : Options()), matcher(std::move(matcher_)) {} @@ -894,37 +1006,6 @@ namespace args : params.proglineNonrequiredOpen + res + params.proglineNonrequiredClose }; } - virtual std::vector> GetDescription(const HelpParams ¶ms, const unsigned indentLevel) const override - { - std::tuple description; - const std::string postfix = !params.showValueName || NumberOfArguments() == 0 ? std::string() : Name(); - std::string flags; - const auto flagStrings = matcher.GetFlagStrings(); - const bool useValueNameOnce = flagStrings.size() == 1 ? false : params.useValueNameOnce; - for (auto it = flagStrings.begin(); it != flagStrings.end(); ++it) - { - auto &flag = *it; - if (it != flagStrings.begin()) - { - flags += ", "; - } - - flags += flag.isShort ? params.shortPrefix : params.longPrefix; - flags += flag.str(); - - if (!postfix.empty() && (!useValueNameOnce || it + 1 == flagStrings.end())) - { - flags += flag.isShort ? params.shortSeparator : params.longSeparator; - flags += params.valueOpen + postfix + params.valueClose; - } - } - - std::get<0>(description) = std::move(flags); - std::get<1>(description) = help; - std::get<2>(description) = indentLevel; - return { std::move(description) }; - } - virtual bool HasFlag() const override { return true; @@ -2703,13 +2784,19 @@ namespace args { protected: T value; + T defaultValue; + + virtual std::string GetDefaultString(const HelpParams&) const + { + return detail::ToString(defaultValue); + } private: Reader reader; public: - ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_, Options options_): ValueFlagBase(name_, help_, std::move(matcher_), options_), value(defaultValue_) + ValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_, Options options_): ValueFlagBase(name_, help_, std::move(matcher_), options_), value(defaultValue_), defaultValue(defaultValue_) { group_.Add(*this); } @@ -2738,12 +2825,25 @@ namespace args #endif } + virtual void Reset() noexcept override + { + ValueFlagBase::Reset(); + value = defaultValue; + } + /** Get the value */ T &Get() noexcept { return value; } + + /** Get the default value + */ + const T &GetDefault() noexcept + { + return defaultValue; + } }; /** An optional argument-accepting flag class @@ -2757,24 +2857,22 @@ namespace args class ImplicitValueFlag : public ValueFlag { protected: - T implicitValue; - T defaultValue; public: ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &implicitValue_, const T &defaultValue_ = T(), Options options_ = {}) - : ValueFlag(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(implicitValue_), defaultValue(defaultValue_) + : ValueFlag(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(implicitValue_) { } ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const T &defaultValue_ = T(), Options options_ = {}) - : ValueFlag(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(defaultValue_), defaultValue(defaultValue_) + : ValueFlag(group_, name_, help_, std::move(matcher_), defaultValue_, options_), implicitValue(defaultValue_) { } ImplicitValueFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, Options options_) - : ValueFlag(group_, name_, help_, std::move(matcher_), {}, options_), implicitValue(), defaultValue() + : ValueFlag(group_, name_, help_, std::move(matcher_), {}, options_), implicitValue() { } @@ -2795,12 +2893,6 @@ namespace args ValueFlag::ParseValue(value_); } } - - virtual void Reset() noexcept override - { - this->value = defaultValue; - ValueFlag::Reset(); - } }; /** A variadic arguments accepting flag class @@ -3028,6 +3120,31 @@ namespace args T value; Reader reader; + protected: + virtual std::string GetChoicesString(const HelpParams &) const override + { + std::string res; + if (detail::IsConvertableToString::value) + { + std::vector values; + for (const auto &p : map) + { + values.push_back(detail::ToString(p.first)); + } + + std::sort(values.begin(), values.end()); + for (const auto &s : values) + { + if (!res.empty()) + { + res += ", "; + } + res += s; + } + } + return res; + } + public: MapFlag(Group &group_, const std::string &name_, const std::string &help_, Matcher &&matcher_, const Map &map_, const T &defaultValue_, Options options_): ValueFlagBase(name_, help_, std::move(matcher_), options_), map(map_), value(defaultValue_) -- cgit v1.2.1