diff --git a/include/argparse.hpp b/include/argparse.hpp index d61c4c4..df33ccc 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -41,6 +41,8 @@ SOFTWARE. #include #include #include +#include +#include namespace argparse { @@ -168,6 +170,18 @@ public: } } + size_t get_arguments_length() const { + return std::accumulate(std::begin(mNames), std::end(mNames), size_t(0), [](const auto& sum, const auto& s) { + return sum + s.size() + 1; // +1 for space between names + }); + } + + friend std::ostream& operator<<(std::ostream& stream, const Argument& argument) { + std::stringstream nameStream; + std::copy(std::begin(argument.mNames), std::end(argument.mNames), std::ostream_iterator(nameStream, " ")); + return stream << nameStream.str() << "\t" << argument.mHelp << "\n"; + } + template bool operator!=(const T& aRhs) const { @@ -366,6 +380,7 @@ class ArgumentParser { // TODO: support user-defined help and usage messages for the ArgumentParser std::string print_help() { std::stringstream stream; + stream << std::left; stream << "Usage: " << mProgramName << " [options]"; size_t tLongestArgumentLength = get_length_of_longest_argument(); @@ -378,24 +393,8 @@ class ArgumentParser { if (!mPositionalArguments.empty()) stream << "Positional arguments:\n"; for (const auto& mPositionalArgument : mPositionalArguments) { - size_t tCurrentLength = 0; - auto tNames = mPositionalArgument->mNames; - for (size_t j = 0; j < tNames.size() - 1; j++) { - auto tCurrentName = tNames[j]; - stream << tCurrentName; - stream << ", "; - tCurrentLength += tCurrentName.length() + 2; - } - stream << tNames[tNames.size() - 1]; - tCurrentLength += tNames[tNames.size() - 1].length(); - if (tCurrentLength < tLongestArgumentLength) - stream << std::string((tLongestArgumentLength - tCurrentLength) + 2, ' '); - else if (tCurrentLength == tLongestArgumentLength) - stream << std::string(2, ' '); - else - stream << std::string((tCurrentLength - tLongestArgumentLength) + 2, ' '); - - stream << mPositionalArgument->mHelp << "\n"; + stream.width(tLongestArgumentLength); + stream << *mPositionalArgument; } if (!mOptionalArguments.empty() && !mPositionalArguments.empty()) @@ -403,24 +402,8 @@ class ArgumentParser { else if (!mOptionalArguments.empty()) stream << "Optional arguments:\n"; for (const auto & mOptionalArgument : mOptionalArguments) { - size_t tCurrentLength = 0; - auto tNames = mOptionalArgument->mNames; - for (size_t j = 0; j < tNames.size() - 1; j++) { - auto tCurrentName = tNames[j]; - stream << tCurrentName; - stream << ", "; - tCurrentLength += tCurrentName.length() + 2; - } - stream << tNames[tNames.size() - 1]; - tCurrentLength += tNames[tNames.size() - 1].length(); - if (tCurrentLength < tLongestArgumentLength) - stream << std::string((tLongestArgumentLength - tCurrentLength) + 2, ' '); - else if (tCurrentLength == tLongestArgumentLength) - stream << std::string(2, ' '); - else - stream << std::string((tCurrentLength - tLongestArgumentLength) + 2, ' '); - - stream << mOptionalArgument->mHelp << "\n"; + stream.width(tLongestArgumentLength); + stream << *mOptionalArgument; } std::cout << stream.str(); @@ -493,11 +476,7 @@ class ArgumentParser { std::vector argumentLengths(mArgumentMap.size()); std::transform(std::begin(mArgumentMap), std::end(mArgumentMap), std::begin(argumentLengths), [](const auto& argPair) { const auto& [key, arg] = argPair; - const auto& names = arg->mNames; - auto maxLength = std::accumulate(std::begin(names), std::end(names), std::string::size_type{0}, [](const auto& sum, const auto& s) { - return sum + s.size() + 2; // +2 for ", " - }); - return maxLength - 2; // -2 since the last one doesn't need ", " + return arg->get_arguments_length(); }); return *std::max_element(std::begin(argumentLengths), std::end(argumentLengths)); }