From 6bf39b5400c606b0d23b2834bc6d2b1ab81ebf11 Mon Sep 17 00:00:00 2001 From: Volker Christian Date: Sun, 12 Mar 2023 13:05:36 +0100 Subject: [PATCH 1/2] Polish empty lines and disable description printing for apps and subcommands with empty name, empty group and with no options and subcommands. Mark required but not yet configured options as "" and not yet configured default options as "" in a commented line in the config file. Add commentDefaults() to comment default value options in case default_also is true --- include/CLI/ConfigFwd.hpp | 7 +++++++ include/CLI/impl/Config_inl.hpp | 29 +++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/include/CLI/ConfigFwd.hpp b/include/CLI/ConfigFwd.hpp index a9ae2176a..4bb5b5d63 100644 --- a/include/CLI/ConfigFwd.hpp +++ b/include/CLI/ConfigFwd.hpp @@ -98,6 +98,8 @@ class ConfigBase : public Config { uint8_t maximumLayers{255}; /// the separator used to separator parent layers char parentSeparatorChar{'.'}; + /// the character used as prefix for default value options + bool commentDefaultsBool = false; /// Specify the configuration index to use for arrayed sections int16_t configIndex{-1}; /// Specify the configuration section that should be used @@ -145,6 +147,11 @@ class ConfigBase : public Config { parentSeparatorChar = sep; return this; } + /// Specify the character used as prefix for default value options + ConfigBase *commentDefaults(bool comDef = true) { + commentDefaultsBool = comDef; + return this; + } /// get a reference to the configuration section std::string §ionRef() { return configSection; } /// get the section diff --git a/include/CLI/impl/Config_inl.hpp b/include/CLI/impl/Config_inl.hpp index 8021d5f63..c62f9d544 100644 --- a/include/CLI/impl/Config_inl.hpp +++ b/include/CLI/impl/Config_inl.hpp @@ -308,9 +308,6 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description, std::vector groups = app->get_groups(); bool defaultUsed = false; groups.insert(groups.begin(), std::string("Options")); - if(write_description && (app->get_configurable() || app->get_parent() == nullptr || app->get_name().empty())) { - out << commentLead << detail::fix_newlines(commentLead, app->get_description()) << '\n'; - } for(auto &group : groups) { if(group == "Options" || group.empty()) { if(defaultUsed) { @@ -319,10 +316,9 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description, defaultUsed = true; } if(write_description && group != "Options" && !group.empty()) { - out << '\n' << commentLead << group << " Options\n"; + out << '\n' << commentChar << commentLead << group << " Options\n"; } for(const Option *opt : app->get_options({})) { - // Only process options that are configurable if(opt->get_configurable()) { if(opt->get_group() != group) { @@ -334,6 +330,7 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description, std::string value = detail::ini_join( opt->reduced_results(), arraySeparator, arrayStart, arrayEnd, stringQuote, characterQuote); + bool isDefault = false; if(value.empty() && default_also) { if(!opt->get_default_str().empty()) { value = detail::convert_arg_for_ini(opt->get_default_str(), stringQuote, characterQuote); @@ -341,7 +338,12 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description, value = "false"; } else if(opt->get_run_callback_for_default()) { value = "\"\""; // empty string default value + } else if(opt->get_required()) { + value = "\"\""; + } else { + value = "\"\""; } + isDefault = true; } if(!value.empty()) { @@ -349,14 +351,19 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description, value = opt->get_flag_value(name, value); } if(write_description && opt->has_description()) { - out << '\n'; out << commentLead << detail::fix_newlines(commentLead, opt->get_description()) << '\n'; } - out << name << valueDelimiter << value << '\n'; + if(commentDefaultsBool && isDefault) { + name = commentChar + name; + } + out << name << valueDelimiter << value << "\n\n"; } } } } + if(write_description && !out.str().empty()) { + out << '\n'; + } auto subcommands = app->get_subcommands({}); for(const App *subcom : subcommands) { if(subcom->get_name().empty()) { @@ -389,7 +396,13 @@ ConfigBase::to_config(const App *app, bool default_also, bool write_description, } } - return out.str(); + std::string outString; + if(write_description && !out.str().empty()) { + outString = + commentChar + commentLead + detail::fix_newlines(commentChar + commentLead, app->get_description()) + '\n'; + } + + return outString + out.str(); } // [CLI11:config_inl_hpp:end] } // namespace CLI From 9a661b226b2505d1b18fd3e495423e7a2e6a74f5 Mon Sep 17 00:00:00 2001 From: Philip Top Date: Wed, 9 Oct 2024 06:19:36 -0700 Subject: [PATCH 2/2] style: pre-commit.ci fixes initialize values fix clang-tidy issue style: pre-commit.ci fixes clean up config documentation and structure ordering style: pre-commit.ci fixes add some tests for coverage style: pre-commit.ci fixes fix config tests and help usage example --- book/chapters/config.md | 12 +++++++++-- examples/CMakeLists.txt | 5 +++++ examples/help_usage.cpp | 37 ++++++++++++++++++--------------- include/CLI/ConfigFwd.hpp | 8 +++---- include/CLI/Option.hpp | 2 +- include/CLI/impl/Config_inl.hpp | 22 +++++++++----------- tests/ConfigFileTest.cpp | 25 ++++++++++++++++++++++ 7 files changed, 75 insertions(+), 36 deletions(-) diff --git a/book/chapters/config.md b/book/chapters/config.md index 8a726102e..8991bf9ee 100644 --- a/book/chapters/config.md +++ b/book/chapters/config.md @@ -323,6 +323,10 @@ char literalQuote = '\''; uint8_t maximumLayers{255}; /// the separator used to separator parent layers char parentSeparatorChar{'.'}; +/// comment default values +bool commentDefaultsBool = false; +/// specify the config reader should collapse repeated field names to a single vector +bool allowMultipleDuplicateFields{false}; /// Specify the configuration index to use for arrayed sections uint16_t configIndex{0}; /// Specify the configuration section that should be used @@ -341,6 +345,10 @@ These can be modified via setter functions and value - `ConfigBase *quoteCharacter(char qString, char literalChar)` :specify the characters to use around strings and single characters +- `ConfigBase *commentDefaults(bool comDef)` : set to true to comment lines with + a default value +- `ConfigBase *allowDuplicateFields(bool value)` :set to true to allow duplicate + fields to be merged even if not sequential - `ConfigBase *maxLayers(uint8_t layers)` : specify the maximum number of parent layers to process. This is useful to limit processing for larger config files - `ConfigBase *parentSeparator(char sep)` : specify the character to separate @@ -450,8 +458,8 @@ positional, or the environment variable name. When generating a config file it will create an option name in following priority. 1. First long name -2. Positional name -3. First short name +2. First short name +3. Positional name 4. Environment name In config files the name will be enclosed in quotes if there is any potential diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 24a5be64a..1173d6b6e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -251,6 +251,11 @@ add_cli_exe(custom_parse custom_parse.cpp) add_test(NAME cp_test COMMAND custom_parse --dv 1.7) set_property(TEST cp_test PROPERTY PASS_REGULAR_EXPRESSION "called correct") +#----------------------------------------------------- +add_cli_exe(help_usage help_usage.cpp) +add_test(NAME help_use COMMAND help_usage --help) +set_property(TEST help_use PROPERTY PASS_REGULAR_EXPRESSION "[1..9]") + #------------------------------------------------ # This executable is for manual testing and is expected to change regularly diff --git a/examples/help_usage.cpp b/examples/help_usage.cpp index 6b7d19011..d747cb3cf 100644 --- a/examples/help_usage.cpp +++ b/examples/help_usage.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2023, University of Cincinnati, developed by Henry Schreiner +// Copyright (c) 2017-2024, University of Cincinnati, developed by Henry Schreiner // under NSF AWARD 1414736 and by the respective contributors. // All rights reserved. // @@ -9,7 +9,7 @@ int main(int argc, char **argv) { std::string input_file_name, output_file_name; - int level, subopt; + int level{5}, subopt{0}; // app caption CLI::App app{"CLI11 help"}; @@ -47,26 +47,29 @@ int main(int argc, char **argv) { /* $ ./help_usage -h -CLI11 help -Usage: help_usage [options] + CLI11 help -Options: - -h,--help +OPTIONS: + -h, --help -Subcommands: +SUBCOMMANDS: e encode - Positionals: - input input file - output output file - Options: - -l,--level [1..9] encoding level - -K,--remove INT remove input file - -s,--suboption suboption + +POSITIONALS: + input input file + output output file + +OPTIONS: + -l, --level [1..9] encoding level + -R, --remove remove input file + -s, --suboption suboption + d decode - Positionals: - input input file - output output file + +POSITIONALS: + input input file + output output file */ diff --git a/include/CLI/ConfigFwd.hpp b/include/CLI/ConfigFwd.hpp index bb361c8a3..ef1c83d9e 100644 --- a/include/CLI/ConfigFwd.hpp +++ b/include/CLI/ConfigFwd.hpp @@ -102,12 +102,12 @@ class ConfigBase : public Config { uint8_t maximumLayers{255}; /// the separator used to separator parent layers char parentSeparatorChar{'.'}; - /// the character used as prefix for default value options + /// comment default values bool commentDefaultsBool = false; - /// Specify the configuration index to use for arrayed sections - int16_t configIndex{-1}; /// specify the config reader should collapse repeated field names to a single vector bool allowMultipleDuplicateFields{false}; + /// Specify the configuration index to use for arrayed sections + int16_t configIndex{-1}; /// Specify the configuration section that should be used std::string configSection{}; @@ -153,7 +153,7 @@ class ConfigBase : public Config { parentSeparatorChar = sep; return this; } - /// Specify the character used as prefix for default value options + /// comment default value options ConfigBase *commentDefaults(bool comDef = true) { commentDefaultsBool = comDef; return this; diff --git a/include/CLI/Option.hpp b/include/CLI/Option.hpp index f6f848aa7..24acc82d3 100644 --- a/include/CLI/Option.hpp +++ b/include/CLI/Option.hpp @@ -547,7 +547,7 @@ class Option : public OptionBase