Wrap strings which are likely long when printing help

to preserve indentation
This commit is contained in:
Martchus 2017-09-29 20:58:58 +02:00
parent 6e80640db5
commit b7b218c831
2 changed files with 64 additions and 15 deletions

View File

@ -260,6 +260,35 @@ void ArgumentReader::read(ArgumentVector &args)
} // while(argv != end) } // while(argv != end)
} }
ostream &operator<<(ostream &os, const Wrapper &wrapper)
{
// determine max. number of columns
static const TerminalSize termSize(determineTerminalSize());
const auto maxColumns = termSize.columns ? termSize.columns : numeric_limits<unsigned short>::max();
// print wrapped string considering indentation
unsigned short currentCol = wrapper.m_indentation.level;
for (const char *currentChar = wrapper.m_str; *currentChar; ++currentChar) {
const bool wrappingRequired = currentCol >= maxColumns;
if (wrappingRequired || *currentChar == '\n') {
// insert newline (TODO: wrap only at end of a word)
os << '\n';
// print indentation (if enough space)
if (wrapper.m_indentation.level < maxColumns) {
os << wrapper.m_indentation;
currentCol = wrapper.m_indentation.level;
} else {
currentCol = 0;
}
}
if (*currentChar != '\n' && (!wrappingRequired || *currentChar != ' ')) {
os << *currentChar;
++currentCol;
}
}
return os;
}
/// \brief Specifies the name of the application (used by ArgumentParser::printHelp()). /// \brief Specifies the name of the application (used by ArgumentParser::printHelp()).
const char *applicationName = nullptr; const char *applicationName = nullptr;
/// \brief Specifies the author of the application (used by ArgumentParser::printHelp()). /// \brief Specifies the author of the application (used by ArgumentParser::printHelp()).
@ -351,7 +380,8 @@ const char *Argument::firstValue() const
*/ */
void Argument::printInfo(ostream &os, unsigned char indentation) const void Argument::printInfo(ostream &os, unsigned char indentation) const
{ {
os << Indentation(indentation); Indentation ident(indentation);
os << ident;
EscapeCodes::setStyle(os, EscapeCodes::TextAttribute::Bold); EscapeCodes::setStyle(os, EscapeCodes::TextAttribute::Bold);
if (notEmpty(name())) { if (notEmpty(name())) {
if (!denotesOperation()) { if (!denotesOperation()) {
@ -372,7 +402,7 @@ void Argument::printInfo(ostream &os, unsigned char indentation) const
os << ' ' << '[' << *i << ']'; os << ' ' << '[' << *i << ']';
++valueNamesPrint; ++valueNamesPrint;
} }
if (requiredValueCount() == static_cast<size_t>(-1)) { if (requiredValueCount() == Argument::varValueCount) {
os << " ..."; os << " ...";
} else { } else {
for (; valueNamesPrint < requiredValueCount(); ++valueNamesPrint) { for (; valueNamesPrint < requiredValueCount(); ++valueNamesPrint) {
@ -380,34 +410,28 @@ void Argument::printInfo(ostream &os, unsigned char indentation) const
} }
} }
} }
indentation += 2; ident.level += 2;
if (notEmpty(description())) { if (notEmpty(description())) {
os << '\n' << Indentation(indentation) << description(); os << '\n' << ident << Wrapper(description(), ident);
} }
if (isRequired()) { if (isRequired()) {
os << '\n' << Indentation(indentation) << "particularities: mandatory"; os << '\n' << ident << "particularities: mandatory";
if (!isMainArgument()) { if (!isMainArgument()) {
os << " if parent argument is present"; os << " if parent argument is present";
} }
} }
if (environmentVariable()) { if (environmentVariable()) {
os << '\n' << Indentation(indentation) << "default environment variable: " << environmentVariable(); os << '\n' << ident << "default environment variable: " << Wrapper(environmentVariable(), ident + 30);
} }
os << '\n'; os << '\n';
for (const auto *arg : subArguments()) { for (const auto *arg : subArguments()) {
arg->printInfo(os, indentation); arg->printInfo(os, ident.level);
} }
if (notEmpty(example())) { if (notEmpty(example())) {
if (indentation == 2 && !subArguments().empty()) { if (ident.level == 2 && !subArguments().empty()) {
os << '\n'; os << '\n';
} }
os << Indentation(indentation) << "example: "; os << ident << "example: " << Wrapper(example(), ident + 9);
for (const char *c = example(); *c; ++c) {
os << *c;
if (*c == '\n') {
os << Indentation(indentation + 9);
}
}
os << '\n'; os << '\n';
} }
} }

View File

@ -1,6 +1,9 @@
#ifndef APPLICATION_UTILITIES_ARGUMENTPARSER_PRIVATE_H #ifndef APPLICATION_UTILITIES_ARGUMENTPARSER_PRIVATE_H
#define APPLICATION_UTILITIES_ARGUMENTPARSER_PRIVATE_H #define APPLICATION_UTILITIES_ARGUMENTPARSER_PRIVATE_H
#include "./argumentparser.h"
#include "./commandlineutils.h"
namespace ApplicationUtilities { namespace ApplicationUtilities {
class CPP_UTILITIES_EXPORT ArgumentReader { class CPP_UTILITIES_EXPORT ArgumentReader {
@ -31,6 +34,28 @@ public:
/// \brief Whether completion mode is enabled. In this case reading args will be continued even if an denotation is unknown (regardless of unknownArgumentBehavior()). /// \brief Whether completion mode is enabled. In this case reading args will be continued even if an denotation is unknown (regardless of unknownArgumentBehavior()).
bool completionMode; bool completionMode;
}; };
class Wrapper;
std::ostream &operator<<(std::ostream &os, const Wrapper &wrapper);
class Wrapper {
friend std::ostream &operator<<(std::ostream &os, const Wrapper &wrapper);
public:
Wrapper(const char *str, Indentation currentIndentation = Indentation());
private:
const char *const m_str;
Indentation m_indentation;
};
Wrapper::Wrapper(const char *str, Indentation currentIndentation)
: m_str(str)
, m_indentation(currentIndentation)
{
}
} // namespace ApplicationUtilities } // namespace ApplicationUtilities
#endif // APPLICATION_UTILITIES_ARGUMENTPARSER_PRIVATE_H #endif // APPLICATION_UTILITIES_ARGUMENTPARSER_PRIVATE_H