mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 20:23:55 +00:00
Subcommand parse order corrected and preserved
This commit is contained in:
parent
512b3604e2
commit
9acaeebd1e
@ -102,6 +102,9 @@ class App {
|
|||||||
/// This is a list of pointers to options with the original parse order
|
/// This is a list of pointers to options with the original parse order
|
||||||
std::vector<Option *> parse_order_;
|
std::vector<Option *> parse_order_;
|
||||||
|
|
||||||
|
/// This is a list of the subcommands collected, in order
|
||||||
|
std::vector<App *> parsed_subcommands_;
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
/// @name Subcommands
|
/// @name Subcommands
|
||||||
///@{
|
///@{
|
||||||
@ -732,6 +735,7 @@ class App {
|
|||||||
|
|
||||||
parsed_ = false;
|
parsed_ = false;
|
||||||
missing_.clear();
|
missing_.clear();
|
||||||
|
parsed_subcommands_.clear();
|
||||||
|
|
||||||
for(const Option_p &opt : options_) {
|
for(const Option_p &opt : options_) {
|
||||||
opt->clear();
|
opt->clear();
|
||||||
@ -755,13 +759,18 @@ class App {
|
|||||||
throw OptionNotFound(name);
|
throw OptionNotFound(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a subcommand pointer list to the currently selected subcommands (after parsing)
|
/// Get a subcommand pointer list to the currently selected subcommands (after parsing by default, in command line
|
||||||
std::vector<App *> get_subcommands() const {
|
/// order)
|
||||||
std::vector<App *> subcomms;
|
std::vector<App *> get_subcommands(bool parsed = true) const {
|
||||||
for(const App_p &subcomptr : subcommands_)
|
if(parsed) {
|
||||||
if(subcomptr->parsed_)
|
return parsed_subcommands_;
|
||||||
subcomms.push_back(subcomptr.get());
|
} else {
|
||||||
return subcomms;
|
std::vector<App *> subcomms(subcommands_.size());
|
||||||
|
std::transform(std::begin(subcommands_), std::end(subcommands_), std::begin(subcomms), [](const App_p &v) {
|
||||||
|
return v.get();
|
||||||
|
});
|
||||||
|
return subcomms;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check to see if given subcommand was selected
|
/// Check to see if given subcommand was selected
|
||||||
@ -952,7 +961,7 @@ class App {
|
|||||||
miss_list.push_back(std::get<1>(miss));
|
miss_list.push_back(std::get<1>(miss));
|
||||||
}
|
}
|
||||||
if(recurse) {
|
if(recurse) {
|
||||||
for(const App_p &sub : subcommands_) {
|
for(const App *sub : parsed_subcommands_) {
|
||||||
std::vector<std::string> output = sub->remaining(recurse);
|
std::vector<std::string> output = sub->remaining(recurse);
|
||||||
std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));
|
std::copy(std::begin(output), std::end(output), std::back_inserter(miss_list));
|
||||||
}
|
}
|
||||||
@ -1260,6 +1269,9 @@ class App {
|
|||||||
for(const App_p &com : subcommands_) {
|
for(const App_p &com : subcommands_) {
|
||||||
if(com->check_name(args.back())) {
|
if(com->check_name(args.back())) {
|
||||||
args.pop_back();
|
args.pop_back();
|
||||||
|
if(std::find(std::begin(parsed_subcommands_), std::end(parsed_subcommands_), com.get()) ==
|
||||||
|
std::end(parsed_subcommands_))
|
||||||
|
parsed_subcommands_.push_back(com.get());
|
||||||
com->_parse(args);
|
com->_parse(args);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ TEST_F(TApp, BasicSubcommands) {
|
|||||||
|
|
||||||
args = {"sub2"};
|
args = {"sub2"};
|
||||||
run();
|
run();
|
||||||
|
EXPECT_EQ((size_t)1, app.get_subcommands().size());
|
||||||
EXPECT_EQ(sub2, app.get_subcommands().at(0));
|
EXPECT_EQ(sub2, app.get_subcommands().at(0));
|
||||||
|
|
||||||
app.reset();
|
app.reset();
|
||||||
@ -560,3 +561,84 @@ TEST_F(SubcommandProgram, Groups) {
|
|||||||
EXPECT_THAT(help, HasSubstr("More Commands:"));
|
EXPECT_THAT(help, HasSubstr("More Commands:"));
|
||||||
EXPECT_THAT(help, Not(HasSubstr("Subcommands:")));
|
EXPECT_THAT(help, Not(HasSubstr("Subcommands:")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SubcommandProgram, ExtrasErrors) {
|
||||||
|
|
||||||
|
args = {"one", "two", "start", "three", "four"};
|
||||||
|
EXPECT_THROW(run(), CLI::ExtrasError);
|
||||||
|
app.reset();
|
||||||
|
|
||||||
|
args = {"start", "three", "four"};
|
||||||
|
EXPECT_THROW(run(), CLI::ExtrasError);
|
||||||
|
app.reset();
|
||||||
|
|
||||||
|
args = {"one", "two"};
|
||||||
|
EXPECT_THROW(run(), CLI::ExtrasError);
|
||||||
|
app.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SubcommandProgram, OrderedExtras) {
|
||||||
|
|
||||||
|
app.allow_extras();
|
||||||
|
args = {"one", "two", "start", "three", "four"};
|
||||||
|
EXPECT_THROW(run(), CLI::ExtrasError);
|
||||||
|
app.reset();
|
||||||
|
|
||||||
|
start->allow_extras();
|
||||||
|
|
||||||
|
run();
|
||||||
|
|
||||||
|
EXPECT_EQ(app.remaining(), std::vector<std::string>({"one", "two"}));
|
||||||
|
EXPECT_EQ(start->remaining(), std::vector<std::string>({"three", "four"}));
|
||||||
|
EXPECT_EQ(app.remaining(true), std::vector<std::string>({"one", "two", "three", "four"}));
|
||||||
|
|
||||||
|
app.reset();
|
||||||
|
args = {"one", "two", "start", "three", "--", "four"};
|
||||||
|
|
||||||
|
run();
|
||||||
|
|
||||||
|
EXPECT_EQ(app.remaining(), std::vector<std::string>({"one", "two"}));
|
||||||
|
EXPECT_EQ(start->remaining(), std::vector<std::string>({"three", "--", "four"}));
|
||||||
|
EXPECT_EQ(app.remaining(true), std::vector<std::string>({"one", "two", "three", "--", "four"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SubcommandProgram, MixedOrderExtras) {
|
||||||
|
|
||||||
|
app.allow_extras();
|
||||||
|
start->allow_extras();
|
||||||
|
stop->allow_extras();
|
||||||
|
|
||||||
|
args = {"one", "two", "start", "three", "four", "stop", "five", "six"};
|
||||||
|
run();
|
||||||
|
|
||||||
|
EXPECT_EQ(app.remaining(), std::vector<std::string>({"one", "two"}));
|
||||||
|
EXPECT_EQ(start->remaining(), std::vector<std::string>({"three", "four"}));
|
||||||
|
EXPECT_EQ(stop->remaining(), std::vector<std::string>({"five", "six"}));
|
||||||
|
EXPECT_EQ(app.remaining(true), std::vector<std::string>({"one", "two", "three", "four", "five", "six"}));
|
||||||
|
|
||||||
|
app.reset();
|
||||||
|
args = {"one", "two", "stop", "three", "four", "start", "five", "six"};
|
||||||
|
run();
|
||||||
|
|
||||||
|
EXPECT_EQ(app.remaining(), std::vector<std::string>({"one", "two"}));
|
||||||
|
EXPECT_EQ(stop->remaining(), std::vector<std::string>({"three", "four"}));
|
||||||
|
EXPECT_EQ(start->remaining(), std::vector<std::string>({"five", "six"}));
|
||||||
|
EXPECT_EQ(app.remaining(true), std::vector<std::string>({"one", "two", "three", "four", "five", "six"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SubcommandProgram, CallbackOrder) {
|
||||||
|
std::vector<int> callback_order;
|
||||||
|
start->set_callback([&callback_order]() { callback_order.push_back(1); });
|
||||||
|
stop->set_callback([&callback_order]() { callback_order.push_back(2); });
|
||||||
|
|
||||||
|
args = {"start", "stop"};
|
||||||
|
run();
|
||||||
|
EXPECT_EQ(callback_order, std::vector<int>({1, 2}));
|
||||||
|
|
||||||
|
app.reset();
|
||||||
|
callback_order.clear();
|
||||||
|
|
||||||
|
args = {"stop", "start"};
|
||||||
|
run();
|
||||||
|
EXPECT_EQ(callback_order, std::vector<int>({2, 1}));
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user