mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-29 12:13:52 +00:00
merge upstream App (#246)
Make sure that nameless subcommands can handle subcommands and that App will treat subcommands in a group nearly the same as if they were in the in the app to begin with.
This commit is contained in:
parent
0631189b4d
commit
6aa546fc42
@ -1045,10 +1045,10 @@ class App {
|
||||
|
||||
/// Check to see if a subcommand is part of this command (text version)
|
||||
App *get_subcommand(std::string subcom) const {
|
||||
for(const App_p &subcomptr : subcommands_)
|
||||
if(subcomptr->check_name(subcom))
|
||||
return subcomptr.get();
|
||||
throw OptionNotFound(subcom);
|
||||
auto subc = _find_subcommand(subcom, false);
|
||||
if(subc == nullptr)
|
||||
throw OptionNotFound(subcom);
|
||||
return subc;
|
||||
}
|
||||
/// Get a pointer to subcommand by index
|
||||
App *get_subcommand(int index = 0) const {
|
||||
@ -1736,11 +1736,10 @@ class App {
|
||||
if(require_subcommand_max_ != 0 && parsed_subcommands_.size() >= require_subcommand_max_) {
|
||||
return parent_ != nullptr && parent_->_valid_subcommand(current);
|
||||
}
|
||||
|
||||
for(const App_p &com : subcommands_)
|
||||
if(!com->disabled_ && com->check_name(current) && !*com)
|
||||
return true;
|
||||
|
||||
auto com = _find_subcommand(current, true);
|
||||
if((com != nullptr) && !*com) {
|
||||
return true;
|
||||
}
|
||||
// Check parent if exists, else return false
|
||||
return parent_ != nullptr && parent_->_valid_subcommand(current);
|
||||
}
|
||||
@ -2151,28 +2150,43 @@ class App {
|
||||
}
|
||||
}
|
||||
|
||||
/// Locate a subcommand by name
|
||||
App *_find_subcommand(const std::string &subc_name, bool ignore_disabled) const noexcept {
|
||||
for(const App_p &com : subcommands_) {
|
||||
if((com->disabled_) && (ignore_disabled))
|
||||
continue;
|
||||
if(com->get_name().empty()) {
|
||||
auto subc = com->_find_subcommand(subc_name, ignore_disabled);
|
||||
if(subc != nullptr) {
|
||||
return subc;
|
||||
}
|
||||
} else if(com->check_name(subc_name)) {
|
||||
return com.get();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Parse a subcommand, modify args and continue
|
||||
///
|
||||
/// Unlike the others, this one will always allow fallthrough
|
||||
void _parse_subcommand(std::vector<std::string> &args) {
|
||||
if(_count_remaining_positionals(/* required */ true) > 0)
|
||||
return _parse_positional(args);
|
||||
for(const App_p &com : subcommands_) {
|
||||
if(com->disabled_)
|
||||
continue;
|
||||
if(com->check_name(args.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);
|
||||
return;
|
||||
}
|
||||
auto com = _find_subcommand(args.back(), true);
|
||||
if(com != nullptr) {
|
||||
args.pop_back();
|
||||
if(std::find(std::begin(parsed_subcommands_), std::end(parsed_subcommands_), com) ==
|
||||
std::end(parsed_subcommands_))
|
||||
parsed_subcommands_.push_back(com);
|
||||
com->_parse(args);
|
||||
return;
|
||||
}
|
||||
if(parent_ != nullptr)
|
||||
return parent_->_parse_subcommand(args);
|
||||
else
|
||||
|
||||
if(parent_ == nullptr)
|
||||
throw HorribleError("Subcommand " + args.back() + " missing");
|
||||
|
||||
return parent_->_parse_subcommand(args);
|
||||
}
|
||||
|
||||
/// Parse a short (false) or long (true) argument, must be at the top of the list
|
||||
|
@ -234,6 +234,109 @@ TEST_F(TApp, NamelessSubComPositionals) {
|
||||
EXPECT_EQ(val, 2);
|
||||
}
|
||||
|
||||
TEST_F(TApp, NamelessSubWithSub) {
|
||||
|
||||
auto sub = app.add_subcommand();
|
||||
auto subsub = sub->add_subcommand("val");
|
||||
|
||||
args = {"val"};
|
||||
run();
|
||||
EXPECT_TRUE(subsub->parsed());
|
||||
EXPECT_TRUE(app.got_subcommand("val"));
|
||||
}
|
||||
|
||||
TEST_F(TApp, NamelessSubWithMultipleSub) {
|
||||
|
||||
auto sub1 = app.add_subcommand();
|
||||
auto sub2 = app.add_subcommand();
|
||||
auto sub1sub1 = sub1->add_subcommand("val1");
|
||||
auto sub1sub2 = sub1->add_subcommand("val2");
|
||||
auto sub2sub1 = sub2->add_subcommand("val3");
|
||||
auto sub2sub2 = sub2->add_subcommand("val4");
|
||||
args = {"val1"};
|
||||
run();
|
||||
EXPECT_TRUE(sub1sub1->parsed());
|
||||
EXPECT_TRUE(app.got_subcommand("val1"));
|
||||
|
||||
args = {"val2"};
|
||||
run();
|
||||
EXPECT_TRUE(sub1sub2->parsed());
|
||||
EXPECT_TRUE(app.got_subcommand("val2"));
|
||||
|
||||
args = {"val3"};
|
||||
run();
|
||||
EXPECT_TRUE(sub2sub1->parsed());
|
||||
EXPECT_TRUE(app.got_subcommand("val3"));
|
||||
|
||||
args = {"val4"};
|
||||
run();
|
||||
EXPECT_TRUE(sub2sub2->parsed());
|
||||
EXPECT_TRUE(app.got_subcommand("val4"));
|
||||
|
||||
args = {"val4", "val1"};
|
||||
run();
|
||||
EXPECT_TRUE(sub2sub2->parsed());
|
||||
EXPECT_TRUE(app.got_subcommand("val4"));
|
||||
EXPECT_TRUE(sub1sub1->parsed());
|
||||
EXPECT_TRUE(app.got_subcommand("val1"));
|
||||
}
|
||||
|
||||
TEST_F(TApp, Nameless4LayerDeep) {
|
||||
|
||||
auto sub = app.add_subcommand();
|
||||
auto ssub = sub->add_subcommand();
|
||||
auto sssub = ssub->add_subcommand();
|
||||
|
||||
auto ssssub = sssub->add_subcommand();
|
||||
auto sssssub = ssssub->add_subcommand("val");
|
||||
|
||||
args = {"val"};
|
||||
run();
|
||||
EXPECT_TRUE(sssssub->parsed());
|
||||
EXPECT_TRUE(app.got_subcommand("val"));
|
||||
}
|
||||
|
||||
/// Put subcommands in some crazy pattern and make everything still works
|
||||
TEST_F(TApp, Nameless4LayerDeepMulit) {
|
||||
|
||||
auto sub1 = app.add_subcommand();
|
||||
auto sub2 = app.add_subcommand();
|
||||
auto ssub1 = sub1->add_subcommand();
|
||||
auto ssub2 = sub2->add_subcommand();
|
||||
|
||||
auto sssub1 = ssub1->add_subcommand();
|
||||
auto sssub2 = ssub2->add_subcommand();
|
||||
sssub1->add_subcommand("val1");
|
||||
ssub2->add_subcommand("val2");
|
||||
sub2->add_subcommand("val3");
|
||||
ssub1->add_subcommand("val4");
|
||||
sssub2->add_subcommand("val5");
|
||||
args = {"val1"};
|
||||
run();
|
||||
EXPECT_TRUE(app.got_subcommand("val1"));
|
||||
|
||||
args = {"val2"};
|
||||
run();
|
||||
EXPECT_TRUE(app.got_subcommand("val2"));
|
||||
|
||||
args = {"val3"};
|
||||
run();
|
||||
EXPECT_TRUE(app.got_subcommand("val3"));
|
||||
|
||||
args = {"val4"};
|
||||
run();
|
||||
EXPECT_TRUE(app.got_subcommand("val4"));
|
||||
args = {"val5"};
|
||||
run();
|
||||
EXPECT_TRUE(app.got_subcommand("val5"));
|
||||
|
||||
args = {"val4", "val1", "val5"};
|
||||
run();
|
||||
EXPECT_TRUE(app.got_subcommand("val4"));
|
||||
EXPECT_TRUE(app.got_subcommand("val1"));
|
||||
EXPECT_TRUE(app.got_subcommand("val5"));
|
||||
}
|
||||
|
||||
TEST_F(TApp, FallThroughRegular) {
|
||||
app.fallthrough();
|
||||
int val = 1;
|
||||
|
Loading…
x
Reference in New Issue
Block a user