chore: update readme.md

This commit is contained in:
2026-05-05 11:44:18 +04:00
parent 1479892e7b
commit 1c63622fd8

217
README.md
View File

@@ -1,17 +1,21 @@
# argument-parser # argument-parser
A lightweight, modern, expressively typed, and highly customizable C++17 argument parser library. 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.
> `v1` is deprecated and mainly kept as implementation history. For new projects, use `argument_parser::v2` together with `argument_parser::builder`.
## Features ## Features
- **Type-safe Argument Extraction**: Use type traits to automatically parse fundamental types and custom structures (e.g. `std::vector<int>`, `std::regex`, `Point`). - Native platform parser alias: `argument_parser::v2::parser` resolves to the current platform parser and reads arguments directly from OS APIs.
- **Support for Multiple Parsing Conventions**: Pluggable convention system out of the box, offering GNU-style (`-a`, `--arg`), GNU-equal-style (`--arg=value`), Windows-style (`/arg`), and Windows-equal-style (`/arg:value`). - Fluent builder API with compile-time builder constraints that prevent invalid combinations after a terminal/mutually exclusive mode has been selected.
- **Automated Help Text Formatting**: Call `parser.display_help(conventions)` to easily generate beautifully formatted usage instructions. - Type-safe parsing and extraction. Just extend `parser_trait<T>` for your types and if just want to store use `get_optional<T>()`!
- **Cross-Platform Native Parsers**: Dedicated parsers that automatically fetch command-line arguments using OS-specific APIs (`windows_parser`, `linux_parser`, `macos_parser`), so you don't need to manually pass `argc` and `argv` on most platforms. - Positional arguments with optional explicit ordering and support for `--` as a positional separator.
- **Fluid setup**: Enjoy fluid setup routines with maps and initializer lists. - 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.
### Important Note: - Auto-formatted help output..
V1 is deprecated and is mainly kept as a base implementation for the V2. You should use V2 for your projects. If any features are missing compared to V1, please let me know so I can introduce them! - 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!
- Testing helper + pseudo command handler `argument_parser::v2::fake_parser`.
## Requirements ## Requirements
@@ -20,104 +24,193 @@ V1 is deprecated and is mainly kept as a base implementation for the V2. You sho
## Quick Start ## Quick Start
### 1. Create your Parser and Define Arguments
```cpp ```cpp
#include <argparse>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <regex>
#include <argparse> // Provides the native parser for your compiling platform using argument = argument_parser::builder::argument<>;
int main() { int main() {
using namespace argument_parser::v2::flags; argument_parser::v2::parser parser(false); // --help prints without exiting immediately
// Automatically uses the platform-native parser! int threshold = 0;
// It will fetch arguments directly from OS APIs (e.g., GetCommandLineW on Windows)
argument_parser::v2::parser parser;
// A flag with an action argument::start()
parser.add_argument<std::string>({ .short_argument("e")
{ShortArgument, "e"}, .long_argument("echo")
{LongArgument, "echo"}, .action<std::string>([](std::string const& text) {
{Action, argument_parser::helpers::make_parametered_action<std::string>( std::cout << text << '\n';
[](std::string const &text) { std::cout << text << std::endl; } })
)}, .build(parser);
{HelpText, "echoes given variable"}
});
// A flag that just stores the value to extract later argument::start()
parser.add_argument<std::regex>({ .long_argument("file")
{ShortArgument, "g"}, .store<std::string>()
{LongArgument, "grep"}, .required()
{HelpText, "Grep pattern"} .help_text("Input file to process.")
}); .build(parser);
// A required flag argument::start()
parser.add_argument<std::string>({ .long_argument("threshold")
{LongArgument, "file"}, .reference(threshold)
{Required, true}, .build(parser);
{HelpText, "File to grep"}
});
// Run action callback on complete argument::start()
parser.on_complete([](argument_parser::base_parser const &p) { .short_argument("v")
auto filename = p.get_optional<std::string>("file"); .long_argument("verbose")
auto pattern = p.get_optional<std::regex>("grep"); .flag()
.help_text("Enable verbose output.")
.build(parser);
if (filename && pattern) { argument::start()
std::cout << "Grepping " << filename.value() << " with pattern." << std::endl; .positional("output")
.position(0)
.help_text("Output file.")
.build(parser);
parser.on_complete([](auto const& state) {
if (auto file = state.template get_optional<std::string>("file")) {
std::cout << "completed for: " << *file << '\n';
} }
}); });
// Register Conventions
const std::initializer_list<argument_parser::conventions::convention const *const> conventions = { const std::initializer_list<argument_parser::conventions::convention const *const> conventions = {
&argument_parser::conventions::gnu_argument_convention, &argument_parser::conventions::gnu_argument_convention,
&argument_parser::conventions::windows_argument_convention &argument_parser::conventions::gnu_equal_argument_convention,
&argument_parser::conventions::windows_argument_convention,
&argument_parser::conventions::windows_equal_argument_convention,
}; };
// Execute logic!
parser.handle_arguments(conventions); parser.handle_arguments(conventions);
return 0; if (auto file = parser.get_optional<std::string>("file")) {
std::cout << "file: " << *file << '\n';
}
std::cout << "threshold: " << threshold << '\n';
} }
``` ```
### 2. Custom Type Parsing ## Trait-Driven Parsing and Hints
You can natively parse your custom structs, objects, or arrays by specializing `argument_parser::parsing_traits::parser_trait<T>`. Specialize `argument_parser::parsing_traits::parser_trait<T>` to add support for your own types and to describe their expected format.
```cpp ```cpp
#include <macros.h>
#include <traits.hpp>
#include <stdexcept>
#include <string>
struct Point { struct Point {
int x, y; int x;
int y;
}; };
template <> struct argument_parser::parsing_traits::parser_trait<Point> { template <>
static Point parse(const std::string &input) { struct argument_parser::parsing_traits::parser_trait<Point> {
auto comma_pos = input.find(','); static Point parse(std::string const& input) {
int x = std::stoi(input.substr(0, comma_pos)); auto comma = input.find(',');
int y = std::stoi(input.substr(comma_pos + 1)); if (comma == std::string::npos) {
return {x, y}; throw std::runtime_error("Expected x,y");
} }
};
// Now you can directly use your type: return {
// parser.add_argument<Point>({ {LongArgument, "point"} }); std::stoi(input.substr(0, comma)),
// auto point = parser.get_optional<Point>("point"); std::stoi(input.substr(comma + 1))
};
}
ARGPARSE_TRAIT_FORMAT_HINT = "x,y";
ARGPARSE_TRAIT_PURPOSE_HINT = "point coordinates";
};
```
Then use the type directly from the builder:
```cpp
argument::start()
.long_argument("point")
.store<Point>()
.build(parser);
```
If you omit `help_text()`, `v2` uses the trait hints to generate help such as `Accepts point coordinates in x,y format.` The same hints are also included in type conversion errors.
## Help Behavior
`argument_parser::v2::parser` automatically registers `-h` and `--help`.
```cpp
argument_parser::v2::parser parser; // help prints and exits
argument_parser::v2::parser parser(false); // help prints without immediate exit
```
You can also display help manually:
```cpp
parser.display_help(conventions);
```
## Supported Conventions
- GNU next-token: `-o value`, `--output value`
- GNU equal-style: `-o=value`, `--output=value`
- Windows next-token: `/output value`
- Windows inline value: `/output=value`, `/output:value`
Mix any of them in the same parser by passing the conventions you want to `handle_arguments()`.
## Builder Modes
`argument_parser::builder::argument<>` is a staged builder. `build(parser)` is the terminal call.
Before `build(...)`, you compose an argument from three kinds of steps:
- Identifier selection: `short_argument(...)`, `long_argument(...)`, or `positional(...)`
- Optional metadata: `position(...)` for positional arguments, `help_text(...)`, and `required(...)`
- One mutually exclusive value behavior:
- `store<T>()` to parse and retain a value for later `get_optional<T>()`
- `flag()` to store a boolean presence flag
- `reference(value)` to write the parsed result directly into an existing variable
- `action([] { ... })` for no-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.
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`.
## Testing
For unit tests or synthetic argument lists, use `argument_parser::v2::fake_parser` instead of the native platform parser:
```cpp
#include <fake_parser.hpp>
argument_parser::v2::fake_parser parser("tool", {"--count", "3", "input.txt"});
``` ```
## CMake Integration ## CMake Integration
The library can be installed globally via CMake or incorporated into your project. Use the project directly:
```cmake ```cmake
add_subdirectory(argument-parser) add_subdirectory(argument-parser)
target_link_libraries(your_target PRIVATE argument_parser) target_link_libraries(your_target PRIVATE argument_parser)
``` ```
Or install and consume it as a package:
```cmake
find_package(argument_parser CONFIG REQUIRED)
target_link_libraries(your_target PRIVATE argument_parser::argument_parser)
```
## Building & Installing ## Building & Installing
```bash ```bash
mkdir build && cd build mkdir build && cd build
cmake .. cmake ..
cmake --build . cmake --build .
cmake --install .
``` ```