mirror of
https://github.com/sametersoylu/argument-parser.git
synced 2026-04-13 03:41:18 +00:00
feat: improve help text for better readability, less duplication on the conventions, better syntax information.
This commit is contained in:
123
README.md
Normal file
123
README.md
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
# argument-parser
|
||||||
|
|
||||||
|
A lightweight, modern, expressively typed, and highly customizable C++17 argument parser library.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Type-safe Argument Extraction**: Use type traits to automatically parse fundamental types and custom structures (e.g. `std::vector<int>`, `std::regex`, `Point`).
|
||||||
|
- **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`).
|
||||||
|
- **Automated Help Text Formatting**: Call `parser.display_help(conventions)` to easily generate beautifully formatted usage instructions.
|
||||||
|
- **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.
|
||||||
|
- **Fluid setup**: Enjoy fluid setup routines with maps and initializer lists.
|
||||||
|
|
||||||
|
### Important Note:
|
||||||
|
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!
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- C++17 or later
|
||||||
|
- CMake 3.15 or later
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Create your Parser and Define Arguments
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <regex>
|
||||||
|
#include <argparse> // Provides the native parser for your compiling platform
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
using namespace argument_parser::v2::flags;
|
||||||
|
|
||||||
|
// Automatically uses the platform-native parser!
|
||||||
|
// It will fetch arguments directly from OS APIs (e.g., GetCommandLineW on Windows)
|
||||||
|
argument_parser::v2::parser parser;
|
||||||
|
|
||||||
|
// A flag with an action
|
||||||
|
parser.add_argument<std::string>({
|
||||||
|
{ShortArgument, "e"},
|
||||||
|
{LongArgument, "echo"},
|
||||||
|
{Action, argument_parser::helpers::make_parametered_action<std::string>(
|
||||||
|
[](std::string const &text) { std::cout << text << std::endl; }
|
||||||
|
)},
|
||||||
|
{HelpText, "echoes given variable"}
|
||||||
|
});
|
||||||
|
|
||||||
|
// A flag that just stores the value to extract later
|
||||||
|
parser.add_argument<std::regex>({
|
||||||
|
{ShortArgument, "g"},
|
||||||
|
{LongArgument, "grep"},
|
||||||
|
{HelpText, "Grep pattern"}
|
||||||
|
});
|
||||||
|
|
||||||
|
// A required flag
|
||||||
|
parser.add_argument<std::string>({
|
||||||
|
{LongArgument, "file"},
|
||||||
|
{Required, true},
|
||||||
|
{HelpText, "File to grep"}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run action callback on complete
|
||||||
|
parser.on_complete([](argument_parser::base_parser const &p) {
|
||||||
|
auto filename = p.get_optional<std::string>("file");
|
||||||
|
auto pattern = p.get_optional<std::regex>("grep");
|
||||||
|
|
||||||
|
if (filename && pattern) {
|
||||||
|
std::cout << "Grepping " << filename.value() << " with pattern." << std::endl;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Register Conventions
|
||||||
|
const std::initializer_list<argument_parser::conventions::convention const *const> conventions = {
|
||||||
|
&argument_parser::conventions::gnu_argument_convention,
|
||||||
|
&argument_parser::conventions::windows_argument_convention
|
||||||
|
};
|
||||||
|
|
||||||
|
// Execute logic!
|
||||||
|
parser.handle_arguments(conventions);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Custom Type Parsing
|
||||||
|
|
||||||
|
You can natively parse your custom structs, objects, or arrays by specializing `argument_parser::parsing_traits::parser_trait<T>`.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
struct Point {
|
||||||
|
int x, y;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct argument_parser::parsing_traits::parser_trait<Point> {
|
||||||
|
static Point parse(const std::string &input) {
|
||||||
|
auto comma_pos = input.find(',');
|
||||||
|
int x = std::stoi(input.substr(0, comma_pos));
|
||||||
|
int y = std::stoi(input.substr(comma_pos + 1));
|
||||||
|
return {x, y};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Now you can directly use your type:
|
||||||
|
// parser.add_argument<Point>({ {LongArgument, "point"} });
|
||||||
|
// auto point = parser.get_optional<Point>("point");
|
||||||
|
```
|
||||||
|
|
||||||
|
## CMake Integration
|
||||||
|
|
||||||
|
The library can be installed globally via CMake or incorporated into your project.
|
||||||
|
|
||||||
|
```cmake
|
||||||
|
add_subdirectory(argument-parser)
|
||||||
|
target_link_libraries(your_target PRIVATE argument_parser)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building & Installing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake ..
|
||||||
|
cmake --build .
|
||||||
|
```
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#ifndef BASE_CONVENTION_HPP
|
#ifndef BASE_CONVENTION_HPP
|
||||||
#define BASE_CONVENTION_HPP
|
#define BASE_CONVENTION_HPP
|
||||||
|
|
||||||
namespace argument_parser::conventions {
|
namespace argument_parser::conventions {
|
||||||
|
enum class convention_features { ALLOW_SHORT_TO_LONG_FALLBACK, ALLOW_LONG_TO_SHORT_FALLBACK };
|
||||||
enum class argument_type { SHORT, LONG, POSITIONAL, INTERCHANGABLE, ERROR };
|
enum class argument_type { SHORT, LONG, POSITIONAL, INTERCHANGABLE, ERROR };
|
||||||
|
|
||||||
using parsed_argument = std::pair<argument_type, std::string>;
|
using parsed_argument = std::pair<argument_type, std::string>;
|
||||||
@@ -18,6 +20,9 @@ namespace argument_parser::conventions {
|
|||||||
virtual std::string name() const = 0;
|
virtual std::string name() const = 0;
|
||||||
virtual std::string short_prec() const = 0;
|
virtual std::string short_prec() const = 0;
|
||||||
virtual std::string long_prec() const = 0;
|
virtual std::string long_prec() const = 0;
|
||||||
|
virtual std::string make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
|
bool requires_value) const = 0;
|
||||||
|
virtual std::vector<convention_features> get_features() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
base_convention() = default;
|
base_convention() = default;
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ namespace argument_parser::conventions::implementations {
|
|||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
std::string short_prec() const override;
|
std::string short_prec() const override;
|
||||||
std::string long_prec() const override;
|
std::string long_prec() const override;
|
||||||
|
std::string make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
|
bool requires_value) const override;
|
||||||
|
std::vector<convention_features> get_features() const override;
|
||||||
|
|
||||||
static gnu_argument_convention instance;
|
static gnu_argument_convention instance;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -28,6 +32,10 @@ namespace argument_parser::conventions::implementations {
|
|||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
std::string short_prec() const override;
|
std::string short_prec() const override;
|
||||||
std::string long_prec() const override;
|
std::string long_prec() const override;
|
||||||
|
std::string make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
|
bool requires_value) const override;
|
||||||
|
std::vector<convention_features> get_features() const override;
|
||||||
|
|
||||||
static gnu_equal_argument_convention instance;
|
static gnu_equal_argument_convention instance;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ namespace argument_parser::conventions::implementations {
|
|||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
std::string short_prec() const override;
|
std::string short_prec() const override;
|
||||||
std::string long_prec() const override;
|
std::string long_prec() const override;
|
||||||
|
std::string make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
|
bool requires_value) const override;
|
||||||
|
std::vector<convention_features> get_features() const override;
|
||||||
|
|
||||||
static windows_argument_convention instance;
|
static windows_argument_convention instance;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -33,6 +37,10 @@ namespace argument_parser::conventions::implementations {
|
|||||||
std::string name() const override;
|
std::string name() const override;
|
||||||
std::string short_prec() const override;
|
std::string short_prec() const override;
|
||||||
std::string long_prec() const override;
|
std::string long_prec() const override;
|
||||||
|
std::string make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
|
bool requires_value) const override;
|
||||||
|
std::vector<convention_features> get_features() const override;
|
||||||
|
|
||||||
static windows_kv_argument_convention instance;
|
static windows_kv_argument_convention instance;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -256,7 +256,7 @@ namespace argument_parser {
|
|||||||
std::optional<argument> &found_help);
|
std::optional<argument> &found_help);
|
||||||
|
|
||||||
void invoke_arguments(std::unordered_map<std::string, std::string> const &values_for_arguments,
|
void invoke_arguments(std::unordered_map<std::string, std::string> const &values_for_arguments,
|
||||||
std::vector<std::pair<std::string, argument>> const &found_arguments,
|
std::vector<std::pair<std::string, argument>> &found_arguments,
|
||||||
std::optional<argument> const &found_help);
|
std::optional<argument> const &found_help);
|
||||||
void enforce_creation_thread();
|
void enforce_creation_thread();
|
||||||
|
|
||||||
|
|||||||
@@ -120,10 +120,10 @@ namespace argument_parser::v2 {
|
|||||||
found_params[extended_add_argument_flags::LongArgument] = true;
|
found_params[extended_add_argument_flags::LongArgument] = true;
|
||||||
long_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::LongArgument), "long");
|
long_arg = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::LongArgument), "long");
|
||||||
if (short_arg.empty())
|
if (short_arg.empty())
|
||||||
short_arg = long_arg;
|
short_arg = "-";
|
||||||
} else {
|
} else {
|
||||||
if (!short_arg.empty())
|
if (!short_arg.empty())
|
||||||
long_arg = short_arg;
|
long_arg = "-";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argument_pairs.find(add_argument_flags::Action) != argument_pairs.end()) {
|
if (argument_pairs.find(add_argument_flags::Action) != argument_pairs.end()) {
|
||||||
@@ -133,7 +133,18 @@ namespace argument_parser::v2 {
|
|||||||
if (argument_pairs.find(add_argument_flags::HelpText) != argument_pairs.end()) {
|
if (argument_pairs.find(add_argument_flags::HelpText) != argument_pairs.end()) {
|
||||||
help_text = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::HelpText), "help");
|
help_text = get_or_throw<std::string>(argument_pairs.at(add_argument_flags::HelpText), "help");
|
||||||
} else {
|
} else {
|
||||||
help_text = short_arg + ", " + long_arg;
|
help_text = "";
|
||||||
|
if (short_arg != "-") {
|
||||||
|
help_text += short_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (long_arg != "-") {
|
||||||
|
if (!help_text.empty()) {
|
||||||
|
help_text += ", ";
|
||||||
|
}
|
||||||
|
|
||||||
|
help_text += long_arg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argument_pairs.find(add_argument_flags::Required) != argument_pairs.end() &&
|
if (argument_pairs.find(add_argument_flags::Required) != argument_pairs.end() &&
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
#include <argparse>
|
#include <argparse>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <parser_v2.hpp>
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -168,8 +167,9 @@ int v2Examples() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
return v2Examples();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return v2Examples();
|
|
||||||
} catch (std::exception const &e) {
|
} catch (std::exception const &e) {
|
||||||
std::cerr << "Error: " << e.what() << std::endl;
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -35,6 +35,31 @@ namespace argument_parser::conventions::implementations {
|
|||||||
std::string gnu_argument_convention::long_prec() const {
|
std::string gnu_argument_convention::long_prec() const {
|
||||||
return "--";
|
return "--";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<convention_features> gnu_argument_convention::get_features() const {
|
||||||
|
return {}; // no fallback allowed
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string gnu_argument_convention::make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
|
bool requires_value) const {
|
||||||
|
std::string res = "";
|
||||||
|
if (short_arg != "-" && short_arg != "") {
|
||||||
|
res += short_prec() + short_arg;
|
||||||
|
if (requires_value) {
|
||||||
|
res += " <value>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (long_arg != "-" && long_arg != "") {
|
||||||
|
if (!res.empty()) {
|
||||||
|
res += ", ";
|
||||||
|
}
|
||||||
|
res += long_prec() + long_arg;
|
||||||
|
if (requires_value) {
|
||||||
|
res += " <value>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
} // namespace argument_parser::conventions::implementations
|
} // namespace argument_parser::conventions::implementations
|
||||||
|
|
||||||
namespace argument_parser::conventions::implementations {
|
namespace argument_parser::conventions::implementations {
|
||||||
@@ -72,4 +97,29 @@ namespace argument_parser::conventions::implementations {
|
|||||||
return "--";
|
return "--";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string gnu_equal_argument_convention::make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
|
bool requires_value) const {
|
||||||
|
std::string res = "";
|
||||||
|
if (short_arg != "-" && short_arg != "") {
|
||||||
|
res += short_prec() + short_arg;
|
||||||
|
if (requires_value) {
|
||||||
|
res += "=<value>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (long_arg != "-" && long_arg != "") {
|
||||||
|
if (!res.empty()) {
|
||||||
|
res += ", ";
|
||||||
|
}
|
||||||
|
res += long_prec() + long_arg;
|
||||||
|
if (requires_value) {
|
||||||
|
res += "=<value>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<convention_features> gnu_equal_argument_convention::get_features() const {
|
||||||
|
return {}; // no fallback allowed
|
||||||
|
}
|
||||||
} // namespace argument_parser::conventions::implementations
|
} // namespace argument_parser::conventions::implementations
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "windows_argument_convention.hpp"
|
#include "windows_argument_convention.hpp"
|
||||||
|
#include "base_convention.hpp"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace argument_parser::conventions::implementations {
|
namespace argument_parser::conventions::implementations {
|
||||||
@@ -49,6 +50,33 @@ namespace argument_parser::conventions::implementations {
|
|||||||
return "/";
|
return "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string windows_argument_convention::make_help_text(std::string const &short_arg, std::string const &long_arg,
|
||||||
|
bool requires_value) const {
|
||||||
|
std::string res = "";
|
||||||
|
if (short_arg != "-" && short_arg != "") {
|
||||||
|
res += short_prec() + short_arg;
|
||||||
|
if (requires_value) {
|
||||||
|
res += " <value>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (long_arg != "-" && long_arg != "") {
|
||||||
|
if (!res.empty()) {
|
||||||
|
res += ", ";
|
||||||
|
}
|
||||||
|
res += long_prec() + long_arg;
|
||||||
|
if (requires_value) {
|
||||||
|
res += " <value>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<convention_features> windows_argument_convention::get_features() const {
|
||||||
|
return {convention_features::ALLOW_LONG_TO_SHORT_FALLBACK,
|
||||||
|
convention_features::ALLOW_SHORT_TO_LONG_FALLBACK}; // interchangable
|
||||||
|
}
|
||||||
} // namespace argument_parser::conventions::implementations
|
} // namespace argument_parser::conventions::implementations
|
||||||
|
|
||||||
namespace argument_parser::conventions::implementations {
|
namespace argument_parser::conventions::implementations {
|
||||||
@@ -101,4 +129,35 @@ namespace argument_parser::conventions::implementations {
|
|||||||
std::string windows_kv_argument_convention::long_prec() const {
|
std::string windows_kv_argument_convention::long_prec() const {
|
||||||
return "/";
|
return "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string windows_kv_argument_convention::make_help_text(std::string const &short_arg,
|
||||||
|
std::string const &long_arg, bool requires_value) const {
|
||||||
|
std::string res = "";
|
||||||
|
if (short_arg != "-" && short_arg != "") {
|
||||||
|
res += short_prec() + short_arg;
|
||||||
|
if (requires_value) {
|
||||||
|
res += "=<value>";
|
||||||
|
res += ", " + short_prec() + short_arg;
|
||||||
|
res += ":<value>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (long_arg != "-" && long_arg != "") {
|
||||||
|
if (!res.empty()) {
|
||||||
|
res += ", ";
|
||||||
|
}
|
||||||
|
res += long_prec() + long_arg;
|
||||||
|
if (requires_value) {
|
||||||
|
res += "=<value>"
|
||||||
|
", " +
|
||||||
|
long_prec() + long_arg + ":<value>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<convention_features> windows_kv_argument_convention::get_features() const {
|
||||||
|
return {convention_features::ALLOW_LONG_TO_SHORT_FALLBACK,
|
||||||
|
convention_features::ALLOW_SHORT_TO_LONG_FALLBACK}; // interchangable
|
||||||
|
}
|
||||||
} // namespace argument_parser::conventions::implementations
|
} // namespace argument_parser::conventions::implementations
|
||||||
@@ -4,8 +4,10 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class deferred_exec {
|
class deferred_exec {
|
||||||
@@ -85,11 +87,19 @@ namespace argument_parser {
|
|||||||
ss << "Usage: " << program_name << " [OPTIONS]...\n";
|
ss << "Usage: " << program_name << " [OPTIONS]...\n";
|
||||||
|
|
||||||
for (auto const &[id, arg] : argument_map) {
|
for (auto const &[id, arg] : argument_map) {
|
||||||
auto short_arg = reverse_short_arguments.at(id);
|
auto short_arg =
|
||||||
auto long_arg = reverse_long_arguments.at(id);
|
reverse_short_arguments.find(id) != reverse_short_arguments.end() ? reverse_short_arguments.at(id) : "";
|
||||||
|
auto long_arg =
|
||||||
|
reverse_long_arguments.find(id) != reverse_long_arguments.end() ? reverse_long_arguments.at(id) : "";
|
||||||
|
|
||||||
ss << "\t";
|
ss << "\t";
|
||||||
|
std::unordered_set<std::string> hasOnce;
|
||||||
for (auto const &convention : convention_types) {
|
for (auto const &convention : convention_types) {
|
||||||
ss << convention->short_prec() << short_arg << ", " << convention->long_prec() << long_arg << "\t";
|
auto generatedHelpText = convention->make_help_text(short_arg, long_arg, arg.expects_parameter());
|
||||||
|
if (hasOnce.find(generatedHelpText) == hasOnce.end()) {
|
||||||
|
ss << generatedHelpText << "\t";
|
||||||
|
hasOnce.insert(generatedHelpText);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ss << arg.help_text << "\n";
|
ss << arg.help_text << "\n";
|
||||||
}
|
}
|
||||||
@@ -143,20 +153,19 @@ namespace argument_parser {
|
|||||||
|
|
||||||
if (extracted.second == "h" || extracted.second == "help") {
|
if (extracted.second == "h" || extracted.second == "help") {
|
||||||
found_help = corresponding_argument;
|
found_help = corresponding_argument;
|
||||||
continue;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
found_arguments.emplace_back(extracted.second, corresponding_argument);
|
found_arguments.emplace_back(extracted.second, corresponding_argument);
|
||||||
|
|
||||||
if (corresponding_argument.expects_parameter()) {
|
if (corresponding_argument.expects_parameter()) {
|
||||||
if (convention_type->requires_next_token() && (it + 1) == parsed_arguments.end()) {
|
if (convention_type->requires_next_token() && (it + 1) == parsed_arguments.end()) {
|
||||||
throw std::runtime_error("expected value for argument " + extracted.second);
|
throw std::runtime_error("Expected value for argument " + extracted.second);
|
||||||
}
|
}
|
||||||
values_for_arguments[extracted.second] =
|
values_for_arguments[extracted.second] =
|
||||||
convention_type->requires_next_token() ? *(++it) : convention_type->extract_value(*it);
|
convention_type->requires_next_token() ? *(++it) : convention_type->extract_value(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
corresponding_argument.set_invoked(true);
|
|
||||||
return true;
|
return true;
|
||||||
} catch (const std::runtime_error &e) {
|
} catch (const std::runtime_error &e) {
|
||||||
error_stream << "Convention \"" << convention_type->name() << "\" failed with: " << e.what() << "\n";
|
error_stream << "Convention \"" << convention_type->name() << "\" failed with: " << e.what() << "\n";
|
||||||
@@ -183,7 +192,7 @@ namespace argument_parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void base_parser::invoke_arguments(std::unordered_map<std::string, std::string> const &values_for_arguments,
|
void base_parser::invoke_arguments(std::unordered_map<std::string, std::string> const &values_for_arguments,
|
||||||
std::vector<std::pair<std::string, argument>> const &found_arguments,
|
std::vector<std::pair<std::string, argument>> &found_arguments,
|
||||||
std::optional<argument> const &found_help) {
|
std::optional<argument> const &found_help) {
|
||||||
|
|
||||||
if (found_help) {
|
if (found_help) {
|
||||||
@@ -192,13 +201,14 @@ namespace argument_parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream error_stream;
|
std::stringstream error_stream;
|
||||||
for (auto const &[key, value] : found_arguments) {
|
for (auto &[key, value] : found_arguments) {
|
||||||
try {
|
try {
|
||||||
if (value.expects_parameter()) {
|
if (value.expects_parameter()) {
|
||||||
value.action->invoke_with_parameter(values_for_arguments.at(key));
|
value.action->invoke_with_parameter(values_for_arguments.at(key));
|
||||||
} else {
|
} else {
|
||||||
value.action->invoke();
|
value.action->invoke();
|
||||||
}
|
}
|
||||||
|
value.set_invoked(true);
|
||||||
} catch (const std::runtime_error &e) {
|
} catch (const std::runtime_error &e) {
|
||||||
error_stream << "Argument " << key << " failed with: " << e.what() << "\n";
|
error_stream << "Argument " << key << " failed with: " << e.what() << "\n";
|
||||||
}
|
}
|
||||||
@@ -255,26 +265,60 @@ namespace argument_parser {
|
|||||||
void base_parser::place_argument(int id, argument const &arg, std::string const &short_arg,
|
void base_parser::place_argument(int id, argument const &arg, std::string const &short_arg,
|
||||||
std::string const &long_arg) {
|
std::string const &long_arg) {
|
||||||
argument_map[id] = arg;
|
argument_map[id] = arg;
|
||||||
short_arguments[short_arg] = id;
|
if (short_arg != "-") {
|
||||||
reverse_short_arguments[id] = short_arg;
|
short_arguments[short_arg] = id;
|
||||||
long_arguments[long_arg] = id;
|
reverse_short_arguments[id] = short_arg;
|
||||||
reverse_long_arguments[id] = long_arg;
|
}
|
||||||
|
if (long_arg != "-") {
|
||||||
|
long_arguments[long_arg] = id;
|
||||||
|
reverse_long_arguments[id] = long_arg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_one_name(std::string const &short_name, std::string const &long_name) {
|
||||||
|
std::string res{};
|
||||||
|
if (short_name != "-") {
|
||||||
|
res += short_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (long_name != "-") {
|
||||||
|
if (!res.empty()) {
|
||||||
|
res += ", ";
|
||||||
|
}
|
||||||
|
|
||||||
|
res += long_name;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void base_parser::check_for_required_arguments(
|
void base_parser::check_for_required_arguments(
|
||||||
std::initializer_list<conventions::convention const *const> convention_types) {
|
std::initializer_list<conventions::convention const *const> convention_types) {
|
||||||
std::vector<std::pair<std::string, std::string>> required_args;
|
std::vector<std::tuple<std::string, std::string, bool>> required_args;
|
||||||
for (auto const &[key, arg] : argument_map) {
|
for (auto const &[key, arg] : argument_map) {
|
||||||
if (arg.is_required() && !arg.is_invoked()) {
|
if (arg.is_required() && !arg.is_invoked()) {
|
||||||
required_args.emplace_back<std::pair<std::string, std::string>>(
|
auto short_arg = reverse_short_arguments.find(key) != reverse_short_arguments.end()
|
||||||
{reverse_short_arguments[key], reverse_long_arguments[key]});
|
? reverse_short_arguments.at(key)
|
||||||
|
: "-";
|
||||||
|
auto long_arg = reverse_long_arguments.find(key) != reverse_long_arguments.end()
|
||||||
|
? reverse_long_arguments.at(key)
|
||||||
|
: "-";
|
||||||
|
|
||||||
|
required_args.emplace_back<std::tuple<std::string, std::string, bool>>(
|
||||||
|
{short_arg, long_arg, arg.expects_parameter()});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!required_args.empty()) {
|
if (!required_args.empty()) {
|
||||||
std::cerr << "These arguments were expected but not provided: ";
|
std::cerr << "These arguments were expected but not provided: \n";
|
||||||
for (auto const &[s, l] : required_args) {
|
for (auto const &[s, l, p] : required_args) {
|
||||||
std::cerr << "[-" << s << ", --" << l << "] ";
|
std::cerr << "\t" << get_one_name(s, l) << ": must be provided as one of [";
|
||||||
|
for (auto it = convention_types.begin(); it != convention_types.end(); ++it) {
|
||||||
|
std::cerr << (*it)->make_help_text(s, l, p);
|
||||||
|
if (it + 1 != convention_types.end()) {
|
||||||
|
std::cerr << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cerr << "]\n";
|
||||||
}
|
}
|
||||||
std::cerr << "\n";
|
std::cerr << "\n";
|
||||||
display_help(convention_types);
|
display_help(convention_types);
|
||||||
|
|||||||
Reference in New Issue
Block a user