mirror of
https://github.com/KeqingMoe/argparse.git
synced 2025-07-04 15:14:39 +00:00
Merge pull request #206 from p-ranav/feature/metavar_help_and_usage
METAVAR, Improved help, Samples (Based on #187)
This commit is contained in:
commit
ce0b491571
@ -28,6 +28,9 @@ target_include_directories(argparse INTERFACE
|
|||||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>)
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>)
|
||||||
|
|
||||||
|
if(ARGPARSE_BUILD_SAMPLES)
|
||||||
|
add_subdirectory(samples)
|
||||||
|
endif()
|
||||||
|
|
||||||
if(ARGPARSE_BUILD_TESTS)
|
if(ARGPARSE_BUILD_TESTS)
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
88
README.md
88
README.md
@ -142,7 +142,7 @@ catch (const std::runtime_error& err) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (program["--verbose"] == true) {
|
if (program["--verbose"] == true) {
|
||||||
std::cout << "Verbosity enabled" << std::endl;
|
std::cout << "Verbosity enabled" << std::endl;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -338,15 +338,15 @@ The square of 4 is 16
|
|||||||
|
|
||||||
```
|
```
|
||||||
foo@bar:/home/dev/$ ./main --help
|
foo@bar:/home/dev/$ ./main --help
|
||||||
Usage: main [options] square
|
Usage: main [-h] [--verbose] square
|
||||||
|
|
||||||
Positional arguments:
|
Positional arguments:
|
||||||
square display the square of a given number
|
square display the square of a given number
|
||||||
|
|
||||||
Optional arguments:
|
Optional arguments:
|
||||||
-h --help shows help message and exits [default: false]
|
-h, --help shows help message and exits
|
||||||
-v --version prints version information and exits [default: false]
|
-v, --version prints version information and exits
|
||||||
--verbose [default: false]
|
--verbose
|
||||||
```
|
```
|
||||||
|
|
||||||
You may also get the help message in string via `program.help().str()`.
|
You may also get the help message in string via `program.help().str()`.
|
||||||
@ -357,30 +357,36 @@ You may also get the help message in string via `program.help().str()`.
|
|||||||
information. `ArgumentParser::add_epilog` will add text after all other help output.
|
information. `ArgumentParser::add_epilog` will add text after all other help output.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
argparse::ArgumentParser program("main");
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
program.add_argument("thing")
|
int main(int argc, char *argv[]) {
|
||||||
.help("Thing to use.");
|
argparse::ArgumentParser program("main");
|
||||||
program.add_description("Forward a thing to the next member.");
|
program.add_argument("thing").help("Thing to use.").metavar("THING");
|
||||||
program.add_epilog("Possible things include betingalw, chiz, and res.");
|
program.add_argument("--member").help("The alias for the member to pass to.").metavar("ALIAS");
|
||||||
|
program.add_argument("--verbose").default_value(false).implicit_value(true);
|
||||||
|
|
||||||
program.parse_args(argc, argv);
|
program.add_description("Forward a thing to the next member.");
|
||||||
|
program.add_epilog("Possible things include betingalw, chiz, and res.");
|
||||||
|
|
||||||
std::cout << program << std::endl;
|
program.parse_args(argc, argv);
|
||||||
|
|
||||||
|
std::cout << program << std::endl;
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
```console
|
```console
|
||||||
foo@bar:/home/dev/$ ./main --help
|
Usage: main [-h] [--member ALIAS] [--verbose] THING
|
||||||
Usage: main thing
|
|
||||||
|
|
||||||
Forward a thing to the next member.
|
Forward a thing to the next member.
|
||||||
|
|
||||||
Positional arguments:
|
Positional arguments:
|
||||||
thing Thing to use.
|
THING Thing to use.
|
||||||
|
|
||||||
Optional arguments:
|
Optional arguments:
|
||||||
-h --help shows help message and exits [default: false]
|
-h, --help shows help message and exits
|
||||||
-v --version prints version information and exits [default: false]
|
-v, --version prints version information and exits
|
||||||
|
--member ALIAS The alias for the member to pass to.
|
||||||
|
--verbose
|
||||||
|
|
||||||
Possible things include betingalw, chiz, and res.
|
Possible things include betingalw, chiz, and res.
|
||||||
```
|
```
|
||||||
@ -710,12 +716,14 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// git add subparser
|
// git add subparser
|
||||||
argparse::ArgumentParser add_command("add");
|
argparse::ArgumentParser add_command("add");
|
||||||
|
add_command.add_description("Add file contents to the index");
|
||||||
add_command.add_argument("files")
|
add_command.add_argument("files")
|
||||||
.help("Files to add content from. Fileglobs (e.g. *.c) can be given to add all matching files.")
|
.help("Files to add content from. Fileglobs (e.g. *.c) can be given to add all matching files.")
|
||||||
.remaining();
|
.remaining();
|
||||||
|
|
||||||
// git commit subparser
|
// git commit subparser
|
||||||
argparse::ArgumentParser commit_command("commit");
|
argparse::ArgumentParser commit_command("commit");
|
||||||
|
commit_command.add_description("Record changes to the repository");
|
||||||
commit_command.add_argument("-a", "--all")
|
commit_command.add_argument("-a", "--all")
|
||||||
.help("Tell the command to automatically stage files that have been modified and deleted.")
|
.help("Tell the command to automatically stage files that have been modified and deleted.")
|
||||||
.default_value(false)
|
.default_value(false)
|
||||||
@ -726,6 +734,7 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// git cat-file subparser
|
// git cat-file subparser
|
||||||
argparse::ArgumentParser catfile_command("cat-file");
|
argparse::ArgumentParser catfile_command("cat-file");
|
||||||
|
catfile_command.add_description("Provide content or type and size information for repository objects");
|
||||||
catfile_command.add_argument("-t")
|
catfile_command.add_argument("-t")
|
||||||
.help("Instead of the content, show the object type identified by <object>.");
|
.help("Instead of the content, show the object type identified by <object>.");
|
||||||
|
|
||||||
@ -734,7 +743,9 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
// git submodule subparser
|
// git submodule subparser
|
||||||
argparse::ArgumentParser submodule_command("submodule");
|
argparse::ArgumentParser submodule_command("submodule");
|
||||||
|
submodule_command.add_description("Initialize, update or inspect submodules");
|
||||||
argparse::ArgumentParser submodule_update_command("update");
|
argparse::ArgumentParser submodule_update_command("update");
|
||||||
|
submodule_update_command.add_description("Update the registered submodules to match what the superproject expects");
|
||||||
submodule_update_command.add_argument("--init")
|
submodule_update_command.add_argument("--init")
|
||||||
.default_value(false)
|
.default_value(false)
|
||||||
.implicit_value(true);
|
.implicit_value(true);
|
||||||
@ -763,41 +774,52 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
```console
|
```console
|
||||||
foo@bar:/home/dev/$ ./git --help
|
foo@bar:/home/dev/$ ./git --help
|
||||||
Usage: git [options] <command> [<args>]
|
Usage: git [-h] {add,cat-file,commit,submodule}
|
||||||
|
|
||||||
Optional arguments:
|
Optional arguments:
|
||||||
-h --help shows help message and exits [default: false]
|
-h, --help shows help message and exits
|
||||||
-v --version prints version information and exits [default: false]
|
-v, --version prints version information and exits
|
||||||
|
|
||||||
Subcommands:
|
Subcommands:
|
||||||
add Add file contents to the index
|
add Add file contents to the index
|
||||||
cat-file Provide content or type and size information for repository objects
|
cat-file Provide content or type and size information for repository objects
|
||||||
commit Record changes to the repository
|
commit Record changes to the repository
|
||||||
submodule Initialize, update or inspect submodules
|
submodule Initialize, update or inspect submodules
|
||||||
|
|
||||||
foo@bar:/home/dev/$ ./git add --help
|
foo@bar:/home/dev/$ ./git add --help
|
||||||
Usage: git add [options] files
|
Usage: add [-h] files
|
||||||
|
|
||||||
Add file contents to the index
|
Add file contents to the index
|
||||||
|
|
||||||
Positional arguments:
|
Positional arguments:
|
||||||
files Files to add content from. Fileglobs (e.g. *.c) can be given to add all matching files.
|
files Files to add content from. Fileglobs (e.g. *.c) can be given to add all matching files.
|
||||||
|
|
||||||
Optional arguments:
|
Optional arguments:
|
||||||
-h --help shows help message and exits [default: false]
|
-h, --help shows help message and exits
|
||||||
-v --version prints version information and exits [default: false]
|
-v, --version prints version information and exits
|
||||||
|
|
||||||
|
foo@bar:/home/dev/$ ./git commit --help
|
||||||
|
Usage: commit [-h] [--all] [--message VAR]
|
||||||
|
|
||||||
|
Record changes to the repository
|
||||||
|
|
||||||
|
Optional arguments:
|
||||||
|
-h, --help shows help message and exits
|
||||||
|
-v, --version prints version information and exits
|
||||||
|
-a, --all Tell the command to automatically stage files that have been modified and deleted.
|
||||||
|
-m, --message Use the given <msg> as the commit message.
|
||||||
|
|
||||||
foo@bar:/home/dev/$ ./git submodule --help
|
foo@bar:/home/dev/$ ./git submodule --help
|
||||||
Usage: git submodule [options] <command> [<args>]
|
Usage: submodule [-h] {update}
|
||||||
|
|
||||||
Initialize, update or inspect submodules
|
Initialize, update or inspect submodules
|
||||||
|
|
||||||
Optional arguments:
|
Optional arguments:
|
||||||
-h --help shows help message and exits [default: false]
|
-h, --help shows help message and exits
|
||||||
-v --version prints version information and exits [default: false]
|
-v, --version prints version information and exits
|
||||||
|
|
||||||
Subcommands:
|
Subcommands:
|
||||||
update Update the registered submodules to match what the superproject expects
|
update Update the registered submodules to match what the superproject expects
|
||||||
```
|
```
|
||||||
|
|
||||||
When a help message is requested from a subparser, only the help for that particular parser will be printed. The help message will not include parent parser or sibling parser messages.
|
When a help message is requested from a subparser, only the help for that particular parser will be printed. The help message will not include parent parser or sibling parser messages.
|
||||||
|
@ -1 +1 @@
|
|||||||
clang-format -i include/argparse/*.hpp test/*.cpp
|
clang-format -i include/argparse/*.hpp test/*.cpp samples/*.cpp
|
||||||
|
@ -36,6 +36,7 @@ SOFTWARE.
|
|||||||
#include <charconv>
|
#include <charconv>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
@ -329,6 +330,21 @@ template <class T> struct parse_number<T, chars_format::fixed> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename StrIt>
|
||||||
|
std::string join(StrIt first, StrIt last, const std::string &separator) {
|
||||||
|
if (first == last) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
std::stringstream value;
|
||||||
|
value << *first;
|
||||||
|
++first;
|
||||||
|
while (first != last) {
|
||||||
|
value << separator << *first;
|
||||||
|
++first;
|
||||||
|
}
|
||||||
|
return value.str();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
enum class nargs_pattern { optional, any, at_least_one };
|
enum class nargs_pattern { optional, any, at_least_one };
|
||||||
@ -379,6 +395,11 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Argument &metavar(std::string metavar) {
|
||||||
|
m_metavar = std::move(metavar);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T> Argument &default_value(T &&value) {
|
template <typename T> Argument &default_value(T &&value) {
|
||||||
m_default_value_repr = details::repr(value);
|
m_default_value_repr = details::repr(value);
|
||||||
m_default_value = std::forward<T>(value);
|
m_default_value = std::forward<T>(value);
|
||||||
@ -573,29 +594,90 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string get_inline_usage() const {
|
||||||
|
std::stringstream usage;
|
||||||
|
// Find the longest variant to show in the usage string
|
||||||
|
std::string longest_name = m_names[0];
|
||||||
|
for (const auto &s : m_names) {
|
||||||
|
if (s.size() > longest_name.size()) {
|
||||||
|
longest_name = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!m_is_required) {
|
||||||
|
usage << "[";
|
||||||
|
}
|
||||||
|
usage << longest_name;
|
||||||
|
const std::string metavar = !m_metavar.empty() ? m_metavar : "VAR";
|
||||||
|
if (m_num_args_range.get_max() > 0) {
|
||||||
|
usage << " " << metavar;
|
||||||
|
if (m_num_args_range.get_max() > 1) {
|
||||||
|
usage << "...";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!m_is_required) {
|
||||||
|
usage << "]";
|
||||||
|
}
|
||||||
|
return usage.str();
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t get_arguments_length() const {
|
std::size_t get_arguments_length() const {
|
||||||
return std::accumulate(std::begin(m_names), std::end(m_names),
|
|
||||||
std::size_t(0), [](const auto &sum, const auto &s) {
|
std::size_t names_size = std::accumulate(
|
||||||
return sum + s.size() +
|
std::begin(m_names), std::end(m_names), std::size_t(0),
|
||||||
1; // +1 for space between names
|
[](const auto &sum, const auto &s) { return sum + s.size(); });
|
||||||
});
|
|
||||||
|
if (is_positional(m_names.front(), m_prefix_chars)) {
|
||||||
|
// A set metavar means this replaces the names
|
||||||
|
if (!m_metavar.empty()) {
|
||||||
|
// Indent and metavar
|
||||||
|
return 2 + m_metavar.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indent and space-separated
|
||||||
|
return 2 + names_size + (m_names.size() - 1);
|
||||||
|
}
|
||||||
|
// Is an option - include both names _and_ metavar
|
||||||
|
// size = text + (", " between names)
|
||||||
|
std::size_t size = names_size + 2 * (m_names.size() - 1);
|
||||||
|
if (!m_metavar.empty() && m_num_args_range == NArgsRange{1, 1}) {
|
||||||
|
size += m_metavar.size() + 1;
|
||||||
|
}
|
||||||
|
return size + 2; // indent
|
||||||
}
|
}
|
||||||
|
|
||||||
friend std::ostream &operator<<(std::ostream &stream,
|
friend std::ostream &operator<<(std::ostream &stream,
|
||||||
const Argument &argument) {
|
const Argument &argument) {
|
||||||
std::stringstream name_stream;
|
std::stringstream name_stream;
|
||||||
std::copy(std::begin(argument.m_names), std::end(argument.m_names),
|
name_stream << " "; // indent
|
||||||
std::ostream_iterator<std::string>(name_stream, " "));
|
if (argument.is_positional(argument.m_names.front(),
|
||||||
stream << name_stream.str() << "\t" << argument.m_help;
|
argument.m_prefix_chars)) {
|
||||||
if (argument.m_default_value.has_value()) {
|
if (!argument.m_metavar.empty()) {
|
||||||
if (!argument.m_help.empty()) {
|
name_stream << argument.m_metavar;
|
||||||
stream << " ";
|
} else {
|
||||||
|
name_stream << details::join(argument.m_names.begin(),
|
||||||
|
argument.m_names.end(), " ");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
name_stream << details::join(argument.m_names.begin(),
|
||||||
|
argument.m_names.end(), ", ");
|
||||||
|
// If we have a metavar, and one narg - print the metavar
|
||||||
|
if (!argument.m_metavar.empty() &&
|
||||||
|
argument.m_num_args_range == NArgsRange{1, 1}) {
|
||||||
|
name_stream << " " << argument.m_metavar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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}) {
|
||||||
stream << "[default: " << argument.m_default_value_repr << "]";
|
stream << "[default: " << argument.m_default_value_repr << "]";
|
||||||
} else if (argument.m_is_required) {
|
} else if (argument.m_is_required) {
|
||||||
if (!argument.m_help.empty()) {
|
|
||||||
stream << " ";
|
|
||||||
}
|
|
||||||
stream << "[required]";
|
stream << "[required]";
|
||||||
}
|
}
|
||||||
stream << "\n";
|
stream << "\n";
|
||||||
@ -647,6 +729,29 @@ private:
|
|||||||
std::size_t get_min() const { return m_min; }
|
std::size_t get_min() const { return m_min; }
|
||||||
|
|
||||||
std::size_t get_max() const { return m_max; }
|
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<std::size_t>::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const NArgsRange &rhs) const { return !(*this == rhs); }
|
||||||
};
|
};
|
||||||
|
|
||||||
void throw_nargs_range_validation_error() const {
|
void throw_nargs_range_validation_error() const {
|
||||||
@ -913,6 +1018,7 @@ private:
|
|||||||
std::vector<std::string> m_names;
|
std::vector<std::string> m_names;
|
||||||
std::string_view m_used_name;
|
std::string_view m_used_name;
|
||||||
std::string m_help;
|
std::string m_help;
|
||||||
|
std::string m_metavar;
|
||||||
std::any m_default_value;
|
std::any m_default_value;
|
||||||
std::string m_default_value_repr;
|
std::string m_default_value_repr;
|
||||||
std::any m_implicit_value;
|
std::any m_implicit_value;
|
||||||
@ -1094,8 +1200,8 @@ public:
|
|||||||
* @throws std::runtime_error in case of any invalid argument
|
* @throws std::runtime_error in case of any invalid argument
|
||||||
*/
|
*/
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays)
|
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays)
|
||||||
void parse_known_args(int argc, const char *const argv[]) {
|
auto parse_known_args(int argc, const char *const argv[]) {
|
||||||
parse_known_args({argv, argv + argc});
|
return parse_known_args({argv, argv + argc});
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Getter for options with default values.
|
/* Getter for options with default values.
|
||||||
@ -1171,17 +1277,10 @@ public:
|
|||||||
friend auto operator<<(std::ostream &stream, const ArgumentParser &parser)
|
friend auto operator<<(std::ostream &stream, const ArgumentParser &parser)
|
||||||
-> std::ostream & {
|
-> std::ostream & {
|
||||||
stream.setf(std::ios_base::left);
|
stream.setf(std::ios_base::left);
|
||||||
stream << "Usage: " << parser.m_parser_path << " [options] ";
|
|
||||||
for (const auto &argument : parser.m_positional_arguments) {
|
|
||||||
stream << argument.m_names.front() << " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!parser.m_subparser_map.empty()) {
|
auto longest_arg_length = parser.get_length_of_longest_argument();
|
||||||
stream << (parser.m_positional_arguments.empty() ? "" : " ")
|
|
||||||
<< "<command> [<args>]";
|
stream << parser.usage() << "\n\n";
|
||||||
}
|
|
||||||
std::size_t longest_arg_length = parser.get_length_of_longest_argument();
|
|
||||||
stream << "\n\n";
|
|
||||||
|
|
||||||
if (!parser.m_description.empty()) {
|
if (!parser.m_description.empty()) {
|
||||||
stream << parser.m_description << "\n\n";
|
stream << parser.m_description << "\n\n";
|
||||||
@ -1212,8 +1311,10 @@ public:
|
|||||||
: "\n")
|
: "\n")
|
||||||
<< "Subcommands:\n";
|
<< "Subcommands:\n";
|
||||||
for (const auto &[command, subparser] : parser.m_subparser_map) {
|
for (const auto &[command, subparser] : parser.m_subparser_map) {
|
||||||
stream.width(static_cast<std::streamsize>(longest_arg_length));
|
stream << std::setw(2) << " ";
|
||||||
stream << command << "\t" << subparser->get().m_description << "\n";
|
stream << std::setw(static_cast<int>(longest_arg_length - 2))
|
||||||
|
<< command;
|
||||||
|
stream << " " << subparser->get().m_description << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1232,6 +1333,48 @@ public:
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format usage part of help only
|
||||||
|
auto usage() const -> std::string {
|
||||||
|
std::stringstream stream;
|
||||||
|
|
||||||
|
stream << "Usage: " << this->m_program_name;
|
||||||
|
|
||||||
|
// Add any options inline here
|
||||||
|
for (const auto &argument : this->m_optional_arguments) {
|
||||||
|
if (argument.m_names[0] == "-v") {
|
||||||
|
continue;
|
||||||
|
} else if (argument.m_names[0] == "-h") {
|
||||||
|
stream << " [-h]";
|
||||||
|
} else {
|
||||||
|
stream << " " << argument.get_inline_usage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Put positional arguments after the optionals
|
||||||
|
for (const auto &argument : this->m_positional_arguments) {
|
||||||
|
if (!argument.m_metavar.empty()) {
|
||||||
|
stream << " " << argument.m_metavar;
|
||||||
|
} else {
|
||||||
|
stream << " " << argument.m_names.front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Put subcommands after positional arguments
|
||||||
|
if (!m_subparser_map.empty()) {
|
||||||
|
stream << " {";
|
||||||
|
std::size_t i{0};
|
||||||
|
for (const auto &[command, unused] : m_subparser_map) {
|
||||||
|
if (i == 0) {
|
||||||
|
stream << command;
|
||||||
|
} else {
|
||||||
|
stream << "," << command;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
stream << "}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
// Printing the one and only help message
|
// Printing the one and only help message
|
||||||
// I've stuck with a simple message format, nothing fancy.
|
// I've stuck with a simple message format, nothing fancy.
|
||||||
[[deprecated("Use cout << program; instead. See also help().")]] std::string
|
[[deprecated("Use cout << program; instead. See also help().")]] std::string
|
||||||
|
46
samples/CMakeLists.txt
Normal file
46
samples/CMakeLists.txt
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.6)
|
||||||
|
project(argparse_samples)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
# Force to always compile with W4
|
||||||
|
if(CMAKE_CXX_FLAGS MATCHES "/W[0-4]")
|
||||||
|
string(REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||||
|
else()
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4")
|
||||||
|
endif()
|
||||||
|
elseif(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
# Update if necessary
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic -Wsign-conversion -Wshadow -Wconversion")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE Release)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Disable deprecation for windows
|
||||||
|
if (WIN32)
|
||||||
|
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
function(add_sample NAME)
|
||||||
|
ADD_EXECUTABLE(ARGPARSE_SAMPLE_${NAME} ${NAME}.cpp)
|
||||||
|
INCLUDE_DIRECTORIES("../include" ".")
|
||||||
|
TARGET_LINK_LIBRARIES(ARGPARSE_SAMPLE_${NAME} PRIVATE argparse::argparse)
|
||||||
|
set_target_properties(ARGPARSE_SAMPLE_${NAME} PROPERTIES OUTPUT_NAME ${NAME})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
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(description_epilog_metavar)
|
||||||
|
add_sample(list_of_arguments)
|
||||||
|
add_sample(compound_arguments)
|
||||||
|
add_sample(gathering_remaining_arguments)
|
||||||
|
add_sample(subcommands)
|
||||||
|
add_sample(parse_known_args)
|
||||||
|
add_sample(custom_prefix_characters)
|
||||||
|
add_sample(custom_assignment_characters)
|
36
samples/compound_arguments.cpp
Normal file
36
samples/compound_arguments.cpp
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
|
||||||
|
program.add_argument("-a").default_value(false).implicit_value(true);
|
||||||
|
|
||||||
|
program.add_argument("-b").default_value(false).implicit_value(true);
|
||||||
|
|
||||||
|
program.add_argument("-c")
|
||||||
|
.nargs(2)
|
||||||
|
.default_value(std::vector<float>{0.0f, 0.0f})
|
||||||
|
.scan<'g', float>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
program.parse_args(argc, argv); // Example: ./main -abc 1.95 2.47
|
||||||
|
} catch (const std::runtime_error &err) {
|
||||||
|
std::cerr << err.what() << std::endl;
|
||||||
|
std::cerr << program;
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto a = program.get<bool>("-a"); // true
|
||||||
|
auto b = program.get<bool>("-b"); // true
|
||||||
|
auto c = program.get<std::vector<float>>("-c"); // {1.95, 2.47}
|
||||||
|
|
||||||
|
std::cout << "a: " << std::boolalpha << a << "\n";
|
||||||
|
std::cout << "b: " << b << "\n";
|
||||||
|
if (!c.empty()) {
|
||||||
|
std::cout << "c: ";
|
||||||
|
for (auto &v : c) {
|
||||||
|
std::cout << v << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
27
samples/custom_assignment_characters.cpp
Normal file
27
samples/custom_assignment_characters.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.set_prefix_chars("-+/");
|
||||||
|
program.set_assign_chars("=:");
|
||||||
|
|
||||||
|
program.add_argument("--foo");
|
||||||
|
program.add_argument("/B");
|
||||||
|
|
||||||
|
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("--foo")) {
|
||||||
|
std::cout << "--foo : " << program.get("--foo") << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program.is_used("/B")) {
|
||||||
|
std::cout << "/B : " << program.get("/B") << "\n";
|
||||||
|
}
|
||||||
|
}
|
31
samples/custom_prefix_characters.cpp
Normal file
31
samples/custom_prefix_characters.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.set_prefix_chars("-+/");
|
||||||
|
|
||||||
|
program.add_argument("+f");
|
||||||
|
program.add_argument("--bar");
|
||||||
|
program.add_argument("/foo");
|
||||||
|
|
||||||
|
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("+f")) {
|
||||||
|
std::cout << "+f : " << program.get("+f") << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program.is_used("--bar")) {
|
||||||
|
std::cout << "--bar : " << program.get("--bar") << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program.is_used("/foo")) {
|
||||||
|
std::cout << "/foo : " << program.get("/foo") << "\n";
|
||||||
|
}
|
||||||
|
}
|
17
samples/description_epilog_metavar.cpp
Normal file
17
samples/description_epilog_metavar.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
argparse::ArgumentParser program("main");
|
||||||
|
program.add_argument("thing").help("Thing to use.").metavar("THING");
|
||||||
|
program.add_argument("--member")
|
||||||
|
.help("The alias for the member to pass to.")
|
||||||
|
.metavar("ALIAS");
|
||||||
|
program.add_argument("--verbose").default_value(false).implicit_value(true);
|
||||||
|
|
||||||
|
program.add_description("Forward a thing to the next member.");
|
||||||
|
program.add_epilog("Possible things include betingalw, chiz, and res.");
|
||||||
|
|
||||||
|
program.parse_args(argc, argv);
|
||||||
|
|
||||||
|
std::cout << program << std::endl;
|
||||||
|
}
|
24
samples/gathering_remaining_arguments.cpp
Normal file
24
samples/gathering_remaining_arguments.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
argparse::ArgumentParser program("compiler");
|
||||||
|
|
||||||
|
program.add_argument("files").remaining();
|
||||||
|
|
||||||
|
try {
|
||||||
|
program.parse_args(argc, argv);
|
||||||
|
} catch (const std::runtime_error &err) {
|
||||||
|
std::cerr << err.what() << std::endl;
|
||||||
|
std::cerr << program;
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto files = program.get<std::vector<std::string>>("files");
|
||||||
|
std::cout << files.size() << " files provided" << std::endl;
|
||||||
|
for (auto &file : files)
|
||||||
|
std::cout << file << std::endl;
|
||||||
|
} catch (std::logic_error &e) {
|
||||||
|
std::cout << "No files provided" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
26
samples/is_used.cpp
Normal file
26
samples/is_used.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
|
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<std::string>
|
||||||
|
.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<std::string>("--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";
|
||||||
|
}
|
28
samples/joining_repeated_optional_arguments.cpp
Normal file
28
samples/joining_repeated_optional_arguments.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
|
||||||
|
program.add_argument("--color")
|
||||||
|
.default_value<std::vector<std::string>>({"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<std::vector<std::string>>(
|
||||||
|
"--color"); // {"red", "green", "blue"}
|
||||||
|
|
||||||
|
std::cout << "Colors: ";
|
||||||
|
for (const auto &c : colors) {
|
||||||
|
std::cout << c << " ";
|
||||||
|
}
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
30
samples/list_of_arguments.cpp
Normal file
30
samples/list_of_arguments.cpp
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
|
argparse::ArgumentParser program("main");
|
||||||
|
|
||||||
|
program.add_argument("--input_files")
|
||||||
|
.help("The list of input files")
|
||||||
|
.nargs(2);
|
||||||
|
|
||||||
|
try {
|
||||||
|
program.parse_args(
|
||||||
|
argc, argv); // Example: ./main --input_files config.yml System.xml
|
||||||
|
} catch (const std::runtime_error &err) {
|
||||||
|
std::cerr << err.what() << std::endl;
|
||||||
|
std::cerr << program;
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto files = program.get<std::vector<std::string>>(
|
||||||
|
"--input_files"); // {"config.yml", "System.xml"}
|
||||||
|
|
||||||
|
if (!files.empty()) {
|
||||||
|
std::cout << "Files: ";
|
||||||
|
for (auto &file : files) {
|
||||||
|
std::cout << file << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
32
samples/negative_numbers.cpp
Normal file
32
samples/negative_numbers.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
|
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<int>("integer") << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program.is_used("floats")) {
|
||||||
|
std::cout << "Floats : ";
|
||||||
|
for (const auto &f : program.get<std::vector<float>>("floats")) {
|
||||||
|
std::cout << f << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
22
samples/optional_flag_argument.cpp
Normal file
22
samples/optional_flag_argument.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
26
samples/parse_known_args.cpp
Normal file
26
samples/parse_known_args.cpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
argparse::ArgumentParser program("test");
|
||||||
|
program.add_argument("--foo").implicit_value(true).default_value(false);
|
||||||
|
program.add_argument("bar");
|
||||||
|
|
||||||
|
auto unknown_args = program.parse_known_args(argc, argv);
|
||||||
|
|
||||||
|
if (program.is_used("--foo")) {
|
||||||
|
std::cout << "--foo : " << program.get<bool>("--foo") << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (program.is_used("bar")) {
|
||||||
|
std::cout << "bar : " << program.get<std::string>("bar") << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!unknown_args.empty()) {
|
||||||
|
std::cout << "Unknown args : ";
|
||||||
|
for (const auto &u : unknown_args) {
|
||||||
|
std::cout << u << " ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
}
|
28
samples/positional_argument.cpp
Normal file
28
samples/positional_argument.cpp
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
argparse::ArgumentParser program("main");
|
||||||
|
|
||||||
|
program.add_argument("square")
|
||||||
|
.help("display the square of a given number")
|
||||||
|
.scan<'i', int>();
|
||||||
|
|
||||||
|
program.add_argument("--verbose").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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int input = program.get<int>("square");
|
||||||
|
|
||||||
|
if (program["--verbose"] == true) {
|
||||||
|
std::cout << "The square of " << input << " is " << (input * input)
|
||||||
|
<< std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << (input * input) << std::endl;
|
||||||
|
}
|
||||||
|
}
|
17
samples/repeating_argument_to_increase_value.cpp
Normal file
17
samples/repeating_argument_to_increase_value.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
19
samples/required_optional_argument.cpp
Normal file
19
samples/required_optional_argument.cpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
|
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";
|
||||||
|
}
|
65
samples/subcommands.cpp
Normal file
65
samples/subcommands.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include <argparse/argparse.hpp>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
argparse::ArgumentParser program("git");
|
||||||
|
|
||||||
|
// git add subparser
|
||||||
|
argparse::ArgumentParser add_command("add");
|
||||||
|
add_command.add_description("Add file contents to the index");
|
||||||
|
add_command.add_argument("files")
|
||||||
|
.help("Files to add content from. Fileglobs (e.g. *.c) can be given to "
|
||||||
|
"add all matching files.")
|
||||||
|
.remaining();
|
||||||
|
|
||||||
|
// git commit subparser
|
||||||
|
argparse::ArgumentParser commit_command("commit");
|
||||||
|
commit_command.add_description("Record changes to the repository");
|
||||||
|
commit_command.add_argument("-a", "--all")
|
||||||
|
.help("Tell the command to automatically stage files that have been "
|
||||||
|
"modified and deleted.")
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true);
|
||||||
|
|
||||||
|
commit_command.add_argument("-m", "--message")
|
||||||
|
.help("Use the given <msg> as the commit message.");
|
||||||
|
|
||||||
|
// git cat-file subparser
|
||||||
|
argparse::ArgumentParser catfile_command("cat-file");
|
||||||
|
catfile_command.add_description(
|
||||||
|
"Provide content or type and size information for repository objects");
|
||||||
|
catfile_command.add_argument("-t").help(
|
||||||
|
"Instead of the content, show the object type identified by <object>.");
|
||||||
|
|
||||||
|
catfile_command.add_argument("-p").help(
|
||||||
|
"Pretty-print the contents of <object> based on its type.");
|
||||||
|
|
||||||
|
// git submodule subparser
|
||||||
|
argparse::ArgumentParser submodule_command("submodule");
|
||||||
|
submodule_command.add_description("Initialize, update or inspect submodules");
|
||||||
|
argparse::ArgumentParser submodule_update_command("update");
|
||||||
|
submodule_update_command.add_description(
|
||||||
|
"Update the registered submodules to match what the superproject "
|
||||||
|
"expects");
|
||||||
|
submodule_update_command.add_argument("--init")
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true);
|
||||||
|
submodule_update_command.add_argument("--recursive")
|
||||||
|
.default_value(false)
|
||||||
|
.implicit_value(true);
|
||||||
|
submodule_command.add_subparser(submodule_update_command);
|
||||||
|
|
||||||
|
program.add_subparser(add_command);
|
||||||
|
program.add_subparser(commit_command);
|
||||||
|
program.add_subparser(catfile_command);
|
||||||
|
program.add_subparser(submodule_command);
|
||||||
|
|
||||||
|
try {
|
||||||
|
program.parse_args(argc, argv);
|
||||||
|
} catch (const std::runtime_error &err) {
|
||||||
|
std::cerr << err.what() << std::endl;
|
||||||
|
std::cerr << program;
|
||||||
|
std::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use arguments
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.6)
|
cmake_minimum_required(VERSION 3.6)
|
||||||
project(argparse)
|
project(argparse_tests)
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
# Force to always compile with W4
|
# Force to always compile with W4
|
||||||
@ -54,10 +54,10 @@ file(GLOB ARGPARSE_TEST_SOURCES
|
|||||||
set_source_files_properties(main.cpp
|
set_source_files_properties(main.cpp
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
COMPILE_DEFINITIONS DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN)
|
COMPILE_DEFINITIONS DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN)
|
||||||
ADD_EXECUTABLE(ARGPARSE ${ARGPARSE_TEST_SOURCES})
|
ADD_EXECUTABLE(ARGPARSE_TESTS ${ARGPARSE_TEST_SOURCES})
|
||||||
INCLUDE_DIRECTORIES("../include" ".")
|
INCLUDE_DIRECTORIES("../include" ".")
|
||||||
set_target_properties(ARGPARSE PROPERTIES OUTPUT_NAME tests)
|
set_target_properties(ARGPARSE_TESTS PROPERTIES OUTPUT_NAME tests)
|
||||||
set_property(TARGET ARGPARSE PROPERTY CXX_STANDARD 17)
|
set_property(TARGET ARGPARSE_TESTS PROPERTY CXX_STANDARD 17)
|
||||||
|
|
||||||
# Set ${PROJECT_NAME} as the startup project
|
# Set ${PROJECT_NAME} as the startup project
|
||||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ARGPARSE)
|
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ARGPARSE_TESTS)
|
||||||
|
Loading…
Reference in New Issue
Block a user