|
|
@@ -7,6 +7,9 @@
|
|
|
|
|
|
namespace program {
|
|
|
|
|
|
+/**
|
|
|
+ * @brief A string-literal object that requires input arguments to be two or more characters
|
|
|
+ */
|
|
|
struct LongArg {
|
|
|
template <size_t N> constexpr LongArg(char const (&str)[N]) : str(str) {
|
|
|
static_assert(N > 1, "cannot create longargs with 0 or 1 character");
|
|
|
@@ -33,20 +36,72 @@ public:
|
|
|
}
|
|
|
|
|
|
protected:
|
|
|
+ /**
|
|
|
+ * @brief Define an "action"/"subcommand"/"verb" to be executed. An example of this pattern
|
|
|
+ * would be how git visualizes sub-commands in its interface, even though in implementation
|
|
|
+ * it appears different.
|
|
|
+ * @invariant Will fail to compile if bound to something that isn't a subtype of Arguments
|
|
|
+ * @param name A name of the action for usage messages
|
|
|
+ * @param description An optional description object
|
|
|
+ * @return A binding object that can implicitly cast to a subtype of Arguments
|
|
|
+ *
|
|
|
+ * @throws ArgumentMixingError if both argument() and action() have been invoked in this
|
|
|
+ */
|
|
|
auto action(LongArg name, std::string const &description = "");
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Define an argument to be passed in to this program
|
|
|
+ *
|
|
|
+ * @param index The 0-based index of this argument in the program args array.
|
|
|
+ * @param name A name of the argument for usage messages
|
|
|
+ * @param description An optional description object
|
|
|
+ * @return A binding object that will write its data in to an object of arity 1
|
|
|
+ *
|
|
|
+ * @throws ArgumentMixingError if both argument() and action() have been invoked in this
|
|
|
+ * @throws ArgumentStructureError if this argument is required, but a prior argument was optional
|
|
|
+ * @throws IllegalPositionError if index is already in use in this
|
|
|
+ * @throws IllegalPositionError if no argument is available at index
|
|
|
+ */
|
|
|
auto argument(size_t index, LongArg name,
|
|
|
std::string const & description = "");
|
|
|
- std::vector<std::string> rest(LongArg name = "args") {
|
|
|
- rest_name_ = name;
|
|
|
- size_t const i = std::min(arguments.size(), argument_names.size());
|
|
|
- return {arguments.begin() + i, arguments.end()};
|
|
|
- }
|
|
|
- auto flag(LongArg name, std::string const & description = "");
|
|
|
+ /**
|
|
|
+ * @brief Return all unbound arguments
|
|
|
+ * @param name An optional name to describe these arguments
|
|
|
+ * @param description An optional description object
|
|
|
+ * @returns All unbound arguments in {@sa Arguments::arguments}
|
|
|
+
|
|
|
+ * @throws ArgumentMixingError if both argument() and action() have been invoked in this
|
|
|
+ * @throws ArgumentStructureError if rest is called with multiple names
|
|
|
+ */
|
|
|
+ std::vector<std::string> rest(LongArg name = "args",
|
|
|
+ std::string const & description = "");
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Define a flag (option with an arity of zero).
|
|
|
+ * If a flag binds to a boolean and has a name, then t will be invertable with "--no-" prefix.
|
|
|
+ * If a flag binds to an integer, then it increments the value with each repetition.
|
|
|
+ * @invariant One or both of name and abbrev must be provided
|
|
|
+ * @param name The name of the flag, to be parsed from the commandline with a "--" prefix
|
|
|
+ * @param abbrev A single-character version of a flag, to be parsed from the commandline
|
|
|
+ * with a '-' prefix
|
|
|
+ * @param description An optional description object
|
|
|
+ */
|
|
|
auto flag(LongArg name, char abbrev, std::string const & description = "");
|
|
|
+ auto flag(LongArg name, std::string const & description = "");
|
|
|
auto flag(char abbrev, std::string const & description = "");
|
|
|
- auto option(LongArg name, std::string const & description = "");
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @brief Define an option. If an option is repeated, then it can be used to fill out multiple
|
|
|
+ * entries in a map or vector.
|
|
|
+ * @invariant One or both of name and abbrev must be provided
|
|
|
+ * @param name The name of the option, to be parsed from the commandline with a "--" prefix
|
|
|
+ * @param abbrev A single-character version of an option, to be parsed from the commandline
|
|
|
+ * with a '-' prefix
|
|
|
+ * @param description An optional description object
|
|
|
+ */
|
|
|
auto option(LongArg name, char abbrev,
|
|
|
std::string const & description = "");
|
|
|
+ auto option(LongArg name, std::string const & description = "");
|
|
|
auto option(char abbrev, std::string const & description = "");
|
|
|
|
|
|
private:
|
|
|
@@ -54,14 +109,21 @@ private:
|
|
|
void add_options(std::string const & name, char abbrev,
|
|
|
std::string const & description,
|
|
|
std::vector<std::string> aliases = {});
|
|
|
+
|
|
|
+ bool has_actions() const { return !action_descriptions.empty(); }
|
|
|
+ bool has_arguments() const { return !(rest_name.empty() && argument_names.empty()); }
|
|
|
+
|
|
|
option_id id(std::string const & arg) const;
|
|
|
option_id id(char arg) const { return id({'-', arg}); }
|
|
|
+
|
|
|
bool is_option(std::string const & arg) const;
|
|
|
bool is_option(char arg) const { return is_option({'-', arg}); }
|
|
|
+
|
|
|
bool is_flag(std::string const & arg) const;
|
|
|
bool is_flag(char arg) const { return is_flag({'-', arg}); }
|
|
|
|
|
|
private:
|
|
|
+ // A helper for what limited introspection is required for handling actions in test
|
|
|
friend struct ArgumentTestHelper;
|
|
|
friend int main(int, char const * const *);
|
|
|
|
|
|
@@ -70,7 +132,7 @@ private:
|
|
|
using make_hook_t = std::function<main_callback_t(size_t, char const * const *)>;
|
|
|
// Metadata variables
|
|
|
bool primed_{false};
|
|
|
- std::string rest_name_;
|
|
|
+ std::string rest_name;
|
|
|
std::map<option_id, std::string> argument_descriptions;
|
|
|
std::map<size_t, option_id> argument_names;
|
|
|
std::map<option_id, std::string> option_descriptions;
|