Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ else()
endif()

project(cpp-ap
VERSION 3.0.0.5
VERSION 3.0.0.6
DESCRIPTION "Command-line argument parser for C++20"
HOMEPAGE_URL "https://github.com/SpectraL519/cpp-ap"
LANGUAGES CXX
Expand Down
2 changes: 1 addition & 1 deletion Doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ PROJECT_NAME = CPP-AP
# could be handy for archiving the generated documentation or if some version
# control system is used.

PROJECT_NUMBER = 3.0.0.5
PROJECT_NUMBER = 3.0.0.6

# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
Expand Down
2 changes: 1 addition & 1 deletion MODULE.bazel
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module(
name = "cpp-ap",
version = "3.0.0.5",
version = "3.0.0.6",
)
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ Command-line argument parser for C++20
- [The Parser Class](/docs/tutorial.md#the-parser-class)
- [Adding Arguments](/docs/tutorial.md#adding-arguments)
- [Argument Parameters](/docs/tutorial.md#argument-parameters)
- [Common Parameters](/docs/tutorial.md##common-parameters)
- [Parameters Specific for Optional Arguments](/docs/tutorial.md##parameters-specific-for-optional-arguments)
- [Common Parameters](/docs/tutorial.md#common-parameters)
- [Parameters Specific for Optional Arguments](/docs/tutorial.md#parameters-specific-for-optional-arguments)
- [Default Arguments](/docs/tutorial.md#default-arguments)
- [Parsing Arguments](/docs/tutorial.md#parsing-arguments)
- [Basic Argument Parsing Rules](/docs/tutorial.md#basic-argument-parsing-rules)
Expand Down
76 changes: 66 additions & 10 deletions docs/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,18 @@
- [Adding Arguments](#adding-arguments)
- [Argument Parameters](#argument-parameters)
- [Common Parameters](#common-parameters)
- [help](#1-help---the-arguments-description-which-will-be-printed-when-printing-the-parser-class-instance)
- [hidden](#2-hidden---if-this-option-is-set-for-an-argument-then-it-will-not-be-included-in-the-program-description)
- [required](#3-required---if-this-option-is-set-for-an-argument-and-its-value-is-not-passed-in-the-command-line-an-exception-will-be-thrown)
- [bypass required](#4-bypass_required---if-this-option-is-set-for-an-argument-the-required-option-for-other-arguments-will-be-discarded-if-the-bypassing-argument-is-used-in-the-command-line)
- [nargs](#5-nargs---sets-the-allowed-number-of-values-to-be-parsed-for-an-argument)
- [greedy](#6-greedy---if-this-option-is-set-the-argument-will-consume-all-command-line-values-until-its-upper-nargs-bound-is-reached)
- [choices](#7-choices---a-list-of-valid-argument-values)
- [value actions](#8-value-actions---functions-that-are-called-after-parsing-an-arguments-value)
- [default values](#9-default_values---a-list-of-values-which-will-be-used-if-no-values-for-an-argument-have-been-parsed)
- [Parameters Specific for Optional Arguments](#parameters-specific-for-optional-arguments)
- [on-flag actions](#1-on-flag-actions---functions-that-are-called-immediately-after-parsing-an-arguments-flag)
- [implicit values](#2-implicit_values---a-list-of-values-which-will-be-set-for-an-argument-if-only-its-flag-but-no-values-are-parsed-from-the-command-line)
- [Predefined Parameter Values](#predefined-parameter-values)
- [Default Arguments](#default-arguments)
- [Parsing Arguments](#parsing-arguments)
Expand Down Expand Up @@ -189,9 +200,10 @@ parser.add_<positional/optional>_argument<value_type>("argument", "a");
>
> - If the argument's value type is `ap::none_type`, the argument will not accept any values and therefore no value-related parameters can be set for such argument. This includes:
> - [nargs](#5-nargs---sets-the-allowed-number-of-values-to-be-parsed-for-an-argument-this-can-be-set-as-a)
> - [choices](#6-choices---a-list-of-valid-argument-values)
> - [value actions](#7-value-actions---function-performed-after-parsing-an-arguments-value)
> - [default_values](#8-default_values---a-list-of-values-which-will-be-used-if-no-values-for-an-argument-have-been-parsed)
> - [greedy](#6-greedy---if-this-option-is-set-the-argument-will-consume-all-command-line-values-until-its-upper-nargs-bound-is-reached)
> - [choices](#7-choices---a-list-of-valid-argument-values)
> - [value actions](#8-value-actions---functions-that-are-called-after-parsing-an-arguments-value)
> - [default_values](#9-default_values---a-list-of-values-which-will-be-used-if-no-values-for-an-argument-have-been-parsed)
> - [implicit_values](#2-implicit_values---a-list-of-values-which-will-be-set-for-an-argument-if-only-its-flag-but-no-values-are-parsed-from-the-command-line)

You can also add boolean flags:
Expand Down Expand Up @@ -343,8 +355,8 @@ Command Result

> [!NOTE]
>
> - Both positional and optional arguments have the `bypass_required` option disabled.
> - The default value of the value parameter of the `bypass_required(bool)` function is `true` for both positional and optional arguments.
> - Both all arguments have the `bypass_required` option disabled.
> - The default value of the value parameter of the `argument::bypass_required(bool)` method is `true` for all arguments.

> [!WARNING]
>
Expand Down Expand Up @@ -377,7 +389,9 @@ os << data << std::endl;

<br />

#### 5. `nargs` - Sets the allowed number of values to be parsed for an argument. This can be set as a:
#### 5. `nargs` - Sets the allowed number of values to be parsed for an argument.

The `nargs` parameter can be set as:

- Specific number:

Expand Down Expand Up @@ -416,7 +430,49 @@ os << data << std::endl;

<br />

#### 6. `choices` - A list of valid argument values.
#### 6. `greedy` - If this option is set, the argument will consume ALL command-line values until it's upper nargs bound is reached.

> [!NOTE]
>
> - By default the `greedy` option is disabled for all arguments.
> - The default value of the parameter of the `argument::greedy(bool)` method is true for all arguments.

> [!TIP]
>
> - Enabling the `greedy` option for an argument only makes sense for arguments with string-like value types.
> - If no explicit `nargs` bound is set for a greedy argument, once it starts being parsed, it will consume all remaining command-line arguments.

Consider a simple example:

```cpp
ap::argument_parser parser;
parser.program_name("run-script")
.default_arguments(ap::default_argument::o_help);

parser.add_positional_argument("script")
.help("The name of the script to run");
parser.add_optional_argument("args")
.greedy()
.help("Set the execution option");

parser.try_parse_args(argc, argv);

// Application logic here
std::cout << "Executing: " << parser.value("script") << " " << ap::util::join(parser.values("args")) << std::endl;
```

Here the program execution should look something like this:

```txt
> ./run-script remove-comments --args module.py -v --type py
Executing: remove-comments module.py -v --type py
```

Notice that even though the `-v` and `--type` command-line arguments have flag prefixes and are not defined in the program, they are not treated as unknown arguments (and therefore no exception is thrown) because the `--args` argument is marked as `greedy` and it consumes these command-line arguments as its values.

<br />

#### 7. `choices` - A list of valid argument values.

```cpp
parser.add_optional_argument<char>("method", "m").choices('a', 'b', 'c');
Expand All @@ -433,7 +489,7 @@ parser.add_optional_argument<char>("method", "m").choices('a', 'b', 'c');

<br />

#### 7. Value actions - Function performed after parsing an argument's value.
#### 8. value actions - Functions that are called after parsing an argument's value.
Actions are represented as functions, which take the argument's value as an argument. The available action types are:

- `observe` actions | `void(const value_type&)` - applied to the parsed value. No value is returned - this action type is used to perform some logic on the parsed value without modifying it.
Expand Down Expand Up @@ -478,7 +534,7 @@ Actions are represented as functions, which take the argument's value as an argu

<br />

#### 8. `default_values` - A list of values which will be used if no values for an argument have been parsed
#### 9. `default_values` - A list of values which will be used if no values for an argument have been parsed

> [!WARNING]
>
Expand Down Expand Up @@ -541,7 +597,7 @@ Command Result

Apart from the common parameters listed above, for optional arguments you can also specify the following parameters:

#### 1. On-flag actions - For optional arguments, apart from value actions, you can specify on-flag actions which are executed immediately after parsing an argument's flag.
#### 1. on-flag actions - Functions that are called immediately after parsing an argument's flag.

```cpp
void print_debug_info() noexcept {
Expand Down
33 changes: 25 additions & 8 deletions include/ap/argument.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@ class argument : public detail::argument_base {
return not this->_required and this->_bypass_required;
}

/// @return `true` if the argument is greedy, `false` otherwise.
[[nodiscard]] bool is_greedy() const noexcept override {
return this->_greedy;
}

// attribute setters

/**
Expand Down Expand Up @@ -171,6 +176,19 @@ class argument : public detail::argument_base {
return *this;
}

/**
* @brief Set the `greedy` attribute of the argument.
* @param g The attribute value.
* @return Reference to the argument instance.
* @note The method is enabled only if `value_type` is not `none_type`.
*/
argument& greedy(const bool g = true) noexcept
requires(not util::c_is_none<value_type>)
{
this->_greedy = g;
return *this;
}

/**
* @brief Set the nargs range for the argument.
* @param range The attribute value.
Expand All @@ -193,8 +211,7 @@ class argument : public detail::argument_base {
argument& nargs(const count_type n) noexcept
requires(not util::c_is_none<value_type>)
{
this->_nargs_range = nargs::range(n);
return *this;
return this->nargs(nargs::range(n));
}

/**
Expand All @@ -207,8 +224,7 @@ class argument : public detail::argument_base {
argument& nargs(const count_type lower, const count_type upper) noexcept
requires(not util::c_is_none<value_type>)
{
this->_nargs_range = nargs::range(lower, upper);
return *this;
return this->nargs(nargs::range(lower, upper));
}

/**
Expand Down Expand Up @@ -671,7 +687,7 @@ class argument : public detail::argument_base {
// attributes
const ap::detail::argument_name _name; ///< The argument's name.
std::optional<std::string> _help_msg; ///< The argument's help message.
nargs::range _nargs_range; ///< The argument's nargs range attribute.
nargs::range _nargs_range; ///< The argument's nargs range attribute value.
[[no_unique_address]] value_arg_specific_type<std::vector<std::any>>
_default_values; ///< The argument's default value list.
[[no_unique_address]] value_arg_specific_type<optional_specific_type<std::vector<std::any>>>
Expand All @@ -683,9 +699,10 @@ class argument : public detail::argument_base {
[[no_unique_address]] value_arg_specific_type<std::vector<value_action_type>>
_value_actions; ///< The argument's value actions collection.

bool _required : 1; ///< The argument's `required` attribute.
bool _bypass_required : 1 = false; ///< The argument's `bypass_required` attribute.
bool _hidden : 1 = false; ///< The argument's `hidden` attribute.
bool _required : 1; ///< The argument's `required` attribute value.
bool _bypass_required : 1 = false; ///< The argument's `bypass_required` attribute value.
bool _greedy : 1 = false; ///< The argument's `greedy` attribute value.
bool _hidden : 1 = false; ///< The argument's `hidden` attribute value.

// parsing result
[[no_unique_address]] optional_specific_type<std::size_t>
Expand Down
Loading