Commit 9b5867869d841cb4626691546ff7f9d0ce1817a8
Committed by
Henry Schreiner
1 parent
675f1e7f
Refactoring default for options
Showing
3 changed files
with
40 additions
and
23 deletions
examples/subcom_in_files/subcommand_a.cpp
| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | void setup_subcommand_a(CLI::App &app) { |
| 12 | 12 | // Create the option and subcommand objects. |
| 13 | 13 | auto opt = std::make_shared<SubcommandAOptions>(); |
| 14 | - auto sub = app.add_subcommand("subcommand_a", "performs subcommand a", true); | |
| 14 | + auto sub = app.add_subcommand("subcommand_a", "performs subcommand a"); | |
| 15 | 15 | |
| 16 | 16 | // Add options to sub, binding them to opt. |
| 17 | 17 | sub->add_option("-f,--file", opt->file, "File name")->required(); | ... | ... |
include/CLI/App.hpp
| ... | ... | @@ -63,13 +63,13 @@ class App { |
| 63 | 63 | /// Description of the current program/subcommand |
| 64 | 64 | std::string description_; |
| 65 | 65 | |
| 66 | - /// Footer to put after all options in the help output | |
| 66 | + /// Footer to put after all options in the help output INHERITABLE | |
| 67 | 67 | std::string footer_; |
| 68 | 68 | |
| 69 | - /// If true, allow extra arguments (ie, don't throw an error). | |
| 69 | + /// If true, allow extra arguments (ie, don't throw an error). INHERITABLE | |
| 70 | 70 | bool allow_extras_{false}; |
| 71 | 71 | |
| 72 | - /// If true, return immediately on an unrecognised option (implies allow_extras) | |
| 72 | + /// If true, return immediately on an unrecognised option (implies allow_extras) INHERITABLE | |
| 73 | 73 | bool prefix_command_{false}; |
| 74 | 74 | |
| 75 | 75 | /// This is a function that runs when complete. Great for subcommands. Can throw. |
| ... | ... | @@ -78,11 +78,14 @@ class App { |
| 78 | 78 | ///@} |
| 79 | 79 | /// @name Options |
| 80 | 80 | ///@{ |
| 81 | + | |
| 82 | + /// The default values for options, customizable and changeable INHERITABLE | |
| 83 | + OptionDefaults option_defaults_; | |
| 81 | 84 | |
| 82 | 85 | /// The list of options, stored locally |
| 83 | 86 | std::vector<Option_p> options_; |
| 84 | 87 | |
| 85 | - /// A pointer to the help flag if there is one | |
| 88 | + /// A pointer to the help flag if there is one INHERITABLE | |
| 86 | 89 | Option *help_ptr_{nullptr}; |
| 87 | 90 | |
| 88 | 91 | ///@} |
| ... | ... | @@ -106,10 +109,10 @@ class App { |
| 106 | 109 | /// Storage for subcommand list |
| 107 | 110 | std::vector<App_p> subcommands_; |
| 108 | 111 | |
| 109 | - /// If true, the program name is not case sensitive | |
| 112 | + /// If true, the program name is not case sensitive INHERITABLE | |
| 110 | 113 | bool ignore_case_{false}; |
| 111 | 114 | |
| 112 | - /// Allow subcommand fallthrough, so that parent commands can collect commands after subcommand. | |
| 115 | + /// Allow subcommand fallthrough, so that parent commands can collect commands after subcommand. INHERITABLE | |
| 113 | 116 | bool fallthrough_{false}; |
| 114 | 117 | |
| 115 | 118 | /// A pointer to the parent if this is a subcommand |
| ... | ... | @@ -121,7 +124,7 @@ class App { |
| 121 | 124 | /// -1 for 1 or more, 0 for not required, # for exact number required |
| 122 | 125 | int require_subcommand_ = 0; |
| 123 | 126 | |
| 124 | - /// The group membership | |
| 127 | + /// The group membership INHERITABLE | |
| 125 | 128 | std::string group_{"Subcommands"}; |
| 126 | 129 | |
| 127 | 130 | ///@} |
| ... | ... | @@ -140,10 +143,22 @@ class App { |
| 140 | 143 | ///@} |
| 141 | 144 | |
| 142 | 145 | /// Special private constructor for subcommand |
| 143 | - App(std::string description_, bool help, detail::enabler) : description_(std::move(description_)) { | |
| 144 | - | |
| 145 | - if(help) | |
| 146 | - set_help_flag("-h,--help", "Print this help message and exit"); | |
| 146 | + App(std::string description_, App* parent) : description_(std::move(description_)), parent_(parent) { | |
| 147 | + // Inherit if not from a nullptr | |
| 148 | + if(parent_ != nullptr) { | |
| 149 | + if(parent_->help_ptr_ != nullptr) | |
| 150 | + set_help_flag(parent_->help_ptr_->get_name(), parent_->help_ptr_->get_description()); | |
| 151 | + | |
| 152 | + /// OptionDefaults | |
| 153 | + option_defaults_ = parent_->option_defaults_; | |
| 154 | + | |
| 155 | + // INHERITABLE | |
| 156 | + allow_extras_ = parent_->allow_extras_; | |
| 157 | + prefix_command_ = parent_->prefix_command_; | |
| 158 | + ignore_case_ = parent_->ignore_case_; | |
| 159 | + fallthrough_ = parent_->fallthrough_; | |
| 160 | + group_ = parent_->group_; | |
| 161 | + } | |
| 147 | 162 | } |
| 148 | 163 | |
| 149 | 164 | public: |
| ... | ... | @@ -151,7 +166,9 @@ class App { |
| 151 | 166 | ///@{ |
| 152 | 167 | |
| 153 | 168 | /// Create a new program. Pass in the same arguments as main(), along with a help string. |
| 154 | - App(std::string description_ = "", bool help = true) : App(description_, help, detail::dummy) {} | |
| 169 | + App(std::string description_ = "") : App(description_, nullptr) { | |
| 170 | + set_help_flag("-h,--help", "Print this help message and exit"); | |
| 171 | + } | |
| 155 | 172 | |
| 156 | 173 | /// Set footer. |
| 157 | 174 | App *set_footer(std::string footer) { |
| ... | ... | @@ -223,6 +240,9 @@ class App { |
| 223 | 240 | |
| 224 | 241 | /// Get the group of this subcommand |
| 225 | 242 | const std::string &get_group() const { return group_; } |
| 243 | + | |
| 244 | + /// Get the OptionDefault object, to set option defaults | |
| 245 | + OptionDefaults* option_defaults() {return &option_defaults_;} | |
| 226 | 246 | |
| 227 | 247 | ///@} |
| 228 | 248 | /// @name Adding options |
| ... | ... | @@ -251,6 +271,7 @@ class App { |
| 251 | 271 | options_.emplace_back(); |
| 252 | 272 | Option_p &option = options_.back(); |
| 253 | 273 | option.reset(new Option(name, description, callback, defaulted, this)); |
| 274 | + option->copy_from(option_defaults_); | |
| 254 | 275 | return option.get(); |
| 255 | 276 | } else |
| 256 | 277 | throw OptionAlreadyAdded(myopt.get_name()); |
| ... | ... | @@ -615,15 +636,10 @@ class App { |
| 615 | 636 | /// @name Subcommmands |
| 616 | 637 | ///@{ |
| 617 | 638 | |
| 618 | - /// Add a subcommand. Like the constructor, you can override the help message addition by setting help=false | |
| 619 | - App *add_subcommand(std::string name, std::string description = "", bool help = true) { | |
| 620 | - subcommands_.emplace_back(new App(description, help, detail::dummy)); | |
| 639 | + /// Add a subcommand. Inherits INHERITABLE and OptionDefaults, and help flag | |
| 640 | + App *add_subcommand(std::string name, std::string description = "") { | |
| 641 | + subcommands_.emplace_back(new App(description, this)); | |
| 621 | 642 | subcommands_.back()->name_ = name; |
| 622 | - subcommands_.back()->allow_extras_ = allow_extras_; | |
| 623 | - subcommands_.back()->prefix_command_ = prefix_command_; | |
| 624 | - subcommands_.back()->parent_ = this; | |
| 625 | - subcommands_.back()->ignore_case_ = ignore_case_; | |
| 626 | - subcommands_.back()->fallthrough_ = fallthrough_; | |
| 627 | 643 | for(const auto &subc : subcommands_) |
| 628 | 644 | if(subc.get() != subcommands_.back().get()) |
| 629 | 645 | if(subc->check_name(subcommands_.back()->name_) || subcommands_.back()->check_name(subc->name_)) | ... | ... |
tests/HelpTest.cpp
| ... | ... | @@ -314,7 +314,8 @@ TEST(THelp, RemoveHelp) { |
| 314 | 314 | } |
| 315 | 315 | |
| 316 | 316 | TEST(THelp, NoHelp) { |
| 317 | - CLI::App app{"My prog", false}; | |
| 317 | + CLI::App app{"My prog"}; | |
| 318 | + app.set_help_flag(); | |
| 318 | 319 | |
| 319 | 320 | std::string help = app.help(); |
| 320 | 321 | |
| ... | ... | @@ -332,7 +333,7 @@ TEST(THelp, NoHelp) { |
| 332 | 333 | } |
| 333 | 334 | |
| 334 | 335 | TEST(THelp, CustomHelp) { |
| 335 | - CLI::App app{"My prog", false}; | |
| 336 | + CLI::App app{"My prog"}; | |
| 336 | 337 | |
| 337 | 338 | CLI::Option *help_option = app.set_help_flag("--yelp", "display help and exit"); |
| 338 | 339 | EXPECT_EQ(app.get_help_ptr(), help_option); | ... | ... |