From 6f1e89885e61f713b863242e969f6e573ba2a740 Mon Sep 17 00:00:00 2001 From: Pranav Srinivas Kumar Date: Wed, 21 Sep 2022 18:48:11 -0700 Subject: [PATCH] Added nargs to help output, added test samples --- README.md | 2 +- include/argparse/argparse.hpp | 29 +++++++++++++---- samples/CMakeLists.txt | 10 ++++-- samples/is_used.cpp | 26 +++++++++++++++ .../joining_repeated_optional_arguments.cpp | 28 ++++++++++++++++ samples/negative_numbers.cpp | 32 +++++++++++++++++++ samples/optional_flag_argument.cpp | 22 +++++++++++++ ...e_a_number.cpp => positional_argument.cpp} | 0 .../repeating_argument_to_increase_value.cpp | 17 ++++++++++ samples/required_optional_argument.cpp | 19 +++++++++++ .../{git_subcommands.cpp => subcommands.cpp} | 0 11 files changed, 176 insertions(+), 9 deletions(-) create mode 100644 samples/is_used.cpp create mode 100644 samples/joining_repeated_optional_arguments.cpp create mode 100644 samples/negative_numbers.cpp create mode 100644 samples/optional_flag_argument.cpp rename samples/{square_a_number.cpp => positional_argument.cpp} (100%) create mode 100644 samples/repeating_argument_to_increase_value.cpp create mode 100644 samples/required_optional_argument.cpp rename samples/{git_subcommands.cpp => subcommands.cpp} (100%) diff --git a/README.md b/README.md index 72c6bb8..2a173d9 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ catch (const std::runtime_error& err) { } if (program["--verbose"] == true) { - std::cout << "Verbosity enabled" << std::endl; + std::cout << "Verbosity enabled" << std::endl; } ``` diff --git a/include/argparse/argparse.hpp b/include/argparse/argparse.hpp index 87bbfe0..e0fb880 100644 --- a/include/argparse/argparse.hpp +++ b/include/argparse/argparse.hpp @@ -668,16 +668,16 @@ public: } stream << name_stream.str() << "\t" << argument.m_help; + // print nargs spec + if (!argument.m_help.empty()) { + stream << " "; + } + stream << argument.m_num_args_range; + if (argument.m_default_value.has_value() && argument.m_num_args_range != NArgsRange{0, 0}) { - if (!argument.m_help.empty()) { - stream << " "; - } stream << "[default: " << argument.m_default_value_repr << "]"; } else if (argument.m_is_required) { - if (!argument.m_help.empty()) { - stream << " "; - } stream << "[required]"; } stream << "\n"; @@ -730,6 +730,23 @@ private: std::size_t get_max() const { return m_max; } + // Print help message + friend auto operator<<(std::ostream &stream, const NArgsRange &range) + -> std::ostream & { + if (range.m_min == range.m_max) { + if (range.m_min != 0 && range.m_min != 1) { + stream << "[nargs: " << range.m_min << "] "; + } + } else { + if (range.m_max == std::numeric_limits::max()) { + stream << "[nargs: " << range.m_min << " or more] "; + } else { + stream << "[nargs=" << range.m_min << ".." << range.m_max << "] "; + } + } + return stream; + } + bool operator==(const NArgsRange &rhs) const { return rhs.m_min == m_min && rhs.m_max == m_max; } diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 3272234..5404b74 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -29,5 +29,11 @@ function(add_sample NAME) set_target_properties(ARGPARSE_SAMPLE_${NAME} PROPERTIES OUTPUT_NAME ${NAME}) endfunction() -add_sample(git_subcommands) -add_sample(square_a_number) \ No newline at end of file +add_sample(positional_argument) +add_sample(optional_flag_argument) +add_sample(required_optional_argument) +add_sample(is_used) +add_sample(joining_repeated_optional_arguments) +add_sample(repeating_argument_to_increase_value) +add_sample(negative_numbers) +add_sample(subcommands) \ No newline at end of file diff --git a/samples/is_used.cpp b/samples/is_used.cpp new file mode 100644 index 0000000..a2f0a14 --- /dev/null +++ b/samples/is_used.cpp @@ -0,0 +1,26 @@ +#include + +int main(int argc, char *argv[]) { + argparse::ArgumentParser program("test"); + + program.add_argument("--color") + .default_value(std::string{ + "orange"}) // might otherwise be type const char* leading to an error + // when trying program.get + .help("specify the cat's fur color"); + + try { + program.parse_args(argc, argv); // Example: ./main --color orange + } catch (const std::runtime_error &err) { + std::cerr << err.what() << std::endl; + std::cerr << program; + std::exit(1); + } + + auto color = program.get("--color"); // "orange" + auto explicit_color = + program.is_used("--color"); // true, user provided orange + std::cout << "Color: " << color << "\n"; + std::cout << "Argument was explicitly provided by user? " << std::boolalpha + << explicit_color << "\n"; +} diff --git a/samples/joining_repeated_optional_arguments.cpp b/samples/joining_repeated_optional_arguments.cpp new file mode 100644 index 0000000..ab819c8 --- /dev/null +++ b/samples/joining_repeated_optional_arguments.cpp @@ -0,0 +1,28 @@ +#include + +int main(int argc, char *argv[]) { + argparse::ArgumentParser program("test"); + + program.add_argument("--color") + .default_value>({"orange"}) + .append() + .help("specify the cat's fur color"); + + try { + program.parse_args( + argc, argv); // Example: ./main --color red --color green --color blue + } catch (const std::runtime_error &err) { + std::cerr << err.what() << std::endl; + std::cerr << program; + std::exit(1); + } + + auto colors = program.get>( + "--color"); // {"red", "green", "blue"} + + std::cout << "Colors: "; + for (const auto &c : colors) { + std::cout << c << " "; + } + std::cout << "\n"; +} diff --git a/samples/negative_numbers.cpp b/samples/negative_numbers.cpp new file mode 100644 index 0000000..bb1c888 --- /dev/null +++ b/samples/negative_numbers.cpp @@ -0,0 +1,32 @@ +#include + +int main(int argc, char *argv[]) { + argparse::ArgumentParser program("test"); + + program.add_argument("integer").help("Input number").scan<'i', int>(); + + program.add_argument("floats") + .help("Vector of floats") + .nargs(4) + .scan<'g', float>(); + + try { + program.parse_args(argc, argv); + } catch (const std::runtime_error &err) { + std::cerr << err.what() << std::endl; + std::cerr << program; + std::exit(1); + } + + if (program.is_used("integer")) { + std::cout << "Integer : " << program.get("integer") << "\n"; + } + + if (program.is_used("floats")) { + std::cout << "Floats : "; + for (const auto &f : program.get>("floats")) { + std::cout << f << " "; + } + std::cout << std::endl; + } +} diff --git a/samples/optional_flag_argument.cpp b/samples/optional_flag_argument.cpp new file mode 100644 index 0000000..fff720a --- /dev/null +++ b/samples/optional_flag_argument.cpp @@ -0,0 +1,22 @@ +#include + +int main(int argc, char *argv[]) { + argparse::ArgumentParser program("test"); + + program.add_argument("--verbose") + .help("increase output verbosity") + .default_value(false) + .implicit_value(true); + + try { + program.parse_args(argc, argv); + } catch (const std::runtime_error &err) { + std::cerr << err.what() << std::endl; + std::cerr << program; + std::exit(1); + } + + if (program["--verbose"] == true) { + std::cout << "Verbosity enabled" << std::endl; + } +} diff --git a/samples/square_a_number.cpp b/samples/positional_argument.cpp similarity index 100% rename from samples/square_a_number.cpp rename to samples/positional_argument.cpp diff --git a/samples/repeating_argument_to_increase_value.cpp b/samples/repeating_argument_to_increase_value.cpp new file mode 100644 index 0000000..e0de41e --- /dev/null +++ b/samples/repeating_argument_to_increase_value.cpp @@ -0,0 +1,17 @@ +#include + +int main(int argc, char *argv[]) { + argparse::ArgumentParser program("test"); + + int verbosity = 0; + program.add_argument("-V", "--verbose") + .action([&](const auto &) { ++verbosity; }) + .append() + .default_value(false) + .implicit_value(true) + .nargs(0); + + program.parse_args(argc, argv); // Example: ./main -VVVV + + std::cout << "verbose level: " << verbosity << std::endl; // verbose level: 4 +} diff --git a/samples/required_optional_argument.cpp b/samples/required_optional_argument.cpp new file mode 100644 index 0000000..1fe2dcc --- /dev/null +++ b/samples/required_optional_argument.cpp @@ -0,0 +1,19 @@ +#include + +int main(int argc, char *argv[]) { + argparse::ArgumentParser program("test"); + + program.add_argument("-o", "--output") + .required() + .help("specify the output file."); + + try { + program.parse_args(argc, argv); + } catch (const std::runtime_error &err) { + std::cerr << err.what() << std::endl; + std::cerr << program; + std::exit(1); + } + + std::cout << "Output written to " << program.get("-o") << "\n"; +} diff --git a/samples/git_subcommands.cpp b/samples/subcommands.cpp similarity index 100% rename from samples/git_subcommands.cpp rename to samples/subcommands.cpp