Skip to content

Commit

Permalink
Merge pull request #273 from ismagilli/issue_258
Browse files Browse the repository at this point in the history
NEW: suppress flag for subcommand
  • Loading branch information
p-ranav authored Nov 5, 2023
2 parents 086c8f3 + 3314612 commit 3cc913d
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 4 deletions.
35 changes: 34 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ Optional arguments:
-h, --help shows help message and exits
-v, --version prints version information and exits
--member ALIAS The alias for the member to pass to.
--verbose
--verbose
Possible things include betingalw, chiz, and res.
```
Expand Down Expand Up @@ -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.

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

```Argument``` and ```ArgumentParser``` instances added to an ```ArgumentParser``` can be retrieved with ```.at<T>()```. The default return type is ```Argument```.
Expand Down
26 changes: 23 additions & 3 deletions include/argparse/argparse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1405,7 +1405,8 @@ class ArgumentParser {
m_assign_chars(other.m_assign_chars), m_is_parsed(other.m_is_parsed),
m_positional_arguments(other.m_positional_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);
it != std::end(m_positional_arguments); ++it) {
index_argument(it);
Expand Down Expand Up @@ -1747,12 +1748,22 @@ class ArgumentParser {
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()
? (parser.m_optional_arguments.empty() ? "" : "\n")
: "\n")
<< "Subcommands:\n";
for (const auto &[command, subparser] : parser.m_subparser_map) {
if (subparser->get().m_suppress) {
continue;
}

stream << std::setw(2) << " ";
stream << std::setw(static_cast<int>(longest_arg_length - 2))
<< command;
Expand Down Expand Up @@ -1797,7 +1808,11 @@ class ArgumentParser {
if (!m_subparser_map.empty()) {
stream << " {";
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) {
stream << command;
} else {
Expand Down Expand Up @@ -1827,6 +1842,10 @@ class ArgumentParser {
m_subparser_used.insert_or_assign(parser.m_program_name, false);
}

void set_suppress(bool suppress) {
m_suppress = suppress;
}

private:
bool is_valid_prefix_char(char c) const {
return m_prefix_chars.find(c) != std::string::npos;
Expand Down Expand Up @@ -2120,6 +2139,7 @@ class ArgumentParser {
std::map<std::string_view, argument_parser_it> m_subparser_map;
std::map<std::string_view, bool> m_subparser_used;
std::vector<MutuallyExclusiveGroup> m_mutually_exclusive_groups;
bool m_suppress = false;
};

} // namespace argparse
36 changes: 36 additions & 0 deletions test/test_subparsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,3 +244,39 @@ TEST_CASE("Check is_subcommand_used after parse" * test_suite("subparsers")) {
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);
}
}

0 comments on commit 3cc913d

Please sign in to comment.