Commit c02130b7db98f2389fe45a823cb189265c47c075

Authored by Henry Fredrick Schreiner
1 parent 1dfe8dce

Nicer docs

Showing 1 changed file with 133 additions and 96 deletions
include/CLI/App.hpp
... ... @@ -109,10 +109,13 @@ protected:
109 109 /// Pointer to the config option
110 110 Option* config_ptr_ {nullptr};
111 111  
112   - ///@}
  112 + yy///@}
113 113  
114 114  
115 115 public:
  116 + /// @name Basic
  117 + ///@{
  118 +
116 119 /// Create a new program. Pass in the same arguments as main(), along with a help string.
117 120 App(std::string description_="", bool help=true)
118 121 : description_(description_) {
... ... @@ -133,67 +136,49 @@ public:
133 136 callback_ = callback;
134 137 }
135 138  
136   - /// Reset the parsed data
137   - void reset() {
138   -
139   - selected_subcommands_.clear();
140   - missing_.clear();
  139 + /// Remove the error when extras are left over on the command line.
  140 + void allow_extras (bool allow=true) {
  141 + allow_extras_ = allow;
  142 + }
141 143  
142   - for(const Option_p &opt : options_) {
143   - opt->clear();
144   - }
145   - for(const App_p &app : subcommands_) {
146   - app->reset();
  144 + /// Ignore case
  145 + App* ignore_case(bool value = true) {
  146 + ignore_case_ = value;
  147 + if(parent_ != nullptr) {
  148 + for(const auto &subc : parent_->subcommands_) {
  149 + if(subc.get() != this && (this->check_name(subc->name_) || subc->check_name(this->name_)))
  150 + throw OptionAlreadyAdded(subc->name_);
  151 + }
147 152 }
  153 + return this;
148 154 }
149 155  
150   - /// Get a pointer to the help flag.
151   - Option* get_help_ptr() {
152   - return help_ptr_;
  156 + /// Require a subcommand to be given (does not affect help call)
  157 + /// Does not return a pointer since it is supposed to be called on the main App.
  158 + void require_subcommand(int value = -1) {
  159 + require_subcommand_ = value;
153 160 }
154 161  
155   - /// Get a pointer to the config option.
156   - Option* get_config_ptr() {
157   - return config_ptr_;
158   - }
159 162  
160   - /// Produce a string that could be read in as a config of the current values of the App
161   - std::string config_to_str() const {
162   - std::stringstream out;
163   - for(const Option_p &opt : options_) {
164   - if(opt->lnames.size() > 0 && opt->count() > 0 && opt->get_expected() > 0)
165   - out << opt->lnames[0] << "=" << detail::join(opt->flatten_results()) << std::endl;
166   - }
167   - return out.str();
168   - }
169   -
170   - /// Add a subcommand. Like the constructor, you can override the help message addition by setting help=false
171   - App* add_subcommand(std::string name, std::string description="", bool help=true) {
172   - subcommands_.emplace_back(new App(description, help));
173   - subcommands_.back()->name_ = name;
174   - subcommands_.back()->allow_extras();
175   - subcommands_.back()->parent_ = this;
176   - subcommands_.back()->ignore_case_ = ignore_case_;
177   - for(const auto& subc : subcommands_)
178   - if(subc.get() != subcommands_.back().get())
179   - if(subc->check_name(subcommands_.back()->name_) || subcommands_.back()->check_name(subc->name_))
180   - throw OptionAlreadyAdded(subc->name_);
181   - return subcommands_.back().get();
182   - }
183 163  
  164 + ///@}
  165 + /// @name Adding options
  166 + ///@{
  167 +
184 168 /// Add an option, will automatically understand the type for common types.
185   - /** To use, create a variable with the expected type, and pass it in after the name.
186   - * After start is called, you can use count to see if the value was passed, and
187   - * the value will be initialized properly.
188   - *
189   - * ->required(), ->default, and the validators are options_,
190   - * The positional options take an optional number of arguments.
191   - *
192   - * For example,
193   - *
194   - * std::string filename
195   - * program.add_option("filename", filename, "description of filename");
196   - */
  169 + ///
  170 + /// To use, create a variable with the expected type, and pass it in after the name.
  171 + /// After start is called, you can use count to see if the value was passed, and
  172 + /// the value will be initialized properly. Numbers, vectors, and strings are supported.
  173 + ///
  174 + /// ->required(), ->default, and the validators are options,
  175 + /// The positional options take an optional number of arguments.
  176 + ///
  177 + /// For example,
  178 + ///
  179 + /// std::string filename
  180 + /// program.add_option("filename", filename, "description of filename");
  181 +
197 182 Option* add_option(
198 183 std::string name,
199 184 callback_t callback,
... ... @@ -213,7 +198,7 @@ public:
213 198  
214 199 }
215 200  
216   - /// Add option for string
  201 + /// Add option for non-vectors
217 202 template<typename T, enable_if_t<!is_vector<T>::value, detail::enabler> = detail::dummy>
218 203 Option* add_option(
219 204 std::string name,
... ... @@ -243,7 +228,7 @@ public:
243 228 return retval;
244 229 }
245 230  
246   - /// Add option for vector of results
  231 + /// Add option for vectors
247 232 template<typename T>
248 233 Option* add_option(
249 234 std::string name,
... ... @@ -272,7 +257,6 @@ public:
272 257 return retval;
273 258 }
274 259  
275   -
276 260 /// Add option for flag
277 261 Option* add_flag(
278 262 std::string name,
... ... @@ -430,11 +414,39 @@ public:
430 414 }
431 415 return false;
432 416 }
  417 +
  418 + ///@}
  419 + /// @name Subcommmands
  420 + ///@{
  421 +
  422 + /// Add a subcommand. Like the constructor, you can override the help message addition by setting help=false
  423 + App* add_subcommand(std::string name, std::string description="", bool help=true) {
  424 + subcommands_.emplace_back(new App(description, help));
  425 + subcommands_.back()->name_ = name;
  426 + subcommands_.back()->allow_extras();
  427 + subcommands_.back()->parent_ = this;
  428 + subcommands_.back()->ignore_case_ = ignore_case_;
  429 + for(const auto& subc : subcommands_)
  430 + if(subc.get() != subcommands_.back().get())
  431 + if(subc->check_name(subcommands_.back()->name_) || subcommands_.back()->check_name(subc->name_))
  432 + throw OptionAlreadyAdded(subc->name_);
  433 + return subcommands_.back().get();
  434 + }
  435 +
  436 +
  437 +
  438 + ///@}
  439 + /// @name Extras for subclassing
  440 + ///@{
433 441  
434 442 /// This allows subclasses to inject code before callbacks but after parse
435 443 /// This does not run if any errors or help is thrown.
436 444 virtual void pre_callback() {}
437 445  
  446 + ///@}
  447 + /// @name Parsing
  448 + ///@{
  449 +
438 450 /// Parses the command line - throws errors
439 451 /// This must be called after the options are in but before the rest of the program.
440 452 std::vector<std::string> parse(int argc, char **argv) {
... ... @@ -452,12 +464,6 @@ public:
452 464 return _parse(args);
453 465 }
454 466  
455   - /// Remove the error when extras are left over on the command line.
456   - void allow_extras (bool allow=true) {
457   - allow_extras_ = allow;
458   - }
459   -
460   -
461 467 /// Print a nice error message and return the exit code
462 468 int exit(const Error& e) const {
463 469 if(e.exit_code != 0) {
... ... @@ -472,6 +478,24 @@ public:
472 478 return e.exit_code;
473 479 }
474 480  
  481 + /// Reset the parsed data
  482 + void reset() {
  483 +
  484 + selected_subcommands_.clear();
  485 + missing_.clear();
  486 +
  487 + for(const Option_p &opt : options_) {
  488 + opt->clear();
  489 + }
  490 + for(const App_p &app : subcommands_) {
  491 + app->reset();
  492 + }
  493 + }
  494 +
  495 + ///@}
  496 + /// @name Post parsing
  497 + ///@{
  498 +
475 499 /// Counts the number of times the given option was passed.
476 500 int count(std::string name) const {
477 501 for(const Option_p &opt : options_) {
... ... @@ -482,6 +506,41 @@ public:
482 506 throw OptionNotFound(name);
483 507 }
484 508  
  509 + /// Get a subcommand pointer list to the currently selected subcommands (after parsing)
  510 + std::vector<App*> get_subcommands() {
  511 + return selected_subcommands_;
  512 + }
  513 +
  514 +
  515 + /// Check to see if selected subcommand in list
  516 + bool got_subcommand(App* subcom) const {
  517 + return std::find(std::begin(selected_subcommands_),
  518 + std::end(selected_subcommands_), subcom)
  519 + != std::end(selected_subcommands_);
  520 + }
  521 +
  522 + /// Check with name instead of pointer
  523 + bool got_subcommand(std::string name) const {
  524 + for(const auto subcomptr : selected_subcommands_)
  525 + if(subcomptr->check_name(name))
  526 + return true;
  527 + return false;
  528 + }
  529 +
  530 + ///@}
  531 + /// @name Help
  532 + ///@{
  533 +
  534 + /// Produce a string that could be read in as a config of the current values of the App
  535 + std::string config_to_str() const {
  536 + std::stringstream out;
  537 + for(const Option_p &opt : options_) {
  538 + if(opt->lnames.size() > 0 && opt->count() > 0 && opt->get_expected() > 0)
  539 + out << opt->lnames[0] << "=" << detail::join(opt->flatten_results()) << std::endl;
  540 + }
  541 + return out.str();
  542 + }
  543 +
485 544 /// Makes a help message, with a column wid for column 1
486 545 std::string help(size_t wid=30, std::string prev="") const {
487 546 // Delegate to subcommand if needed
... ... @@ -568,34 +627,27 @@ public:
568 627 }
569 628 return out.str();
570 629 }
571   -
572   - /// Get a subcommand pointer list to the currently selected subcommands (after parsing)
573   - std::vector<App*> get_subcommands() {
574   - return selected_subcommands_;
575   - }
576 630  
  631 + ///@}
  632 + /// @name Getters
  633 + ///@{
577 634  
578   - /// Check to see if selected subcommand in list
579   - bool got_subcommand(App* subcom) const {
580   - return std::find(std::begin(selected_subcommands_),
581   - std::end(selected_subcommands_), subcom)
582   - != std::end(selected_subcommands_);
  635 + /// Get a pointer to the help flag.
  636 + Option* get_help_ptr() {
  637 + return help_ptr_;
583 638 }
584 639  
585   - /// Check with name instead of pointer
586   - bool got_subcommand(std::string name) const {
587   - for(const auto subcomptr : selected_subcommands_)
588   - if(subcomptr->check_name(name))
589   - return true;
590   - return false;
  640 + /// Get a pointer to the config option.
  641 + Option* get_config_ptr() {
  642 + return config_ptr_;
591 643 }
592   -
  644 +
593 645 /// Get the name of the current app
594 646 std::string get_name() const {
595 647 return name_;
596 648 }
597 649  
598   - /// Check the name_, case insensitive if set
  650 + /// Check the name, case insensitive if set
599 651 bool check_name(std::string name_to_check) const {
600 652 std::string local_name = name_;
601 653 if(ignore_case_) {
... ... @@ -606,23 +658,8 @@ public:
606 658 return local_name == name_to_check;
607 659 }
608 660  
609   - /// Ignore case
610   - App* ignore_case(bool value = true) {
611   - ignore_case_ = value;
612   - if(parent_ != nullptr) {
613   - for(const auto &subc : parent_->subcommands_) {
614   - if(subc.get() != this && (this->check_name(subc->name_) || subc->check_name(this->name_)))
615   - throw OptionAlreadyAdded(subc->name_);
616   - }
617   - }
618   - return this;
619   - }
  661 + ///@}
620 662  
621   - /// Require a subcommand to be given (does not affect help call)
622   - /// Does not return a pointer since it is supposed to be called on the main App.
623   - void require_subcommand(int value = -1) {
624   - require_subcommand_ = value;
625   - }
626 663  
627 664 protected:
628 665  
... ...