mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-05-03 14:03:52 +00:00
Adding size instead of expected + unchangable
This commit is contained in:
parent
de06d50f34
commit
447bda047f
@ -835,7 +835,7 @@ class App {
|
|||||||
std::string value;
|
std::string value;
|
||||||
|
|
||||||
// Non-flags
|
// Non-flags
|
||||||
if(opt->get_expected() != 0) {
|
if(opt->get_type_size() != 0) {
|
||||||
|
|
||||||
// If the option was found on command line
|
// If the option was found on command line
|
||||||
if(opt->count() > 0)
|
if(opt->count() > 0)
|
||||||
@ -1069,7 +1069,7 @@ class App {
|
|||||||
/// Currently checks to see if multiple positionals exist with -1 args
|
/// Currently checks to see if multiple positionals exist with -1 args
|
||||||
void _validate() const {
|
void _validate() const {
|
||||||
auto count = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
|
auto count = std::count_if(std::begin(options_), std::end(options_), [](const Option_p &opt) {
|
||||||
return opt->get_expected() == -1 && opt->get_positional();
|
return opt->get_items_expected() < 0 && opt->get_positional();
|
||||||
});
|
});
|
||||||
if(count > 1)
|
if(count > 1)
|
||||||
throw InvalidError(name_);
|
throw InvalidError(name_);
|
||||||
@ -1189,8 +1189,8 @@ class App {
|
|||||||
// Required or partially filled
|
// Required or partially filled
|
||||||
if(opt->get_required() || opt->count() != 0) {
|
if(opt->get_required() || opt->count() != 0) {
|
||||||
// Make sure enough -N arguments parsed (+N is already handled in parsing function)
|
// Make sure enough -N arguments parsed (+N is already handled in parsing function)
|
||||||
if(opt->get_expected() < 0 && opt->count() < static_cast<size_t>(-opt->get_expected()))
|
if(opt->get_items_expected() < 0 && opt->count() < static_cast<size_t>(-opt->get_items_expected()))
|
||||||
throw ArgumentMismatch::AtLeast(opt->single_name(), -opt->get_expected());
|
throw ArgumentMismatch::AtLeast(opt->single_name(), -opt->get_items_expected());
|
||||||
|
|
||||||
// Required but empty
|
// Required but empty
|
||||||
if(opt->get_required() && opt->count() == 0)
|
if(opt->get_required() && opt->count() == 0)
|
||||||
@ -1260,7 +1260,7 @@ class App {
|
|||||||
|
|
||||||
if(op->results_.empty()) {
|
if(op->results_.empty()) {
|
||||||
// Flag parsing
|
// Flag parsing
|
||||||
if(op->get_expected() == 0) {
|
if(op->get_type_size() == 0) {
|
||||||
if(current.inputs.size() == 1) {
|
if(current.inputs.size() == 1) {
|
||||||
std::string val = current.inputs.at(0);
|
std::string val = current.inputs.at(0);
|
||||||
val = detail::to_lower(val);
|
val = detail::to_lower(val);
|
||||||
@ -1320,9 +1320,9 @@ class App {
|
|||||||
size_t _count_remaining_positionals(bool required = false) const {
|
size_t _count_remaining_positionals(bool required = false) const {
|
||||||
size_t retval = 0;
|
size_t retval = 0;
|
||||||
for(const Option_p &opt : options_)
|
for(const Option_p &opt : options_)
|
||||||
if(opt->get_positional() && (!required || opt->get_required()) && opt->get_expected() > 0 &&
|
if(opt->get_positional() && (!required || opt->get_required()) && opt->get_items_expected() > 0 &&
|
||||||
static_cast<int>(opt->count()) < opt->get_expected())
|
static_cast<int>(opt->count()) < opt->get_items_expected())
|
||||||
retval = static_cast<size_t>(opt->get_expected()) - opt->count();
|
retval = static_cast<size_t>(opt->get_items_expected()) - opt->count();
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@ -1334,7 +1334,7 @@ class App {
|
|||||||
for(const Option_p &opt : options_) {
|
for(const Option_p &opt : options_) {
|
||||||
// Eat options, one by one, until done
|
// Eat options, one by one, until done
|
||||||
if(opt->get_positional() &&
|
if(opt->get_positional() &&
|
||||||
(static_cast<int>(opt->count()) < opt->get_expected() || opt->get_expected() < 0)) {
|
(static_cast<int>(opt->count()) < opt->get_items_expected() || opt->get_items_expected() < 0)) {
|
||||||
|
|
||||||
opt->add_result(positional);
|
opt->add_result(positional);
|
||||||
parse_order_.push_back(opt.get());
|
parse_order_.push_back(opt.get());
|
||||||
@ -1421,7 +1421,7 @@ class App {
|
|||||||
// Get a reference to the pointer to make syntax bearable
|
// Get a reference to the pointer to make syntax bearable
|
||||||
Option_p &op = *op_ptr;
|
Option_p &op = *op_ptr;
|
||||||
|
|
||||||
int num = op->get_expected();
|
int num = op->get_items_expected();
|
||||||
|
|
||||||
// Make sure we always eat the minimum for unlimited vectors
|
// Make sure we always eat the minimum for unlimited vectors
|
||||||
int collected = 0;
|
int collected = 0;
|
||||||
@ -1459,7 +1459,7 @@ class App {
|
|||||||
|
|
||||||
// If there are any unlimited positionals, those also take priority
|
// If there are any unlimited positionals, those also take priority
|
||||||
if(std::any_of(std::begin(options_), std::end(options_), [](const Option_p &opt) {
|
if(std::any_of(std::begin(options_), std::end(options_), [](const Option_p &opt) {
|
||||||
return opt->get_positional() && opt->get_expected() < 0;
|
return opt->get_positional() && opt->get_items_expected() < 0;
|
||||||
}))
|
}))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,9 @@ class IncorrectConstruction : public ConstructionError {
|
|||||||
static IncorrectConstruction Set0Opt(std::string name) {
|
static IncorrectConstruction Set0Opt(std::string name) {
|
||||||
return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead");
|
return IncorrectConstruction(name + ": Cannot set 0 expected, use a flag instead");
|
||||||
}
|
}
|
||||||
|
static IncorrectConstruction SetFlag(std::string name) {
|
||||||
|
return IncorrectConstruction(name + ": Cannot set an expected number for flags");
|
||||||
|
}
|
||||||
static IncorrectConstruction ChangeNotVector(std::string name) {
|
static IncorrectConstruction ChangeNotVector(std::string name) {
|
||||||
return IncorrectConstruction(name + ": You can only change the expected arguments for vectors");
|
return IncorrectConstruction(name + ": You can only change the expected arguments for vectors");
|
||||||
}
|
}
|
||||||
|
@ -180,11 +180,13 @@ class Option : public OptionBase<Option> {
|
|||||||
/// @name Configuration
|
/// @name Configuration
|
||||||
///@{
|
///@{
|
||||||
|
|
||||||
/// The number of expected values, 0 for flag, -1 for unlimited vector
|
/// The number of arguments that make up one option. -1=unlimited (vector-like), 0=flag, 1=normal option,
|
||||||
int expected_{1};
|
/// 2=complex/pair, etc. Set only when the option is created; this is intrinsic to the type. Eventually, -2 may mean
|
||||||
|
/// vector of pairs.
|
||||||
|
int type_size_{1};
|
||||||
|
|
||||||
/// A private setting to allow args to not be able to accept incorrect expected values
|
/// The number of expected values, type_size_ must be < 0. Ignored for flag. N < 0 means at least -N values.
|
||||||
bool changeable_{false};
|
int expected_{1};
|
||||||
|
|
||||||
/// A list of validators to run on each value parsed
|
/// A list of validators to run on each value parsed
|
||||||
std::vector<std::function<std::string(std::string &)>> validators_;
|
std::vector<std::function<std::string(std::string &)>> validators_;
|
||||||
@ -244,14 +246,25 @@ class Option : public OptionBase<Option> {
|
|||||||
/// @name Setting options
|
/// @name Setting options
|
||||||
///@{
|
///@{
|
||||||
|
|
||||||
/// Set the number of expected arguments (Flags bypass this)
|
/// Set the number of expected arguments (Flags don't use this)
|
||||||
Option *expected(int value) {
|
Option *expected(int value) {
|
||||||
if(expected_ == value)
|
// Break if this is a flag
|
||||||
return this;
|
if(type_size_ == 0)
|
||||||
|
throw IncorrectConstruction::SetFlag(single_name());
|
||||||
|
|
||||||
|
// Setting 0 is not allowed
|
||||||
else if(value == 0)
|
else if(value == 0)
|
||||||
throw IncorrectConstruction::Set0Opt(single_name());
|
throw IncorrectConstruction::Set0Opt(single_name());
|
||||||
else if(!changeable_)
|
|
||||||
|
// No change is okay, quit now
|
||||||
|
else if(expected_ == value)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
// Type must be a vector
|
||||||
|
else if(type_size_ >= 0)
|
||||||
throw IncorrectConstruction::ChangeNotVector(single_name());
|
throw IncorrectConstruction::ChangeNotVector(single_name());
|
||||||
|
|
||||||
|
// TODO: Can support multioption for non-1 values (except for join)
|
||||||
else if(value != 1 && multi_option_policy_ != MultiOptionPolicy::Throw)
|
else if(value != 1 && multi_option_policy_ != MultiOptionPolicy::Throw)
|
||||||
throw IncorrectConstruction::AfterMultiOpt(single_name());
|
throw IncorrectConstruction::AfterMultiOpt(single_name());
|
||||||
|
|
||||||
@ -368,9 +381,10 @@ class Option : public OptionBase<Option> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Take the last argument if given multiple times
|
/// Take the last argument if given multiple times (or another policy)
|
||||||
Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
|
Option *multi_option_policy(MultiOptionPolicy value = MultiOptionPolicy::Throw) {
|
||||||
if(get_expected() != 0 && get_expected() != 1)
|
// TODO: This can support multiple options
|
||||||
|
if(get_type_size() != 0 && get_expected() != 1)
|
||||||
throw IncorrectConstruction::MultiOptionPolicy(single_name());
|
throw IncorrectConstruction::MultiOptionPolicy(single_name());
|
||||||
multi_option_policy_ = value;
|
multi_option_policy_ = value;
|
||||||
return this;
|
return this;
|
||||||
@ -381,8 +395,19 @@ class Option : public OptionBase<Option> {
|
|||||||
///@{
|
///@{
|
||||||
|
|
||||||
/// The number of arguments the option expects
|
/// The number of arguments the option expects
|
||||||
|
int get_type_size() const { return type_size_; }
|
||||||
|
|
||||||
|
/// The number of times the option expects to be included
|
||||||
int get_expected() const { return expected_; }
|
int get_expected() const { return expected_; }
|
||||||
|
|
||||||
|
/// The total number of expected values (including the type)
|
||||||
|
int get_items_expected() const {
|
||||||
|
// type_size == 0, return 0
|
||||||
|
// type_size > 1, return type_size_
|
||||||
|
// type_size < 0, return -type_size * expected;
|
||||||
|
return type_size_ < 0 ? -1 * type_size_ * expected_ : type_size_;
|
||||||
|
}
|
||||||
|
|
||||||
/// 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_; }
|
||||||
|
|
||||||
@ -428,7 +453,7 @@ class Option : public OptionBase<Option> {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The most discriptive name available
|
/// The most descriptive name available
|
||||||
std::string single_name() const {
|
std::string single_name() const {
|
||||||
if(!lnames_.empty())
|
if(!lnames_.empty())
|
||||||
return std::string("--") + lnames_[0];
|
return std::string("--") + lnames_[0];
|
||||||
@ -456,7 +481,7 @@ class Option : public OptionBase<Option> {
|
|||||||
std::string help_aftername() const {
|
std::string help_aftername() const {
|
||||||
std::stringstream out;
|
std::stringstream out;
|
||||||
|
|
||||||
if(get_expected() != 0) {
|
if(get_type_size() != 0) {
|
||||||
if(!typeval_.empty())
|
if(!typeval_.empty())
|
||||||
out << " " << typeval_;
|
out << " " << typeval_;
|
||||||
if(!defaultval_.empty())
|
if(!defaultval_.empty())
|
||||||
@ -502,18 +527,23 @@ class Option : public OptionBase<Option> {
|
|||||||
|
|
||||||
// Operation depends on the policy setting
|
// Operation depends on the policy setting
|
||||||
if(multi_option_policy_ == MultiOptionPolicy::TakeLast) {
|
if(multi_option_policy_ == MultiOptionPolicy::TakeLast) {
|
||||||
|
// TODO: add non-1 size arguments here
|
||||||
results_t partial_result = {results_.back()};
|
results_t partial_result = {results_.back()};
|
||||||
local_result = !callback_(partial_result);
|
local_result = !callback_(partial_result);
|
||||||
|
|
||||||
} else if(multi_option_policy_ == MultiOptionPolicy::TakeFirst) {
|
} else if(multi_option_policy_ == MultiOptionPolicy::TakeFirst) {
|
||||||
results_t partial_result = {results_.at(0)};
|
results_t partial_result = {results_.at(0)};
|
||||||
local_result = !callback_(partial_result);
|
local_result = !callback_(partial_result);
|
||||||
|
|
||||||
} else if(multi_option_policy_ == MultiOptionPolicy::Join) {
|
} else if(multi_option_policy_ == MultiOptionPolicy::Join) {
|
||||||
results_t partial_result = {detail::join(results_, "\n")};
|
results_t partial_result = {detail::join(results_, "\n")};
|
||||||
local_result = !callback_(partial_result);
|
local_result = !callback_(partial_result);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if((expected_ > 0 && results_.size() != static_cast<size_t>(expected_)) ||
|
// For now, vector of non size 1 types are not supported but possibility included here
|
||||||
(expected_ < 0 && results_.size() < static_cast<size_t>(-expected_)))
|
if((get_items_expected() > 0 && results_.size() != static_cast<size_t>(get_items_expected())) ||
|
||||||
throw ArgumentMismatch(single_name(), expected_, results_.size());
|
(get_items_expected() < 0 && results_.size() < static_cast<size_t>(-get_items_expected())))
|
||||||
|
throw ArgumentMismatch(single_name(), get_items_expected(), results_.size());
|
||||||
else
|
else
|
||||||
local_result = !callback_(results_);
|
local_result = !callback_(results_);
|
||||||
}
|
}
|
||||||
@ -595,13 +625,14 @@ class Option : public OptionBase<Option> {
|
|||||||
/// @name Custom options
|
/// @name Custom options
|
||||||
///@{
|
///@{
|
||||||
|
|
||||||
/// Set a custom option, typestring, expected; locks changeable unless expected is -1
|
/// Set a custom option, typestring, type_size
|
||||||
void set_custom_option(std::string typeval, int expected = 1) {
|
void set_custom_option(std::string typeval, int type_size = 1) {
|
||||||
typeval_ = typeval;
|
typeval_ = typeval;
|
||||||
expected_ = expected;
|
type_size_ = type_size;
|
||||||
if(expected == 0)
|
if(type_size_ == 0)
|
||||||
required_ = false;
|
required_ = false;
|
||||||
changeable_ = expected < 0;
|
if(type_size < 0)
|
||||||
|
expected_ = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the default value string representation
|
/// Set the default value string representation
|
||||||
|
@ -125,7 +125,7 @@ TEST_F(TApp, IncorrectConstructionFlagPositional3) {
|
|||||||
|
|
||||||
TEST_F(TApp, IncorrectConstructionFlagExpected) {
|
TEST_F(TApp, IncorrectConstructionFlagExpected) {
|
||||||
auto cat = app.add_flag("--cat");
|
auto cat = app.add_flag("--cat");
|
||||||
EXPECT_NO_THROW(cat->expected(0));
|
EXPECT_THROW(cat->expected(0), CLI::IncorrectConstruction);
|
||||||
EXPECT_THROW(cat->expected(1), CLI::IncorrectConstruction);
|
EXPECT_THROW(cat->expected(1), CLI::IncorrectConstruction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user