Commit 0f47620704f85579fc6a8e972d7968eb7298a457

Authored by Henry Fredrick Schreiner
1 parent 92c5621f

Removing run, clean up App structure

CHANGELOG.md
1 1 ## Version 0.4 (in progress)
2 2  
3 3 * Updates to help print
  4 +* Removed `run`, please use `parse` unless you subclass and add it
4 5  
5 6 ## Version 0.3
6 7  
... ...
README.md
... ... @@ -57,7 +57,7 @@ std::string filename = "default";
57 57 app.add_option("-f,--file", file, "A help string");
58 58  
59 59 try {
60   - app.run(argc, argv);
  60 + app.parse(argc, argv);
61 61 } catch (const CLI::ParseError &e) {
62 62 return app.exit(e);
63 63 }
... ...
examples/try.cpp
... ... @@ -15,7 +15,7 @@ int main (int argc, char** argv) {
15 15 app.add_option("-d,--double", value, "Some Value");
16 16  
17 17 try {
18   - app.run(argc, argv);
  18 + app.parse(argc, argv);
19 19 } catch (const CLI::Error &e) {
20 20 return app.exit(e);
21 21 }
... ...
examples/try1.cpp
... ... @@ -14,7 +14,7 @@ int main (int argc, char** argv) {
14 14 CLI::Option* s = stop->add_flag("-c,--count", "Counter");
15 15  
16 16 try {
17   - app.run(argc, argv);
  17 + app.parse(argc, argv);
18 18 } catch (const CLI::Error &e) {
19 19 return app.exit(e);
20 20 }
... ...
examples/try2.cpp
... ... @@ -18,7 +18,7 @@ int main (int argc, char** argv) {
18 18 ->group("Other");
19 19  
20 20 try {
21   - app.run(argc, argv);
  21 + app.parse(argc, argv);
22 22 } catch (const CLI::Error &e) {
23 23 return app.exit(e);
24 24 }
... ...
include/CLI/App.hpp
... ... @@ -58,6 +58,15 @@ protected:
58 58  
59 59  
60 60 public:
  61 + /// Create a new program. Pass in the same arguments as main(), along with a help string.
  62 + App(std::string prog_description="", bool help=true)
  63 + : prog_description(prog_description) {
  64 +
  65 + if(help)
  66 + help_flag = add_flag("-h,--help", "Print this help message and exit");
  67 +
  68 + }
  69 +
61 70  
62 71 /// Set a callback for the end of parsing. Due to a bug in c++11,
63 72 /// it is not possible to overload on std::function (fixed in c++14
... ... @@ -67,11 +76,6 @@ public:
67 76 app_callback = callback;
68 77 }
69 78  
70   - void run_callback() {
71   - if(app_callback)
72   - app_callback();
73   - }
74   -
75 79 /// Reset the parsed data
76 80 void reset() {
77 81  
... ... @@ -97,15 +101,6 @@ public:
97 101 }
98 102  
99 103  
100   - /// Create a new program. Pass in the same arguments as main(), along with a help string.
101   - App(std::string prog_description="", bool help=true)
102   - : prog_description(prog_description) {
103   -
104   - if(help)
105   - help_flag = add_flag("-h,--help", "Print this help message and exit");
106   -
107   - }
108   -
109 104 /// Add a subcommand. Like the constructor, you can override the help message addition by setting help=false
110 105 App* add_subcommand(std::string name, std::string description="", bool help=true) {
111 106 subcommands.emplace_back(new App(description, help));
... ... @@ -331,6 +326,7 @@ public:
331 326 virtual void pre_callback() {}
332 327  
333 328 /// Parses the command line - throws errors
  329 + /// This must be called after the options are in but before the rest of the program.
334 330 void parse(int argc, char **argv) {
335 331 progname = argv[0];
336 332 std::vector<std::string> args;
... ... @@ -340,7 +336,149 @@ public:
340 336 }
341 337  
342 338 /// The real work is done here. Expects a reversed vector
343   - void parse(std::vector<std::string> & args, bool first_parse=true) {
  339 + void parse(std::vector<std::string> &args) {
  340 + return _parse(args, true);
  341 + }
  342 +
  343 +
  344 + /// Print a nice error message and return the exit code
  345 + int exit(const Error& e) const {
  346 + if(e.exit_code != 0) {
  347 + std::cerr << "ERROR: ";
  348 + std::cerr << e.what() << std::endl;
  349 + if(e.print_help)
  350 + std::cerr << help();
  351 + } else {
  352 + if(e.print_help)
  353 + std::cout << help();
  354 + }
  355 + return e.exit_code;
  356 + }
  357 +
  358 + /// Counts the number of times the given option was passed.
  359 + int count(std::string name) const {
  360 + for(const Option_p &opt : options) {
  361 + if(opt->check_name(name)) {
  362 + return opt->count();
  363 + }
  364 + }
  365 + throw OptionNotFound(name);
  366 + }
  367 +
  368 + /// Makes a help message, with a column `wid` for column 1
  369 + std::string help(size_t wid=30, std::string prev="") const {
  370 + // Delegate to subcommand if needed
  371 + if(prev == "")
  372 + prev = progname;
  373 + else
  374 + prev += " " + name;
  375 +
  376 + if(subcommand != nullptr)
  377 + return subcommand->help(wid, prev);
  378 +
  379 + std::stringstream out;
  380 + out << prog_description << std::endl;
  381 + out << "Usage: " << prev;
  382 +
  383 + // Check for options
  384 + bool npos = false;
  385 + std::set<std::string> groups;
  386 + for(const Option_p &opt : options) {
  387 + if(opt->nonpositional()) {
  388 + npos = true;
  389 + groups.insert(opt->get_group());
  390 + }
  391 + }
  392 +
  393 + if(npos)
  394 + out << " [OPTIONS]";
  395 +
  396 + // Positionals
  397 + bool pos=false;
  398 + for(const Option_p &opt : options)
  399 + if(opt->get_positional()) {
  400 + out << " " << opt->help_positional();
  401 + if(opt->has_description())
  402 + pos=true;
  403 + }
  404 +
  405 + if(subcommands.size() > 0)
  406 + out << " [SUBCOMMANDS]";
  407 +
  408 + out << std::endl << std::endl;
  409 +
  410 + // Positional descriptions
  411 + if(pos) {
  412 + out << "Positionals:" << std::endl;
  413 + for(const Option_p &opt : options)
  414 + if(opt->get_positional() && opt->has_description())
  415 + detail::format_help(out, opt->help_pname(), opt->get_description(), wid);
  416 + out << std::endl;
  417 +
  418 + }
  419 +
  420 +
  421 + // Options
  422 + if(npos) {
  423 + for (const std::string& group : groups) {
  424 + out << group << ":" << std::endl;
  425 + for(const Option_p &opt : options) {
  426 + if(opt->nonpositional() && opt->get_group() == group)
  427 + detail::format_help(out, opt->help_name(), opt->get_description(), wid);
  428 +
  429 + }
  430 + out << std::endl;
  431 + }
  432 + }
  433 +
  434 + // Subcommands
  435 + if(subcommands.size()> 0) {
  436 + out << "Subcommands:" << std::endl;
  437 + for(const App_p &com : subcommands)
  438 + detail::format_help(out, com->get_name(), com->prog_description, wid);
  439 + }
  440 + return out.str();
  441 + }
  442 +
  443 + /// Get a subcommand pointer to the currently selected subcommand (after parsing)
  444 + App* get_subcommand() {
  445 + return subcommand;
  446 + }
  447 +
  448 + /// Get the name of the current app
  449 + std::string get_name() const {
  450 + return name;
  451 + }
  452 +
  453 +
  454 +protected:
  455 +
  456 + /// Internal function to run (App) callback
  457 + void run_callback() {
  458 + if(app_callback)
  459 + app_callback();
  460 + }
  461 +
  462 + /// Selects a Classifer enum based on the type of the current argument
  463 + Classifer _recognize(std::string current) const {
  464 + std::string dummy1, dummy2;
  465 +
  466 + if(current == "--")
  467 + return Classifer::POSITIONAL_MARK;
  468 + for(const App_p &com : subcommands) {
  469 + if(com->name == current)
  470 + return Classifer::SUBCOMMAND;
  471 + }
  472 + if(detail::split_long(current, dummy1, dummy2))
  473 + return Classifer::LONG;
  474 + if(detail::split_short(current, dummy1, dummy2))
  475 + return Classifer::SHORT;
  476 + return Classifer::NONE;
  477 + }
  478 +
  479 +
  480 + /// Internal parse function
  481 + void _parse(std::vector<std::string> &args, bool first_parse) {
344 482 parsed = true;
345 483  
346 484 bool positional_only = false;
... ... @@ -403,7 +541,7 @@ public:
403 541 std::reverse(std::begin(values), std::end(values));
404 542  
405 543 values.insert(std::begin(values), std::begin(positionals), std::end(positionals));
406   - return parse(values, false);
  544 + return _parse(values, false);
407 545 } catch (const FileError &e) {
408 546 if(ini_required)
409 547 throw;
... ... @@ -433,6 +571,7 @@ public:
433 571 run_callback();
434 572 }
435 573  
  574 +
436 575 void _parse_subcommand(std::vector<std::string> &args) {
437 576 for(const App_p &com : subcommands) {
438 577 if(com->name == args.back()){
... ... @@ -445,6 +584,7 @@ public:
445 584 throw HorribleError("Subcommand");
446 585 }
447 586  
  587 + /// Parse a short argument, must be at the top of the list
448 588 void _parse_short(std::vector<std::string> &args) {
449 589 std::string current = args.back();
450 590  
... ... @@ -495,22 +635,7 @@ public:
495 635 }
496 636 }
497 637  
498   - Classifer _recognize(std::string current) const {
499   - std::string dummy1, dummy2;
500   -
501   - if(current == "--")
502   - return Classifer::POSITIONAL_MARK;
503   - for(const App_p &com : subcommands) {
504   - if(com->name == current)
505   - return Classifer::SUBCOMMAND;
506   - }
507   - if(detail::split_long(current, dummy1, dummy2))
508   - return Classifer::LONG;
509   - if(detail::split_short(current, dummy1, dummy2))
510   - return Classifer::SHORT;
511   - return Classifer::NONE;
512   - }
513   -
  638 + /// Parse a long argument, must be at the top of the list
514 639 void _parse_long(std::vector<std::string> &args) {
515 640 std::string current = args.back();
516 641  
... ... @@ -554,117 +679,6 @@ public:
554 679 return;
555 680 }
556 681  
557   - /// This must be called after the options are in but before the rest of the program.
558   - /** Instead of throwing erros, this gives an error code
559   - * if -h or an invalid option is passed. Continue with your program if returns -1 */
560   - void run(int argc, char** argv) {
561   - parse(argc, argv);
562   - }
563   -
564   - int exit(const Error& e) const {
565   - if(e.exit_code != 0) {
566   - std::cerr << "ERROR: ";
567   - std::cerr << e.what() << std::endl;
568   - if(e.print_help)
569   - std::cerr << help();
570   - } else {
571   - if(e.print_help)
572   - std::cout << help();
573   - }
574   - return e.exit_code;
575   - }
576   -
577   - /// Counts the number of times the given option was passed.
578   - int count(std::string name) const {
579   - for(const Option_p &opt : options) {
580   - if(opt->check_name(name)) {
581   - return opt->count();
582   - }
583   - }
584   - throw OptionNotFound(name);
585   - }
586   -
587   - std::string help(size_t wid=30, std::string prev="") const {
588   - // Delegate to subcommand if needed
589   - if(prev == "")
590   - prev = progname;
591   - else
592   - prev += " " + name;
593   -
594   - if(subcommand != nullptr)
595   - return subcommand->help(wid, prev);
596   -
597   - std::stringstream out;
598   - out << prog_description << std::endl;
599   - out << "Usage: " << prev;
600   -
601   - // Check for options
602   - bool npos = false;
603   - std::set<std::string> groups;
604   - for(const Option_p &opt : options) {
605   - if(opt->nonpositional()) {
606   - npos = true;
607   - groups.insert(opt->get_group());
608   - }
609   - }
610   -
611   - if(npos)
612   - out << " [OPTIONS]";
613   -
614   - // Positionals
615   - bool pos=false;
616   - for(const Option_p &opt : options)
617   - if(opt->get_positional()) {
618   - out << " " << opt->help_positional();
619   - if(opt->has_description())
620   - pos=true;
621   - }
622   -
623   - if(subcommands.size() > 0)
624   - out << " [SUBCOMMANDS]";
625   -
626   - out << std::endl << std::endl;
627   -
628   - // Positional descriptions
629   - if(pos) {
630   - out << "Positionals:" << std::endl;
631   - for(const Option_p &opt : options)
632   - if(opt->get_positional() && opt->has_description())
633   - detail::format_help(out, opt->help_pname(), opt->get_description(), wid);
634   - out << std::endl;
635   -
636   - }
637   -
638   -
639   - // Options
640   - if(npos) {
641   - for (const std::string& group : groups) {
642   - out << group << ":" << std::endl;
643   - for(const Option_p &opt : options) {
644   - if(opt->nonpositional() && opt->get_group() == group)
645   - detail::format_help(out, opt->help_name(), opt->get_description(), wid);
646   -
647   - }
648   - out << std::endl;
649   - }
650   - }
651   -
652   - // Subcommands
653   - if(subcommands.size()> 0) {
654   - out << "Subcommands:" << std::endl;
655   - for(const App_p &com : subcommands)
656   - detail::format_help(out, com->get_name(), com->prog_description, wid);
657   - }
658   - return out.str();
659   - }
660   -
661   - App* get_subcommand() {
662   - return subcommand;
663   - }
664   -
665   - std::string get_name() const {
666   - return name;
667   - }
668 682 };
669 683  
670 684  
... ...