some help
parent
f8ed21fda5
commit
8b03dda1fe
|
@ -1,6 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
include(cmake/color.cmake)
|
||||
set(BLT_VERSION 4.0.23)
|
||||
set(BLT_VERSION 4.0.24)
|
||||
|
||||
set(BLT_TARGET BLT)
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
#include <complex>
|
||||
#include <blt/std/types.h>
|
||||
#include <blt/std/hashmap.h>
|
||||
#include <blt/fs/path_helper.h>
|
||||
#include <blt/meta/meta.h>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
@ -432,10 +431,8 @@ namespace blt::argparse
|
|||
{
|
||||
auto& data = storage.m_data[dest];
|
||||
if (!std::holds_alternative<std::vector<T>>(data))
|
||||
{
|
||||
throw detail::type_error("Invalid type conversion. Trying to add type " + blt::type_string<T>() +
|
||||
" but this does not match existing type index '" + std::to_string(data.index()) + "'!");
|
||||
}
|
||||
auto& converted_values = std::get<std::vector<T>>(data);
|
||||
for (const auto& value : values)
|
||||
converted_values.push_back(detail::arg_string_converter_t<T>::convert(value));
|
||||
|
@ -456,41 +453,7 @@ namespace blt::argparse
|
|||
return set_action(action_t::STORE_TRUE);
|
||||
}
|
||||
|
||||
argument_builder_t& set_action(const action_t action)
|
||||
{
|
||||
m_action = action;
|
||||
switch (m_action)
|
||||
{
|
||||
case action_t::STORE_TRUE:
|
||||
set_nargs(0);
|
||||
as_type<bool>();
|
||||
set_default(false);
|
||||
break;
|
||||
case action_t::STORE_FALSE:
|
||||
set_nargs(0);
|
||||
as_type<bool>();
|
||||
set_default(true);
|
||||
break;
|
||||
case action_t::STORE_CONST:
|
||||
case action_t::APPEND_CONST:
|
||||
set_nargs(0);
|
||||
break;
|
||||
case action_t::COUNT:
|
||||
set_nargs(0);
|
||||
as_type<size_t>();
|
||||
break;
|
||||
case action_t::EXTEND:
|
||||
set_nargs(nargs_t::ALL);
|
||||
break;
|
||||
case action_t::HELP:
|
||||
case action_t::VERSION:
|
||||
set_nargs(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
argument_builder_t& set_action(action_t action);
|
||||
|
||||
argument_builder_t& set_required(const bool required)
|
||||
{
|
||||
|
@ -602,9 +565,10 @@ namespace blt::argparse
|
|||
friend argument_subparser_t;
|
||||
|
||||
public:
|
||||
explicit argument_parser_t(const std::optional<std::string_view> name = {}, const std::optional<std::string_view> usage = {},
|
||||
const std::optional<std::string_view> description = {}, const std::optional<std::string_view> epilogue = {}):
|
||||
m_name(name), m_usage(usage), m_description(description), m_epilogue(epilogue)
|
||||
explicit argument_parser_t(const std::optional<std::string_view> description = {}, const std::optional<std::string_view> epilogue = {},
|
||||
const std::optional<std::string_view> version = {},
|
||||
const std::optional<std::string_view> usage = {}, const std::optional<std::string_view> name = {}):
|
||||
m_name(name), m_usage(usage), m_description(description), m_epilogue(epilogue), m_version(version)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -633,6 +597,18 @@ namespace blt::argparse
|
|||
|
||||
argument_subparser_t& add_subparser(std::string_view dest);
|
||||
|
||||
argument_parser_t& with_help()
|
||||
{
|
||||
add_flag("--help", "-h").set_action(action_t::HELP);
|
||||
return *this;
|
||||
}
|
||||
|
||||
argument_parser_t& with_version()
|
||||
{
|
||||
add_flag("--version").set_action(action_t::VERSION);
|
||||
return *this;
|
||||
}
|
||||
|
||||
argument_storage_t parse(argument_consumer_t& consumer); // NOLINT
|
||||
|
||||
argument_storage_t parse(const std::vector<std::string_view>& args)
|
||||
|
@ -669,15 +645,15 @@ namespace blt::argparse
|
|||
|
||||
void print_usage();
|
||||
|
||||
void print_version();
|
||||
void print_version() const;
|
||||
|
||||
argument_parser_t& set_name(const std::string_view name)
|
||||
argument_parser_t& set_name(const std::optional<std::string>& name)
|
||||
{
|
||||
m_name = name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
argument_parser_t& set_usage(const std::string_view usage)
|
||||
argument_parser_t& set_usage(const std::optional<std::string>& usage)
|
||||
{
|
||||
m_usage = usage;
|
||||
return *this;
|
||||
|
@ -688,7 +664,7 @@ namespace blt::argparse
|
|||
return m_usage;
|
||||
}
|
||||
|
||||
argument_parser_t& set_description(const std::string_view description)
|
||||
argument_parser_t& set_description(const std::optional<std::string>& description)
|
||||
{
|
||||
m_description = description;
|
||||
return *this;
|
||||
|
@ -699,7 +675,7 @@ namespace blt::argparse
|
|||
return m_description;
|
||||
}
|
||||
|
||||
argument_parser_t& set_epilogue(const std::string_view epilogue)
|
||||
argument_parser_t& set_epilogue(const std::optional<std::string>& epilogue)
|
||||
{
|
||||
m_epilogue = epilogue;
|
||||
return *this;
|
||||
|
@ -710,6 +686,17 @@ namespace blt::argparse
|
|||
return m_epilogue;
|
||||
}
|
||||
|
||||
argument_parser_t& set_version(const std::optional<std::string>& version)
|
||||
{
|
||||
m_epilogue = version;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::optional<std::string>& get_version() const
|
||||
{
|
||||
return m_version;
|
||||
}
|
||||
|
||||
[[nodiscard]] const hashset_t<char>& get_allowed_flag_prefixes() const
|
||||
{
|
||||
return allowed_flag_prefixes;
|
||||
|
@ -732,6 +719,7 @@ namespace blt::argparse
|
|||
std::optional<std::string> m_usage;
|
||||
std::optional<std::string> m_description;
|
||||
std::optional<std::string> m_epilogue;
|
||||
std::optional<std::string> m_version;
|
||||
std::vector<std::pair<std::string_view, argument_subparser_t>> m_subparsers;
|
||||
std::vector<std::unique_ptr<argument_builder_t>> m_argument_builders;
|
||||
hashmap_t<std::string_view, argument_builder_t*> m_flag_arguments;
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <blt/meta/type_traits.h>
|
||||
#include <blt/std/logging.h>
|
||||
#include <blt/iterator/enumerate.h>
|
||||
#include <blt/fs/path_helper.h>
|
||||
#include <blt/std/string.h>
|
||||
|
||||
namespace blt::argparse
|
||||
{
|
||||
|
@ -89,6 +91,60 @@ namespace blt::argparse
|
|||
return std::vector<std::string_view>{"./program", strings...};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void add(std::string& out, T&& value, size_t line_size = 60)
|
||||
{
|
||||
const auto lines = string::split(out, '\n');
|
||||
auto str = ensure_is_string(std::forward<T>(value));
|
||||
if (lines.empty())
|
||||
{
|
||||
out = str;
|
||||
return;
|
||||
}
|
||||
if (lines.back().size() + str.size() > line_size)
|
||||
{
|
||||
out += '\n';
|
||||
out += '\t';
|
||||
}
|
||||
out += str;
|
||||
}
|
||||
|
||||
argument_builder_t& argument_builder_t::set_action(const action_t action)
|
||||
{
|
||||
m_action = action;
|
||||
switch (m_action)
|
||||
{
|
||||
case action_t::STORE_TRUE:
|
||||
set_nargs(0);
|
||||
as_type<bool>();
|
||||
set_default(false);
|
||||
break;
|
||||
case action_t::STORE_FALSE:
|
||||
set_nargs(0);
|
||||
as_type<bool>();
|
||||
set_default(true);
|
||||
break;
|
||||
case action_t::STORE_CONST:
|
||||
case action_t::APPEND_CONST:
|
||||
set_nargs(0);
|
||||
break;
|
||||
case action_t::COUNT:
|
||||
set_nargs(0);
|
||||
as_type<size_t>();
|
||||
break;
|
||||
case action_t::EXTEND:
|
||||
set_nargs(nargs_t::ALL);
|
||||
break;
|
||||
case action_t::HELP:
|
||||
case action_t::VERSION:
|
||||
set_nargs(0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
argument_subparser_t& argument_parser_t::add_subparser(const std::string_view dest)
|
||||
{
|
||||
m_subparsers.emplace_back(dest, argument_subparser_t{*this});
|
||||
|
@ -98,7 +154,7 @@ namespace blt::argparse
|
|||
argument_storage_t argument_parser_t::parse(argument_consumer_t& consumer)
|
||||
{
|
||||
if (!m_name)
|
||||
m_name = consumer.absolute_first().get_argument();
|
||||
m_name = fs::base_name_sv(consumer.absolute_first().get_argument());
|
||||
argument_positional_storage_t positional_storage{m_positional_arguments};
|
||||
hashset_t<std::string> found_flags;
|
||||
argument_storage_t parsed_args;
|
||||
|
@ -146,14 +202,105 @@ namespace blt::argparse
|
|||
|
||||
void argument_parser_t::print_help()
|
||||
{
|
||||
print_usage();
|
||||
std::cout << std::endl;
|
||||
std::string help;
|
||||
if (!m_flag_arguments.empty())
|
||||
{
|
||||
help += "Options:\n";
|
||||
hashmap_t<argument_builder_t*, std::vector<std::string>> same_flags;
|
||||
for (const auto& [key, value] : m_flag_arguments)
|
||||
same_flags[value].emplace_back(key);
|
||||
for (const auto& [builder, flag_list] : same_flags)
|
||||
{
|
||||
// find max size and algin?
|
||||
add(help, '\t');
|
||||
for (const auto& [i, flag] : enumerate(flag_list))
|
||||
{
|
||||
add(help, flag);
|
||||
if (i != flag_list.size() - 1)
|
||||
add(help, ", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void argument_parser_t::print_usage()
|
||||
{
|
||||
if (!m_usage)
|
||||
{
|
||||
std::string usage = m_name.value_or("");
|
||||
|
||||
hashmap_t<std::string, std::vector<std::string>> singleFlags;
|
||||
std::vector<std::pair<argument_string_t, argument_builder_t*>> compoundFlags;
|
||||
|
||||
for (const auto& [key, value] : m_flag_arguments)
|
||||
{
|
||||
argument_string_t arg{key, allowed_flag_prefixes};
|
||||
if (arg.get_flag().size() == 1)
|
||||
{
|
||||
if (std::holds_alternative<i32>(value->m_nargs) && std::get<i32>(value->m_nargs) == 0)
|
||||
singleFlags[arg.get_flag()].emplace_back(arg.get_name());
|
||||
else
|
||||
compoundFlags.emplace_back(arg, value);
|
||||
} else
|
||||
compoundFlags.emplace_back(arg, value);
|
||||
}
|
||||
|
||||
for (const auto& [i, kv] : enumerate(singleFlags))
|
||||
{
|
||||
const auto& [key, value] = kv;
|
||||
add(usage, "[");
|
||||
add(usage, key);
|
||||
for (const auto& name : value)
|
||||
add(usage, name);
|
||||
add(usage, "]");
|
||||
if (i != singleFlags.size() - 1)
|
||||
add(usage, " ");
|
||||
}
|
||||
|
||||
for (const auto& [i, kv] : enumerate(compoundFlags))
|
||||
{
|
||||
const auto& [name, builder] = kv;
|
||||
add(usage, "[");
|
||||
add(usage, name.get_argument());
|
||||
auto lambda = [&]()
|
||||
{
|
||||
add(usage, " ");
|
||||
add(usage, builder->m_metavar.value_or(string::toUpperCase(name.get_name())));
|
||||
};
|
||||
std::visit(lambda_visitor{[&](const nargs_t)
|
||||
{
|
||||
lambda();
|
||||
}, [&](const int argc)
|
||||
{
|
||||
if (argc == 0)
|
||||
return;
|
||||
lambda();
|
||||
}}, builder->m_nargs);
|
||||
add(usage, "]");
|
||||
if (i != compoundFlags.size() - 1)
|
||||
add(usage, " ");
|
||||
}
|
||||
|
||||
for (const auto& [i, pair] : enumerate(m_positional_arguments))
|
||||
{
|
||||
const auto& [name, _] = pair;
|
||||
add(usage, "<");
|
||||
add(usage, name);
|
||||
add(usage, ">");
|
||||
if (i != m_positional_arguments.size() - 1)
|
||||
add(usage, " ");
|
||||
}
|
||||
|
||||
m_usage = usage;
|
||||
}
|
||||
std::cout << "Usage: " << *m_usage << std::endl;
|
||||
}
|
||||
|
||||
void argument_parser_t::print_version()
|
||||
void argument_parser_t::print_version() const
|
||||
{
|
||||
std::cout << m_name.value_or("NO NAME") << " " << m_version.value_or("NO VERSION") << std::endl;
|
||||
}
|
||||
|
||||
void argument_parser_t::handle_compound_flags(hashset_t<std::string>& found_flags, argument_storage_t& parsed_args,
|
||||
|
|
Loading…
Reference in New Issue