mirror of
https://github.com/sametersoylu/argument-parser.git
synced 2026-05-28 20:08:10 +00:00
docs: add docs.
This commit is contained in:
866
DOCS.MD
Normal file
866
DOCS.MD
Normal file
@@ -0,0 +1,866 @@
|
|||||||
|
# Argument Parser API Documentation
|
||||||
|
|
||||||
|
This document covers the public API exposed by:
|
||||||
|
|
||||||
|
- `src/headers/parser/argument_parser.hpp`: the original v1 parser surface.
|
||||||
|
- `src/headers/parser/parser_v2.hpp`: the v2 map/initializer-list facade.
|
||||||
|
- `src/headers/parser/argument_builder.hpp`: the staged fluent builder for v2.
|
||||||
|
|
||||||
|
The lower-level v1 API still powers the platform parsers and v2. New code will
|
||||||
|
usually be clearest with `argument_parser::v2` and
|
||||||
|
`argument_parser::builder::new_argument()`, but the v1 types remain public and
|
||||||
|
useful when you need direct control over actions, stored values, or positional
|
||||||
|
registration.
|
||||||
|
|
||||||
|
## Common Concepts
|
||||||
|
|
||||||
|
Argument names are registered without command-line prefixes. Use `"v"` and
|
||||||
|
`"verbose"`, not `"-v"` or `"--verbose"`. The active convention objects decide
|
||||||
|
which concrete syntaxes are accepted during parsing and how help text is
|
||||||
|
rendered.
|
||||||
|
|
||||||
|
Typed values are parsed through
|
||||||
|
`argument_parser::parsing_traits::parser_trait<T>::parse(std::string const&)`.
|
||||||
|
The built-in traits cover common scalar types such as `std::string`, `bool`,
|
||||||
|
`int`, `float`, and `double`; custom value types need a trait specialization.
|
||||||
|
Trait `format_hint` and `purpose_hint` members are used in help text and parse
|
||||||
|
error messages when available.
|
||||||
|
|
||||||
|
Stored values are type-erased internally. Retrieve them with the same type used
|
||||||
|
when the argument was registered.
|
||||||
|
|
||||||
|
## v1 API: `argument_parser.hpp`
|
||||||
|
|
||||||
|
The public v1 types live in the `argument_parser` namespace unless otherwise
|
||||||
|
noted.
|
||||||
|
|
||||||
|
### `action_base`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class action_base {
|
||||||
|
public:
|
||||||
|
virtual ~action_base() = default;
|
||||||
|
[[nodiscard]] virtual bool expects_parameter() const = 0;
|
||||||
|
virtual void invoke() const = 0;
|
||||||
|
virtual void invoke_with_parameter(std::string const& param) const = 0;
|
||||||
|
[[nodiscard]] virtual std::pair<std::string, std::string> get_trait_hints() const = 0;
|
||||||
|
[[nodiscard]] virtual std::unique_ptr<action_base> clone() const = 0;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
`action_base` is the polymorphic interface stored by registered arguments.
|
||||||
|
Application code normally uses `action_with_param<T>`, `action_no_param`, or
|
||||||
|
the overloaded `helpers::make_action(...)` factories instead of implementing
|
||||||
|
this interface directly.
|
||||||
|
|
||||||
|
- `expects_parameter()` reports whether the action consumes a value token.
|
||||||
|
- `invoke()` runs a no-value action. On `action_with_param<T>`, it throws
|
||||||
|
`std::runtime_error`.
|
||||||
|
- `invoke_with_parameter(param)` runs a value action. On
|
||||||
|
`action_no_param`, the parameter is ignored.
|
||||||
|
- `get_trait_hints()` returns `{format_hint, purpose_hint}` for typed actions
|
||||||
|
when the parser trait exposes those members.
|
||||||
|
- `clone()` returns a heap-allocated copy used by `argument`.
|
||||||
|
|
||||||
|
### `action_with_param<T>`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template <typename T>
|
||||||
|
class action_with_param : public action_base {
|
||||||
|
public:
|
||||||
|
using parameter_type = T;
|
||||||
|
|
||||||
|
explicit action_with_param(std::function<void(T const&)> const& handler);
|
||||||
|
void invoke(T const& arg) const;
|
||||||
|
[[nodiscard]] bool expects_parameter() const override;
|
||||||
|
void invoke() const override;
|
||||||
|
void invoke_with_parameter(std::string const& param) const override;
|
||||||
|
[[nodiscard]] std::pair<std::string, std::string> get_trait_hints() const override;
|
||||||
|
[[nodiscard]] std::unique_ptr<action_base> clone() const override;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Adapts a `std::function<void(T const&)>` into a parser action. During
|
||||||
|
`invoke_with_parameter`, the raw string is converted with
|
||||||
|
`parser_trait<T>::parse(param)` and the parsed value is passed to the handler.
|
||||||
|
Parse failures are reported as `std::runtime_error` with trait-derived hints
|
||||||
|
when available.
|
||||||
|
|
||||||
|
### `action_no_param`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class action_no_param : public action_base {
|
||||||
|
public:
|
||||||
|
explicit action_no_param(std::function<void()> const& handler);
|
||||||
|
|
||||||
|
void invoke() const override;
|
||||||
|
[[nodiscard]] bool expects_parameter() const override;
|
||||||
|
void invoke_with_parameter(std::string const& param) const override;
|
||||||
|
[[nodiscard]] std::pair<std::string, std::string> get_trait_hints() const override;
|
||||||
|
[[nodiscard]] std::unique_ptr<action_base> clone() const override;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Adapts a `std::function<void()>` into a flag-style action.
|
||||||
|
`expects_parameter()` returns `false`; `invoke_with_parameter(...)` ignores the
|
||||||
|
parameter and runs the no-value handler.
|
||||||
|
|
||||||
|
### `argument_parser::helpers`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
namespace argument_parser::helpers {
|
||||||
|
template <typename T>
|
||||||
|
action_with_param<T>
|
||||||
|
make_action(std::function<void(T const&)> const& function);
|
||||||
|
|
||||||
|
action_no_param
|
||||||
|
make_action(std::function<void()> const& function);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Factory helpers for creating action objects used by `base_parser` and v2.
|
||||||
|
|
||||||
|
### `argument`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class argument {
|
||||||
|
public:
|
||||||
|
argument();
|
||||||
|
|
||||||
|
template <typename ActionType>
|
||||||
|
argument(int id, std::string name, ActionType const& action);
|
||||||
|
|
||||||
|
argument(argument const& other);
|
||||||
|
argument& operator=(argument const& other);
|
||||||
|
argument(argument&& other) noexcept = default;
|
||||||
|
argument& operator=(argument&& other) noexcept = default;
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_required() const;
|
||||||
|
[[nodiscard]] std::string get_name() const;
|
||||||
|
[[nodiscard]] bool is_invoked() const;
|
||||||
|
[[nodiscard]] bool expects_parameter() const;
|
||||||
|
[[nodiscard]] std::string get_help_text() const;
|
||||||
|
[[nodiscard]] bool is_positional() const;
|
||||||
|
[[nodiscard]] bool is_positional_accumulator() const;
|
||||||
|
[[nodiscard]] std::optional<int> get_position_index() const;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
`argument` is the public descriptor returned by parser lookup operations. It is
|
||||||
|
copyable; copies clone their stored action.
|
||||||
|
|
||||||
|
- `is_required()` reports whether parsing must see this argument.
|
||||||
|
- `get_name()` returns the registered display name. Named options are stored as
|
||||||
|
`"<short>|<long>"`; positional arguments use their positional name.
|
||||||
|
- `is_invoked()` reports whether the action ran during `handle_arguments(...)`.
|
||||||
|
- `expects_parameter()` mirrors the stored action.
|
||||||
|
- `get_help_text()` returns the registration help text.
|
||||||
|
- `is_positional()` identifies positional arguments.
|
||||||
|
- `is_positional_accumulator()` is true for positional accumulators.
|
||||||
|
- `get_position_index()` returns the explicit requested position, or
|
||||||
|
`std::nullopt`.
|
||||||
|
|
||||||
|
### `base_parser`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
class base_parser {
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
void add_argument(
|
||||||
|
std::string const& short_arg,
|
||||||
|
std::string const& long_arg,
|
||||||
|
std::string const& help_text,
|
||||||
|
action_with_param<T> const& action,
|
||||||
|
bool required);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void add_argument(
|
||||||
|
std::string const& short_arg,
|
||||||
|
std::string const& long_arg,
|
||||||
|
std::string const& help_text,
|
||||||
|
bool required);
|
||||||
|
|
||||||
|
void add_argument(
|
||||||
|
std::string const& short_arg,
|
||||||
|
std::string const& long_arg,
|
||||||
|
std::string const& help_text,
|
||||||
|
action_no_param const& action,
|
||||||
|
bool required);
|
||||||
|
|
||||||
|
void add_argument(
|
||||||
|
std::string const& short_arg,
|
||||||
|
std::string const& long_arg,
|
||||||
|
std::string const& help_text,
|
||||||
|
bool required);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void add_positional_argument(
|
||||||
|
std::string const& name,
|
||||||
|
std::string const& help_text,
|
||||||
|
action_with_param<T> const& action,
|
||||||
|
bool required,
|
||||||
|
std::optional<int> position = std::nullopt);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void add_positional_argument(
|
||||||
|
std::string const& name,
|
||||||
|
std::string const& help_text,
|
||||||
|
bool required,
|
||||||
|
std::optional<int> position = std::nullopt);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void add_positional_accumulator(
|
||||||
|
std::string const& name,
|
||||||
|
std::string const& help_text,
|
||||||
|
action_with_param<T> const& action,
|
||||||
|
bool required,
|
||||||
|
std::optional<int> position = std::nullopt);
|
||||||
|
|
||||||
|
void on_complete(std::function<void(base_parser const&)> const& action);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::optional<T> get_optional(std::string const& arg) const;
|
||||||
|
|
||||||
|
[[nodiscard]] std::string build_help_text(
|
||||||
|
std::initializer_list<conventions::convention const* const> convention_types) const;
|
||||||
|
|
||||||
|
argument& get_argument(conventions::parsed_argument const& arg);
|
||||||
|
[[nodiscard]] std::optional<int> find_argument_id(std::string const& arg) const;
|
||||||
|
void handle_arguments(
|
||||||
|
std::initializer_list<conventions::convention const* const> convention_types);
|
||||||
|
void display_help(
|
||||||
|
std::initializer_list<conventions::convention const* const> convention_types) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
base_parser() = default;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
`base_parser` owns registrations, parsed command-line tokens, stored values,
|
||||||
|
required-argument checks, and completion hooks. Its constructor is protected;
|
||||||
|
users normally instantiate a concrete parser from `<argparse>` or a platform
|
||||||
|
header. Platform parser constructors populate `program_name` and
|
||||||
|
`parsed_arguments` from the native process arguments.
|
||||||
|
|
||||||
|
`base_parser` is not thread-safe. `handle_arguments(...)` must be called on the
|
||||||
|
same thread that created the parser or it throws `std::runtime_error`.
|
||||||
|
|
||||||
|
#### Named Arguments
|
||||||
|
|
||||||
|
Use `add_argument(...)` for short and/or long options. The v1 API uses `"-"` as
|
||||||
|
the sentinel for an omitted short or long name.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
argument_parser::parser parser;
|
||||||
|
|
||||||
|
parser.add_argument<std::string>(
|
||||||
|
"o",
|
||||||
|
"output",
|
||||||
|
"Output file.",
|
||||||
|
argument_parser::helpers::make_action<std::string>(
|
||||||
|
[](std::string const& value) {
|
||||||
|
// use value
|
||||||
|
}),
|
||||||
|
true);
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"v",
|
||||||
|
"verbose",
|
||||||
|
"Enable verbose output.",
|
||||||
|
false);
|
||||||
|
```
|
||||||
|
|
||||||
|
Registration fails with `std::runtime_error("The key already exists!")` if the
|
||||||
|
short or long key is already registered. Because duplicate checks also see the
|
||||||
|
`"-"` sentinel, avoid registering multiple v1 arguments that pass `"-"` for the
|
||||||
|
same side unless you have verified that behavior.
|
||||||
|
|
||||||
|
The overloads behave as follows:
|
||||||
|
|
||||||
|
- `add_argument<T>(..., action_with_param<T> const& action, bool required)`
|
||||||
|
parses a value and invokes the supplied typed action.
|
||||||
|
- `add_argument<T>(..., bool required)` parses a value and stores it internally
|
||||||
|
for `get_optional<T>(...)`.
|
||||||
|
- `add_argument(..., action_no_param const& action, bool required)`
|
||||||
|
invokes a no-value action.
|
||||||
|
- `add_argument(..., bool required)` stores `true` internally when the option is
|
||||||
|
present.
|
||||||
|
|
||||||
|
#### Positional Arguments
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
parser.add_positional_argument<std::string>(
|
||||||
|
"input",
|
||||||
|
"Input path.",
|
||||||
|
true,
|
||||||
|
0);
|
||||||
|
|
||||||
|
parser.add_positional_argument<int>(
|
||||||
|
"count",
|
||||||
|
"Number of iterations.",
|
||||||
|
argument_parser::helpers::make_action<int>(
|
||||||
|
[](int value) {
|
||||||
|
// use value
|
||||||
|
}),
|
||||||
|
false);
|
||||||
|
```
|
||||||
|
|
||||||
|
Positional arguments are matched against tokens that do not match any supplied
|
||||||
|
convention. You can provide an explicit zero-based `position`, or omit it to use
|
||||||
|
the next available positional slot.
|
||||||
|
|
||||||
|
`add_positional_argument<T>(..., bool required, ...)` stores the parsed value
|
||||||
|
internally under the positional name. The action overload invokes the supplied
|
||||||
|
typed action.
|
||||||
|
|
||||||
|
`add_positional_accumulator<T>(...)` registers a typed positional action that can
|
||||||
|
consume repeated positional tokens at its slot. Only one positional accumulator
|
||||||
|
is allowed, and it must be the last positional argument. Duplicate names,
|
||||||
|
negative explicit positions, or invalid accumulator placement throw
|
||||||
|
`std::runtime_error`.
|
||||||
|
|
||||||
|
#### Parsing
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
parser.handle_arguments({
|
||||||
|
&argument_parser::conventions::gnu_argument_convention,
|
||||||
|
&argument_parser::conventions::gnu_equal_argument_convention,
|
||||||
|
&argument_parser::conventions::windows_argument_convention,
|
||||||
|
&argument_parser::conventions::windows_equal_argument_convention,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
`handle_arguments(...)` invokes matching actions, records stored values, checks
|
||||||
|
required arguments, then runs completion hooks. For each token, conventions are
|
||||||
|
tried in order. If no convention matches, the token is consumed as the next
|
||||||
|
positional value when one is available. `--` forces all following tokens to be
|
||||||
|
treated as positional values.
|
||||||
|
|
||||||
|
Unknown options, missing values, parse failures, unexpected positional values,
|
||||||
|
and action errors are reported with `std::runtime_error`. Missing required
|
||||||
|
arguments print diagnostics and help text, then call `std::exit(1)`.
|
||||||
|
|
||||||
|
If a registered argument named `h` or `help` is found, the parser invokes that
|
||||||
|
help argument and returns from argument invocation early. Required checks and
|
||||||
|
completion hooks still run after invocation returns.
|
||||||
|
|
||||||
|
#### Lookup And Help
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
if (auto output = parser.get_optional<std::string>("output")) {
|
||||||
|
// *output is the stored value
|
||||||
|
}
|
||||||
|
|
||||||
|
auto id = parser.find_argument_id("output");
|
||||||
|
std::string help = parser.build_help_text({
|
||||||
|
&argument_parser::conventions::gnu_argument_convention,
|
||||||
|
});
|
||||||
|
parser.display_help({
|
||||||
|
&argument_parser::conventions::gnu_argument_convention,
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
`get_optional<T>(arg)` returns a stored value for a registered short name, long
|
||||||
|
name, or positional name. It returns `std::nullopt` when no argument by that name
|
||||||
|
exists or when no value was stored. If a value exists but `T` does not match the
|
||||||
|
stored type, `std::any_cast<T>` throws `std::bad_any_cast`.
|
||||||
|
|
||||||
|
`find_argument_id(arg)` returns the internal integer id for a registered short
|
||||||
|
name, long name, or positional name. `get_argument(parsed_argument)` resolves a
|
||||||
|
parsed convention result to an `argument&` and throws when no match exists.
|
||||||
|
|
||||||
|
`build_help_text(...)` returns formatted usage text. `display_help(...)` writes
|
||||||
|
that text to `std::cout`.
|
||||||
|
|
||||||
|
#### Completion Hooks
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
parser.on_complete([](argument_parser::base_parser const& state) {
|
||||||
|
// inspect state.get_optional<T>(...)
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
`on_complete(...)` appends a callback that runs after successful argument
|
||||||
|
invocation and required-argument checks.
|
||||||
|
|
||||||
|
## v2 API: `parser_v2.hpp`
|
||||||
|
|
||||||
|
The v2 API is declared under `argument_parser::v2`. It provides a
|
||||||
|
map/initializer-list facade over the v1 `base_parser`, while still accepting the
|
||||||
|
same convention objects and action helpers.
|
||||||
|
|
||||||
|
Typical use is through the platform alias from `<argparse>`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <argparse>
|
||||||
|
|
||||||
|
using namespace argument_parser::v2::flags;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
argument_parser::v2::parser parser;
|
||||||
|
|
||||||
|
parser.add_argument<int>({
|
||||||
|
{LongArgument, "count"},
|
||||||
|
{HelpText, "Number of items to process."},
|
||||||
|
{Required, true},
|
||||||
|
});
|
||||||
|
|
||||||
|
parser.handle_arguments({
|
||||||
|
&argument_parser::conventions::gnu_argument_convention,
|
||||||
|
&argument_parser::conventions::windows_argument_convention,
|
||||||
|
});
|
||||||
|
|
||||||
|
auto count = parser.get_optional<int>("count");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### `enum class add_argument_flags`
|
||||||
|
|
||||||
|
These keys describe an argument passed to `v2::base_parser::add_argument`.
|
||||||
|
|
||||||
|
| Flag | Value type | Meaning |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `ShortArgument` | `std::string` | Short option name, such as `"v"`. |
|
||||||
|
| `LongArgument` | `std::string` | Long option name, such as `"verbose"`. |
|
||||||
|
| `Positional` | `std::string` | Registers a positional argument. When present, the positional registration path is used. |
|
||||||
|
| `Position` | `int` | Optional zero-based position for a positional argument. |
|
||||||
|
| `HelpText` | `std::string` | Help text shown in generated help output. |
|
||||||
|
| `Action` | `action_with_param<T>` or `action_no_param` | Callback invoked when the argument is found. |
|
||||||
|
| `Required` | `bool` | Marks the argument required when `true`. |
|
||||||
|
| `Reference` | `T*` | Stores a parsed typed value into an external object. Cannot be combined with `Action`. |
|
||||||
|
| `Accumulate` | `bool` or `T*` | Repeated-value mode. For `std::vector<U>`, each parsed `U` is appended. For `int`, each occurrence increments the count. |
|
||||||
|
|
||||||
|
The `argument_parser::v2::flags` namespace exposes inline constants with the
|
||||||
|
same names for concise initializer-list calls.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace argument_parser::v2::flags;
|
||||||
|
|
||||||
|
parser.add_argument({
|
||||||
|
{ShortArgument, "q"},
|
||||||
|
{HelpText, "Quiet mode."},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### `argument_parser::v2::deducers`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template <typename, typename = void>
|
||||||
|
struct has_value_type;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_vector;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
constexpr bool is_vector_v = is_vector<T>::test();
|
||||||
|
```
|
||||||
|
|
||||||
|
These public type traits are used by v2 accumulator logic. `has_value_type`
|
||||||
|
detects `T::value_type`. `is_vector<T>::test()` and `is_vector_v<T>` are true
|
||||||
|
only when `T` is exactly a `std::vector` specialization.
|
||||||
|
|
||||||
|
### `argument_parser::v2::base_parser`
|
||||||
|
|
||||||
|
`v2::base_parser` is the v2 facade. Concrete platform parsers such as
|
||||||
|
`argument_parser::v2::linux_parser`, `macos_parser`, `windows_parser`, and the
|
||||||
|
portable `<argparse>` alias `argument_parser::v2::parser` derive from it.
|
||||||
|
|
||||||
|
The class privately inherits from the v1 `argument_parser::base_parser` and
|
||||||
|
re-exposes selected operations.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template <typename T>
|
||||||
|
using typed_flag_value =
|
||||||
|
std::variant<std::string, action_with_param<T>, bool, int, T*>;
|
||||||
|
|
||||||
|
using non_typed_flag_value =
|
||||||
|
std::variant<std::string, action_no_param, bool, int>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using typed_argument_pair =
|
||||||
|
std::pair<add_argument_flags, typed_flag_value<T>>;
|
||||||
|
|
||||||
|
using non_typed_argument_pair =
|
||||||
|
std::pair<add_argument_flags, non_typed_flag_value>;
|
||||||
|
```
|
||||||
|
|
||||||
|
Use typed aliases for arguments that parse a value of `T`, run an
|
||||||
|
`action_with_param<T>`, store into a `T`, or accumulate values. Use non-typed
|
||||||
|
aliases for boolean flags and no-parameter actions.
|
||||||
|
|
||||||
|
#### Typed `add_argument`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template <typename T>
|
||||||
|
void add_argument(
|
||||||
|
std::unordered_map<add_argument_flags, typed_flag_value<T>> const& argument_pairs);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void add_argument(std::initializer_list<typed_argument_pair<T>> const& pairs);
|
||||||
|
```
|
||||||
|
|
||||||
|
Registers a typed option or positional argument. For non-positional options,
|
||||||
|
provide at least one of `ShortArgument` or `LongArgument`. If only one name is
|
||||||
|
supplied, the other is internally set to `"-"` and not registered.
|
||||||
|
|
||||||
|
Without `Action`, `Reference`, or `Accumulate`, the parsed `T` is stored
|
||||||
|
internally and can be read with `get_optional<T>()`. For positional arguments,
|
||||||
|
include `Positional`; `Position` can place the argument at a specific zero-based
|
||||||
|
slot.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int threshold = 0;
|
||||||
|
|
||||||
|
parser.add_argument<int>({
|
||||||
|
{LongArgument, "threshold"},
|
||||||
|
{Reference, &threshold},
|
||||||
|
{HelpText, "Store the parsed threshold."},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Non-Typed `add_argument`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
void add_argument(
|
||||||
|
std::unordered_map<add_argument_flags, non_typed_flag_value> const& argument_pairs);
|
||||||
|
|
||||||
|
void add_argument(std::initializer_list<non_typed_argument_pair> const& pairs);
|
||||||
|
```
|
||||||
|
|
||||||
|
Registers a non-typed option or positional argument. For options, provide at
|
||||||
|
least one of `ShortArgument` or `LongArgument`. Without `Action`, the argument
|
||||||
|
behaves as a boolean flag: when present, it stores `true` for
|
||||||
|
`get_optional<bool>()`.
|
||||||
|
|
||||||
|
With `Action`, provide an `action_no_param`. Non-typed arguments cannot use
|
||||||
|
`Reference` or `Accumulate`. A non-typed positional argument is stored as
|
||||||
|
`std::string`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
parser.add_argument({
|
||||||
|
{ShortArgument, "v"},
|
||||||
|
{LongArgument, "verbose"},
|
||||||
|
{HelpText, "Enable verbose output."},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Other Public Operations
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
argument_parser::base_parser& to_v1();
|
||||||
|
|
||||||
|
void handle_arguments(
|
||||||
|
std::initializer_list<conventions::convention const* const> convention_types);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
std::optional<T> get_optional(std::string const& arg);
|
||||||
|
|
||||||
|
using argument_parser::base_parser::display_help;
|
||||||
|
using argument_parser::base_parser::on_complete;
|
||||||
|
```
|
||||||
|
|
||||||
|
`to_v1()` returns a mutable reference to the underlying v1 parser interface.
|
||||||
|
`handle_arguments(...)`, `get_optional<T>(...)`, `display_help(...)`, and
|
||||||
|
`on_complete(...)` follow the v1 behavior described above.
|
||||||
|
|
||||||
|
### Accumulation
|
||||||
|
|
||||||
|
`Accumulate` has special typed behavior:
|
||||||
|
|
||||||
|
- `T = std::vector<U>` registers an argument that accepts repeated `U` values.
|
||||||
|
- `T = int` registers a counter-style option; each occurrence increments the
|
||||||
|
count.
|
||||||
|
- `Accumulate` set to `true` stores the accumulated result internally and makes
|
||||||
|
it available through `get_optional<T>()`.
|
||||||
|
- `Accumulate` set to `T*`, or `Accumulate` combined with `Reference`, writes
|
||||||
|
directly to an external object.
|
||||||
|
|
||||||
|
For vector accumulators, the public argument type is `std::vector<U>`, but each
|
||||||
|
individual command-line occurrence is parsed as `U`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
parser.add_argument<std::vector<int>>({
|
||||||
|
{LongArgument, "include-id"},
|
||||||
|
{Accumulate, true},
|
||||||
|
{HelpText, "May be repeated."},
|
||||||
|
});
|
||||||
|
|
||||||
|
auto ids = parser.get_optional<std::vector<int>>("include-id");
|
||||||
|
```
|
||||||
|
|
||||||
|
## Builder API: `argument_builder.hpp`
|
||||||
|
|
||||||
|
The public builder API lives under `argument_parser::builder`. It provides a
|
||||||
|
staged fluent interface for registering arguments with
|
||||||
|
`argument_parser::v2::base_parser`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <argument_builder.hpp>
|
||||||
|
// or
|
||||||
|
#include <argparse>
|
||||||
|
|
||||||
|
using argument_parser::builder::new_argument;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Public Types
|
||||||
|
|
||||||
|
`non_type` is a marker type used before a value-producing mode has been
|
||||||
|
selected. Application code normally does not need to name it.
|
||||||
|
|
||||||
|
`builder_mask` is a public namespace containing the compile-time machinery used
|
||||||
|
by `argument<mask, store_type>`. It exposes `mask_type`, `value_mode`,
|
||||||
|
`extra_capability`, capability constants such as `short_argument`,
|
||||||
|
`long_argument`, `positional`, `help_text`, `required`, `reference`,
|
||||||
|
`accumulate`, `count`, `store`, and `flag`, plus constexpr helpers such as
|
||||||
|
`bit`, `has`, `remove`, `replace`, `is_buildable`, and
|
||||||
|
`is_build_and_gettable`. These are mainly useful for type-level tests or
|
||||||
|
advanced wrappers.
|
||||||
|
|
||||||
|
### `container<store_type>`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template <typename store_type>
|
||||||
|
class container;
|
||||||
|
```
|
||||||
|
|
||||||
|
Returned by `build_and_get(parser)`. It is populated after
|
||||||
|
`parser.handle_arguments(...)` completes.
|
||||||
|
|
||||||
|
- `store_type get() const` returns the stored value. Call only after the
|
||||||
|
container is populated.
|
||||||
|
- `store_type& operator*()` dereferences the stored value.
|
||||||
|
- `store_type* operator->()` accesses members of the stored value.
|
||||||
|
- `operator bool()` reports whether a value is available.
|
||||||
|
|
||||||
|
For builder-managed storage, `build_and_get()` registers an `on_complete`
|
||||||
|
callback that reads the parsed value by lookup key. For
|
||||||
|
`accumulate(existing_vector)`, the container references the provided vector
|
||||||
|
directly.
|
||||||
|
|
||||||
|
### `argument<mask, store_type>`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template <
|
||||||
|
argument_parser::builder::builder_mask::mask_type mask =
|
||||||
|
argument_parser::builder::builder_mask::initial,
|
||||||
|
typename store_type = argument_parser::builder::non_type>
|
||||||
|
class argument;
|
||||||
|
```
|
||||||
|
|
||||||
|
The staged fluent builder. `mask` enables only valid next methods at compile
|
||||||
|
time. `store_type` is the type produced by the selected value mode. Most users
|
||||||
|
should create builders with `new_argument()`.
|
||||||
|
|
||||||
|
### Entry Points
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
static auto argument<>::start() -> argument<builder_mask::initial>;
|
||||||
|
static inline auto new_argument();
|
||||||
|
```
|
||||||
|
|
||||||
|
`new_argument()` is equivalent to `argument<>::start()`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
new_argument()
|
||||||
|
.long_argument("output")
|
||||||
|
.store<std::string>()
|
||||||
|
.required()
|
||||||
|
.build(parser);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Identifier Methods
|
||||||
|
|
||||||
|
At least one identifier method must be used before `build(parser)` or
|
||||||
|
`build_and_get(parser)`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto short_argument(std::string short_name) const -> argument<..., store_type>;
|
||||||
|
auto long_argument(std::string long_name) const -> argument<..., store_type>;
|
||||||
|
auto positional(std::string positional_name) const -> argument<..., store_type>;
|
||||||
|
auto position(int index) const -> argument<..., store_type>;
|
||||||
|
```
|
||||||
|
|
||||||
|
`short_argument(...)` and `long_argument(...)` set named option identifiers and
|
||||||
|
can be combined with each other. `positional(...)` registers a positional
|
||||||
|
argument and is mutually exclusive with named identifiers. `position(...)` is
|
||||||
|
available only after `positional(...)` and only once. If no value mode is
|
||||||
|
selected for a positional argument, `build(parser)` registers a `std::string`
|
||||||
|
positional value.
|
||||||
|
|
||||||
|
### Metadata Methods
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto help_text(std::string help) const -> argument<..., store_type>;
|
||||||
|
auto required(bool value = true) const -> argument<..., store_type>;
|
||||||
|
```
|
||||||
|
|
||||||
|
`help_text(...)` sets generated help text and is single-use. If omitted, v2
|
||||||
|
generates default text, often using parser trait hints for typed value modes.
|
||||||
|
|
||||||
|
`required(...)` marks the argument required when `value` is `true`. There is no
|
||||||
|
public `setRequired(...)` method in `argument_builder.hpp`; the public fluent API
|
||||||
|
is `required(...)`.
|
||||||
|
|
||||||
|
### Terminal Value Modes
|
||||||
|
|
||||||
|
Exactly one terminal value mode can be selected. Once selected, the other modes
|
||||||
|
are removed from the builder type.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
template <typename T = std::string>
|
||||||
|
auto store() const -> argument<..., T>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto reference(T& value) const -> argument<..., T>;
|
||||||
|
|
||||||
|
auto flag() const -> argument<..., bool>;
|
||||||
|
|
||||||
|
template <typename T = std::string>
|
||||||
|
auto accumulate() const -> argument<..., std::vector<T>>;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto accumulate(T& value) const -> argument<..., T>;
|
||||||
|
|
||||||
|
auto count() const -> argument<..., int>;
|
||||||
|
auto count(int& value) const -> argument<..., int>;
|
||||||
|
|
||||||
|
template <typename Callable>
|
||||||
|
auto action(Callable&& handler) const -> argument<..., non_type>;
|
||||||
|
|
||||||
|
template <typename T = std::string, typename Callable>
|
||||||
|
auto action(Callable&& handler) const -> argument<..., T>;
|
||||||
|
```
|
||||||
|
|
||||||
|
`store<T>()` parses a value and stores it in the parser for later lookup.
|
||||||
|
`store<void>()` is rejected at compile time.
|
||||||
|
|
||||||
|
`reference(T&)` parses a value and assigns it directly to an object that must
|
||||||
|
outlive parsing.
|
||||||
|
|
||||||
|
`flag()` registers a boolean presence flag. It is not available for positional
|
||||||
|
arguments. Named arguments also default to flag behavior when no terminal mode
|
||||||
|
is selected.
|
||||||
|
|
||||||
|
`accumulate<T>()` accepts repeated values and stores them as `std::vector<T>`.
|
||||||
|
`accumulate(existing)` appends repeated values into an existing vector. The
|
||||||
|
existing object must be a `std::vector` and must outlive parsing.
|
||||||
|
|
||||||
|
`count()` counts how many times a named argument appears. `count(int&)` writes
|
||||||
|
the count into an existing integer. `count()` is not available for positional
|
||||||
|
arguments.
|
||||||
|
|
||||||
|
`action(handler)` registers a no-value action when `handler` is invocable as
|
||||||
|
`void()`. For positional arguments, the builder adapts it through a
|
||||||
|
`std::string` positional action and ignores the parsed positional text.
|
||||||
|
|
||||||
|
`action<T>(handler)` registers a typed action when `handler` is invocable as
|
||||||
|
`void(T const&)`. `action<void>(...)` is rejected at compile time.
|
||||||
|
|
||||||
|
### Build Methods
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto build(argument_parser::v2::base_parser& parser) const -> void;
|
||||||
|
|
||||||
|
auto build_and_get(argument_parser::v2::base_parser& parser) const
|
||||||
|
-> container<store_type>;
|
||||||
|
```
|
||||||
|
|
||||||
|
`build(parser)` registers the configured argument with the parser. It requires
|
||||||
|
an identifier, dispatches to the selected terminal mode, and defaults to a named
|
||||||
|
boolean flag or `std::string` positional value when no terminal mode was
|
||||||
|
selected. It may propagate validation errors from `v2::base_parser`.
|
||||||
|
|
||||||
|
`build_and_get(parser)` registers the argument and returns a
|
||||||
|
`container<store_type>` for storable modes such as `store<T>()`, `flag()`,
|
||||||
|
default named flags, `accumulate<T>()`, `accumulate(vector&)`, `count()`, and
|
||||||
|
`count(int&)`. It throws `std::logic_error` for unsupported terminal modes such
|
||||||
|
as actions. The returned container is normally empty until
|
||||||
|
`parser.handle_arguments(...)` completes.
|
||||||
|
|
||||||
|
### Compile-Time Builder Rules
|
||||||
|
|
||||||
|
Invalid fluent chains fail to compile rather than failing at runtime.
|
||||||
|
|
||||||
|
- `build(...)` requires `short_argument(...)`, `long_argument(...)`, or
|
||||||
|
`positional(...)`.
|
||||||
|
- `short_argument(...)` and `long_argument(...)` can be combined.
|
||||||
|
- `positional(...)` is mutually exclusive with named identifiers.
|
||||||
|
- `position(...)` is available only after `positional(...)` and only once.
|
||||||
|
- `help_text(...)` and `required(...)` are single-use.
|
||||||
|
- Terminal value modes are mutually exclusive.
|
||||||
|
- `flag()` and `count()` are not available for positional arguments.
|
||||||
|
- `store<void>()` and `action<void>(...)` are rejected with `static_assert`.
|
||||||
|
- `accumulate(existing)` requires `existing` to be a `std::vector`.
|
||||||
|
|
||||||
|
The header also exposes `argument_parser::builder::assertions`, a namespace of
|
||||||
|
small compile-time detection helpers and `static_assert` checks used to verify
|
||||||
|
these staged-builder rules. They are not needed for normal parser
|
||||||
|
configuration.
|
||||||
|
|
||||||
|
### Complete Builder Example
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <argparse>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using argument_parser::builder::new_argument;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
argument_parser::v2::parser parser(false);
|
||||||
|
|
||||||
|
int threshold = 0;
|
||||||
|
std::vector<int> ids;
|
||||||
|
|
||||||
|
new_argument()
|
||||||
|
.long_argument("file")
|
||||||
|
.store<std::string>()
|
||||||
|
.required()
|
||||||
|
.help_text("Input file.")
|
||||||
|
.build(parser);
|
||||||
|
|
||||||
|
new_argument()
|
||||||
|
.long_argument("threshold")
|
||||||
|
.reference(threshold)
|
||||||
|
.build(parser);
|
||||||
|
|
||||||
|
new_argument()
|
||||||
|
.long_argument("id")
|
||||||
|
.accumulate(ids)
|
||||||
|
.help_text("Repeatable numeric id.")
|
||||||
|
.build(parser);
|
||||||
|
|
||||||
|
auto verbose = new_argument()
|
||||||
|
.short_argument("v")
|
||||||
|
.count()
|
||||||
|
.build_and_get(parser);
|
||||||
|
|
||||||
|
parser.handle_arguments({
|
||||||
|
&argument_parser::conventions::gnu_argument_convention,
|
||||||
|
&argument_parser::conventions::windows_argument_convention,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (auto file = parser.get_optional<std::string>("file")) {
|
||||||
|
std::cout << "file: " << *file << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "verbosity: " << *verbose << '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "threshold: " << threshold << '\n';
|
||||||
|
std::cout << "ids: " << ids.size() << '\n';
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Caveats
|
||||||
|
|
||||||
|
- The v1 API is retained as public compatibility surface, but the newer v2 and
|
||||||
|
builder APIs are generally more ergonomic.
|
||||||
|
- Parser registration and parsing are single-threaded; `handle_arguments(...)`
|
||||||
|
enforces the parser creation thread.
|
||||||
|
- `handle_arguments(...)` resets the current convention list after it returns
|
||||||
|
or throws.
|
||||||
|
- Namespaces named `argument_parser::internal::*` are implementation details
|
||||||
|
despite being present in public headers.
|
||||||
115
README.md
115
README.md
@@ -1,6 +1,6 @@
|
|||||||
# argument-parser
|
# argument-parser
|
||||||
|
|
||||||
A lightweight, modern, and highly customizable C++17 argument parser with native platform argument collection, trait-driven typed parsing, pluggable option conventions, and a fluent `v2` builder API.
|
A lightweight, modern, and highly customizable C++17 argument parser with native platform argument collection, trait-driven typed parsing, repeatable argument accumulation, pluggable option conventions, and a fluent `v2` builder API.
|
||||||
|
|
||||||
> `v1` is deprecated and mainly kept as implementation history. For new projects, use `argument_parser::v2` together with `argument_parser::builder`.
|
> `v1` is deprecated and mainly kept as implementation history. For new projects, use `argument_parser::v2` together with `argument_parser::builder`.
|
||||||
|
|
||||||
@@ -8,11 +8,13 @@ A lightweight, modern, and highly customizable C++17 argument parser with native
|
|||||||
|
|
||||||
- Native platform parser alias: `argument_parser::v2::parser` resolves to the current platform parser and reads arguments directly from OS APIs.
|
- Native platform parser alias: `argument_parser::v2::parser` resolves to the current platform parser and reads arguments directly from OS APIs.
|
||||||
- Fluent builder API with compile-time builder constraints that prevent invalid combinations after a terminal/mutually exclusive mode has been selected.
|
- Fluent builder API with compile-time builder constraints that prevent invalid combinations after a terminal/mutually exclusive mode has been selected.
|
||||||
- Type-safe parsing and extraction. Just extend `parser_trait<T>` for your types and if just want to store use `get_optional<T>()`!
|
- Type-safe parsing and extraction. Extend `parser_trait<T>` for your own types and retrieve stored values with `get_optional<T>()`.
|
||||||
|
- Repeatable value accumulation with `accumulate<T>()`, `accumulate(vector&)`, `count()`, and `count(int&)`.
|
||||||
|
- `build_and_get(parser)` for storable builder modes, returning a small container that is populated after parsing completes.
|
||||||
- Positional arguments with optional explicit ordering and support for `--` as a positional separator.
|
- Positional arguments with optional explicit ordering and support for `--` as a positional separator.
|
||||||
- Trait-driven `format_hint` and `purpose_hint` metadata used in generated help text and parse errors.
|
- Trait-driven `format_hint` and `purpose_hint` metadata used in generated help text and parse errors.
|
||||||
- Automatic help flag on `argument_parser::v2::parser` (`-h`, `--help`) with configurable exit behavior.
|
- Automatic help flag on `argument_parser::v2::parser` (`-h`, `--help`) with configurable exit behavior.
|
||||||
- Auto-formatted help output..
|
- Auto-formatted help output.
|
||||||
- Completion hooks via `parser.on_complete(...)`.
|
- Completion hooks via `parser.on_complete(...)`.
|
||||||
- Pluggable conventions for GNU next-token, GNU equal-style, Windows next-token, and Windows inline `=` / `:` parsing, or bring your own!
|
- Pluggable conventions for GNU next-token, GNU equal-style, Windows next-token, and Windows inline `=` / `:` parsing, or bring your own!
|
||||||
- Testing helper + pseudo command handler `argument_parser::v2::fake_parser`.
|
- Testing helper + pseudo command handler `argument_parser::v2::fake_parser`.
|
||||||
@@ -28,15 +30,17 @@ A lightweight, modern, and highly customizable C++17 argument parser with native
|
|||||||
#include <argparse>
|
#include <argparse>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
using argument = argument_parser::builder::argument<>;
|
using argument_parser::builder::new_argument;
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
argument_parser::v2::parser parser(false); // --help prints without exiting immediately
|
argument_parser::v2::parser parser(false); // --help prints without exiting immediately
|
||||||
|
|
||||||
int threshold = 0;
|
int threshold = 0;
|
||||||
|
std::vector<int> ids;
|
||||||
|
|
||||||
argument::start()
|
new_argument()
|
||||||
.short_argument("e")
|
.short_argument("e")
|
||||||
.long_argument("echo")
|
.long_argument("echo")
|
||||||
.action<std::string>([](std::string const& text) {
|
.action<std::string>([](std::string const& text) {
|
||||||
@@ -44,26 +48,32 @@ int main() {
|
|||||||
})
|
})
|
||||||
.build(parser);
|
.build(parser);
|
||||||
|
|
||||||
argument::start()
|
new_argument()
|
||||||
.long_argument("file")
|
.long_argument("file")
|
||||||
.store<std::string>()
|
.store<std::string>()
|
||||||
.required()
|
.required()
|
||||||
.help_text("Input file to process.")
|
.help_text("Input file to process.")
|
||||||
.build(parser);
|
.build(parser);
|
||||||
|
|
||||||
argument::start()
|
new_argument()
|
||||||
.long_argument("threshold")
|
.long_argument("threshold")
|
||||||
.reference(threshold)
|
.reference(threshold)
|
||||||
|
.help_text("Numeric threshold.")
|
||||||
.build(parser);
|
.build(parser);
|
||||||
|
|
||||||
argument::start()
|
auto verbose = new_argument()
|
||||||
.short_argument("v")
|
.short_argument("v")
|
||||||
.long_argument("verbose")
|
.help_text("Increase verbosity. Repeat for a higher level.")
|
||||||
.flag()
|
.count()
|
||||||
.help_text("Enable verbose output.")
|
.build_and_get(parser);
|
||||||
|
|
||||||
|
new_argument()
|
||||||
|
.long_argument("id")
|
||||||
|
.help_text("Collect an id. May be repeated.")
|
||||||
|
.accumulate(ids)
|
||||||
.build(parser);
|
.build(parser);
|
||||||
|
|
||||||
argument::start()
|
new_argument()
|
||||||
.positional("output")
|
.positional("output")
|
||||||
.position(0)
|
.position(0)
|
||||||
.help_text("Output file.")
|
.help_text("Output file.")
|
||||||
@@ -89,6 +99,11 @@ int main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "threshold: " << threshold << '\n';
|
std::cout << "threshold: " << threshold << '\n';
|
||||||
|
std::cout << "ids: " << ids.size() << '\n';
|
||||||
|
|
||||||
|
if (verbose) {
|
||||||
|
std::cout << "verbosity: " << *verbose << '\n';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -129,7 +144,7 @@ struct argument_parser::parsing_traits::parser_trait<Point> {
|
|||||||
Then use the type directly from the builder:
|
Then use the type directly from the builder:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
argument::start()
|
new_argument()
|
||||||
.long_argument("point")
|
.long_argument("point")
|
||||||
.store<Point>()
|
.store<Point>()
|
||||||
.build(parser);
|
.build(parser);
|
||||||
@@ -161,9 +176,15 @@ parser.display_help(conventions);
|
|||||||
|
|
||||||
Mix any of them in the same parser by passing the conventions you want to `handle_arguments()`.
|
Mix any of them in the same parser by passing the conventions you want to `handle_arguments()`.
|
||||||
|
|
||||||
## Builder Modes
|
## Builder API
|
||||||
|
|
||||||
`argument_parser::builder::argument<>` is a staged builder. `build(parser)` is the terminal call.
|
`argument_parser::builder::argument<>` is a staged builder. Prefer `argument_parser::builder::new_argument()` as the entry point:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using argument_parser::builder::new_argument;
|
||||||
|
```
|
||||||
|
|
||||||
|
`build(parser)` registers the argument and returns `void`. `build_and_get(parser)` is available for storable modes and returns a lightweight `builder::container<T>`. The container is filled by an internal completion hook after `handle_arguments(...)` runs.
|
||||||
|
|
||||||
Before `build(...)`, you compose an argument from three kinds of steps:
|
Before `build(...)`, you compose an argument from three kinds of steps:
|
||||||
|
|
||||||
@@ -173,13 +194,75 @@ Before `build(...)`, you compose an argument from three kinds of steps:
|
|||||||
- `store<T>()` to parse and retain a value for later `get_optional<T>()`
|
- `store<T>()` to parse and retain a value for later `get_optional<T>()`
|
||||||
- `flag()` to store a boolean presence flag
|
- `flag()` to store a boolean presence flag
|
||||||
- `reference(value)` to write the parsed result directly into an existing variable
|
- `reference(value)` to write the parsed result directly into an existing variable
|
||||||
|
- `accumulate<T>()` to collect repeated values into a stored `std::vector<T>`
|
||||||
|
- `accumulate(vector)` to collect repeated values into an existing `std::vector<T>`
|
||||||
|
- `count()` to store how many times an option appears
|
||||||
|
- `count(value)` to write the occurrence count into an existing `int`
|
||||||
- `action([] { ... })` for no-value callbacks
|
- `action([] { ... })` for no-value callbacks
|
||||||
- `action<T>([](T const&) { ... })` for typed value callbacks
|
- `action<T>([](T const&) { ... })` for typed value callbacks
|
||||||
|
|
||||||
Once you select one value behavior, the other value behavior methods are disabled at compile time, so combinations like `store<T>().action(...)` or `flag().reference(value)` are rejected by the type system. Also you cannot use the same method repeatedly as it is also disabled at compile time by the type system.
|
Once you select one value behavior, the other value behavior methods are disabled at compile time, so combinations like `store<T>().action(...)` or `flag().reference(value)` are rejected by the type system. The same staged typing also prevents repeating one-shot methods such as `help_text(...)`, `position(...)`, or `store<T>()` on the same builder chain.
|
||||||
|
|
||||||
If you do not select a value behavior explicitly, `build(parser)` uses the default for the argument kind: named arguments become boolean flags, while positional arguments store a `std::string`.
|
If you do not select a value behavior explicitly, `build(parser)` uses the default for the argument kind: named arguments become boolean flags, while positional arguments store a `std::string`.
|
||||||
|
|
||||||
|
## Accumulators and Counts
|
||||||
|
|
||||||
|
Use `accumulate<T>()` when the parser should accept the same value-bearing argument multiple times and store all parsed values:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto values = new_argument()
|
||||||
|
.short_argument("n")
|
||||||
|
.long_argument("number")
|
||||||
|
.accumulate<int>()
|
||||||
|
.build_and_get(parser);
|
||||||
|
|
||||||
|
parser.handle_arguments(conventions);
|
||||||
|
|
||||||
|
if (values) {
|
||||||
|
for (int value : *values) {
|
||||||
|
std::cout << value << '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `accumulate(target)` to append into a vector you own:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
std::vector<int> ids;
|
||||||
|
|
||||||
|
new_argument()
|
||||||
|
.long_argument("id")
|
||||||
|
.accumulate(ids)
|
||||||
|
.build(parser);
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `count()` for repeatable flags such as `-v -v -v`:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
auto verbosity = new_argument()
|
||||||
|
.short_argument("v")
|
||||||
|
.count()
|
||||||
|
.build_and_get(parser);
|
||||||
|
```
|
||||||
|
|
||||||
|
The lower-level `v2::base_parser::add_argument` API exposes the same accumulator behavior through the `Accumulate` flag:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
using namespace argument_parser::v2::flags;
|
||||||
|
|
||||||
|
parser.add_argument<std::vector<int>>({
|
||||||
|
{LongArgument, "id"},
|
||||||
|
{HelpText, "Collect an id. May be repeated."},
|
||||||
|
{Accumulate, true},
|
||||||
|
});
|
||||||
|
|
||||||
|
std::vector<int> captured_ids;
|
||||||
|
parser.add_argument<std::vector<int>>({
|
||||||
|
{LongArgument, "captured-id"},
|
||||||
|
{Accumulate, &captured_ids},
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
For unit tests or synthetic argument lists, use `argument_parser::v2::fake_parser` instead of the native platform parser:
|
For unit tests or synthetic argument lists, use `argument_parser::v2::fake_parser` instead of the native platform parser:
|
||||||
|
|||||||
Reference in New Issue
Block a user