Commit 3b04cd62af5ff2b29c65e561e0c51511ac390aa3
1 parent
05867beb
Adding parse order capture
Showing
2 changed files
with
36 additions
and
2 deletions
include/CLI/App.hpp
| @@ -80,6 +80,9 @@ class App { | @@ -80,6 +80,9 @@ class App { | ||
| 80 | /// | 80 | /// |
| 81 | /// This is faster and cleaner than storing just a list of strings and reparsing. This may contain the -- separator. | 81 | /// This is faster and cleaner than storing just a list of strings and reparsing. This may contain the -- separator. |
| 82 | missing_t missing_; | 82 | missing_t missing_; |
| 83 | + | ||
| 84 | + /// This is a list of pointers to options with the orignal parse order | ||
| 85 | + std::vector<Option*> parse_order_; | ||
| 83 | 86 | ||
| 84 | ///@} | 87 | ///@} |
| 85 | /// @name Subcommands | 88 | /// @name Subcommands |
| @@ -710,6 +713,11 @@ class App { | @@ -710,6 +713,11 @@ class App { | ||
| 710 | 713 | ||
| 711 | return local_name == name_to_check; | 714 | return local_name == name_to_check; |
| 712 | } | 715 | } |
| 716 | + | ||
| 717 | + /// This gets a vector of pointers with the original parse order | ||
| 718 | + const std::vector<Option*> &parse_order() const { | ||
| 719 | + return parse_order_; | ||
| 720 | + } | ||
| 713 | 721 | ||
| 714 | ///@} | 722 | ///@} |
| 715 | 723 | ||
| @@ -949,6 +957,7 @@ class App { | @@ -949,6 +957,7 @@ class App { | ||
| 949 | (static_cast<int>(opt->count()) < opt->get_expected() || opt->get_expected() < 0)) { | 957 | (static_cast<int>(opt->count()) < opt->get_expected() || opt->get_expected() < 0)) { |
| 950 | 958 | ||
| 951 | opt->add_result(positional); | 959 | opt->add_result(positional); |
| 960 | + parse_order_.push_back(opt.get()); | ||
| 952 | args.pop_back(); | 961 | args.pop_back(); |
| 953 | return; | 962 | return; |
| 954 | } | 963 | } |
| @@ -1011,18 +1020,21 @@ class App { | @@ -1011,18 +1020,21 @@ class App { | ||
| 1011 | 1020 | ||
| 1012 | int num = op->get_expected(); | 1021 | int num = op->get_expected(); |
| 1013 | 1022 | ||
| 1014 | - if(num == 0) | 1023 | + if(num == 0) { |
| 1015 | op->add_result(""); | 1024 | op->add_result(""); |
| 1016 | - else if(rest != "") { | 1025 | + parse_order_.push_back(op.get()); |
| 1026 | + } else if(rest != "") { | ||
| 1017 | if(num > 0) | 1027 | if(num > 0) |
| 1018 | num--; | 1028 | num--; |
| 1019 | op->add_result(rest); | 1029 | op->add_result(rest); |
| 1030 | + parse_order_.push_back(op.get()); | ||
| 1020 | rest = ""; | 1031 | rest = ""; |
| 1021 | } | 1032 | } |
| 1022 | 1033 | ||
| 1023 | if(num == -1) { | 1034 | if(num == -1) { |
| 1024 | while(!args.empty() && _recognize(args.back()) == detail::Classifer::NONE) { | 1035 | while(!args.empty() && _recognize(args.back()) == detail::Classifer::NONE) { |
| 1025 | op->add_result(args.back()); | 1036 | op->add_result(args.back()); |
| 1037 | + parse_order_.push_back(op.get()); | ||
| 1026 | args.pop_back(); | 1038 | args.pop_back(); |
| 1027 | } | 1039 | } |
| 1028 | } else | 1040 | } else |
| @@ -1031,6 +1043,7 @@ class App { | @@ -1031,6 +1043,7 @@ class App { | ||
| 1031 | std::string current_ = args.back(); | 1043 | std::string current_ = args.back(); |
| 1032 | args.pop_back(); | 1044 | args.pop_back(); |
| 1033 | op->add_result(current_); | 1045 | op->add_result(current_); |
| 1046 | + parse_order_.push_back(op.get()); | ||
| 1034 | } | 1047 | } |
| 1035 | 1048 | ||
| 1036 | if(rest != "") { | 1049 | if(rest != "") { |
| @@ -1075,19 +1088,23 @@ class App { | @@ -1075,19 +1088,23 @@ class App { | ||
| 1075 | if(num != -1) | 1088 | if(num != -1) |
| 1076 | num--; | 1089 | num--; |
| 1077 | op->add_result(value); | 1090 | op->add_result(value); |
| 1091 | + parse_order_.push_back(op.get()); | ||
| 1078 | } else if(num == 0) { | 1092 | } else if(num == 0) { |
| 1079 | op->add_result(""); | 1093 | op->add_result(""); |
| 1094 | + parse_order_.push_back(op.get()); | ||
| 1080 | } | 1095 | } |
| 1081 | 1096 | ||
| 1082 | if(num == -1) { | 1097 | if(num == -1) { |
| 1083 | while(!args.empty() && _recognize(args.back()) == detail::Classifer::NONE) { | 1098 | while(!args.empty() && _recognize(args.back()) == detail::Classifer::NONE) { |
| 1084 | op->add_result(args.back()); | 1099 | op->add_result(args.back()); |
| 1100 | + parse_order_.push_back(op.get()); | ||
| 1085 | args.pop_back(); | 1101 | args.pop_back(); |
| 1086 | } | 1102 | } |
| 1087 | } else | 1103 | } else |
| 1088 | while(num > 0 && !args.empty()) { | 1104 | while(num > 0 && !args.empty()) { |
| 1089 | num--; | 1105 | num--; |
| 1090 | op->add_result(args.back()); | 1106 | op->add_result(args.back()); |
| 1107 | + parse_order_.push_back(op.get()); | ||
| 1091 | args.pop_back(); | 1108 | args.pop_back(); |
| 1092 | } | 1109 | } |
| 1093 | return; | 1110 | return; |
tests/AppTest.cpp
| @@ -501,6 +501,23 @@ TEST_F(TApp, VectorFancyOpts) { | @@ -501,6 +501,23 @@ TEST_F(TApp, VectorFancyOpts) { | ||
| 501 | EXPECT_THROW(run(), CLI::ParseError); | 501 | EXPECT_THROW(run(), CLI::ParseError); |
| 502 | } | 502 | } |
| 503 | 503 | ||
| 504 | +TEST_F(TApp, OriginalOrder) { | ||
| 505 | + std::vector<int> st1; | ||
| 506 | + CLI::Option* op1 = app.add_option("-a", st1); | ||
| 507 | + std::vector<int> st2; | ||
| 508 | + CLI::Option* op2 = app.add_option("-b", st2); | ||
| 509 | + | ||
| 510 | + args = {"-a", "1", "-b", "2", "-a3", "-a", "4"}; | ||
| 511 | + | ||
| 512 | + run(); | ||
| 513 | + | ||
| 514 | + EXPECT_EQ(st1, std::vector<int>({1,3,4})); | ||
| 515 | + EXPECT_EQ(st2, std::vector<int>({2})); | ||
| 516 | + | ||
| 517 | + EXPECT_EQ(app.parse_order(), std::vector<CLI::Option*>({op1, op2, op1, op1})); | ||
| 518 | + | ||
| 519 | +} | ||
| 520 | + | ||
| 504 | TEST_F(TApp, RequiresFlags) { | 521 | TEST_F(TApp, RequiresFlags) { |
| 505 | CLI::Option *opt = app.add_flag("-s,--string"); | 522 | CLI::Option *opt = app.add_flag("-s,--string"); |
| 506 | app.add_flag("--both")->requires(opt); | 523 | app.add_flag("--both")->requires(opt); |