mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-30 12:43:52 +00:00
commit
b88f1f2ac7
@ -1,3 +1,7 @@
|
|||||||
|
## Version 1.2 (in progress)
|
||||||
|
|
||||||
|
* Required positionals now take priority over subcommands [#23](https://github.com/CLIUtils/CLI11/issues/23)
|
||||||
|
|
||||||
## Version 1.1
|
## Version 1.1
|
||||||
|
|
||||||
* Added simple support for enumerations, allow non-printable objects [#12](https://github.com/CLIUtils/CLI11/issues/12)
|
* Added simple support for enumerations, allow non-printable objects [#12](https://github.com/CLIUtils/CLI11/issues/12)
|
||||||
|
@ -198,6 +198,8 @@ There are several options that are supported on the main app and subcommands. Th
|
|||||||
* `.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).
|
* `.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.
|
* `.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.
|
||||||
|
|
||||||
|
> Note: if you have a fixed number of required positional options, that will match before subcommand names.
|
||||||
|
|
||||||
## Configuration file
|
## Configuration file
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
@ -855,7 +855,7 @@ class App {
|
|||||||
|
|
||||||
bool _valid_subcommand(const std::string ¤t) const {
|
bool _valid_subcommand(const std::string ¤t) const {
|
||||||
for(const App_p &com : subcommands_)
|
for(const App_p &com : subcommands_)
|
||||||
if(com->check_name(current))
|
if(com->check_name(current) && !*com)
|
||||||
return true;
|
return true;
|
||||||
if(parent_ != nullptr)
|
if(parent_ != nullptr)
|
||||||
return parent_->_valid_subcommand(current);
|
return parent_->_valid_subcommand(current);
|
||||||
@ -1064,6 +1064,19 @@ class App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Count the required remaining positional arguments
|
||||||
|
size_t _count_remaining_required_positionals() const {
|
||||||
|
size_t retval = 0;
|
||||||
|
for(const Option_p &opt : options_)
|
||||||
|
if(opt->get_positional()
|
||||||
|
&& opt->get_required()
|
||||||
|
&& opt->get_expected() > 0
|
||||||
|
&& static_cast<int>(opt->count()) < opt->get_expected())
|
||||||
|
retval = static_cast<size_t>(opt->get_expected()) - opt->count();
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a positional, go up the tree to check
|
/// Parse a positional, go up the tree to check
|
||||||
void _parse_positional(std::vector<std::string> &args) {
|
void _parse_positional(std::vector<std::string> &args) {
|
||||||
|
|
||||||
@ -1100,6 +1113,8 @@ class App {
|
|||||||
///
|
///
|
||||||
/// 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_required_positionals() > 0)
|
||||||
|
return _parse_positional(args);
|
||||||
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();
|
||||||
|
@ -74,6 +74,81 @@ TEST_F(TApp, MultiSubFallthrough) {
|
|||||||
EXPECT_THROW(app.got_subcommand("sub3"), CLI::OptionNotFound);
|
EXPECT_THROW(app.got_subcommand("sub3"), CLI::OptionNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(TApp, RequiredAndSubcoms) { // #23
|
||||||
|
|
||||||
|
std::string baz;
|
||||||
|
app.add_option("baz", baz, "Baz Description", true)->required();
|
||||||
|
auto foo = app.add_subcommand("foo");
|
||||||
|
auto bar = app.add_subcommand("bar");
|
||||||
|
|
||||||
|
args = {"bar", "foo"};
|
||||||
|
EXPECT_NO_THROW(run());
|
||||||
|
EXPECT_TRUE(*foo);
|
||||||
|
EXPECT_FALSE(*bar);
|
||||||
|
EXPECT_EQ(baz, "bar");
|
||||||
|
|
||||||
|
app.reset();
|
||||||
|
args = {"foo"};
|
||||||
|
EXPECT_NO_THROW(run());
|
||||||
|
EXPECT_FALSE(*foo);
|
||||||
|
EXPECT_EQ(baz, "foo");
|
||||||
|
|
||||||
|
app.reset();
|
||||||
|
args = {"foo", "foo"};
|
||||||
|
EXPECT_NO_THROW(run());
|
||||||
|
EXPECT_TRUE(*foo);
|
||||||
|
EXPECT_EQ(baz, "foo");
|
||||||
|
|
||||||
|
app.reset();
|
||||||
|
args = {"foo", "other"};
|
||||||
|
EXPECT_THROW(run(), CLI::ExtrasError);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TApp, RequiredAndSubcomFallthrough) {
|
||||||
|
|
||||||
|
std::string baz;
|
||||||
|
app.add_option("baz", baz)->required();
|
||||||
|
app.add_subcommand("foo");
|
||||||
|
auto bar = app.add_subcommand("bar");
|
||||||
|
app.fallthrough();
|
||||||
|
|
||||||
|
args = {"other", "bar"};
|
||||||
|
run();
|
||||||
|
EXPECT_TRUE(bar);
|
||||||
|
EXPECT_EQ(baz, "other");
|
||||||
|
|
||||||
|
app.reset();
|
||||||
|
args = {"bar", "other2"};
|
||||||
|
EXPECT_THROW(run(), CLI::ExtrasError);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TApp, FooFooProblem) {
|
||||||
|
|
||||||
|
std::string baz_str, other_str;
|
||||||
|
auto baz = app.add_option("baz", baz_str);
|
||||||
|
auto foo = app.add_subcommand("foo");
|
||||||
|
auto other = foo->add_option("other", other_str);
|
||||||
|
|
||||||
|
args = {"foo", "foo"};
|
||||||
|
run();
|
||||||
|
EXPECT_TRUE(*foo);
|
||||||
|
EXPECT_FALSE(*baz);
|
||||||
|
EXPECT_TRUE(*other);
|
||||||
|
EXPECT_EQ(baz_str, "");
|
||||||
|
EXPECT_EQ(other_str, "foo");
|
||||||
|
|
||||||
|
app.reset();
|
||||||
|
baz_str = "";
|
||||||
|
other_str = "";
|
||||||
|
baz->required();
|
||||||
|
run();
|
||||||
|
EXPECT_TRUE(*foo);
|
||||||
|
EXPECT_TRUE(*baz);
|
||||||
|
EXPECT_FALSE(*other);
|
||||||
|
EXPECT_EQ(baz_str, "foo");
|
||||||
|
EXPECT_EQ(other_str, "");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TApp, Callbacks) {
|
TEST_F(TApp, Callbacks) {
|
||||||
auto sub1 = app.add_subcommand("sub1");
|
auto sub1 = app.add_subcommand("sub1");
|
||||||
sub1->set_callback([]() { throw CLI::Success(); });
|
sub1->set_callback([]() { throw CLI::Success(); });
|
||||||
|
Loading…
x
Reference in New Issue
Block a user