From 34d259d892578be2d0768498f300f775d6713a51 Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Sat, 25 May 2019 09:44:06 +0200 Subject: [PATCH 1/3] Sort names on argument construction --- include/argparse.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index 067d490..d61c4c4 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -84,7 +84,11 @@ public: explicit Argument(Args... args) : mNames({std::move(args)...}) , mIsOptional((is_optional(args) || ...)) - {} + { + std::sort(mNames.begin(), mNames.end(), [](const auto& lhs, const auto& rhs) { + return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size(); + }); + } Argument& help(std::string aHelp) { mHelp = std::move(aHelp); @@ -401,10 +405,6 @@ class ArgumentParser { for (const auto & mOptionalArgument : mOptionalArguments) { size_t tCurrentLength = 0; auto tNames = mOptionalArgument->mNames; - std::sort(tNames.begin(), tNames.end(), - [](const std::string& lhs, const std::string& rhs) { - return lhs.size() == rhs.size() ? lhs < rhs : lhs.size() < rhs.size(); - }); for (size_t j = 0; j < tNames.size() - 1; j++) { auto tCurrentName = tNames[j]; stream << tCurrentName; From 67e535e1719417e93881a62786b37eead63b3fa4 Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Sat, 25 May 2019 20:01:04 +0200 Subject: [PATCH 2/3] Move print_help logic into Argument --- include/argparse.hpp | 61 +++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 41 deletions(-) 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)); } From 6d46876f5cb461afc664ae7ceec2ffb90e0497b0 Mon Sep 17 00:00:00 2001 From: Stephan van Veen Date: Sat, 25 May 2019 20:07:24 +0200 Subject: [PATCH 3/3] Do some cleanup in print_help --- include/argparse.hpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/include/argparse.hpp b/include/argparse.hpp index df33ccc..f338f58 100644 --- a/include/argparse.hpp +++ b/include/argparse.hpp @@ -381,26 +381,25 @@ class ArgumentParser { std::string print_help() { std::stringstream stream; stream << std::left; - stream << "Usage: " << mProgramName << " [options]"; + stream << "Usage: " << mProgramName << " [options] "; size_t tLongestArgumentLength = get_length_of_longest_argument(); - for (size_t i = 0; i < mPositionalArguments.size(); i++) { - auto tNames = mPositionalArguments[i]->mNames; - stream << (i == 0 ? " " : "") << tNames[0] << " "; + for (const auto& argument : mPositionalArguments) { + stream << argument->mNames.front() << " "; } stream << "\n\n"; if (!mPositionalArguments.empty()) stream << "Positional arguments:\n"; + for (const auto& mPositionalArgument : mPositionalArguments) { stream.width(tLongestArgumentLength); stream << *mPositionalArgument; } - if (!mOptionalArguments.empty() && !mPositionalArguments.empty()) - stream << "\nOptional arguments:\n"; - else if (!mOptionalArguments.empty()) - stream << "Optional arguments:\n"; + if (!mOptionalArguments.empty()) + stream << (mPositionalArguments.empty() ? "" : "\n") << "Optional arguments:\n"; + for (const auto & mOptionalArgument : mOptionalArguments) { stream.width(tLongestArgumentLength); stream << *mOptionalArgument;