Commit 0f47620704f85579fc6a8e972d7968eb7298a457

Authored by Henry Fredrick Schreiner
1 parent 92c5621f

Removing run, clean up App structure

CHANGELOG.md
1 ## Version 0.4 (in progress) 1 ## Version 0.4 (in progress)
2 2
3 * Updates to help print 3 * Updates to help print
  4 +* Removed `run`, please use `parse` unless you subclass and add it
4 5
5 ## Version 0.3 6 ## Version 0.3
6 7
README.md
@@ -57,7 +57,7 @@ std::string filename = "default"; @@ -57,7 +57,7 @@ std::string filename = "default";
57 app.add_option("-f,--file", file, "A help string"); 57 app.add_option("-f,--file", file, "A help string");
58 58
59 try { 59 try {
60 - app.run(argc, argv); 60 + app.parse(argc, argv);
61 } catch (const CLI::ParseError &e) { 61 } catch (const CLI::ParseError &e) {
62 return app.exit(e); 62 return app.exit(e);
63 } 63 }
examples/try.cpp
@@ -15,7 +15,7 @@ int main (int argc, char** argv) { @@ -15,7 +15,7 @@ int main (int argc, char** argv) {
15 app.add_option("-d,--double", value, "Some Value"); 15 app.add_option("-d,--double", value, "Some Value");
16 16
17 try { 17 try {
18 - app.run(argc, argv); 18 + app.parse(argc, argv);
19 } catch (const CLI::Error &e) { 19 } catch (const CLI::Error &e) {
20 return app.exit(e); 20 return app.exit(e);
21 } 21 }
examples/try1.cpp
@@ -14,7 +14,7 @@ int main (int argc, char** argv) { @@ -14,7 +14,7 @@ int main (int argc, char** argv) {
14 CLI::Option* s = stop->add_flag("-c,--count", "Counter"); 14 CLI::Option* s = stop->add_flag("-c,--count", "Counter");
15 15
16 try { 16 try {
17 - app.run(argc, argv); 17 + app.parse(argc, argv);
18 } catch (const CLI::Error &e) { 18 } catch (const CLI::Error &e) {
19 return app.exit(e); 19 return app.exit(e);
20 } 20 }
examples/try2.cpp
@@ -18,7 +18,7 @@ int main (int argc, char** argv) { @@ -18,7 +18,7 @@ int main (int argc, char** argv) {
18 ->group("Other"); 18 ->group("Other");
19 19
20 try { 20 try {
21 - app.run(argc, argv); 21 + app.parse(argc, argv);
22 } catch (const CLI::Error &e) { 22 } catch (const CLI::Error &e) {
23 return app.exit(e); 23 return app.exit(e);
24 } 24 }
include/CLI/App.hpp
@@ -58,6 +58,15 @@ protected: @@ -58,6 +58,15 @@ protected:
58 58
59 59
60 public: 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 /// Set a callback for the end of parsing. Due to a bug in c++11, 71 /// Set a callback for the end of parsing. Due to a bug in c++11,
63 /// it is not possible to overload on std::function (fixed in c++14 72 /// it is not possible to overload on std::function (fixed in c++14
@@ -67,11 +76,6 @@ public: @@ -67,11 +76,6 @@ public:
67 app_callback = callback; 76 app_callback = callback;
68 } 77 }
69 78
70 - void run_callback() {  
71 - if(app_callback)  
72 - app_callback();  
73 - }  
74 -  
75 /// Reset the parsed data 79 /// Reset the parsed data
76 void reset() { 80 void reset() {
77 81
@@ -97,15 +101,6 @@ public: @@ -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 /// Add a subcommand. Like the constructor, you can override the help message addition by setting help=false 104 /// Add a subcommand. Like the constructor, you can override the help message addition by setting help=false
110 App* add_subcommand(std::string name, std::string description="", bool help=true) { 105 App* add_subcommand(std::string name, std::string description="", bool help=true) {
111 subcommands.emplace_back(new App(description, help)); 106 subcommands.emplace_back(new App(description, help));
@@ -331,6 +326,7 @@ public: @@ -331,6 +326,7 @@ public:
331 virtual void pre_callback() {} 326 virtual void pre_callback() {}
332 327
333 /// Parses the command line - throws errors 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 void parse(int argc, char **argv) { 330 void parse(int argc, char **argv) {
335 progname = argv[0]; 331 progname = argv[0];
336 std::vector<std::string> args; 332 std::vector<std::string> args;
@@ -340,7 +336,149 @@ public: @@ -340,7 +336,149 @@ public:
340 } 336 }
341 337
342 /// The real work is done here. Expects a reversed vector 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 parsed = true; 482 parsed = true;
345 483
346 bool positional_only = false; 484 bool positional_only = false;
@@ -403,7 +541,7 @@ public: @@ -403,7 +541,7 @@ public:
403 std::reverse(std::begin(values), std::end(values)); 541 std::reverse(std::begin(values), std::end(values));
404 542
405 values.insert(std::begin(values), std::begin(positionals), std::end(positionals)); 543 values.insert(std::begin(values), std::begin(positionals), std::end(positionals));
406 - return parse(values, false); 544 + return _parse(values, false);
407 } catch (const FileError &e) { 545 } catch (const FileError &e) {
408 if(ini_required) 546 if(ini_required)
409 throw; 547 throw;
@@ -433,6 +571,7 @@ public: @@ -433,6 +571,7 @@ public:
433 run_callback(); 571 run_callback();
434 } 572 }
435 573
  574 +
436 void _parse_subcommand(std::vector<std::string> &args) { 575 void _parse_subcommand(std::vector<std::string> &args) {
437 for(const App_p &com : subcommands) { 576 for(const App_p &com : subcommands) {
438 if(com->name == args.back()){ 577 if(com->name == args.back()){
@@ -445,6 +584,7 @@ public: @@ -445,6 +584,7 @@ public:
445 throw HorribleError("Subcommand"); 584 throw HorribleError("Subcommand");
446 } 585 }
447 586
  587 + /// Parse a short argument, must be at the top of the list
448 void _parse_short(std::vector<std::string> &args) { 588 void _parse_short(std::vector<std::string> &args) {
449 std::string current = args.back(); 589 std::string current = args.back();
450 590
@@ -495,22 +635,7 @@ public: @@ -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 void _parse_long(std::vector<std::string> &args) { 639 void _parse_long(std::vector<std::string> &args) {
515 std::string current = args.back(); 640 std::string current = args.back();
516 641
@@ -554,117 +679,6 @@ public: @@ -554,117 +679,6 @@ public:
554 return; 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