Allow marking argument as deprecated

This commit is contained in:
Martchus 2019-05-04 23:14:43 +02:00
parent 6d4e13f2dc
commit b0b92ff1bf
3 changed files with 56 additions and 12 deletions

View File

@ -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);
}
}
}

View File

@ -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()

View File

@ -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