mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-04-30 12:43:52 +00:00
Remove double vector parse
This commit is contained in:
parent
e870e264c3
commit
84add337bb
@ -1,5 +1,6 @@
|
||||
## Version 0.6
|
||||
|
||||
* Simplified parsing to use `vector<string>` only
|
||||
* Fixed fallthrough, made it optional as well (default: off): `.fallthrough()`.
|
||||
* Added string versions of `->requires()` and `->excludes()` for consistency.
|
||||
* Renamed protected members for internal consistency, grouped docs.
|
||||
|
15
README.md
15
README.md
@ -41,7 +41,6 @@ This library was built to supply the Application object for the GooFit CUDA/OMP
|
||||
* Ini configuration support is basic (long options only, no vector support), is more needed? Could it be tied to the subcommand system?
|
||||
* Evaluate compatibility with [ROOT](https://root.cern.ch)'s TApplication object.
|
||||
* Test "adding to cmake" method
|
||||
* Maybe simplify the `vector<vector>` structure of options, it is more powerful but unlikely to be needed.
|
||||
|
||||
See the [changelog](./CHANGELOG.md) or [GitHub releases](https://github.com/henryiii/CLI11/releases) for details.
|
||||
|
||||
@ -117,7 +116,6 @@ app.add_config(option_name,
|
||||
required=false)
|
||||
|
||||
App* subcom = app.add_subcommand(name, discription);
|
||||
|
||||
```
|
||||
|
||||
An option name must start with a alphabetic character or underscore. For long options, anything but an equals sign or a comma is valid after that. Names are given as a comma separated string, with the dash or dashes. An option or flag can have as many names as you want, and afterward, using `count`, you can use any of the names, with dashes as needed, to count the options. One of the names is allowed to be given without proceeding dash(es); if present the option is a positional option, and that name will be used on help line for its positional form. If you want the default value to print in the help description, pass in `true` for the final parameter for `add_option` or `add_set`.
|
||||
@ -145,7 +143,7 @@ The add commands return a pointer to an internally stored `Option`. If you set t
|
||||
* `->check(CLI::NonexistentPath)`: Requires that the path does not exist.
|
||||
* `->check(CLI::Range(min,max))`: Requires that the option be between min and max (make sure to use floating point if needed). Min defaults to 0.
|
||||
|
||||
These options return the `Option` pointer, so you can chain them together, and even skip storing the pointer entirely. Check takes any function that has the signature `bool(std::string)`. If you want to change the default help option, it is available through `get_help_ptr`.
|
||||
These options return the `Option` pointer, so you can chain them together, and even skip storing the pointer entirely. Check takes any function that has the signature `bool(std::string)`. If you want to change the default help option, it is available through `get_help_ptr`. If you just want to see the unconverted values, use `.results()` to get the `std::vector<std::string>` of results.
|
||||
|
||||
|
||||
On the command line, options can be given as:
|
||||
@ -201,17 +199,16 @@ Also, in a related note, the `App` you get a pointer to is stored in the parent
|
||||
|
||||
## How it works
|
||||
|
||||
Every `add_` option you have seen so far depends on one method that takes a lambda function. Each of these methods is just making a different lambda function with capture to populate the option. The function has full access to the vector of vector of strings, so it knows how many times an option was passed, and how many arguments each passing received (flags add empty strings to keep the counts correct). The lambda returns `true` if it could validate the option strings, and
|
||||
Every `add_` option you have seen so far depends on one method that takes a lambda function. Each of these methods is just making a different lambda function with capture to populate the option. The function has full access to the vector of strings, so it knows how many times an option was passed or how many arguments it recieved (flags add empty strings to keep the counts correct). The lambda returns `true` if it could validate the option strings, and
|
||||
`false` if it failed.
|
||||
|
||||
### Example
|
||||
|
||||
~~~python
|
||||
app.add_option("--fancy-count", [](std::vector<std::vector<std::string>> val){
|
||||
```cpp
|
||||
app.add_option("--fancy-count", [](std::vector<std::string> val){
|
||||
std::cout << "This option was given " << val.size() << " times." << std::endl
|
||||
<< "The first time, it received " << val.at(0).size() << " items" << std::endl;
|
||||
});
|
||||
~~~
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
@ -221,7 +218,7 @@ To contribute, open an [issue](https://github.com/henryiii/CLI11/issues) or [pul
|
||||
|
||||
If you use the [`rang`](https://github.com/agauniyal/rang/wiki) library to add color to your terminal in a safe, multi-platform way, you can combine it with CLI11 nicely:
|
||||
|
||||
```
|
||||
```cpp
|
||||
std::atexit([](){std::cout << rang::style::reset;});
|
||||
try {
|
||||
app.parse(argc, argv);
|
||||
|
@ -227,13 +227,9 @@ public:
|
||||
|
||||
|
||||
CLI::callback_t fun = [&variable](CLI::results_t res){
|
||||
if(res.size()!=1) {
|
||||
if(res.size()!=1)
|
||||
return false;
|
||||
}
|
||||
if(res[0].size()!=1) {
|
||||
return false;
|
||||
}
|
||||
return detail::lexical_cast(res[0][0], variable);
|
||||
return detail::lexical_cast(res[0], variable);
|
||||
};
|
||||
|
||||
Option* opt = add_option(name, fun, description, defaulted);
|
||||
@ -258,11 +254,10 @@ public:
|
||||
CLI::callback_t fun = [&variable](CLI::results_t res){
|
||||
bool retval = true;
|
||||
variable.clear();
|
||||
for(const auto &a : res)
|
||||
for(const auto &b : a) {
|
||||
variable.emplace_back();
|
||||
retval &= detail::lexical_cast(b, variable.back());
|
||||
}
|
||||
for(const auto &a : res) {
|
||||
variable.emplace_back();
|
||||
retval &= detail::lexical_cast(a, variable.back());
|
||||
}
|
||||
return variable.size() > 0 && retval;
|
||||
};
|
||||
|
||||
@ -291,7 +286,7 @@ public:
|
||||
return opt;
|
||||
}
|
||||
|
||||
/// Add option for flag
|
||||
/// Add option for flag integer
|
||||
template<typename T,
|
||||
enable_if_t<std::is_integral<T>::value && !is_bool<T>::value, detail::enabler> = detail::dummy>
|
||||
Option* add_flag(
|
||||
@ -350,10 +345,7 @@ public:
|
||||
if(res.size()!=1) {
|
||||
return false;
|
||||
}
|
||||
if(res[0].size()!=1) {
|
||||
return false;
|
||||
}
|
||||
bool retval = detail::lexical_cast(res[0][0], member);
|
||||
bool retval = detail::lexical_cast(res[0], member);
|
||||
if(!retval)
|
||||
return false;
|
||||
return std::find(std::begin(options), std::end(options), member) != std::end(options);
|
||||
@ -383,10 +375,7 @@ public:
|
||||
if(res.size()!=1) {
|
||||
return false;
|
||||
}
|
||||
if(res[0].size()!=1) {
|
||||
return false;
|
||||
}
|
||||
member = detail::to_lower(res.at(0).at(0));
|
||||
member = detail::to_lower(res[0]);
|
||||
auto iter = std::find_if(std::begin(options), std::end(options),
|
||||
[&member](std::string val){return detail::to_lower(val) == member;});
|
||||
if(iter == std::end(options))
|
||||
@ -558,7 +547,7 @@ public:
|
||||
std::stringstream out;
|
||||
for(const Option_p &opt : options_) {
|
||||
if(opt->lnames_.size() > 0 && opt->count() > 0 && opt->get_expected() > 0)
|
||||
out << opt->lnames_[0] << "=" << detail::join(opt->flatten_results()) << std::endl;
|
||||
out << opt->lnames_[0] << "=" << detail::join(opt->results()) << std::endl;
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
@ -763,8 +752,7 @@ protected:
|
||||
if (opt->count() == 0 && opt->envname_ != "") {
|
||||
char *ename = std::getenv(opt->envname_.c_str());
|
||||
if(ename != nullptr) {
|
||||
opt->get_new();
|
||||
opt->add_result(0, std::string(ename));
|
||||
opt->add_result(std::string(ename));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -851,8 +839,7 @@ protected:
|
||||
&& opt->count() < opt->get_expected()
|
||||
) {
|
||||
|
||||
opt->get_new();
|
||||
opt->add_result(0, positional);
|
||||
opt->add_result(positional);
|
||||
args.pop_back();
|
||||
return;
|
||||
}
|
||||
@ -915,29 +902,28 @@ protected:
|
||||
// Get a reference to the pointer to make syntax bearable
|
||||
Option_p& op = *op_ptr;
|
||||
|
||||
int vnum = op->get_new();
|
||||
int num = op->get_expected();
|
||||
|
||||
if(num == 0)
|
||||
op->add_result(vnum, "");
|
||||
op->add_result("");
|
||||
else if(rest!="") {
|
||||
if (num > 0)
|
||||
num--;
|
||||
op->add_result(vnum, rest);
|
||||
op->add_result(rest);
|
||||
rest = "";
|
||||
}
|
||||
|
||||
|
||||
if(num == -1) {
|
||||
while(args.size()>0 && _recognize(args.back()) == detail::Classifer::NONE) {
|
||||
op->add_result(vnum, args.back());
|
||||
op->add_result(args.back());
|
||||
args.pop_back();
|
||||
}
|
||||
} else while(num>0 && args.size() > 0) {
|
||||
num--;
|
||||
std::string current_ = args.back();
|
||||
args.pop_back();
|
||||
op->add_result(vnum, current_);
|
||||
op->add_result(current_);
|
||||
}
|
||||
|
||||
if(rest != "") {
|
||||
@ -980,25 +966,23 @@ protected:
|
||||
if(!overwrite && op->count() > 0)
|
||||
return;
|
||||
|
||||
int vnum = op->get_new();
|
||||
int num = op->get_expected();
|
||||
|
||||
|
||||
if(value != "") {
|
||||
if(num!=-1) num--;
|
||||
op->add_result(vnum, value);
|
||||
op->add_result(value);
|
||||
} else if (num == 0) {
|
||||
op->add_result(vnum, "");
|
||||
op->add_result("");
|
||||
}
|
||||
|
||||
if(num == -1) {
|
||||
while(args.size() > 0 && _recognize(args.back()) == detail::Classifer::NONE) {
|
||||
op->add_result(vnum, args.back());
|
||||
op->add_result(args.back());
|
||||
args.pop_back();
|
||||
}
|
||||
} else while(num>0 && args.size()>0) {
|
||||
num--;
|
||||
op->add_result(vnum,args.back());
|
||||
op->add_result(args.back());
|
||||
args.pop_back();
|
||||
}
|
||||
return;
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
namespace CLI {
|
||||
|
||||
typedef std::vector<std::vector<std::string>> results_t;
|
||||
typedef std::vector<std::string> results_t;
|
||||
typedef std::function<bool(results_t)> callback_t;
|
||||
|
||||
class Option;
|
||||
@ -121,16 +121,13 @@ public:
|
||||
|
||||
/// Count the total number of times an option was passed
|
||||
int count() const {
|
||||
int out = 0;
|
||||
for(const std::vector<std::string>& vec : results_)
|
||||
out += vec.size();
|
||||
return out;
|
||||
return results_.size();
|
||||
}
|
||||
|
||||
|
||||
/// This class is true if option is passed.
|
||||
operator bool() const {
|
||||
return results_.size() > 0;
|
||||
return count() > 0;
|
||||
}
|
||||
|
||||
/// Clear the parsed results (mostly for testing)
|
||||
@ -372,9 +369,9 @@ public:
|
||||
/// Process the callback
|
||||
void run_callback() const {
|
||||
if(!callback_(results_))
|
||||
throw ConversionError(get_name() + "=" + detail::join(flatten_results()));
|
||||
throw ConversionError(get_name() + "=" + detail::join(results_));
|
||||
if(validators_.size()>0) {
|
||||
for(const std::string & result : flatten_results())
|
||||
for(const std::string & result : results_)
|
||||
for(const std::function<bool(std::string)> &vali : validators_)
|
||||
if(!vali(result))
|
||||
throw ValidationError(get_name() + "=" + result);
|
||||
@ -440,23 +437,14 @@ public:
|
||||
|
||||
|
||||
/// Puts a result at position r
|
||||
void add_result(int r, std::string s) {
|
||||
results_.at(r).push_back(s);
|
||||
}
|
||||
|
||||
/// Starts a new results vector (used for r in add_result)
|
||||
int get_new() {
|
||||
results_.emplace_back();
|
||||
return results_.size() - 1;
|
||||
void add_result(std::string s) {
|
||||
results_.push_back(s);
|
||||
}
|
||||
|
||||
|
||||
/// Produce a flattened vector of results, vs. a vector of vectors.
|
||||
std::vector<std::string> flatten_results() const {
|
||||
std::vector<std::string> output;
|
||||
for(const std::vector<std::string> result : results_)
|
||||
output.insert(std::end(output), std::begin(result), std::end(result));
|
||||
return output;
|
||||
/// Get a copy of the results
|
||||
std::vector<std::string> results() const {
|
||||
return results_;
|
||||
}
|
||||
|
||||
///@}
|
||||
|
Loading…
x
Reference in New Issue
Block a user