Commit 37667f523d1fe9b343ca0d6bde8bb780baed3126
Committed by
GitHub
1 parent
adbd2aa7
Adding simple flag callback (#33)
* Addind simple flag callback * Give flag function a new name, old name only on C++14 * Fixing reference to destroyed function * Better GCC 4.7 support, travis prepared for C++17 (not used yet) * Updating documentation
Showing
8 changed files
with
106 additions
and
3 deletions
.ci/travis.sh
| @@ -3,8 +3,18 @@ set -evx | @@ -3,8 +3,18 @@ set -evx | ||
| 3 | 3 | ||
| 4 | mkdir build || true | 4 | mkdir build || true |
| 5 | cd build | 5 | cd build |
| 6 | -cmake .. -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug | 6 | +cmake .. -DCLI_CXX_STD=11 -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug |
| 7 | cmake --build . -- -j2 | 7 | cmake --build . -- -j2 |
| 8 | ctest --output-on-failure | 8 | ctest --output-on-failure |
| 9 | +if [ -n "$CLI_CXX_STD" ] && [ "$CLI_CXX_STD" -ge "14" ] ; then | ||
| 10 | + cmake .. -DCLI_CXX_STD=14 -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug | ||
| 11 | + cmake --build . -- -j2 | ||
| 12 | + ctest --output-on-failure | ||
| 13 | +fi | ||
| 14 | +if [ -n "$CLI_CXX_STD" ] && [ "$CLI_CXX_STD" -ge "17" ] ; then | ||
| 15 | + cmake .. -DCLI_CXX_STD=17 -DCLI_SINGLE_FILE_TESTS=ON -DCMAKE_BUILD_TYPE=Debug | ||
| 16 | + cmake --build . -- -j2 | ||
| 17 | + ctest --output-on-failure | ||
| 18 | +fi | ||
| 9 | 19 | ||
| 10 | set +evx | 20 | set +evx |
.travis.yml
| @@ -20,6 +20,7 @@ matrix: | @@ -20,6 +20,7 @@ matrix: | ||
| 20 | env: | 20 | env: |
| 21 | - COMPILER=3.9 | 21 | - COMPILER=3.9 |
| 22 | - CHECK_STYLE=yes | 22 | - CHECK_STYLE=yes |
| 23 | + - CLI_CXX_STD=14 | ||
| 23 | - compiler: clang | 24 | - compiler: clang |
| 24 | addons: | 25 | addons: |
| 25 | apt: | 26 | apt: |
| @@ -41,6 +42,7 @@ matrix: | @@ -41,6 +42,7 @@ matrix: | ||
| 41 | env: | 42 | env: |
| 42 | - COMPILER=6 | 43 | - COMPILER=6 |
| 43 | - COVERALLS=yes | 44 | - COVERALLS=yes |
| 45 | + - CLI_CXX_STD=14 | ||
| 44 | - compiler: gcc | 46 | - compiler: gcc |
| 45 | addons: | 47 | addons: |
| 46 | apt: | 48 | apt: |
| @@ -48,7 +50,6 @@ matrix: | @@ -48,7 +50,6 @@ matrix: | ||
| 48 | - g++-4.7 | 50 | - g++-4.7 |
| 49 | env: | 51 | env: |
| 50 | - COMPILER=4.7 | 52 | - COMPILER=4.7 |
| 51 | - - CXXFLAGS=-D_GLIBCXX_USE_NANOSLEEP | ||
| 52 | - os: osx | 53 | - os: osx |
| 53 | install: | 54 | install: |
| 54 | - python -c 'import sys; print(sys.version_info[:])' | 55 | - python -c 'import sys; print(sys.version_info[:])' |
CHANGELOG.md
| 1 | ## Version 1.2 (in progress) | 1 | ## Version 1.2 (in progress) |
| 2 | 2 | ||
| 3 | +* Added functional form of flag [#33](https://github.com/CLIUtils/CLI11/pull/33), automatic on C++14 | ||
| 3 | * Fixed Config file search if passed on command line [#30](https://github.com/CLIUtils/CLI11/issues/30) | 4 | * Fixed Config file search if passed on command line [#30](https://github.com/CLIUtils/CLI11/issues/30) |
| 4 | * Added `CLI11_PARSE(app, argc, argv)` macro for simple parse commands (does not support returning arg) | 5 | * Added `CLI11_PARSE(app, argc, argv)` macro for simple parse commands (does not support returning arg) |
| 5 | * The name string can now contain spaces around commas [#29](https://github.com/CLIUtils/CLI11/pull/29) | 6 | * The name string can now contain spaces around commas [#29](https://github.com/CLIUtils/CLI11/pull/29) |
CMakeLists.txt
| @@ -4,9 +4,11 @@ project(CLI11 CXX) | @@ -4,9 +4,11 @@ project(CLI11 CXX) | ||
| 4 | 4 | ||
| 5 | SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) | 5 | SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) |
| 6 | 6 | ||
| 7 | +set(CLI_CXX_STD "11" CACHE STRING "The CMake standard to require") | ||
| 8 | + | ||
| 7 | if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) | 9 | if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) |
| 8 | set(CUR_PROJ ON) | 10 | set(CUR_PROJ ON) |
| 9 | - set(CMAKE_CXX_STANDARD 11) | 11 | + set(CMAKE_CXX_STANDARD ${CLI_CXX_STD}) |
| 10 | set(CMAKE_CXX_EXTENSIONS OFF) | 12 | set(CMAKE_CXX_EXTENSIONS OFF) |
| 11 | set(CMAKE_CXX_STANDARD_REQUIRED ON) | 13 | set(CMAKE_CXX_STANDARD_REQUIRED ON) |
| 12 | 14 |
README.md
| @@ -120,6 +120,10 @@ app.add_flag(option_name, | @@ -120,6 +120,10 @@ app.add_flag(option_name, | ||
| 120 | int_or_bool = nothing, | 120 | int_or_bool = nothing, |
| 121 | help_string="") | 121 | help_string="") |
| 122 | 122 | ||
| 123 | +app.add_flag_function(option_name, | ||
| 124 | + function <void(size_t count)>, | ||
| 125 | + help_string="") | ||
| 126 | + | ||
| 123 | app.add_set(option_name, | 127 | app.add_set(option_name, |
| 124 | variable_to_bind_to, | 128 | variable_to_bind_to, |
| 125 | set_of_possible_options, | 129 | set_of_possible_options, |
| @@ -133,6 +137,8 @@ App* subcom = app.add_subcommand(name, discription); | @@ -133,6 +137,8 @@ App* subcom = app.add_subcommand(name, discription); | ||
| 133 | 137 | ||
| 134 | 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`. The set options allow your users to pick from a set of predefined options. | 138 | 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`. The set options allow your users to pick from a set of predefined options. |
| 135 | 139 | ||
| 140 | +On a C++14 compiler, you can pass a callback function directly to `.add_flag`, while in C++11 mode you'll need to use `.add_flag_function` if you want a callback function. The function will be given the number of times the flag was passed. You can throw a `CLI::ParseError` to signal a failure. | ||
| 141 | + | ||
| 136 | ### Example | 142 | ### Example |
| 137 | 143 | ||
| 138 | * `"one,-o,--one"`: Valid as long as not a flag, would create an option that can be specified positionally, or with `-o` or `--one` | 144 | * `"one,-o,--one"`: Valid as long as not a flag, would create an option that can be specified positionally, or with `-o` or `--one` |
include/CLI/App.hpp
| @@ -370,6 +370,33 @@ class App { | @@ -370,6 +370,33 @@ class App { | ||
| 370 | return opt; | 370 | return opt; |
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | + /// Add option for callback | ||
| 374 | + Option *add_flag_function(std::string name, | ||
| 375 | + std::function<void(size_t)> function, ///< A function to call, void(size_t) | ||
| 376 | + std::string description = "") { | ||
| 377 | + | ||
| 378 | + CLI::callback_t fun = [function](CLI::results_t res) { | ||
| 379 | + auto count = static_cast<size_t>(res.size()); | ||
| 380 | + function(count); | ||
| 381 | + return true; | ||
| 382 | + }; | ||
| 383 | + | ||
| 384 | + Option *opt = add_option(name, fun, description, false); | ||
| 385 | + if(opt->get_positional()) | ||
| 386 | + throw IncorrectConstruction("Flags cannot be positional"); | ||
| 387 | + opt->set_custom_option("", 0); | ||
| 388 | + return opt; | ||
| 389 | + } | ||
| 390 | + | ||
| 391 | +#if __cplusplus >= 201402L | ||
| 392 | + /// Add option for callback (C++14 or better only) | ||
| 393 | + Option *add_flag(std::string name, | ||
| 394 | + std::function<void(size_t)> function, ///< A function to call, void(size_t) | ||
| 395 | + std::string description = "") { | ||
| 396 | + return add_flag_function(name, function, description); | ||
| 397 | + } | ||
| 398 | +#endif | ||
| 399 | + | ||
| 373 | /// Add set of options (No default) | 400 | /// Add set of options (No default) |
| 374 | template <typename T> | 401 | template <typename T> |
| 375 | Option *add_set(std::string name, | 402 | Option *add_set(std::string name, |
include/CLI/Timer.hpp
| @@ -3,6 +3,12 @@ | @@ -3,6 +3,12 @@ | ||
| 3 | // Distributed under the 3-Clause BSD License. See accompanying | 3 | // Distributed under the 3-Clause BSD License. See accompanying |
| 4 | // file LICENSE or https://github.com/CLIUtils/CLI11 for details. | 4 | // file LICENSE or https://github.com/CLIUtils/CLI11 for details. |
| 5 | 5 | ||
| 6 | +// On GCC < 4.8, the following define is often missing. Due to the | ||
| 7 | +// fact that this library only uses sleep_for, this should be safe | ||
| 8 | +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 && __GNUC_MINOR__ < 8 | ||
| 9 | +#define _GLIBCXX_USE_NANOSLEEP | ||
| 10 | +#endif | ||
| 11 | + | ||
| 6 | #include <chrono> | 12 | #include <chrono> |
| 7 | #include <functional> | 13 | #include <functional> |
| 8 | #include <iostream> | 14 | #include <iostream> |
tests/AppTest.cpp
| @@ -243,6 +243,56 @@ TEST_F(TApp, RequiredFlags) { | @@ -243,6 +243,56 @@ TEST_F(TApp, RequiredFlags) { | ||
| 243 | run(); | 243 | run(); |
| 244 | } | 244 | } |
| 245 | 245 | ||
| 246 | +TEST_F(TApp, CallbackFlags) { | ||
| 247 | + | ||
| 248 | + int value = 0; | ||
| 249 | + | ||
| 250 | + auto func = [&value](size_t x) { value = x; }; | ||
| 251 | + | ||
| 252 | + app.add_flag_function("-v", func); | ||
| 253 | + | ||
| 254 | + run(); | ||
| 255 | + EXPECT_EQ(value, 0); | ||
| 256 | + | ||
| 257 | + app.reset(); | ||
| 258 | + args = {"-v"}; | ||
| 259 | + run(); | ||
| 260 | + EXPECT_EQ(value, 1); | ||
| 261 | + | ||
| 262 | + app.reset(); | ||
| 263 | + args = {"-vv"}; | ||
| 264 | + run(); | ||
| 265 | + EXPECT_EQ(value, 2); | ||
| 266 | + | ||
| 267 | + EXPECT_THROW(app.add_flag_function("hi", func), CLI::IncorrectConstruction); | ||
| 268 | +} | ||
| 269 | + | ||
| 270 | +#if __cplusplus >= 201402L | ||
| 271 | +TEST_F(TApp, CallbackFlagsAuto) { | ||
| 272 | + | ||
| 273 | + int value = 0; | ||
| 274 | + | ||
| 275 | + auto func = [&value](size_t x) { value = x; }; | ||
| 276 | + | ||
| 277 | + app.add_flag("-v", func); | ||
| 278 | + | ||
| 279 | + run(); | ||
| 280 | + EXPECT_EQ(value, 0); | ||
| 281 | + | ||
| 282 | + app.reset(); | ||
| 283 | + args = {"-v"}; | ||
| 284 | + run(); | ||
| 285 | + EXPECT_EQ(value, 1); | ||
| 286 | + | ||
| 287 | + app.reset(); | ||
| 288 | + args = {"-vv"}; | ||
| 289 | + run(); | ||
| 290 | + EXPECT_EQ(value, 2); | ||
| 291 | + | ||
| 292 | + EXPECT_THROW(app.add_flag("hi", func), CLI::IncorrectConstruction); | ||
| 293 | +} | ||
| 294 | +#endif | ||
| 295 | + | ||
| 246 | TEST_F(TApp, Positionals) { | 296 | TEST_F(TApp, Positionals) { |
| 247 | 297 | ||
| 248 | std::string posit1; | 298 | std::string posit1; |