Commit 8f1215873c8f5aa2c82c89294e4874ebd071817d

Authored by Henry Fredrick Schreiner
Committed by Henry Schreiner
1 parent 03039295

Allow -- to end unlimited options

CHANGELOG.md
1 -## Version 1.5: Optional  
2 - 1 +## Version 1.5: Optionals
3 2
4 This version introduced support for optionals, along with clarification and examples of custom conversion overloads. Enums now have been dropped from the automatic conversion system, allowing explicit protection for out-of-range ints (or a completely custom conversion). This version has some internal cleanup and improved support for the newest compilers. Several bugs were fixed, as well. 3 This version introduced support for optionals, along with clarification and examples of custom conversion overloads. Enums now have been dropped from the automatic conversion system, allowing explicit protection for out-of-range ints (or a completely custom conversion). This version has some internal cleanup and improved support for the newest compilers. Several bugs were fixed, as well.
5 4
@@ -11,6 +10,7 @@ Note: This is the final release with `requires`, please switch to `needs`. @@ -11,6 +10,7 @@ Note: This is the final release with `requires`, please switch to `needs`.
11 * All macros/CMake variables now start with `CLI11_` instead of just `CLI_` [#95] 10 * All macros/CMake variables now start with `CLI11_` instead of just `CLI_` [#95]
12 * The internal stream was not being cleared before use in some cases. Fixed. [#95] 11 * The internal stream was not being cleared before use in some cases. Fixed. [#95]
13 * Using an emum now requires explicit conversion overload [#97] 12 * Using an emum now requires explicit conversion overload [#97]
  13 +* The separator `--` now is removed when it ends unlimited arguments [#100]
14 14
15 Other, non-user facing changes: 15 Other, non-user facing changes:
16 16
@@ -21,12 +21,15 @@ Other, non-user facing changes: @@ -21,12 +21,15 @@ Other, non-user facing changes:
21 * Better single file generation [#95] 21 * Better single file generation [#95]
22 * Added support for GTest on MSVC 2017 (but not in C++17 mode, will need next version of GTest) 22 * Added support for GTest on MSVC 2017 (but not in C++17 mode, will need next version of GTest)
23 * Types now have a specific size, separate from the expected number - cleaner and more powerful internally [#92] 23 * Types now have a specific size, separate from the expected number - cleaner and more powerful internally [#92]
  24 +* Examples now run as part of testing [#99]
24 25
25 [#64]: https://github.com/CLIUtils/CLI11/issues/64 26 [#64]: https://github.com/CLIUtils/CLI11/issues/64
26 [#90]: https://github.com/CLIUtils/CLI11/issues/90 27 [#90]: https://github.com/CLIUtils/CLI11/issues/90
27 [#92]: https://github.com/CLIUtils/CLI11/issues/92 28 [#92]: https://github.com/CLIUtils/CLI11/issues/92
28 [#95]: https://github.com/CLIUtils/CLI11/pull/95 29 [#95]: https://github.com/CLIUtils/CLI11/pull/95
29 [#97]: https://github.com/CLIUtils/CLI11/pull/97 30 [#97]: https://github.com/CLIUtils/CLI11/pull/97
  31 +[#99]: https://github.com/CLIUtils/CLI11/pull/99
  32 +[#100]: https://github.com/CLIUtils/CLI11/pull/100
30 33
31 34
32 ## Version 1.4: More feedback 35 ## Version 1.4: More feedback
README.md
@@ -176,7 +176,7 @@ On a compiler that supports C++17's `__has_include`, you can also use `std::opti @@ -176,7 +176,7 @@ On a compiler that supports C++17's `__has_include`, you can also use `std::opti
176 The add commands return a pointer to an internally stored `Option`. If you set the final argument to true, the default value is captured and printed on the command line with the help flag. This option can be used directly to check for the count (`->count()`) after parsing to avoid a string based lookup. Before parsing, you can set the following options: 176 The add commands return a pointer to an internally stored `Option`. If you set the final argument to true, the default value is captured and printed on the command line with the help flag. This option can be used directly to check for the count (`->count()`) after parsing to avoid a string based lookup. Before parsing, you can set the following options:
177 177
178 * `->required()`: The program will quit if this option is not present. This is `mandatory` in Plumbum, but required options seems to be a more standard term. For compatibility, `->mandatory()` also works. 178 * `->required()`: The program will quit if this option is not present. This is `mandatory` in Plumbum, but required options seems to be a more standard term. For compatibility, `->mandatory()` also works.
179 -* `->expected(N)`: Take `N` values instead of as many as possible, only for vector args. If negative, require at least `-N`. 179 +* `->expected(N)`: Take `N` values instead of as many as possible, only for vector args. If negative, require at least `-N`; end with `--` or another recognized option.
180 * `->needs(opt)`: This option requires another option to also be present, opt is an `Option` pointer. 180 * `->needs(opt)`: This option requires another option to also be present, opt is an `Option` pointer.
181 * `->excludes(opt)`: This option cannot be given with `opt` present, opt is an `Option` pointer. 181 * `->excludes(opt)`: This option cannot be given with `opt` present, opt is an `Option` pointer.
182 * `->envname(name)`: Gets the value from the environment if present and not passed on the command line. 182 * `->envname(name)`: Gets the value from the environment if present and not passed on the command line.
examples/CMakeLists.txt
@@ -65,7 +65,7 @@ add_cli_exe(prefix_command prefix_command.cpp) @@ -65,7 +65,7 @@ add_cli_exe(prefix_command prefix_command.cpp)
65 add_test(NAME prefix_command COMMAND prefix_command -v 3 2 1 -- other one two 3) 65 add_test(NAME prefix_command COMMAND prefix_command -v 3 2 1 -- other one two 3)
66 set_property(TEST prefix_command PROPERTY PASS_REGULAR_EXPRESSION 66 set_property(TEST prefix_command PROPERTY PASS_REGULAR_EXPRESSION
67 "Prefix: 3 : 2 : 1" 67 "Prefix: 3 : 2 : 1"
68 - "Remaining commands: -- other one two 3") 68 + "Remaining commands: other one two 3")
69 69
70 add_cli_exe(enum enum.cpp) 70 add_cli_exe(enum enum.cpp)
71 add_test(NAME enum_pass COMMAND enum -l 1) 71 add_test(NAME enum_pass COMMAND enum -l 1)
include/CLI/App.hpp
@@ -1035,12 +1035,14 @@ class App { @@ -1035,12 +1035,14 @@ class App {
1035 /// This gets a vector of pointers with the original parse order 1035 /// This gets a vector of pointers with the original parse order
1036 const std::vector<Option *> &parse_order() const { return parse_order_; } 1036 const std::vector<Option *> &parse_order() const { return parse_order_; }
1037 1037
1038 - /// This retuns the missing options from the current subcommand 1038 + /// This returns the missing options from the current subcommand
1039 std::vector<std::string> remaining(bool recurse = false) const { 1039 std::vector<std::string> remaining(bool recurse = false) const {
1040 std::vector<std::string> miss_list; 1040 std::vector<std::string> miss_list;
1041 for(const std::pair<detail::Classifer, std::string> &miss : missing_) { 1041 for(const std::pair<detail::Classifer, std::string> &miss : missing_) {
1042 miss_list.push_back(std::get<1>(miss)); 1042 miss_list.push_back(std::get<1>(miss));
1043 } 1043 }
  1044 +
  1045 + // Recurse into subcommands
1044 if(recurse) { 1046 if(recurse) {
1045 for(const App *sub : parsed_subcommands_) { 1047 for(const App *sub : parsed_subcommands_) {
1046 std::vector<std::string> output = sub->remaining(recurse); 1048 std::vector<std::string> output = sub->remaining(recurse);
@@ -1472,6 +1474,10 @@ class App { @@ -1472,6 +1474,10 @@ class App {
1472 collected++; 1474 collected++;
1473 } 1475 }
1474 1476
  1477 + // Allow -- to end an unlimited list and "eat" it
  1478 + if(!args.empty() && _recognize(args.back()) == detail::Classifer::POSITIONAL_MARK)
  1479 + args.pop_back();
  1480 +
1475 } else { 1481 } else {
1476 while(num > 0 && !args.empty()) { 1482 while(num > 0 && !args.empty()) {
1477 num--; 1483 num--;
tests/AppTest.cpp
@@ -581,6 +581,19 @@ TEST_F(TApp, RequiredOptsUnlimitedShort) { @@ -581,6 +581,19 @@ TEST_F(TApp, RequiredOptsUnlimitedShort) {
581 EXPECT_EQ(remain, std::vector<std::string>({"two"})); 581 EXPECT_EQ(remain, std::vector<std::string>({"two"}));
582 } 582 }
583 583
  584 +TEST_F(TApp, OptsUnlimitedEnd) {
  585 + std::vector<std::string> strs;
  586 + app.add_option("-s,--str", strs);
  587 + app.allow_extras();
  588 +
  589 + args = {"one", "-s", "two", "three", "--", "four"};
  590 +
  591 + run();
  592 +
  593 + EXPECT_EQ(strs, std::vector<std::string>({"two", "three"}));
  594 + EXPECT_EQ(app.remaining(), std::vector<std::string>({"one", "four"}));
  595 +}
  596 +
584 TEST_F(TApp, RequireOptPriority) { 597 TEST_F(TApp, RequireOptPriority) {
585 598
586 std::vector<std::string> strs; 599 std::vector<std::string> strs;
tests/SubcommandTest.cpp
@@ -430,7 +430,7 @@ TEST_F(TApp, PrefixSeparation) { @@ -430,7 +430,7 @@ TEST_F(TApp, PrefixSeparation) {
430 430
431 run(); 431 run();
432 432
433 - EXPECT_EQ(app.remaining(), std::vector<std::string>({"--", "other"})); 433 + EXPECT_EQ(app.remaining(), std::vector<std::string>({"other"}));
434 EXPECT_EQ(vals, std::vector<int>({1, 2, 3})); 434 EXPECT_EQ(vals, std::vector<int>({1, 2, 3}));
435 } 435 }
436 436