Merge pull request #44 from lichray/help-stream

Help stream
This commit is contained in:
Pranav Srinivas Kumar 2019-11-13 08:36:58 -06:00 committed by GitHub
commit bda0866320
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 84 additions and 45 deletions

View File

@ -58,7 +58,7 @@ int main(int argc, char *argv[]) {
} }
catch (const std::runtime_error& err) { catch (const std::runtime_error& err) {
std::cout << err.what() << std::endl; std::cout << err.what() << std::endl;
program.print_help(); std::cout << program;
exit(0); exit(0);
} }
@ -100,7 +100,7 @@ try {
} }
catch (const std::runtime_error& err) { catch (const std::runtime_error& err) {
std::cout << err.what() << std::endl; std::cout << err.what() << std::endl;
program.print_help(); std::cout << program;
exit(0); exit(0);
} }
@ -161,7 +161,7 @@ try {
} }
catch (const std::runtime_error& err) { catch (const std::runtime_error& err) {
std::cout << err.what() << std::endl; std::cout << err.what() << std::endl;
program.print_help(); std::cout << program;
exit(0); exit(0);
} }
@ -194,7 +194,7 @@ try {
} }
catch (const std::runtime_error& err) { catch (const std::runtime_error& err) {
std::cout << err.what() << std::endl; std::cout << err.what() << std::endl;
program.print_help(); std::cout << program;
exit(0); exit(0);
} }
@ -221,7 +221,7 @@ The square of 4 is 16
### Printing Help ### Printing Help
```ArgumentParser.print_help()``` print a help message, including the program usage and information about the arguments registered with the ArgumentParser. For the previous example, here's the default help message: `std::cout << program` prints a help message, including the program usage and information about the arguments registered with the `ArgumentParser`. For the previous example, here's the default help message:
``` ```
$ ./main --help $ ./main --help
@ -235,6 +235,8 @@ Optional arguments:
-v, --verbose enable verbose logging -v, --verbose enable verbose logging
``` ```
You may also get the help message in string via `program.help().str()`.
### List of Arguments ### List of Arguments
ArgumentParser objects usually associate a single command-line argument with a single action to be taken. The ```.nargs``` associates a different number of command-line arguments with a single action. When using ```nargs(N)```, N arguments from the command line will be gathered together into a list. ArgumentParser objects usually associate a single command-line argument with a single action to be taken. The ```.nargs``` associates a different number of command-line arguments with a single action. When using ```nargs(N)```, N arguments from the command line will be gathered together into a list.
@ -251,7 +253,7 @@ try {
} }
catch (const std::runtime_error& err) { catch (const std::runtime_error& err) {
std::cout << err.what() << std::endl; std::cout << err.what() << std::endl;
program.print_help(); std::cout << program;
exit(0); exit(0);
} }
@ -280,7 +282,7 @@ try {
} }
catch (const std::runtime_error& err) { catch (const std::runtime_error& err) {
std::cout << err.what() << std::endl; std::cout << err.what() << std::endl;
program.print_help(); std::cout << program;
exit(0); exit(0);
} }
@ -312,7 +314,7 @@ try {
} }
catch (const std::runtime_error& err) { catch (const std::runtime_error& err) {
std::cout << err.what() << std::endl; std::cout << err.what() << std::endl;
program.print_help(); std::cout << program;
exit(0); exit(0);
} }
@ -388,7 +390,7 @@ try {
} }
catch (const std::runtime_error& err) { catch (const std::runtime_error& err) {
std::cout << err.what() << std::endl; std::cout << err.what() << std::endl;
program.print_help(); std::cout << program;
exit(0); exit(0);
} }
@ -424,7 +426,7 @@ try {
} }
catch (const std::runtime_error& err) { catch (const std::runtime_error& err) {
std::cout << err.what() << std::endl; std::cout << err.what() << std::endl;
program.print_help(); std::cout << program;
exit(0); exit(0);
} }
@ -466,7 +468,7 @@ try {
} }
catch (const std::runtime_error& err) { catch (const std::runtime_error& err) {
std::cout << err.what() << std::endl; std::cout << err.what() << std::endl;
program.print_help(); std::cout << program;
exit(0); exit(0);
} }

View File

@ -31,7 +31,6 @@ SOFTWARE.
#include <algorithm> #include <algorithm>
#include <any> #include <any>
#include <functional> #include <functional>
#include <iomanip>
#include <iostream> #include <iostream>
#include <iterator> #include <iterator>
#include <list> #include <list>
@ -75,8 +74,12 @@ template <typename T>
using enable_if_not_container = std::enable_if_t<!is_container_v<T>, T>; using enable_if_not_container = std::enable_if_t<!is_container_v<T>, T>;
} // namespace } // namespace
class ArgumentParser;
class Argument { class Argument {
friend class ArgumentParser; friend class ArgumentParser;
friend auto operator<<(std::ostream &, ArgumentParser const &)
-> std::ostream &;
public: public:
Argument() = default; Argument() = default;
@ -412,39 +415,54 @@ public:
throw std::logic_error("No such argument"); throw std::logic_error("No such argument");
} }
// Printing the one and only help message // Print help message
// I've stuck with a simple message format, nothing fancy. friend auto operator<<(std::ostream &stream, const ArgumentParser &parser)
// TODO: support user-defined help and usage messages for the ArgumentParser -> std::ostream & {
std::string print_help() { if (auto sen = std::ostream::sentry(stream)) {
std::stringstream stream; stream.setf(std::ios_base::left);
stream << std::left; stream << "Usage: " << parser.mProgramName << " [options] ";
stream << "Usage: " << mProgramName << " [options] "; size_t tLongestArgumentLength = parser.get_length_of_longest_argument();
size_t tLongestArgumentLength = get_length_of_longest_argument();
for (const auto &argument : mPositionalArguments) { for (const auto &argument : parser.mPositionalArguments) {
stream << argument->mNames.front() << " "; stream << argument->mNames.front() << " ";
} }
stream << "\n\n"; stream << "\n\n";
if (!mPositionalArguments.empty()) if (!parser.mPositionalArguments.empty())
stream << "Positional arguments:\n"; stream << "Positional arguments:\n";
for (const auto &mPositionalArgument : mPositionalArguments) { for (const auto &mPositionalArgument : parser.mPositionalArguments) {
stream.width(tLongestArgumentLength); stream.width(tLongestArgumentLength);
stream << *mPositionalArgument; stream << *mPositionalArgument;
} }
if (!mOptionalArguments.empty()) if (!parser.mOptionalArguments.empty())
stream << (mPositionalArguments.empty() ? "" : "\n") stream << (parser.mPositionalArguments.empty() ? "" : "\n")
<< "Optional arguments:\n"; << "Optional arguments:\n";
for (const auto &mOptionalArgument : mOptionalArguments) { for (const auto &mOptionalArgument : parser.mOptionalArguments) {
stream.width(tLongestArgumentLength); stream.width(tLongestArgumentLength);
stream << *mOptionalArgument; stream << *mOptionalArgument;
} }
}
std::cout << stream.str(); return stream;
return stream.str(); }
// Format help message
auto help() const -> std::ostringstream {
std::ostringstream out;
out << *this;
return out;
}
// Printing the one and only help message
// I've stuck with a simple message format, nothing fancy.
[[deprecated("Use cout << program; instead. See also help().")]] std::string
print_help() {
auto out = help();
std::cout << out.rdbuf();
return out.str();
} }
private: private:
@ -507,7 +525,7 @@ private:
} }
// Used by print_help. // Used by print_help.
size_t get_length_of_longest_argument() { size_t get_length_of_longest_argument() const {
if (mArgumentMap.empty()) if (mArgumentMap.empty())
return 0; return 0;
std::vector<size_t> argumentLengths(mArgumentMap.size()); std::vector<size_t> argumentLengths(mArgumentMap.size());

View File

@ -1,6 +1,7 @@
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include <iostream> #include <iostream>
#include <argparse.hpp> #include <argparse.hpp>
#include <test_help.hpp>
#include <test_parse_args.hpp> #include <test_parse_args.hpp>
#include <test_positional_arguments.hpp> #include <test_positional_arguments.hpp>
#include <test_optional_arguments.hpp> #include <test_optional_arguments.hpp>

18
test/test_help.hpp Normal file
View File

@ -0,0 +1,18 @@
#pragma once
#include <catch.hpp>
#include <argparse.hpp>
TEST_CASE("Users can format help message", "[help]") {
argparse::ArgumentParser program("test");
program.add_argument("input")
.help("positional input");
program.add_argument("-c")
.help("optional input");
std::ostringstream s;
s << program;
REQUIRE_FALSE(s.str().empty());
auto msg = program.help().str();
REQUIRE(msg == s.str());
}