mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-30 04:33:53 +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)
|
/// Check to see if a subcommand is part of this command (text version)
|
||||||
App *get_subcommand(std::string subcom) const {
|
App *get_subcommand(std::string subcom) const {
|
||||||
for(const App_p &subcomptr : subcommands_)
|
auto subc = _find_subcommand(subcom, false);
|
||||||
if(subcomptr->check_name(subcom))
|
if(subc == nullptr)
|
||||||
return subcomptr.get();
|
throw OptionNotFound(subcom);
|
||||||
throw OptionNotFound(subcom);
|
return subc;
|
||||||
}
|
}
|
||||||
/// Get a pointer to subcommand by index
|
/// Get a pointer to subcommand by index
|
||||||
App *get_subcommand(int index = 0) const {
|
App *get_subcommand(int index = 0) const {
|
||||||
@ -1736,11 +1736,10 @@ class App {
|
|||||||
if(require_subcommand_max_ != 0 && parsed_subcommands_.size() >= require_subcommand_max_) {
|
if(require_subcommand_max_ != 0 && parsed_subcommands_.size() >= require_subcommand_max_) {
|
||||||
return parent_ != nullptr && parent_->_valid_subcommand(current);
|
return parent_ != nullptr && parent_->_valid_subcommand(current);
|
||||||
}
|
}
|
||||||
|
auto com = _find_subcommand(current, true);
|
||||||
for(const App_p &com : subcommands_)
|
if((com != nullptr) && !*com) {
|
||||||
if(!com->disabled_ && com->check_name(current) && !*com)
|
return true;
|
||||||
return true;
|
}
|
||||||
|
|
||||||
// Check parent if exists, else return false
|
// Check parent if exists, else return false
|
||||||
return parent_ != nullptr && parent_->_valid_subcommand(current);
|
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
|
/// Parse a subcommand, modify args and continue
|
||||||
///
|
///
|
||||||
/// Unlike the others, this one will always allow fallthrough
|
/// Unlike the others, this one will always allow fallthrough
|
||||||
void _parse_subcommand(std::vector<std::string> &args) {
|
void _parse_subcommand(std::vector<std::string> &args) {
|
||||||
if(_count_remaining_positionals(/* required */ true) > 0)
|
if(_count_remaining_positionals(/* required */ true) > 0)
|
||||||
return _parse_positional(args);
|
return _parse_positional(args);
|
||||||
for(const App_p &com : subcommands_) {
|
auto com = _find_subcommand(args.back(), true);
|
||||||
if(com->disabled_)
|
if(com != nullptr) {
|
||||||
continue;
|
args.pop_back();
|
||||||
if(com->check_name(args.back())) {
|
if(std::find(std::begin(parsed_subcommands_), std::end(parsed_subcommands_), com) ==
|
||||||
args.pop_back();
|
std::end(parsed_subcommands_))
|
||||||
if(std::find(std::begin(parsed_subcommands_), std::end(parsed_subcommands_), com.get()) ==
|
parsed_subcommands_.push_back(com);
|
||||||
std::end(parsed_subcommands_))
|
com->_parse(args);
|
||||||
parsed_subcommands_.push_back(com.get());
|
return;
|
||||||
com->_parse(args);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(parent_ != nullptr)
|
|
||||||
return parent_->_parse_subcommand(args);
|
if(parent_ == nullptr)
|
||||||
else
|
|
||||||
throw HorribleError("Subcommand " + args.back() + " missing");
|
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
|
/// 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);
|
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) {
|
TEST_F(TApp, FallThroughRegular) {
|
||||||
app.fallthrough();
|
app.fallthrough();
|
||||||
int val = 1;
|
int val = 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user