diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..58911f6 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,30 @@ +name: Tests + +on: + push: + branches: + - master + pull_request: {} + schedule: + - cron: '0 23 * * SUN-THU' + workflow_dispatch: + +jobs: + tests: + runs-on: macos-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Install llvm + run: | + brew isntall llvm + + - name: Install cmake HEAD + run: | + brew isntall cmake --HEAD + + - name: Cmake and Compile + run: | + cmake -B build -S . -DARGO_TEST_ENABLE=true + cmake --build build diff --git a/module/Argo.cc b/Argo/Argo.cc similarity index 100% rename from module/Argo.cc rename to Argo/Argo.cc diff --git a/module/ArgoArg.cc b/Argo/ArgoArg.cc similarity index 91% rename from module/ArgoArg.cc rename to Argo/ArgoArg.cc index c55ff09..45b4041 100644 --- a/module/ArgoArg.cc +++ b/Argo/ArgoArg.cc @@ -136,18 +136,6 @@ struct ArgName : ArgNameTag { template ArgName(const char (&)[N]) -> ArgName; -template -concept ArgType = requires(T& x) { - std::derived_from; - std::is_same_v; - std::is_same_v; - typename T::baseType; - typename T::type; - not std::is_same_v; - std::is_same_v; - std::is_same_v; -}; - template struct ArgBase { static constexpr auto name = Name; @@ -158,11 +146,29 @@ struct ArgBase { using baseType = BaseType; }; +template +concept ArgType = requires(T& x) { + typename T::baseType; + typename T::type; + + not std::is_same_v; + + std::derived_from; + std::is_same_v; + std::is_same_v; + std::is_same_v; + std::is_same_v; + std::is_same_v; + std::is_same_v; +}; + struct ArgTag {}; template consteval std::string get_type_name_base_type() { - if constexpr (std::is_integral_v) { + if constexpr (std::is_same_v) { + return "BOOL"; + } else if constexpr (std::is_integral_v) { return "NUMBER"; } else if constexpr (std::is_floating_point_v) { return "FLOAT"; @@ -170,8 +176,6 @@ consteval std::string get_type_name_base_type() { std::is_same_v or std::is_same_v) { return "STRING"; - } else if constexpr (std::is_same_v) { - return "BOOL"; } else { return "UNKNOWN"; } @@ -283,7 +287,7 @@ struct Arg : ArgTag, struct FlagArgTag {}; template -struct FlagArg : FlagArgTag, ArgBase { +struct FlagArg : FlagArgTag, ArgBase { static constexpr bool isVariadic = false; using type = bool; @@ -295,4 +299,22 @@ struct FlagArg : FlagArgTag, ArgBase { inline static std::string typeName = ""; }; +struct HelpArgTag {}; + +template +struct HelpArg : HelpArgTag, FlagArgTag, ArgBase { + static constexpr bool isVariadic = false; + using type = bool; + inline static type value = {}; + inline static type defaultValue = {}; + + inline static bool assigned = false; + inline static std::string_view description = "Print help information"; + inline static bool required = false; + + inline static constexpr NArgs nargs = NArgs(-1); + inline static std::function callback = nullptr; + inline static std::string typeName = ""; +}; + } // namespace Argo diff --git a/module/ArgoExceptions.cc b/Argo/ArgoExceptions.cc similarity index 100% rename from module/ArgoExceptions.cc rename to Argo/ArgoExceptions.cc diff --git a/module/ArgoHelpGenerator.cc b/Argo/ArgoHelpGenerator.cc similarity index 100% rename from module/ArgoHelpGenerator.cc rename to Argo/ArgoHelpGenerator.cc diff --git a/module/ArgoInitializer.cc b/Argo/ArgoInitializer.cc similarity index 100% rename from module/ArgoInitializer.cc rename to Argo/ArgoInitializer.cc diff --git a/module/ArgoMetaAssigner.cc b/Argo/ArgoMetaAssigner.cc similarity index 100% rename from module/ArgoMetaAssigner.cc rename to Argo/ArgoMetaAssigner.cc diff --git a/module/ArgoMetaChecker.cc b/Argo/ArgoMetaChecker.cc similarity index 100% rename from module/ArgoMetaChecker.cc rename to Argo/ArgoMetaChecker.cc diff --git a/module/ArgoMetaLookup.cc b/Argo/ArgoMetaLookup.cc similarity index 100% rename from module/ArgoMetaLookup.cc rename to Argo/ArgoMetaLookup.cc diff --git a/module/ArgoMetaParse.cc b/Argo/ArgoMetaParse.cc similarity index 100% rename from module/ArgoMetaParse.cc rename to Argo/ArgoMetaParse.cc diff --git a/module/ArgoNArgs.cc b/Argo/ArgoNArgs.cc similarity index 89% rename from module/ArgoNArgs.cc rename to Argo/ArgoNArgs.cc index 96ea723..80b7018 100644 --- a/module/ArgoNArgs.cc +++ b/Argo/ArgoNArgs.cc @@ -10,7 +10,7 @@ constexpr char NULLCHAR = '\0'; /*! * (default)? : If value specified use it else use default -> ValueType - * int: Exactly (n > 1) -> vector + * int: Exactly (n > 1) -> std::array * * : Any number of argument if zero use default -> vector * + : Any number of argument except zero -> vector */ diff --git a/module/ArgoParser.cc b/Argo/ArgoParser.cc similarity index 68% rename from module/ArgoParser.cc rename to Argo/ArgoParser.cc index c1c2dcc..3ff2902 100644 --- a/module/ArgoParser.cc +++ b/Argo/ArgoParser.cc @@ -43,11 +43,11 @@ struct ParserInfo { std::optional usage = std::nullopt; std::optional subcommand_help = std::nullopt; std::optional options_help = std::nullopt; + std::optional positional_argument_help = std::nullopt; }; -export template , - class PositionalArg = void, - class SubParserTuple = std::tuple<>, bool HelpEnabled = false> +export template , class PArg = void, + class HArg = void, class SubParserTuple = std::tuple<>> class Parser { private: bool parsed_ = false; @@ -78,8 +78,6 @@ class Parser { Parser(const Parser&) = delete; Parser(Parser&&) = delete; - using Arguments = Args; - using PositionalArgument = PositionalArg; SubParserTuple subParsers; constexpr explicit Parser(SubParserTuple tuple) : subParsers(tuple) {} @@ -156,17 +154,16 @@ class Parser { return false; } }(); - if constexpr (!std::is_same_v) { - static_assert(!(std::string_view(Name) == - std::string_view(PositionalArgument::name)), + if constexpr (!std::is_same_v) { + static_assert(!(std::string_view(Name) == std::string_view(PArg::name)), "Duplicated name"); } static_assert( (Name.shortName == NULLCHAR) || - (SearchIndexFromShortName::value == -1), + (SearchIndexFromShortName::value == -1), "Duplicated short name"); - static_assert( // - Argo::SearchIndex::value == -1, // + static_assert( // + Argo::SearchIndex::value == -1, // "Duplicated name"); static_assert( // (nargs.nargs > 0 // @@ -190,89 +187,67 @@ class Parser { auto arg2 = Unspecified(), class... T> auto addArg(T... args) { auto arg = createArg(std::forward(args)...); - return Parser< - ID, - decltype(std::tuple_cat( - std::declval(), - std::declval>())), - PositionalArgument, - SubParserTuple, - HelpEnabled>(std::move(this->info_), subParsers); + return Parser, + PArg, + HArg, + SubParserTuple>(std::move(this->info_), subParsers); } template auto addPositionalArg(T... args) { - static_assert(std::is_same_v, + static_assert(std::is_same_v, "Positional argument cannot set more than one"); static_assert(Name.shortName == NULLCHAR, "Positional argment cannot have short name"); auto arg = createArg(std::forward(args)...); - return Parser(std::move(this->info_), subParsers); + return Parser( + std::move(this->info_), subParsers); } template auto addFlag(T... args) { - if constexpr (!std::is_same_v) { - static_assert(!(std::string_view(Name) == - std::string_view(PositionalArgument::name)), + if constexpr (!std::is_same_v) { + static_assert(!(std::string_view(Name) == std::string_view(PArg::name)), "Duplicated name"); } static_assert( (Name.shortName == NULLCHAR) || - (SearchIndexFromShortName::value == -1), + (SearchIndexFromShortName::value == -1), "Duplicated short name"); - static_assert(Argo::SearchIndex::value == -1, + static_assert(Argo::SearchIndex::value == -1, "Duplicated name"); FlagArgInitializer::init(std::forward(args)...); return Parser(), - std::declval>>())), - PositionalArgument, - SubParserTuple, - HelpEnabled>(std::move(this->info_), subParsers); + tuple_append_t>, + PArg, + HArg, + SubParserTuple>(std::move(this->info_), subParsers); } template auto addHelp() { - static_assert( - (SearchIndexFromShortName::value == -1), - "Duplicated short name"); - static_assert(Argo::SearchIndex::value == -1, + static_assert((SearchIndexFromShortName::value == -1), + "Duplicated short name"); + static_assert(Argo::SearchIndex::value == -1, "Duplicated name"); - FlagArgInitializer::init( - Argo::description("Print help information")); - return Parser(), - std::declval>>())), - PositionalArgument, - SubParserTuple, - true>(std::move(this->info_), subParsers); + return Parser, SubParserTuple>( + std::move(this->info_), subParsers); } template auto addHelp(std::string_view help) { - static_assert( - (SearchIndexFromShortName::value == -1), - "Duplicated short name"); - static_assert(Argo::SearchIndex::value == -1, + static_assert((SearchIndexFromShortName::value == -1), + "Duplicated short name"); + static_assert(Argo::SearchIndex::value == -1, "Duplicated name"); + static_assert(!Name.containsInvalidChar(), "Name has invalid char"); + static_assert(Name.hasValidNameLength(), + "Short name can't be more than one charactor"); this->info_->help = help; - FlagArgInitializer::init( - Argo::description("Print help information")); - return Parser(), - std::declval>>())), - PositionalArgument, - SubParserTuple, - true>(std::move(this->info_), subParsers); + return Parser, SubParserTuple>( + std::move(this->info_), subParsers); } template @@ -280,19 +255,18 @@ class Parser { if (!this->parsed_) { throw ParseError("Parser did not parse argument, call parse first"); } - if constexpr (!std::is_same_v) { - if constexpr (std::string_view(Name) == - std::string_view(PositionalArgument::name)) { - return PositionalArgument::value; + if constexpr (!std::is_same_v) { + if constexpr (std::string_view(Name) == std::string_view(PArg::name)) { + return PArg::value; } else { return std::remove_cvref_t< - decltype(std::get::value>( - std::declval()))>::value; + decltype(std::get::value>( + std::declval()))>::value; } } else { return std::remove_cvref_t< - decltype(std::get::value>( - std::declval()))>::value; + decltype(std::get::value>( + std::declval()))>::value; } } @@ -312,19 +286,18 @@ class Parser { if (!this->parsed_) { throw ParseError("Parser did not parse argument, call parse first"); } - if constexpr (!std::is_same_v) { - if constexpr (std::string_view(Name) == - std::string_view(PositionalArgument::name)) { - return PositionalArgument::assigned; + if constexpr (!std::is_same_v) { + if constexpr (std::string_view(Name) == std::string_view(PArg::name)) { + return PArg::assigned; } else { return std::remove_cvref_t< - decltype(std::get::value>( - std::declval()))>::assigned; + decltype(std::get::value>( + std::declval()))>::assigned; } } else { return std::remove_cvref_t< - decltype(std::get::value>( - std::declval()))>::assigned; + decltype(std::get::value>( + std::declval()))>::assigned; } } @@ -336,11 +309,8 @@ class Parser { auto s = std::make_tuple( SubParser{std::ref(sub_parser), description.description}); auto sub_parsers = std::tuple_cat(subParsers, s); - return Parser(std::move(this->info_), sub_parsers); + return Parser( + std::move(this->info_), sub_parsers); } auto resetArgs() -> void; @@ -353,6 +323,10 @@ class Parser { this->info_->subcommand_help = subcommand_help; } + auto addPositionalArgumentHelp(std::string_view positional_argument_help) { + this->info_->positional_argument_help = positional_argument_help; + } + auto addOptionsHelp(std::string_view options_help) { this->info_->options_help = options_help; } diff --git a/module/ArgoParserImpl.cc b/Argo/ArgoParserImpl.cc similarity index 68% rename from module/ArgoParserImpl.cc rename to Argo/ArgoParserImpl.cc index 4d44dba..23f6214 100644 --- a/module/ArgoParserImpl.cc +++ b/Argo/ArgoParserImpl.cc @@ -4,6 +4,7 @@ module; export module Argo:ParserImpl; +import :TypeTraits; import :MetaAssigner; import :Parser; import :MetaLookup; @@ -29,49 +30,46 @@ auto splitStringView(std::string_view str, return ret; } -template -auto Parser::resetArgs() - -> void { - ValueReset(); +template +auto Parser::resetArgs() -> void { + ValueReset(); } -template -auto Parser::setArg( +template +auto Parser::setArg( std::string_view key, std::span val) const -> void { - if constexpr (HelpEnabled) { - if (key == "help") { + if constexpr (!std::is_same_v) { + if (key == HArg::name) { std::println("{}", formatHelp()); std::exit(0); } } - Assigner::assign(key, val); + Assigner::assign(key, val); } -template -auto Parser::setArg( +template +auto Parser::setArg( std::span key, std::span val) const -> void { - if constexpr (HelpEnabled) { + if constexpr (!std::is_same_v) { for (const auto& i : key) { - if (i == 'h') { - std::println("{}", formatHelp()); - std::exit(0); + if constexpr (HArg::name.shortName != '\0') { + if (i == HArg::name.shortName) { + std::println("{}", formatHelp()); + std::exit(0); + } } } } - Assigner::assign(key, val); + Assigner::assign(key, val); } -template -auto Parser::parse( - int argc, char* argv[]) -> void { +template +auto Parser::parse(int argc, + char* argv[]) -> void { if (this->parsed_) [[unlikely]] { throw ParseError("Cannot parse twice"); } - auto assigned_keys = AssignChecker::check(); + auto assigned_keys = AssignChecker::check(); if (!assigned_keys.empty()) [[unlikely]] { throw ParseError(std::format("keys {} already assigned", assigned_keys)); } @@ -112,7 +110,7 @@ auto Parser::parse( short_keys.clear(); values.clear(); } else if (!values.empty()) { - if constexpr (!std::is_same_v) { + if constexpr (!std::is_same_v) { this->setArg(key, values); values.clear(); } @@ -138,7 +136,7 @@ auto Parser::parse( short_keys.clear(); values.clear(); } else if (!values.empty()) { - if constexpr (!std::is_same_v) { + if constexpr (!std::is_same_v) { this->setArg(key, values); values.clear(); } @@ -153,7 +151,7 @@ auto Parser::parse( continue; } } else { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { if (key.empty() && short_keys.empty()) { throw InvalidArgument(std::format("No keys specified")); } @@ -166,7 +164,7 @@ auto Parser::parse( } else if (!short_keys.empty()) { this->setArg(short_keys, values); } else { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { throw InvalidArgument(std::format("No keys specified")); } else { this->setArg(key, values); @@ -175,7 +173,7 @@ auto Parser::parse( } } } - auto required_keys = RequiredChecker::check(); + auto required_keys = RequiredChecker::check(); if (!required_keys.empty()) { throw InvalidArgument(std::format("Requried {}", required_keys)); } @@ -259,21 +257,18 @@ auto createSubcommandSection(const auto& ansi, const auto& sub_commands) { ret.push_back('\n'); auto description = splitStringView(command.description, '\n'); - ret.append(std::format( // - " {}{} {}{} {}", // - ansi.getBold(), - command.name, // - std::string(max_command_length - command.name.size(), ' '), // - ansi.getReset(), - description[0] // - )); + ret.append( + std::format(" {}{} {}{} {}", + ansi.getBold(), + command.name, + std::string(max_command_length - command.name.size(), ' '), + ansi.getReset(), + description[0])); for (std::size_t i = 1; i < description.size(); i++) { ret.push_back('\n'); - ret.append(std::format( // - " {}{}", // - std::string(max_command_length, ' '), // - description[i] // - )); + ret.append(std::format(" {}{}", // + std::string(max_command_length, ' '), + description[i])); } // erase trailing spaces @@ -287,37 +282,31 @@ auto createSubcommandSection(const auto& ansi, const auto& sub_commands) { auto createOptionsSection(const auto& ansi, const auto& help_info) { std::string ret; - std::size_t max_flag_length = 0; + std::size_t max_name_len = 0; for (const auto& option : help_info) { - if (max_flag_length < option.name.size() + option.typeName.size()) { - max_flag_length = option.name.size() + option.typeName.size(); + if (max_name_len < option.name.size() + option.typeName.size()) { + max_name_len = option.name.size() + option.typeName.size(); } } for (const auto& option : help_info) { ret.push_back('\n'); auto description = splitStringView(option.description, '\n'); - ret.append(std::format( // - " {}{} --{} {}{}{} {}", // - (option.shortName == NULLCHAR) - ? " " - : std::format("-{},", option.shortName), // - ansi.getBold(), // - option.name, // - ansi.getReset(), // - option.typeName, // - std::string( - max_flag_length - option.name.size() - option.typeName.size(), - ' '), // - description[0] // - )); + ret.append(std::format( + " {}{} --{} {}{}{} {}", + (option.shortName == NULLCHAR) ? " " + : std::format("-{},", option.shortName), + ansi.getBold(), + option.name, + ansi.getReset(), + option.typeName, + std::string(max_name_len - option.name.size() - option.typeName.size(), + ' '), + description[0])); for (std::size_t i = 1; i < description.size(); i++) { ret.push_back('\n'); - ret.append(std::format( // - " {} {}", // - std::string(max_flag_length, ' '), // - description[i] // - )); + ret.append(std::format( + " {} {}", std::string(max_name_len, ' '), description[i])); } auto pos = ret.find_last_not_of(' '); @@ -326,17 +315,37 @@ auto createOptionsSection(const auto& ansi, const auto& help_info) { return ret; } -template -auto Parser::formatHelp( - bool no_color) const -> std::string { +template +auto createPositionalArgumentSection(const auto& ansi) { + std::string ret; + + ret.push_back('\n'); + auto desc = splitStringView(PArg::description, '\n'); + ret.append(std::format(" {}{}{} {}", + ansi.getBold(), + std::string_view(PArg::name), + ansi.getReset(), + desc[0])); + + for (std::size_t i = 1; i < desc.size(); i++) { + ret.push_back('\n'); + ret.append(std::format("{}{}", std::string(8, ' '), desc[i])); + } + + ret.push_back('\n'); + return ret; +} + +template +auto Parser::formatHelp(bool no_color) const + -> std::string { std::string ret; - AnsiEscapeCode ansi{::isatty(1) and !no_color}; + AnsiEscapeCode ansi(::isatty(1) and !no_color); assert(this->info_); // this->info_ cannot be nullptr - auto help_info = HelpGenerator::generate(); + auto help_info = HelpGenerator>::generate(); auto sub_commands = SubParserInfo(subParsers); if (this->info_->help) { @@ -367,6 +376,14 @@ auto Parser::formatHelp( createSubcommandSection(ansi, sub_commands))); } + if constexpr (!std::is_same_v) { + ret.push_back('\n'); + ret.append(ansi.getBoldUnderline() + + "Positional Argument:" + ansi.getReset()); + ret.append(this->info_->positional_argument_help.value_or( + createPositionalArgumentSection(ansi))); + } + // Options section if (!help_info.empty()) { ret.push_back('\n'); diff --git a/module/ArgoTypeTraits.cc b/Argo/ArgoTypeTraits.cc similarity index 83% rename from module/ArgoTypeTraits.cc rename to Argo/ArgoTypeTraits.cc index be4a686..8154142 100644 --- a/module/ArgoTypeTraits.cc +++ b/Argo/ArgoTypeTraits.cc @@ -6,14 +6,6 @@ import :std_module; export namespace Argo { -template -struct IdentityHolder { - static constexpr auto value = Value; -}; - -template -concept Arithmetic = requires { std::is_arithmetic_v; }; - template struct is_tuple : std::false_type {}; @@ -80,4 +72,17 @@ struct array_base> { template using array_base_t = array_base::type; +template +struct tuple_append { + using type = std::tuple; +}; + +template +struct tuple_append, T> { + using type = std::tuple; +}; + +template +using tuple_append_t = typename tuple_append::type; + }; // namespace Argo diff --git a/module/ArgoValidation.cc b/Argo/ArgoValidation.cc similarity index 98% rename from module/ArgoValidation.cc rename to Argo/ArgoValidation.cc index 1f46983..035d0a9 100644 --- a/module/ArgoValidation.cc +++ b/Argo/ArgoValidation.cc @@ -6,9 +6,9 @@ import :Exceptions; import :TypeTraits; import :std_module; -export namespace Argo::Validation { +namespace Argo::Validation { -struct ValidationBase { +export struct ValidationBase { template auto operator()(const T& value, std::span values, std::string_view option_name) -> void { @@ -92,7 +92,7 @@ struct InvertValidation : ValidationBase { template Rhs> InvertValidation(Rhs) -> InvertValidation; -template +export template struct Range final : public ValidationBase { private: T min_; diff --git a/module/StdModule.cc b/Argo/StdModule.cc similarity index 97% rename from module/StdModule.cc rename to Argo/StdModule.cc index f23fe99..f453c7d 100644 --- a/module/StdModule.cc +++ b/Argo/StdModule.cc @@ -6,6 +6,7 @@ module; #include #include +#include #include #include #include @@ -117,7 +118,9 @@ using ::std::type_identity_t; // NOLINT(misc-unused-using-decls) using ::std::void_t; // NOLINT(misc-unused-using-decls) // concept +using ::std::common_with; // NOLINT(misc-unused-using-decls) using ::std::derived_from; // NOLINT(misc-unused-using-decls) +using ::std::same_as; // NOLINT(misc-unused-using-decls) // exception/stdexcept using ::std::exception; // NOLINT(misc-unused-using-decls) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4acbee8..c78848d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,17 +22,19 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_LIST_DIR}) endif() -add_library(Argo) +add_library(Argo STATIC) + +file(GLOB ARGO_LIBRARY_SOURCES ${CMAKE_CURRENT_LIST_DIR}/Argo/*.cc) -file(GLOB ARGO_LIBRARY_SOURCES ${CMAKE_CURRENT_LIST_DIR}/module/*.cc) target_sources(Argo PUBLIC FILE_SET CXX_MODULES FILES ${ARGO_LIBRARY_SOURCES}) +target_compile_features(Argo PUBLIC cxx_std_23) +export(TARGETS Argo FILE Argo-Config.cmake) + unset(ARGO_LIBRARY_SOURCES) if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_LIST_DIR}) - add_executable(main ${CMAKE_CURRENT_LIST_DIR}/main.cc) target_link_libraries(main Argo) - if(${ARGO_TESTS_ENABLE}) set(CMAKE_CXX_FLAGS_RELEASE "") set(CMAKE_CXX_FLAGS_DEBUG "") @@ -92,7 +94,6 @@ if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_LIST_DIR}) set_target_properties(${debug_target_name} PROPERTIES CXX_STANDARD 23) target_compile_options(${debug_target_name} PRIVATE -Wno-writable-strings -DDEBUG_BUILD) - # Release Target set(release_target_name "bench-${target_name}-release") add_executable(${release_target_name} ${target}) diff --git a/Taskfile.yml b/Taskfile.yml index 73966c1..5f0e548 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -4,7 +4,7 @@ tasks: cmake: cmds: # - cmake -B build -S . -GNinja -DARGO_BENCHMARKS_ENABLE=true - - cmake -B build -S . -GNinja -DARGO_TESTS_ENABLE=true -DARGO_BENCHMARKS_ENABLE=true + - cmake -B build -S . -GNinja -DCMAKE_INSTALL_PREFIX=/Users/gen/.local compile: cmds: - cmake --build build diff --git a/main.cc b/main.cc index 2b90a69..d624d43 100644 --- a/main.cc +++ b/main.cc @@ -12,31 +12,43 @@ std::tuple createArgcArgv(Args... args) { return std::make_tuple(N, array); } +using Argo::description; +using Argo::nargs; + auto main(int argc, char** argv) -> int { auto parser1 = Argo::Parser<"P1">() // .addArg<"p1a1", int>() .addArg<"p1a2", int>(); auto parser2 = Argo::Parser<"Parser2">() - .addArg<"p2a1", int>(Argo::description("Hello\nWorld!")) - .addArg<"p2a2", int>(Argo::description("Hello\nWorld!")) + .addArg<"p2a1", int>(description("Hello\nWorld!")) + .addArg<"p2a2", int>(description("Hello\nWorld!")) .addHelp(); - auto parser = Argo::Parser<"Parser">("Test Program", "Some description") // - .addParser<"cmd1">(parser1, Argo::description("subparser of 1\nsome help")) - .addParser<"cmd2">(parser2, Argo::description("subparser of 2\nsome help")) - .addArg<"test1,a", int>(Argo::description( - "Some long long long long long long long\nlong long long description")) - .addArg<"test2", std::array>() - .addArg<"test3", std::array>() - .addArg<"test4", std::vector>() - .addArg<"test5", std::vector, Argo::nargs('+')>() - .addArg<"test6", std::tuple>() - .addArg<"test7", int>() - .addArg<"test8", bool>() - .addArg<"test9", float>() - .addArg<"test10", const char*>() - .addHelp(); + auto parser = // + Argo::Parser<"Parser">("./main", "Some description") // + .addParser<"cmd1">(parser1, description("subparser of 1\nsome help")) + .addParser<"cmd2">(parser2, description("subparser of 2\nsome help")) + .addPositionalArg<"test", std::array>( + description(R"(positional argument\nlong desc)")) + .addArg<"test1", bool>() + .addArg<"test2", int>() + .addArg<"test3", double>() + .addArg<"test5", std::string>() + .addArg<"test6", const char*>() + .addArg<"test7", std::string_view>() + // nargs + .addArg<"test8", bool, nargs(3)>() + .addArg<"test9", int, nargs('+')>() + .addArg<"test10", double, nargs('*')>() + // STL + .addArg<"test11", std::array>() + .addArg<"test12", std::array>() + .addArg<"test13", std::vector>() + .addArg<"test14", std::vector, Argo::nargs('+')>() + .addArg<"test15", std::tuple>( + [](auto&&...) {}) + .addHelp<"help,h">(); parser.parse(argc, argv);