Skip to content

Commit

Permalink
Merge pull request #16 from CLIUtils/prefix_program
Browse files Browse the repository at this point in the history
Prefix program support
  • Loading branch information
henryiii authored Jun 5, 2017
2 parents e3423bb + 36ac4c1 commit 1c1a622
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## Version 1.1 (in progress)
* Added `app.parse_order()` with original parse order
* Added `prefix_command()`, which is like `allow_extras` but instantly stops and returns.

## Version 1.0
* Cleanup using `clang-tidy` and `clang-format`
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ There are several options that are supported on the main app and subcommands. Th
* `.parsed()`: True if this subcommand was given on the command line
* `.set_callback(void() function)`: Set the callback that runs at the end of parsing. The options have already run at this point.
* `.allow_extras()`: Do not throw an error if extra arguments are left over (Only useful on the main `App`, as that's the one that throws errors).
* `.prefix_command()`: Like `allow_extras`, but stop immediately on the first unrecognised item. It is ideal for allowing your app to be a "prefix" to calling another app.

## Configuration file

Expand Down
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ add_cli_exe(simple simple.cpp)
add_cli_exe(subcommands subcommands.cpp)
add_cli_exe(groups groups.cpp)
add_cli_exe(inter_argument_order inter_argument_order.cpp)
add_cli_exe(prefix_command prefix_command.cpp)
32 changes: 32 additions & 0 deletions examples/prefix_command.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "CLI/CLI.hpp"

int main(int argc, char **argv) {

CLI::App app("Prefix command app");
app.prefix_command();

std::vector<int> vals;
app.add_option("--vals,-v", vals)
->expected(1);

std::vector<std::string> more_comms;
try {
more_comms = app.parse(argc, argv);
} catch(const CLI::ParseError &e) {
return app.exit(e);
}

std::cout << "Prefix:";
for(int v : vals)
std::cout << v << ":";

std::cout << std::endl << "Remaining commands: ";

// Perfer to loop over from beginning, not "pop" order
std::reverse(std::begin(more_comms), std::end(more_comms));
for(auto com : more_comms)
std::cout << com << " ";
std::cout << std::endl;

return 0;
}
19 changes: 18 additions & 1 deletion include/CLI/App.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ class App {
/// If true, allow extra arguments (ie, don't throw an error).
bool allow_extras_{false};

/// If true, return immediatly on an unrecognised option (implies allow_extras)
bool prefix_command_{false};

/// This is a function that runs when complete. Great for subcommands. Can throw.
std::function<void()> callback_;

Expand Down Expand Up @@ -152,6 +155,12 @@ class App {
return this;
}

/// Do not parse anything after the first unrecongnised option and return
App *prefix_command(bool allow = true) {
prefix_command_ = allow;
return this;
}

/// Ignore case. Subcommand inherit value.
App *ignore_case(bool value = true) {
ignore_case_ = value;
Expand Down Expand Up @@ -855,7 +864,7 @@ class App {
return val.first != detail::Classifer::POSITIONAL_MARK;
});

if(num_left_over > 0 && !allow_extras_)
if(num_left_over > 0 && !(allow_extras_ || prefix_command_))
throw ExtrasError("[" + detail::rjoin(args, " ") + "]");
}
}
Expand Down Expand Up @@ -966,7 +975,15 @@ class App {
else {
args.pop_back();
missing()->emplace_back(detail::Classifer::NONE, positional);

if(prefix_command_) {
while(!args.empty()) {
missing()->emplace_back(detail::Classifer::NONE, args.back());
args.pop_back();
}
}
}

}

/// Parse a subcommand, modify args and continue
Expand Down
13 changes: 13 additions & 0 deletions tests/SubcommandTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,19 @@ TEST_F(TApp, BadSubcomSearch) {
EXPECT_THROW(app.get_subcommand(two), CLI::OptionNotFound);
}

TEST_F(TApp, PrefixProgram) {

app.prefix_command();

app.add_flag("--simple");

args = {"--simple", "other", "--simple", "--mine"};
auto ret_args = run();

EXPECT_EQ(ret_args, std::vector<std::string>({"--mine", "--simple", "other"}));

}

struct SubcommandProgram : public TApp {

CLI::App *start;
Expand Down

0 comments on commit 1c1a622

Please sign in to comment.