mirror of
https://github.com/CLIUtils/CLI11.git
synced 2025-05-03 14:03:52 +00:00
Merge pull request #17 from CLIUtils/parse-order
Adding parse order capture
This commit is contained in:
commit
21559bd122
@ -1,3 +1,6 @@
|
||||
## Version 1.1 (in progress)
|
||||
* Added `app.parse_order()` with original parse order
|
||||
|
||||
## Version 1.0
|
||||
* Cleanup using `clang-tidy` and `clang-format`
|
||||
* Small improvements to Timers, easier to subclass Error
|
||||
|
@ -164,7 +164,7 @@ On the command line, options can be given as:
|
||||
* `--file=filename` (equals)
|
||||
|
||||
Extra positional arguments will cause the program to exit, so at least one positional option with a vector is recommended if you want to allow extraneous arguments.
|
||||
If you set `.allow_extras()` on the main `App`, the parse function will return the left over arguments instead of throwing an error.
|
||||
If you set `.allow_extras()` on the main `App`, the parse function will return the left over arguments instead of throwing an error. You can access a vector of pointers to the parsed options in the original order using `parse_order()`.
|
||||
If `--` is present in the command line,
|
||||
everything after that is positional only.
|
||||
|
||||
|
@ -17,3 +17,4 @@ endfunction()
|
||||
add_cli_exe(simple simple.cpp)
|
||||
add_cli_exe(subcommands subcommands.cpp)
|
||||
add_cli_exe(groups groups.cpp)
|
||||
add_cli_exe(inter_argument_order inter_argument_order.cpp)
|
||||
|
48
examples/inter_argument_order.cpp
Normal file
48
examples/inter_argument_order.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include <CLI/CLI.hpp>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
CLI::App app;
|
||||
|
||||
std::vector<int> foos;
|
||||
auto foo = app.add_option("--foo,-f", foos);
|
||||
|
||||
std::vector<int> bars;
|
||||
auto bar = app.add_option("--bar", bars);
|
||||
|
||||
app.add_flag("--z,--x"); // Random other flags
|
||||
|
||||
// Standard parsing lines (copy and paste in)
|
||||
try {
|
||||
app.parse(argc, argv);
|
||||
} catch(const CLI::ParseError &e) {
|
||||
return app.exit(e);
|
||||
}
|
||||
|
||||
// I perfer using the back and popping
|
||||
std::reverse(std::begin(foos), std::end(foos));
|
||||
std::reverse(std::begin(bars), std::end(bars));
|
||||
|
||||
std::vector<std::tuple<std::string, int>> keyval;
|
||||
for(auto option : app.parse_order()) {
|
||||
if(option == foo) {
|
||||
keyval.emplace_back("foo", foos.back());
|
||||
foos.pop_back();
|
||||
}
|
||||
if(option == bar) {
|
||||
keyval.emplace_back("bar", bars.back());
|
||||
bars.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
// Prove the vector is correct
|
||||
std::string name;
|
||||
int value;
|
||||
|
||||
for(auto &tuple : keyval) {
|
||||
std::tie(name, value) = tuple;
|
||||
std::cout << name << " : " << value << std::endl;
|
||||
}
|
||||
}
|
@ -81,6 +81,9 @@ class App {
|
||||
/// This is faster and cleaner than storing just a list of strings and reparsing. This may contain the -- separator.
|
||||
missing_t missing_;
|
||||
|
||||
/// This is a list of pointers to options with the orignal parse order
|
||||
std::vector<Option *> parse_order_;
|
||||
|
||||
///@}
|
||||
/// @name Subcommands
|
||||
///@{
|
||||
@ -251,7 +254,7 @@ class App {
|
||||
variable.emplace_back();
|
||||
retval &= detail::lexical_cast(a, variable.back());
|
||||
}
|
||||
return variable.size() > 0 && retval;
|
||||
return (!variable.empty()) && retval;
|
||||
};
|
||||
|
||||
Option *opt = add_option(name, fun, description, defaulted);
|
||||
@ -711,6 +714,9 @@ class App {
|
||||
return local_name == name_to_check;
|
||||
}
|
||||
|
||||
/// This gets a vector of pointers with the original parse order
|
||||
const std::vector<Option *> &parse_order() const { return parse_order_; }
|
||||
|
||||
///@}
|
||||
|
||||
protected:
|
||||
@ -949,6 +955,7 @@ class App {
|
||||
(static_cast<int>(opt->count()) < opt->get_expected() || opt->get_expected() < 0)) {
|
||||
|
||||
opt->add_result(positional);
|
||||
parse_order_.push_back(opt.get());
|
||||
args.pop_back();
|
||||
return;
|
||||
}
|
||||
@ -1011,18 +1018,21 @@ class App {
|
||||
|
||||
int num = op->get_expected();
|
||||
|
||||
if(num == 0)
|
||||
if(num == 0) {
|
||||
op->add_result("");
|
||||
else if(rest != "") {
|
||||
parse_order_.push_back(op.get());
|
||||
} else if(rest != "") {
|
||||
if(num > 0)
|
||||
num--;
|
||||
op->add_result(rest);
|
||||
parse_order_.push_back(op.get());
|
||||
rest = "";
|
||||
}
|
||||
|
||||
if(num == -1) {
|
||||
while(!args.empty() && _recognize(args.back()) == detail::Classifer::NONE) {
|
||||
op->add_result(args.back());
|
||||
parse_order_.push_back(op.get());
|
||||
args.pop_back();
|
||||
}
|
||||
} else
|
||||
@ -1031,6 +1041,7 @@ class App {
|
||||
std::string current_ = args.back();
|
||||
args.pop_back();
|
||||
op->add_result(current_);
|
||||
parse_order_.push_back(op.get());
|
||||
}
|
||||
|
||||
if(rest != "") {
|
||||
@ -1075,19 +1086,23 @@ class App {
|
||||
if(num != -1)
|
||||
num--;
|
||||
op->add_result(value);
|
||||
parse_order_.push_back(op.get());
|
||||
} else if(num == 0) {
|
||||
op->add_result("");
|
||||
parse_order_.push_back(op.get());
|
||||
}
|
||||
|
||||
if(num == -1) {
|
||||
while(!args.empty() && _recognize(args.back()) == detail::Classifer::NONE) {
|
||||
op->add_result(args.back());
|
||||
parse_order_.push_back(op.get());
|
||||
args.pop_back();
|
||||
}
|
||||
} else
|
||||
while(num > 0 && !args.empty()) {
|
||||
num--;
|
||||
op->add_result(args.back());
|
||||
parse_order_.push_back(op.get());
|
||||
args.pop_back();
|
||||
}
|
||||
return;
|
||||
|
@ -501,6 +501,22 @@ TEST_F(TApp, VectorFancyOpts) {
|
||||
EXPECT_THROW(run(), CLI::ParseError);
|
||||
}
|
||||
|
||||
TEST_F(TApp, OriginalOrder) {
|
||||
std::vector<int> st1;
|
||||
CLI::Option *op1 = app.add_option("-a", st1);
|
||||
std::vector<int> st2;
|
||||
CLI::Option *op2 = app.add_option("-b", st2);
|
||||
|
||||
args = {"-a", "1", "-b", "2", "-a3", "-a", "4"};
|
||||
|
||||
run();
|
||||
|
||||
EXPECT_EQ(st1, std::vector<int>({1, 3, 4}));
|
||||
EXPECT_EQ(st2, std::vector<int>({2}));
|
||||
|
||||
EXPECT_EQ(app.parse_order(), std::vector<CLI::Option *>({op1, op2, op1, op1}));
|
||||
}
|
||||
|
||||
TEST_F(TApp, RequiresFlags) {
|
||||
CLI::Option *opt = app.add_flag("-s,--string");
|
||||
app.add_flag("--both")->requires(opt);
|
||||
|
Loading…
x
Reference in New Issue
Block a user