Improve CLI utils
- Add ArgumentParser::readArgs() - Add Indentation - Fix eraseLine()
This commit is contained in:
parent
4d0807de9b
commit
4c40004f0b
|
@ -12,9 +12,6 @@
|
|||
#include <sstream>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#ifdef LOGGING_ENABLED
|
||||
# include <fstream>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
using namespace std::placeholders;
|
||||
|
@ -110,9 +107,9 @@ const char *Argument::firstValue() const
|
|||
/*!
|
||||
* \brief Writes the name, the abbreviation and other information about the Argument to the give ostream.
|
||||
*/
|
||||
void Argument::printInfo(ostream &os, unsigned char indentionLevel) const
|
||||
void Argument::printInfo(ostream &os, unsigned char indentation) const
|
||||
{
|
||||
for(unsigned char i = 0; i < indentionLevel; ++i) os << ' ' << ' ';
|
||||
os << Indentation(indentation);
|
||||
EscapeCodes::setStyle(os, EscapeCodes::TextAttribute::Bold);
|
||||
if(notEmpty(name())) {
|
||||
os << '-' << '-' << name();
|
||||
|
@ -138,24 +135,25 @@ void Argument::printInfo(ostream &os, unsigned char indentionLevel) const
|
|||
}
|
||||
}
|
||||
}
|
||||
++indentionLevel;
|
||||
indentation += 2;
|
||||
if(notEmpty(description())) {
|
||||
os << endl;
|
||||
for(unsigned char i = 0; i < indentionLevel; ++i) os << ' ' << ' ';
|
||||
os << description();
|
||||
os << '\n' << Indentation(indentation) << description();
|
||||
}
|
||||
if(isRequired()) {
|
||||
os << endl;
|
||||
for(unsigned char i = 0; i < indentionLevel; ++i) os << ' ' << ' ';
|
||||
os << "This argument is required.";
|
||||
os << '\n' << Indentation(indentation) << "particularities: mandatory";
|
||||
if(!isMainArgument()) {
|
||||
os << " if parent argument is present";
|
||||
}
|
||||
}
|
||||
if(environmentVariable()) {
|
||||
os << '\n' << Indentation(indentation) << "default environment variable: " << environmentVariable();
|
||||
}
|
||||
if(notEmpty(example())) {
|
||||
for(unsigned char i = 0; i < indentionLevel; ++i) os << ' ' << ' ';
|
||||
os << endl << "Usage: " << example();
|
||||
os << '\n' << Indentation(indentation) << "\nusage: " << example();
|
||||
}
|
||||
os << endl;
|
||||
os << '\n';
|
||||
for(const auto *arg : subArguments()) {
|
||||
arg->printInfo(os, indentionLevel + 1);
|
||||
arg->printInfo(os, indentation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -365,21 +363,32 @@ void ArgumentParser::printHelp(ostream &os) const
|
|||
* \remarks
|
||||
* - The results are stored in the Argument instances assigned as main arguments and sub arguments.
|
||||
* - Calls the assigned callbacks if no constraints are violated.
|
||||
* \throws Throws Failure if the specified arguments violate the constraints defined
|
||||
* \throws Throws Failure if the specified arguments are invalid or violate the constraints defined
|
||||
* by the Argument instances.
|
||||
* \sa readArgs()
|
||||
*/
|
||||
void ArgumentParser::parseArgs(int argc, const char *const *argv)
|
||||
{
|
||||
#ifdef LOGGING_ENABLED
|
||||
{
|
||||
fstream logFile("/tmp/args.log", ios_base::out);
|
||||
for(const char *const *i = argv, *const *end = argv + argc; i != end; ++i) {
|
||||
logFile << *i << '\n';
|
||||
}
|
||||
readArgs(argc, argv);
|
||||
if(argc) {
|
||||
checkConstraints(m_mainArgs);
|
||||
invokeCallbacks(m_mainArgs);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Parses the specified command line arguments.
|
||||
* \remarks
|
||||
* - The results are stored in the Argument instances assigned as main arguments and sub arguments.
|
||||
* - In contrast to parseArgs() this method does not check whether constraints are violated and it
|
||||
* does not call any callbacks.
|
||||
* \throws Throws Failure if the specified arguments are invalid.
|
||||
* \sa readArgs()
|
||||
*/
|
||||
void ArgumentParser::readArgs(int argc, const char * const *argv)
|
||||
{
|
||||
IF_DEBUG_BUILD(verifyArgs(m_mainArgs);)
|
||||
m_actualArgc = 0;
|
||||
m_actualArgc = 0;
|
||||
if(argc) {
|
||||
// the first argument is the executable name
|
||||
m_executable = *argv;
|
||||
|
@ -395,7 +404,7 @@ void ArgumentParser::parseArgs(int argc, const char *const *argv)
|
|||
currentWordIndex = (--argc ? stringToNumber<unsigned int, string>(*(++argv)) : 0);
|
||||
++argv, --argc;
|
||||
} catch(const ConversionException &) {
|
||||
currentWordIndex = argc - 1;
|
||||
currentWordIndex = static_cast<unsigned int>(argc - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -423,8 +432,6 @@ void ArgumentParser::parseArgs(int argc, const char *const *argv)
|
|||
m_defaultArg->m_occurrences.emplace_back(0);
|
||||
}
|
||||
}
|
||||
checkConstraints(m_mainArgs);
|
||||
invokeCallbacks(m_mainArgs);
|
||||
} else {
|
||||
m_executable = nullptr;
|
||||
}
|
||||
|
|
|
@ -163,7 +163,7 @@ public:
|
|||
bool denotesOperation() const;
|
||||
void setDenotesOperation(bool denotesOperation);
|
||||
void setCallback(CallbackFunction callback);
|
||||
void printInfo(std::ostream &os, unsigned char indentionLevel = 0) const;
|
||||
void printInfo(std::ostream &os, unsigned char indentation = 0) const;
|
||||
const ArgumentVector &subArguments() const;
|
||||
void setSubArguments(const ArgumentInitializerList &subArguments);
|
||||
void addSubArgument(Argument *arg);
|
||||
|
@ -211,12 +211,15 @@ public:
|
|||
void addMainArgument(Argument *argument);
|
||||
void printHelp(std::ostream &os) const;
|
||||
void parseArgs(int argc, const char *const *argv);
|
||||
void readArgs(int argc, const char *const *argv);
|
||||
unsigned int actualArgumentCount() const;
|
||||
const char *executable() const;
|
||||
UnknownArgumentBehavior unknownArgumentBehavior() const;
|
||||
void setUnknownArgumentBehavior(UnknownArgumentBehavior behavior);
|
||||
Argument *defaultArgument() const;
|
||||
void setDefaultArgument(Argument *argument);
|
||||
void checkConstraints();
|
||||
void invokeCallbacks();
|
||||
|
||||
private:
|
||||
IF_DEBUG_BUILD(void verifyArgs(const ArgumentVector &args);)
|
||||
|
@ -767,12 +770,57 @@ inline void ArgumentParser::setDefaultArgument(Argument *argument)
|
|||
m_defaultArg = argument;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether contraints are violated.
|
||||
* \remarks Automatically called by parseArgs().
|
||||
* \throws Throws Failure if constraints are violated.
|
||||
*/
|
||||
inline void ArgumentParser::checkConstraints()
|
||||
{
|
||||
checkConstraints(m_mainArgs);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Invokes all assigned callbacks.
|
||||
* \remarks Automatically called by parseArgs().
|
||||
*/
|
||||
inline void ArgumentParser::invokeCallbacks()
|
||||
{
|
||||
invokeCallbacks(m_mainArgs);
|
||||
}
|
||||
|
||||
class CPP_UTILITIES_EXPORT HelpArgument : public Argument
|
||||
{
|
||||
public:
|
||||
HelpArgument(ArgumentParser &parser);
|
||||
};
|
||||
|
||||
class CPP_UTILITIES_EXPORT OperationArgument : public Argument
|
||||
{
|
||||
public:
|
||||
OperationArgument(const char *name, char abbreviation = '\0', const char *description = nullptr, const char *example = nullptr);
|
||||
};
|
||||
|
||||
inline OperationArgument::OperationArgument(const char *name, char abbreviation, const char *description, const char *example) :
|
||||
Argument(name, abbreviation, description, example)
|
||||
{
|
||||
setDenotesOperation(true);
|
||||
}
|
||||
|
||||
class CPP_UTILITIES_EXPORT ConfigValueArgument : public Argument
|
||||
{
|
||||
public:
|
||||
ConfigValueArgument(const char *name, char abbreviation = '\0', const char *description = nullptr, std::initializer_list<const char *> valueNames = std::initializer_list<const char *>());
|
||||
};
|
||||
|
||||
inline ConfigValueArgument::ConfigValueArgument(const char *name, char abbreviation, const char *description, std::initializer_list<const char *> valueNames) :
|
||||
Argument(name, abbreviation, description)
|
||||
{
|
||||
setCombinable(true);
|
||||
setRequiredValueCount(valueNames.size());
|
||||
setValueNames(valueNames);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // APPLICATION_UTILITIES_ARGUMENTPARSER_H
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "../global.h"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace ApplicationUtilities {
|
||||
|
||||
/*!
|
||||
|
@ -24,6 +26,34 @@ void CPP_UTILITIES_EXPORT startConsole();
|
|||
# define CMD_UTILS_START_CONSOLE
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief The Indent class allows printing indentation conveniently, eg. cout << Ident(4) << ...
|
||||
*/
|
||||
class CPP_UTILITIES_EXPORT Indentation
|
||||
{
|
||||
public:
|
||||
Indentation(unsigned char level = 4, char character = ' ') :
|
||||
level(level),
|
||||
character(character)
|
||||
{}
|
||||
|
||||
Indentation operator +(unsigned char level)
|
||||
{
|
||||
return Indentation(this->level + level, character);
|
||||
}
|
||||
|
||||
unsigned char level;
|
||||
char character;
|
||||
};
|
||||
|
||||
inline CPP_UTILITIES_EXPORT std::ostream &operator<< (std::ostream &out, Indentation indentation)
|
||||
{
|
||||
for(unsigned char i = 0; i < indentation.level; ++i) {
|
||||
out << indentation.character;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace ApplicationUtilities
|
||||
|
||||
#endif // APPLICATIONUTILITIES_COMMANDLINEUTILS_H
|
||||
|
|
|
@ -102,7 +102,7 @@ inline void eraseDisplay(std::ostream &stream)
|
|||
|
||||
inline void eraseLine(std::ostream &stream)
|
||||
{
|
||||
stream << "\e[K";
|
||||
stream << "\33[2K";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue