From 566b9128db24bc89d12b8c1c24b0b8b48d293765 Mon Sep 17 00:00:00 2001 From: "killua.z" Date: Wed, 13 May 2026 13:04:57 +0400 Subject: [PATCH] chore: refactor class names. feat: introduce parser settings for controlling the exit behavior. --- examples/test/main.cpp | 2 +- src/headers/parser/argument_builder.hpp | 31 +++++---- src/headers/parser/argument_parser.hpp | 66 +++++++++++-------- src/headers/parser/exceptions.hpp | 18 +++++ src/headers/parser/parser_v2.hpp | 25 +++---- .../parser/platform_headers/linux_parser.hpp | 2 +- .../parser/platform_headers/macos_parser.hpp | 2 +- .../platform_headers/windows_parser.hpp | 2 +- 8 files changed, 90 insertions(+), 58 deletions(-) create mode 100644 src/headers/parser/exceptions.hpp diff --git a/examples/test/main.cpp b/examples/test/main.cpp index d24074f..a0e0236 100644 --- a/examples/test/main.cpp +++ b/examples/test/main.cpp @@ -42,7 +42,7 @@ template struct parser_trait> { using namespace argument_parser::v2::flags; auto main() -> int { - argument_parser::v2::parser parser(true); + argument_parser::v2::parser parser({.should_exit_on_help = false}); new_argument() .positional("count") diff --git a/src/headers/parser/argument_builder.hpp b/src/headers/parser/argument_builder.hpp index afe3b55..6a6ccd7 100644 --- a/src/headers/parser/argument_builder.hpp +++ b/src/headers/parser/argument_builder.hpp @@ -22,8 +22,8 @@ namespace argument_parser::builder { reference, accumulate, count, - nonparametered_action, - parametered_action + action_no_param, + action_with_param }; enum class extra_capability : unsigned { Store = static_cast(v2_flag::Reference) + 1, Flag }; @@ -321,9 +321,9 @@ namespace argument_parser::builder { argument; next_argument next{*this}; - next.m_action = std::make_shared( + next.m_action = std::make_shared( std::function(std::forward(handler))); - next.m_value_mode = value_mode::nonparametered_action; + next.m_value_mode = value_mode::action_no_param; return next; } @@ -338,9 +338,9 @@ namespace argument_parser::builder { using next_argument = argument; next_argument next{*this}; - next.m_action = std::make_shared>( + next.m_action = std::make_shared>( std::function(std::forward(handler))); - next.m_value_mode = value_mode::parametered_action; + next.m_value_mode = value_mode::action_with_param; return next; } @@ -352,8 +352,8 @@ namespace argument_parser::builder { case value_mode::flag: build_flag(parser); return; - case value_mode::nonparametered_action: - build_nonparametered_action(parser); + case value_mode::action_no_param: + build_action_with_no_param(parser); return; case value_mode::store: if constexpr (!std::is_same_v) { @@ -374,9 +374,9 @@ namespace argument_parser::builder { return; } break; - case value_mode::parametered_action: + case value_mode::action_with_param: if constexpr (!std::is_same_v) { - build_parametered_action(parser); + build_action_with_param(parser); return; } break; @@ -535,9 +535,9 @@ namespace argument_parser::builder { parser.template add_argument(pairs); } - auto build_parametered_action(argument_parser::v2::base_parser &parser) const -> void { + auto build_action_with_param(argument_parser::v2::base_parser &parser) const -> void { auto const *typed_action = - dynamic_cast const *>(m_action.get()); + dynamic_cast const *>(m_action.get()); if (typed_action == nullptr) { throw std::logic_error("Stored action is not compatible with the requested parameter type."); } @@ -547,15 +547,14 @@ namespace argument_parser::builder { parser.template add_argument(pairs); } - auto build_nonparametered_action(argument_parser::v2::base_parser &parser) const -> void { - auto const *nonparametered_action = - dynamic_cast(m_action.get()); + auto build_action_with_no_param(argument_parser::v2::base_parser &parser) const -> void { + auto const *nonparametered_action = dynamic_cast(m_action.get()); if (nonparametered_action == nullptr) { throw std::logic_error("Stored action is not a non-parametered action."); } if (is_positional()) { - auto wrapped_action = argument_parser::helpers::make_parametered_action( + auto wrapped_action = argument_parser::helpers::make_action( [action = *nonparametered_action](std::string const &) { action.invoke(); }); auto pairs = make_typed_pairs(); pairs[argument_parser::v2::flags::Action] = wrapped_action; diff --git a/src/headers/parser/argument_parser.hpp b/src/headers/parser/argument_parser.hpp index f218e27..c2cb228 100644 --- a/src/headers/parser/argument_parser.hpp +++ b/src/headers/parser/argument_parser.hpp @@ -66,7 +66,7 @@ namespace argument_parser { copyable_atomic &operator=(copyable_atomic &&other) noexcept = default; ~copyable_atomic() = default; - copyable_atomic& operator=(T desired) noexcept { + copyable_atomic &operator=(T desired) noexcept { store(desired); return *this; } @@ -104,9 +104,9 @@ namespace argument_parser { [[nodiscard]] virtual std::unique_ptr clone() const = 0; }; - template class parametered_action : public action_base { + template class action_with_param : public action_base { public: - explicit parametered_action(std::function const &handler) : handler(handler) {} + explicit action_with_param(std::function const &handler) : handler(handler) {} using parameter_type = T; void invoke(const T &arg) const { handler(arg); @@ -149,16 +149,16 @@ namespace argument_parser { } [[nodiscard]] std::unique_ptr clone() const override { - return std::make_unique>(handler); + return std::make_unique>(handler); } private: std::function handler; }; - class non_parametered_action : public action_base { + class action_no_param : public action_base { public: - explicit non_parametered_action(std::function const &handler) : handler(handler) {} + explicit action_no_param(std::function const &handler) : handler(handler) {} void invoke() const override { handler(); @@ -177,7 +177,7 @@ namespace argument_parser { } [[nodiscard]] std::unique_ptr clone() const override { - return std::make_unique(handler); + return std::make_unique(handler); } private: @@ -230,16 +230,27 @@ namespace argument_parser { }; namespace helpers { - template - static parametered_action make_parametered_action(std::function const &function) { - return parametered_action(function); + template static action_with_param make_action(std::function const &function) { + return action_with_param(function); } - static non_parametered_action make_non_parametered_action(std::function const &function) { - return non_parametered_action(function); + static action_no_param make_action(std::function const &function) { + return action_no_param(function); } } // namespace helpers + struct parser_settings { + bool should_exit_on_error = true; + bool should_exit_on_missing_required = true; + bool should_exit_on_unknown_argument = true; + bool should_exit_on_help = true; + + bool ignore_unknown_arguments = false; + bool ignore_errors = false; + }; + + constexpr static inline parser_settings no_exit{false, false, false, false}; + /** * @brief Base class for parsing arguments from the command line. * @@ -251,7 +262,7 @@ namespace argument_parser { public: template void add_argument(std::string const &short_arg, std::string const &long_arg, std::string const &help_text, - parametered_action const &action, bool required) { + action_with_param const &action, bool required) { base_add_argument(short_arg, long_arg, help_text, action, required); } @@ -262,7 +273,7 @@ namespace argument_parser { } void add_argument(std::string const &short_arg, std::string const &long_arg, std::string const &help_text, - non_parametered_action const &action, bool required) { + action_no_param const &action, bool required) { base_add_argument(short_arg, long_arg, help_text, action, required); } @@ -273,7 +284,7 @@ namespace argument_parser { template void add_positional_argument(std::string const &name, std::string const &help_text, - parametered_action const &action, bool required, + action_with_param const &action, bool required, std::optional position = std::nullopt) { base_add_positional_argument(name, help_text, action, required, position); } @@ -286,7 +297,7 @@ namespace argument_parser { template void add_positional_accumulator(std::string const &name, std::string const &help_text, - parametered_action const &action, bool required, + action_with_param const &action, bool required, std::optional position = std::nullopt) { base_add_positional_argument(name, help_text, action, required, position, true); } @@ -335,7 +346,12 @@ namespace argument_parser { void on_complete(std::function const &handler, bool to_start); + void set_settings(parser_settings const &settings) { + m_settings = settings; + } + private: + parser_settings m_settings; struct found_argument { std::string key; argument arg; @@ -343,15 +359,12 @@ namespace argument_parser { }; bool test_conventions(std::initializer_list convention_types, - std::vector &found_arguments, - std::optional &found_help, std::vector::iterator &it, - std::stringstream &error_stream); + std::vector &found_arguments, std::optional &found_help, + std::vector::iterator &it, std::stringstream &error_stream); void extract_arguments(std::initializer_list convention_types, - std::vector &found_arguments, - std::optional &found_help); + std::vector &found_arguments, std::optional &found_help); - void invoke_arguments(std::vector &found_arguments, - std::optional const &found_help); + void invoke_arguments(std::vector &found_arguments, std::optional const &found_help); void enforce_creation_thread() const; void assert_argument_not_exist(std::string const &short_arg, std::string const &long_arg) const; @@ -379,13 +392,12 @@ namespace argument_parser { assert_argument_not_exist(short_arg, long_arg); int id = id_counter.fetch_add(1); if constexpr (std::is_same_v) { - auto action = - helpers::make_non_parametered_action([id, this] { stored_arguments[id] = std::any{true}; }); + auto action = helpers::make_action([id, this] { stored_arguments[id] = std::any{true}; }); argument arg(id, short_arg + "|" + long_arg, action); set_argument_status(required, help_text, arg); place_argument(id, arg, short_arg, long_arg); } else { - auto action = helpers::make_parametered_action( + auto action = helpers::make_action( [id, this](StoreType const &value) { stored_arguments[id] = std::any{value}; }); argument arg(id, short_arg + "|" + long_arg, action); set_argument_status(required, help_text, arg); @@ -412,7 +424,7 @@ namespace argument_parser { std::optional position = std::nullopt) { assert_positional_not_exist(name); int id = id_counter.fetch_add(1); - auto action = helpers::make_parametered_action( + auto action = helpers::make_action( [id, this](StoreType const &value) { stored_arguments[id] = std::any{value}; }); argument arg(id, name, action); set_argument_status(required, help_text, arg); diff --git a/src/headers/parser/exceptions.hpp b/src/headers/parser/exceptions.hpp new file mode 100644 index 0000000..1f8d718 --- /dev/null +++ b/src/headers/parser/exceptions.hpp @@ -0,0 +1,18 @@ +#pragma once + +#ifndef ARGUMENT_PARSER_EXCEPTIONS_HPP +#define ARGUMENT_PARSER_EXCEPTIONS_HPP + +#include + +namespace argument_parser { + namespace parser { + class unknown_argument_exception : public std::runtime_error { + public: + unknown_argument_exception(const std::string &message) : std::runtime_error(message) {} + }; + + } // namespace parser +} // namespace argument_parser + +#endif // ARGUMENT_PARSER_EXCEPTIONS_HPP diff --git a/src/headers/parser/parser_v2.hpp b/src/headers/parser/parser_v2.hpp index 46284d4..de8ea76 100644 --- a/src/headers/parser/parser_v2.hpp +++ b/src/headers/parser/parser_v2.hpp @@ -57,15 +57,15 @@ namespace argument_parser::v2 { class base_parser : argument_parser::base_parser { public: - template using typed_flag_value = std::variant, bool, int, T *>; - using non_typed_flag_value = std::variant; + template using typed_flag_value = std::variant, bool, int, T *>; + using non_typed_flag_value = std::variant; template using typed_argument_pair = std::pair>; using non_typed_argument_pair = std::pair; template void add_argument(std::unordered_map> const &argument_pairs) { - add_argument_impl, T>(argument_pairs); + add_argument_impl, T>(argument_pairs); } template void add_argument(std::initializer_list> const &pairs) { @@ -89,7 +89,7 @@ namespace argument_parser::v2 { } void add_argument(std::unordered_map const &argument_pairs) { - add_argument_impl(argument_pairs); + add_argument_impl(argument_pairs); } argument_parser::base_parser &to_v1() { @@ -122,7 +122,7 @@ namespace argument_parser::v2 { void prepare_help_flag(bool should_exit = true) { add_argument({{flags::ShortArgument, "h"}, {flags::LongArgument, "help"}, - {flags::Action, helpers::make_non_parametered_action([this, should_exit] { + {flags::Action, helpers::make_action([this, should_exit] { this->display_help(this->current_conventions()); if (should_exit) { std::exit(0); @@ -131,6 +131,10 @@ namespace argument_parser::v2 { {flags::HelpText, "Prints this help text."}}); } + void set_settings(parser_settings const &settings) { + base::set_settings(settings); + } + private: template void add_argument_impl(ArgsMap const &argument_pairs) { @@ -224,7 +228,7 @@ namespace argument_parser::v2 { base::add_argument( short_arg, long_arg, help_text, - *static_cast *>(&(*action)), required); + *static_cast *>(&(*action)), required); return; } } @@ -375,7 +379,7 @@ namespace argument_parser::v2 { if constexpr (!std::is_same_v && deducers::is_vector_v) { base::add_positional_accumulator( positional_name, help_text, - *static_cast *>(&(*action)), required, position); + *static_cast *>(&(*action)), required, position); return; } } @@ -452,16 +456,15 @@ namespace argument_parser::v2 { } template std::unique_ptr make_reference_action(T *target) { - return helpers::make_parametered_action([target](T const &value) { *target = value; }).clone(); + return helpers::make_action([target](T const &value) { *target = value; }).clone(); } template std::unique_ptr make_accumulate_ref_action(Vector *target) { if constexpr (std::is_same_v) { - return helpers::make_non_parametered_action([target]() { *target += 1; }).clone(); + return helpers::make_action([target]() { *target += 1; }).clone(); } else { using Value = typename Vector::value_type; - return helpers::make_parametered_action( - [target](Value const &value) { target->emplace_back(value); }) + return helpers::make_action([target](Value const &value) { target->emplace_back(value); }) .clone(); } } diff --git a/src/headers/parser/platform_headers/linux_parser.hpp b/src/headers/parser/platform_headers/linux_parser.hpp index 7a1a393..80ff735 100644 --- a/src/headers/parser/platform_headers/linux_parser.hpp +++ b/src/headers/parser/platform_headers/linux_parser.hpp @@ -16,7 +16,7 @@ namespace argument_parser { namespace v2 { class linux_parser : public v2::base_parser { public: - linux_parser(bool should_exit = true); + linux_parser(parser_settings const &settings = {}); using base_parser::display_help; }; } // namespace v2 diff --git a/src/headers/parser/platform_headers/macos_parser.hpp b/src/headers/parser/platform_headers/macos_parser.hpp index d9396b2..b95135c 100644 --- a/src/headers/parser/platform_headers/macos_parser.hpp +++ b/src/headers/parser/platform_headers/macos_parser.hpp @@ -15,7 +15,7 @@ namespace argument_parser { namespace v2 { class macos_parser : public v2::base_parser { public: - explicit macos_parser(bool should_exit = true); + explicit macos_parser(parser_settings const &settings = {}); using base_parser::display_help; }; } // namespace v2 diff --git a/src/headers/parser/platform_headers/windows_parser.hpp b/src/headers/parser/platform_headers/windows_parser.hpp index d71747c..0aaa244 100644 --- a/src/headers/parser/platform_headers/windows_parser.hpp +++ b/src/headers/parser/platform_headers/windows_parser.hpp @@ -12,7 +12,7 @@ namespace argument_parser { namespace v2 { class windows_parser : public v2::base_parser { public: - windows_parser(bool should_exit = true); + windows_parser(parser_settings const &settings = {}); using base_parser::display_help; }; } // namespace v2