mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-05-05 14:43:52 +00:00
Adding take_last
This commit is contained in:
parent
0a35db8f00
commit
20cccfc353
@ -155,6 +155,7 @@ The add commands return a pointer to an internally stored `Option`. If you set t
|
|||||||
* `->envname(name)`: Gets the value from the environment if present and not passed on the command line.
|
* `->envname(name)`: Gets the value from the environment if present and not passed on the command line.
|
||||||
* `->group(name)`: The help group to put the option in. No effect for positional options. Defaults to `"Options"`. `"Hidden"` will not show up in the help print.
|
* `->group(name)`: The help group to put the option in. No effect for positional options. Defaults to `"Options"`. `"Hidden"` will not show up in the help print.
|
||||||
* `->ignore_case()`: Ignore the case on the command line (also works on subcommands, does not affect arguments).
|
* `->ignore_case()`: Ignore the case on the command line (also works on subcommands, does not affect arguments).
|
||||||
|
* `->take_last()`: Only take the last option/flag given on the command line, automatically true for bool flags
|
||||||
* `->check(CLI::ExistingFile)`: Requires that the file exists if given.
|
* `->check(CLI::ExistingFile)`: Requires that the file exists if given.
|
||||||
* `->check(CLI::ExistingDirectory)`: Requires that the directory exists.
|
* `->check(CLI::ExistingDirectory)`: Requires that the directory exists.
|
||||||
* `->check(CLI::NonexistentPath)`: Requires that the path does not exist.
|
* `->check(CLI::NonexistentPath)`: Requires that the path does not exist.
|
||||||
|
@ -351,22 +351,23 @@ class App {
|
|||||||
return opt;
|
return opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bool version
|
/// Bool version - defaults to allowing multiple passings, but can be forced to one if `take_last(false)` is used.
|
||||||
template <typename T, enable_if_t<is_bool<T>::value, detail::enabler> = detail::dummy>
|
template <typename T, enable_if_t<is_bool<T>::value, detail::enabler> = detail::dummy>
|
||||||
Option *add_flag(std::string name,
|
Option *add_flag(std::string name,
|
||||||
T &count, ///< A varaible holding true if passed
|
T &count, ///< A varaible holding true if passed
|
||||||
std::string description = "") {
|
std::string description = "") {
|
||||||
|
|
||||||
count = false;
|
count = false;
|
||||||
CLI::callback_t fun = [&count](CLI::results_t) {
|
CLI::callback_t fun = [&count](CLI::results_t res) {
|
||||||
count = true;
|
count = true;
|
||||||
return true;
|
return res.size() == 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
Option *opt = add_option(name, fun, description, false);
|
Option *opt = add_option(name, fun, description, false);
|
||||||
if(opt->get_positional())
|
if(opt->get_positional())
|
||||||
throw IncorrectConstruction("Flags cannot be positional");
|
throw IncorrectConstruction("Flags cannot be positional");
|
||||||
opt->set_custom_option("", 0);
|
opt->set_custom_option("", 0);
|
||||||
|
opt->take_last();
|
||||||
return opt;
|
return opt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,6 +74,9 @@ class Option {
|
|||||||
/// The number of expected values, 0 for flag, -1 for unlimited vector
|
/// The number of expected values, 0 for flag, -1 for unlimited vector
|
||||||
int expected_{1};
|
int expected_{1};
|
||||||
|
|
||||||
|
/// Only take the last argument (requires `expected_ == 1`)
|
||||||
|
bool last_{false};
|
||||||
|
|
||||||
/// A private setting to allow args to not be able to accept incorrect expected values
|
/// A private setting to allow args to not be able to accept incorrect expected values
|
||||||
bool changeable_{false};
|
bool changeable_{false};
|
||||||
|
|
||||||
@ -155,10 +158,20 @@ class Option {
|
|||||||
throw IncorrectConstruction("Cannot make a flag take arguments!");
|
throw IncorrectConstruction("Cannot make a flag take arguments!");
|
||||||
else if(!changeable_)
|
else if(!changeable_)
|
||||||
throw IncorrectConstruction("You can only change the expected arguments for vectors");
|
throw IncorrectConstruction("You can only change the expected arguments for vectors");
|
||||||
|
else if(last_)
|
||||||
|
throw IncorrectConstruction("You can't change expected arguments after you've set take_last!");
|
||||||
expected_ = value;
|
expected_ = value;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Take the last argument if given multiple times
|
||||||
|
Option *take_last(bool value = true) {
|
||||||
|
if(expected_ != 0 && expected_ != 1)
|
||||||
|
throw IncorrectConstruction("take_last only works for flags and single value options!");
|
||||||
|
last_ = value;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a validator
|
/// Adds a validator
|
||||||
Option *check(std::function<bool(std::string)> validator) {
|
Option *check(std::function<bool(std::string)> validator) {
|
||||||
|
|
||||||
@ -243,6 +256,9 @@ class Option {
|
|||||||
/// The number of arguments the option expects
|
/// The number of arguments the option expects
|
||||||
int get_expected() const { return expected_; }
|
int get_expected() const { return expected_; }
|
||||||
|
|
||||||
|
/// The status of the take last flag
|
||||||
|
bool get_take_last() const { return last_; }
|
||||||
|
|
||||||
/// True if this has a default value
|
/// True if this has a default value
|
||||||
int get_default() const { return default_; }
|
int get_default() const { return default_; }
|
||||||
|
|
||||||
@ -340,7 +356,16 @@ class Option {
|
|||||||
|
|
||||||
/// Process the callback
|
/// Process the callback
|
||||||
void run_callback() const {
|
void run_callback() const {
|
||||||
if(!callback_(results_))
|
bool result;
|
||||||
|
// If take_last, only operate on the final item
|
||||||
|
if(last_) {
|
||||||
|
results_t partial_result = {results_.back()};
|
||||||
|
result = !callback_(partial_result);
|
||||||
|
} else {
|
||||||
|
result = !callback_(results_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(result)
|
||||||
throw ConversionError(get_name() + "=" + detail::join(results_));
|
throw ConversionError(get_name() + "=" + detail::join(results_));
|
||||||
if(!validators_.empty()) {
|
if(!validators_.empty()) {
|
||||||
for(const std::string &result : results_)
|
for(const std::string &result : results_)
|
||||||
@ -407,7 +432,7 @@ class Option {
|
|||||||
return std::find(std::begin(lnames_), std::end(lnames_), name) != std::end(lnames_);
|
return std::find(std::begin(lnames_), std::end(lnames_), name) != std::end(lnames_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Puts a result at position r
|
/// Puts a result at the end, unless last_ is set, in which case it just keeps the last one
|
||||||
void add_result(std::string s) {
|
void add_result(std::string s) {
|
||||||
results_.push_back(s);
|
results_.push_back(s);
|
||||||
callback_run_ = false;
|
callback_run_ = false;
|
||||||
|
@ -167,6 +167,20 @@ TEST_F(TApp, BoolAndIntFlags) {
|
|||||||
EXPECT_EQ((unsigned int)2, uflag);
|
EXPECT_EQ((unsigned int)2, uflag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(TApp, BoolOnlyFlag) {
|
||||||
|
bool bflag;
|
||||||
|
app.add_flag("-b", bflag)->take_last(false);
|
||||||
|
|
||||||
|
args = {"-b"};
|
||||||
|
EXPECT_NO_THROW(run());
|
||||||
|
EXPECT_TRUE(bflag);
|
||||||
|
|
||||||
|
app.reset();
|
||||||
|
|
||||||
|
args = {"-b", "-b"};
|
||||||
|
EXPECT_THROW(run(), CLI::ConversionError);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TApp, ShortOpts) {
|
TEST_F(TApp, ShortOpts) {
|
||||||
|
|
||||||
unsigned long long funnyint;
|
unsigned long long funnyint;
|
||||||
@ -204,6 +218,18 @@ TEST_F(TApp, DefaultOpts) {
|
|||||||
EXPECT_EQ("9", s);
|
EXPECT_EQ("9", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(TApp, TakeLastOpt) {
|
||||||
|
|
||||||
|
std::string str;
|
||||||
|
app.add_option("--str", str)->take_last();
|
||||||
|
|
||||||
|
args = {"--str=one", "--str=two"};
|
||||||
|
|
||||||
|
run();
|
||||||
|
|
||||||
|
EXPECT_EQ(str, "two");
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(TApp, EnumTest) {
|
TEST_F(TApp, EnumTest) {
|
||||||
enum Level : std::int32_t { High, Medium, Low };
|
enum Level : std::int32_t { High, Medium, Low };
|
||||||
Level level = Level::Low;
|
Level level = Level::Low;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user