Merge pull request #273 from ismagilli/issue_258

NEW: suppress flag for subcommand
This commit is contained in:
Pranav 2023-11-05 07:58:02 -06:00 committed by GitHub
commit 3cc913d5ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 93 additions and 4 deletions

View File

@ -899,6 +899,39 @@ When a help message is requested from a subparser, only the help for that partic
Additionally, every parser has the `.is_subcommand_used("<command_name>")` and `.is_subcommand_used(subparser)` member functions to check if a subcommand was used. Additionally, every parser has the `.is_subcommand_used("<command_name>")` and `.is_subcommand_used(subparser)` member functions to check if a subcommand was used.
Sometimes there may be a need to hide part of the subcommands from the user
by suppressing information about them in an help message. To do this,
```ArgumentParser``` contains the method ```.set_suppress(bool suppress)```:
```cpp
argparse::ArgumentParser program("test");
argparse::ArgumentParser hidden_cmd("hidden");
hidden_cmd.add_argument("files").remaining();
hidden_cmd.set_suppress(true);
program.add_subparser(hidden_cmd);
```
```console
foo@bar:/home/dev/$ ./main -h
Usage: test [--help] [--version] {}
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
foo@bar:/home/dev/$ ./main hidden -h
Usage: hidden [--help] [--version] files
Positional arguments:
files [nargs: 0 or more]
Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
```
### Getting Argument and Subparser Instances ### Getting Argument and Subparser Instances
```Argument``` and ```ArgumentParser``` instances added to an ```ArgumentParser``` can be retrieved with ```.at<T>()```. The default return type is ```Argument```. ```Argument``` and ```ArgumentParser``` instances added to an ```ArgumentParser``` can be retrieved with ```.at<T>()```. The default return type is ```Argument```.

View File

@ -1405,7 +1405,8 @@ public:
m_assign_chars(other.m_assign_chars), m_is_parsed(other.m_is_parsed), m_assign_chars(other.m_assign_chars), m_is_parsed(other.m_is_parsed),
m_positional_arguments(other.m_positional_arguments), m_positional_arguments(other.m_positional_arguments),
m_optional_arguments(other.m_optional_arguments), m_optional_arguments(other.m_optional_arguments),
m_parser_path(other.m_parser_path), m_subparsers(other.m_subparsers) { m_parser_path(other.m_parser_path), m_subparsers(other.m_subparsers),
m_suppress(other.m_suppress) {
for (auto it = std::begin(m_positional_arguments); for (auto it = std::begin(m_positional_arguments);
it != std::end(m_positional_arguments); ++it) { it != std::end(m_positional_arguments); ++it) {
index_argument(it); index_argument(it);
@ -1747,12 +1748,22 @@ public:
stream << argument; stream << argument;
} }
if (!parser.m_subparser_map.empty()) { bool has_visible_subcommands = std::any_of(
parser.m_subparser_map.begin(),
parser.m_subparser_map.end(),
[] (auto &p) { return !p.second->get().m_suppress; }
);
if (has_visible_subcommands) {
stream << (parser.m_positional_arguments.empty() stream << (parser.m_positional_arguments.empty()
? (parser.m_optional_arguments.empty() ? "" : "\n") ? (parser.m_optional_arguments.empty() ? "" : "\n")
: "\n") : "\n")
<< "Subcommands:\n"; << "Subcommands:\n";
for (const auto &[command, subparser] : parser.m_subparser_map) { for (const auto &[command, subparser] : parser.m_subparser_map) {
if (subparser->get().m_suppress) {
continue;
}
stream << std::setw(2) << " "; stream << std::setw(2) << " ";
stream << std::setw(static_cast<int>(longest_arg_length - 2)) stream << std::setw(static_cast<int>(longest_arg_length - 2))
<< command; << command;
@ -1797,7 +1808,11 @@ public:
if (!m_subparser_map.empty()) { if (!m_subparser_map.empty()) {
stream << " {"; stream << " {";
std::size_t i{0}; std::size_t i{0};
for (const auto &[command, unused] : m_subparser_map) { for (const auto &[command, subparser] : m_subparser_map) {
if (subparser->get().m_suppress) {
continue;
}
if (i == 0) { if (i == 0) {
stream << command; stream << command;
} else { } else {
@ -1827,6 +1842,10 @@ public:
m_subparser_used.insert_or_assign(parser.m_program_name, false); m_subparser_used.insert_or_assign(parser.m_program_name, false);
} }
void set_suppress(bool suppress) {
m_suppress = suppress;
}
private: private:
bool is_valid_prefix_char(char c) const { bool is_valid_prefix_char(char c) const {
return m_prefix_chars.find(c) != std::string::npos; return m_prefix_chars.find(c) != std::string::npos;
@ -2120,6 +2139,7 @@ private:
std::map<std::string_view, argument_parser_it> m_subparser_map; std::map<std::string_view, argument_parser_it> m_subparser_map;
std::map<std::string_view, bool> m_subparser_used; std::map<std::string_view, bool> m_subparser_used;
std::vector<MutuallyExclusiveGroup> m_mutually_exclusive_groups; std::vector<MutuallyExclusiveGroup> m_mutually_exclusive_groups;
bool m_suppress = false;
}; };
} // namespace argparse } // namespace argparse

View File

@ -244,3 +244,39 @@ TEST_CASE("Check is_subcommand_used after parse" * test_suite("subparsers")) {
REQUIRE(program.is_subcommand_used(command_2) == false); REQUIRE(program.is_subcommand_used(command_2) == false);
} }
} }
static bool contains(const std::string &haystack, const std::string &needle) {
return haystack.find(needle) != std::string::npos;
}
TEST_CASE("Check set_suppress" * test_suite("subparsers")) {
argparse::ArgumentParser command("cmd");
command.add_argument("arg").remaining();
argparse::ArgumentParser program("test");
program.add_subparser(command);
SUBCASE("help message contain info if subcommand not suppressed") {
command.set_suppress(false);
REQUIRE(contains(program.help().str(), "Subcommands") == true);
REQUIRE(contains(program.help().str(), "cmd") == true);
}
SUBCASE("help message does not contain info if subcommand suppressed") {
command.set_suppress(true);
REQUIRE(contains(program.help().str(), "Subcommands") == false);
REQUIRE(contains(program.help().str(), "cmd") == false);
}
SUBCASE("help message contain info if not all subcommands suppressed") {
argparse::ArgumentParser command_2("command_2");
program.add_subparser(command_2);
command.set_suppress(true);
command_2.set_suppress(false);
REQUIRE(contains(program.help().str(), "Subcommands") == true);
REQUIRE(contains(program.help().str(), "cmd") == false);
REQUIRE(contains(program.help().str(), "command_2") == true);
}
}