# Fluent Argument Parser A tool for the processing of command-line arguments to a C++ program using a fluent interface. No need for writing a constructor or having to create a long list of bindings in main. ## Installation ## Usage ### Arguments Positional arguments are provided with their zero-based indices. Arguments can be declared as optional, but you cannot include required arguments with a higher index than any optional positional arg. Arguments always have an arity of 1, and so cannot store information into a container. Arguments past the end requested will be accessible in a public member function called `args()`. ### Options Options are provided as a long-form string name, and input into the command line in the form `--name value`. Options can map to either singular values (e.g. std::string, int) or containers (e.g. std::vector). Options mapped to containers are repeatable, so you can provide the flag more than one time. Those mapped to singular values will generate an error if repeated. In either case, options with an arity greater than one are not allowed. Abbreviated options support key-value concatenation, such as how you can do `-I/path/to/my/include/dir` in gcc/clang. #### Snippets A partial git command arguments: ```c++ struct Push : program::Arguments { using Arguments::Arguments; bool atomic = flag("atomic"); bool dry_run = flag("dry-run", 'n') = false; bool no_verify = flag("no-verify", "skip push hooks") = false; bool quiet = flag("quiet", 'q') = false; bool verbose = flag("verbose", 'v') = false; // ...more options // TODO: Fetch Upstream Implicitly std::string repository = argument(0, "repository") = ""; // TODO: Implement std::vector refspec = rest("refspec"); }; struct Pull : program::Arguments { using Arguments::Arguments; bool quiet = flag("quiet", 'q') = false; bool verbose = flag("verbose", 'v') = false; bool commit = flag("commit", "immediately commit the merged result") = true; bool edit = flag("edit", "edit the commit message before merging") = true; bool fastforward = flag("ff", "resolve the merge with a fast-forward if possible") = true; bool only_ff = flag("ff-only", "fail if fast-forwarding will not succeed"); // ...more options // TODO: Fetch Upstream Implicitly std::string repository = argument(0, "repository") = ""; // TODO: Implement std::vector refspec = arguments("refspec"); }; struct Commit : program::Arguments { using Arguments::Arguments; }; struct Git : program::Arguments { public: using Arguments::Arguments; std::string pwd = option('C'); // TODO: Generator? std::string git_dir = option("git-dir") = PROGRAM_DEFER(locate_git_dir(pwd)); std::map config_env = option("config-env"); // ...more options private: friend int main(int, char const * const*); Commit commit = action("commit"); Push push = action("push"); Pull pull = action("pull"); }; TYPED_MAIN(Git) ``` Singular option storage cannot be repeated ```c++ std::string directory = option("logdir"); $ ./a.out --logdir /var/log --logdir /usr/local/var/log Error in program argument handling: Repeated option not allowed for argument logdir ``` Abbreviations are not automatically generated ```c++ std::string directory = option("logdir"); $ ./a.out -l /var/log Error in program argument handling: Unknown argument provided: -l ``` Pairs/Tuples don't get to use increased arity ```c++ std::pair bounds = options("bounds"); std::cout << args() << std::endl; $ ./a.out --bounds 1920 1080 [ "1080" ] ``` ### Flags Flags are a sub-class of options who do not have a follow-on value, but instead change the state of the given object through being called. Flags are supported for the types of `bool` and `int` only. With boolean flags, in addition to the `--name` argument created and the abbreviated form, a `--no-name` argument will be registered that sets the option value to false (in case the default is set to true). Integer flags cannot have default values, and do not have inverted forms. Instead, it is possible to repeat an integer flag endlessly, incrementing it by one with each appearance. Abbreviated flags have the additional feature that they can be concatenated, and integer flags can be number-repeated. For example, suppose that both `-v` and `-k` are valid flags, representing `int verbosity` and `bool dry_run` respectively. Then the following are all valid input tokens: `-vk`, `-vv`, `-vvvk`, and `-v5`. The argument `-v5k` will still generate a parse error, however.