From b0b92ff1bfa14b3a76144adbf159028e61758fd3 Mon Sep 17 00:00:00 2001 From: Martchus Date: Sat, 4 May 2019 23:14:43 +0200 Subject: [PATCH] Allow marking argument as deprecated --- application/argumentparser.cpp | 35 +++++++++++++++++++++++----------- application/argumentparser.h | 29 ++++++++++++++++++++++++++++ tests/argumentparsertests.cpp | 4 +++- 3 files changed, 56 insertions(+), 12 deletions(-) diff --git a/application/argumentparser.cpp b/application/argumentparser.cpp index 5fad328..82b4388 100644 --- a/application/argumentparser.cpp +++ b/application/argumentparser.cpp @@ -461,6 +461,7 @@ Argument::Argument(const char *name, char abbreviation, const char *description, , m_maxOccurrences(1) , m_requiredValueCount(0) , m_flags(Flags::None) + , m_deprecatedBy(nullptr) , m_isMainArg(false) , m_valueCompletionBehavior(ValueCompletionBehavior::PreDefinedValues | ValueCompletionBehavior::Files | ValueCompletionBehavior::Directories | ValueCompletionBehavior::FileSystemIfNoPreDefinedValues) @@ -498,6 +499,9 @@ const char *Argument::firstValue() const */ void Argument::printInfo(ostream &os, unsigned char indentation) const { + if (isDeprecated()) { + return; + } Indentation ident(indentation); os << ident; EscapeCodes::setStyle(os, EscapeCodes::TextAttribute::Bold); @@ -542,11 +546,16 @@ void Argument::printInfo(ostream &os, unsigned char indentation) const os << '\n' << ident << "default environment variable: " << Wrapper(environmentVariable(), ident + 30); } os << '\n'; - for (const auto *arg : subArguments()) { + bool hasSubArgs = false; + for (const auto *const arg : subArguments()) { + if (arg->isDeprecated()) { + continue; + } + hasSubArgs = true; arg->printInfo(os, ident.level); } if (notEmpty(example())) { - if (ident.level == 2 && !subArguments().empty()) { + if (ident.level == 2 && hasSubArgs) { os << '\n'; } os << ident << "example: " << Wrapper(example(), ident + 9); @@ -735,6 +744,7 @@ void ArgumentParser::setMainArguments(const ArgumentInitializerList &mainArgumen { if (!mainArguments.size()) { m_mainArgs.clear(); + return; } for (Argument *arg : mainArguments) { arg->m_isMainArg = true; @@ -812,26 +822,29 @@ void ArgumentParser::printHelp(ostream &os) const // split top-level operations and other configurations os << "Available operations:"; for (const Argument *const arg : m_mainArgs) { - if (arg->denotesOperation() && strcmp(arg->name(), "help")) { - os << '\n'; - arg->printInfo(os); + if (!arg->denotesOperation() || arg->isDeprecated() || !strcmp(arg->name(), "help")) { + continue; } + os << '\n'; + arg->printInfo(os); } os << "\nAvailable top-level options:"; for (const Argument *const arg : m_mainArgs) { - if (!arg->denotesOperation() && strcmp(arg->name(), "help")) { - os << '\n'; - arg->printInfo(os); + if (arg->denotesOperation() || arg->isDeprecated() || !strcmp(arg->name(), "help")) { + continue; } + os << '\n'; + arg->printInfo(os); } } else { // just show all args if no operations are available os << "Available arguments:"; for (const Argument *const arg : m_mainArgs) { - if (strcmp(arg->name(), "help")) { - os << '\n'; - arg->printInfo(os); + if (arg->isDeprecated() || !strcmp(arg->name(), "help")) { + continue; } + os << '\n'; + arg->printInfo(os); } } } diff --git a/application/argumentparser.h b/application/argumentparser.h index cb80fd2..47f88f7 100644 --- a/application/argumentparser.h +++ b/application/argumentparser.h @@ -265,6 +265,7 @@ public: Combinable = 0x1, Implicit = 0x2, Operation = 0x4, + Deprecated = 0x8, }; Argument(const char *name, char abbreviation = '\0', const char *description = nullptr, const char *example = nullptr); @@ -333,6 +334,9 @@ public: std::size_t index(std::size_t occurrence) const; std::size_t minOccurrences() const; std::size_t maxOccurrences() const; + bool isDeprecated() const; + const Argument *deprecatedBy() const; + void markAsDeprecated(const Argument *deprecatedBy = nullptr); bool isMainArgument() const; bool isParentPresent() const; Argument *conflictsWithArgument() const; @@ -367,6 +371,7 @@ private: ArgumentVector m_subArgs; CallbackFunction m_callbackFunction; ArgumentVector m_parents; + const Argument *m_deprecatedBy; bool m_isMainArg; ValueCompletionBehavior m_valueCompletionBehavior; const char *m_preDefinedCompletionValues; @@ -766,6 +771,30 @@ inline std::size_t Argument::maxOccurrences() const return m_maxOccurrences; } +inline bool Argument::isDeprecated() const +{ + return m_flags & Flags::Deprecated; +} + +/*! + * \brief Returns the argument which obsoletes this argument. + */ +inline const Argument *Argument::deprecatedBy() const +{ + return m_deprecatedBy; +} + +/*! + * \brief Marks the argument as deprecated. + * + * If another argument should be used instead, specify it via \a deprecatedBy. + */ +inline void Argument::markAsDeprecated(const Argument *deprecatedBy) +{ + setFlags(Flags::Deprecated, true); + m_deprecatedBy = deprecatedBy; +} + /*! * \brief Sets the allowed number of occurrences. * \sa minOccurrences() diff --git a/tests/argumentparsertests.cpp b/tests/argumentparsertests.cpp index c5cc060..0c4d4f3 100644 --- a/tests/argumentparsertests.cpp +++ b/tests/argumentparsertests.cpp @@ -767,8 +767,10 @@ void ArgumentParserTests::testHelp() envArg.setEnvironmentVariable("FILES"); envArg.setRequiredValueCount(2); envArg.appendValueName("file"); + Argument deprecatedArg("deprecated"); + deprecatedArg.markAsDeprecated(&filesArg); parser.helpArg().setRequired(true); - parser.setMainArguments({ &verboseArg, &filesArg, &envArg, &parser.noColorArg(), &parser.helpArg() }); + parser.setMainArguments({ &verboseArg, &filesArg, &envArg, &deprecatedArg, &parser.noColorArg(), &parser.helpArg() }); applicationInfo.dependencyVersions = { "somelib", "some other lib" }; // parse args and assert output