fix argparse help
parent
04a5c01704
commit
4fab2595bc
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
include(cmake/color.cmake)
|
include(cmake/color.cmake)
|
||||||
set(BLT_VERSION 5.2.21)
|
set(BLT_VERSION 5.2.22)
|
||||||
|
|
||||||
set(BLT_TARGET BLT)
|
set(BLT_TARGET BLT)
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 154c63489e84d5569d3b466342a2ae8fd99e4734
|
Subproject commit 93201da2ba5a6aba0a6e57ada64973555629b3e3
|
|
@ -28,13 +28,11 @@
|
||||||
|
|
||||||
namespace blt::argparse
|
namespace blt::argparse
|
||||||
{
|
{
|
||||||
constexpr static auto printer_primitive = [](const auto& v)
|
constexpr static auto printer_primitive = [](const auto& v) {
|
||||||
{
|
|
||||||
std::cout << v;
|
std::cout << v;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr static auto printer_vector = [](const auto& v)
|
constexpr static auto printer_vector = [](const auto& v) {
|
||||||
{
|
|
||||||
std::cout << "[";
|
std::cout << "[";
|
||||||
for (const auto& [i, a] : enumerate(v))
|
for (const auto& [i, a] : enumerate(v))
|
||||||
{
|
{
|
||||||
|
@ -53,16 +51,13 @@ namespace blt::argparse
|
||||||
if constexpr (std::is_convertible_v<T, const char*>)
|
if constexpr (std::is_convertible_v<T, const char*>)
|
||||||
{
|
{
|
||||||
return std::char_traits<char>::length(t);
|
return std::char_traits<char>::length(t);
|
||||||
}
|
} else if constexpr (std::is_same_v<T, char> || std::is_same_v<T, unsigned char> || std::is_same_v<T, signed char>)
|
||||||
else if constexpr (std::is_same_v<T, char> || std::is_same_v<T, unsigned char> || std::is_same_v<T, signed char>)
|
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} else if constexpr (std::is_same_v<T, std::string_view> || std::is_same_v<T, std::string>)
|
||||||
else if constexpr (std::is_same_v<T, std::string_view> || std::is_same_v<T, std::string>)
|
|
||||||
{
|
{
|
||||||
return t.size();
|
return t.size();
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -74,14 +69,12 @@ namespace blt::argparse
|
||||||
if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, std::string_view>)
|
if constexpr (std::is_same_v<T, const char*> || std::is_same_v<T, std::string_view>)
|
||||||
{
|
{
|
||||||
return std::string(t);
|
return std::string(t);
|
||||||
}
|
} else if constexpr (std::is_same_v<T, char> || std::is_same_v<T, unsigned char> || std::is_same_v<T, signed char>)
|
||||||
else if constexpr (std::is_same_v<T, char> || std::is_same_v<T, unsigned char> || std::is_same_v<T, signed char>)
|
|
||||||
{
|
{
|
||||||
std::string str;
|
std::string str;
|
||||||
str += t;
|
str += t;
|
||||||
return str;
|
return str;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
{
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
@ -105,11 +98,12 @@ namespace blt::argparse
|
||||||
class aligned_internal_string_t
|
class aligned_internal_string_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit aligned_internal_string_t(std::string& str, const size_t max_line_length,
|
explicit aligned_internal_string_t(std::string& str, const size_t max_line_length, const size_t line_start_size): string(str),
|
||||||
const size_t line_start_size): string(str), max_line_size(max_line_length),
|
max_line_size(
|
||||||
line_start_size(line_start_size)
|
max_line_length),
|
||||||
{
|
line_start_size(
|
||||||
}
|
line_start_size)
|
||||||
|
{}
|
||||||
|
|
||||||
void add(const std::string_view str) const
|
void add(const std::string_view str) const
|
||||||
{
|
{
|
||||||
|
@ -149,8 +143,7 @@ namespace blt::argparse
|
||||||
{
|
{
|
||||||
size_t j = i;
|
size_t j = i;
|
||||||
for (; j < str.size() && !std::isblank(str[j]); ++j)
|
for (; j < str.size() && !std::isblank(str[j]); ++j)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
add(std::string_view(str.data() + i, j - i));
|
add(std::string_view(str.data() + i, j - i));
|
||||||
if (j < str.size())
|
if (j < str.size())
|
||||||
add(std::string_view(str.data() + j, 1));
|
add(std::string_view(str.data() + j, 1));
|
||||||
|
@ -173,10 +166,9 @@ namespace blt::argparse
|
||||||
class aligner_t
|
class aligner_t
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
aligner_t(std::vector<std::string>& buffer, const size_t start_index, const size_t max_line_size):
|
aligner_t(std::vector<std::string>& buffer, const size_t start_index, const size_t max_line_size): buffer(buffer), start_index(start_index),
|
||||||
buffer(buffer), start_index(start_index), max_line_size(max_line_size)
|
max_line_size(max_line_size)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
void align(const size_t spaces_between) const
|
void align(const size_t spaces_between) const
|
||||||
{
|
{
|
||||||
|
@ -186,8 +178,7 @@ namespace blt::argparse
|
||||||
{
|
{
|
||||||
auto size = static_cast<i64>(v.size());
|
auto size = static_cast<i64>(v.size());
|
||||||
for (; size > 0 && std::isblank(v[size - 1]); size--)
|
for (; size > 0 && std::isblank(v[size - 1]); size--)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
aligned_size = std::max(aligned_size, static_cast<size_t>(size));
|
aligned_size = std::max(aligned_size, static_cast<size_t>(size));
|
||||||
}
|
}
|
||||||
const auto offset_size = aligned_size + spaces_between;
|
const auto offset_size = aligned_size + spaces_between;
|
||||||
|
@ -201,16 +192,14 @@ namespace blt::argparse
|
||||||
|
|
||||||
[[nodiscard]] auto iter()
|
[[nodiscard]] auto iter()
|
||||||
{
|
{
|
||||||
return iterate(buffer).skip(start_index).take(compute_take()).map([this](std::string& x)
|
return iterate(buffer).skip(start_index).take(compute_take()).map([this](std::string& x) {
|
||||||
{
|
|
||||||
return aligned_internal_string_t{x, max_line_size, x.size()};
|
return aligned_internal_string_t{x, max_line_size, x.size()};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto iter() const
|
[[nodiscard]] auto iter() const
|
||||||
{
|
{
|
||||||
return iterate(buffer).skip(start_index).take(compute_take()).map([this](std::string& x)
|
return iterate(buffer).skip(start_index).take(compute_take()).map([this](std::string& x) {
|
||||||
{
|
|
||||||
return aligned_internal_string_t{x, max_line_size, x.size()};
|
return aligned_internal_string_t{x, max_line_size, x.size()};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -375,11 +364,8 @@ namespace blt::argparse
|
||||||
for (auto& [name, value] : positional_storage.remaining())
|
for (auto& [name, value] : positional_storage.remaining())
|
||||||
{
|
{
|
||||||
std::visit(lambda_visitor{
|
std::visit(lambda_visitor{
|
||||||
[](const nargs_t)
|
[](const nargs_t) {},
|
||||||
{
|
[](const int argc) {
|
||||||
},
|
|
||||||
[](const int argc)
|
|
||||||
{
|
|
||||||
if (argc == 0)
|
if (argc == 0)
|
||||||
throw detail::bad_positional("Positional Argument takes no values, this is invalid!");
|
throw detail::bad_positional("Positional Argument takes no values, this is invalid!");
|
||||||
}
|
}
|
||||||
|
@ -434,6 +420,7 @@ namespace blt::argparse
|
||||||
{
|
{
|
||||||
help += "Positional Arguments:";
|
help += "Positional Arguments:";
|
||||||
help.newline();
|
help.newline();
|
||||||
|
auto mark = help.mark();
|
||||||
for (auto& [name, builder] : m_positional_arguments)
|
for (auto& [name, builder] : m_positional_arguments)
|
||||||
{
|
{
|
||||||
help += '\t';
|
help += '\t';
|
||||||
|
@ -442,49 +429,55 @@ namespace blt::argparse
|
||||||
help += name;
|
help += name;
|
||||||
if (!builder.m_required)
|
if (!builder.m_required)
|
||||||
help += ']';
|
help += ']';
|
||||||
|
help.newline();
|
||||||
|
}
|
||||||
|
mark.align(4);
|
||||||
|
for (auto zipped_positionals : mark.iter().zip(m_positional_arguments))
|
||||||
|
{
|
||||||
|
auto& line = std::get<0>(zipped_positionals);
|
||||||
|
auto& [name, builder] = std::get<1>(zipped_positionals);
|
||||||
|
line += builder.m_help.value_or("");
|
||||||
if (builder.m_default_value && !(builder.m_action == action_t::STORE_TRUE || builder.m_action == action_t::STORE_FALSE))
|
if (builder.m_default_value && !(builder.m_action == action_t::STORE_TRUE || builder.m_action == action_t::STORE_FALSE))
|
||||||
{
|
{
|
||||||
if (!std::isblank(help.str().back()))
|
if (!std::isblank(line.str().back()))
|
||||||
help += " ";
|
line += " ";
|
||||||
help += "(Default: ";
|
line += "(Default: ";
|
||||||
std::visit(detail::arg_meta_type_helper_t::make_visitor(
|
std::visit(detail::arg_meta_type_helper_t::make_visitor(
|
||||||
[&](auto& value)
|
[&](auto& value)
|
||||||
{
|
{
|
||||||
help += value;
|
line += value;
|
||||||
},
|
},
|
||||||
[&](auto& vec)
|
[&](auto& vec)
|
||||||
{
|
{
|
||||||
if constexpr (!std::is_same_v<std::decay_t<meta::remove_cvref_t<decltype(vec)>>, std::vector<bool>>)
|
if constexpr (!std::is_same_v<std::decay_t<meta::remove_cvref_t<decltype(vec)>>, std::vector<bool>>)
|
||||||
{
|
{
|
||||||
help += '[';
|
line += '[';
|
||||||
for (const auto& [i, v] : enumerate(vec))
|
for (const auto& [i, v] : enumerate(vec))
|
||||||
{
|
{
|
||||||
help += v;
|
line += v;
|
||||||
if (i != vec.size() - 1)
|
if (i != vec.size() - 1)
|
||||||
help += ", ";
|
line += ", ";
|
||||||
}
|
}
|
||||||
help += ']';
|
line += ']';
|
||||||
}
|
}
|
||||||
}), *builder.m_default_value);
|
}), *builder.m_default_value);
|
||||||
help += ")";
|
line += ")";
|
||||||
}
|
}
|
||||||
if (builder.m_choices)
|
if (builder.m_choices)
|
||||||
{
|
{
|
||||||
if (!std::isblank(help.str().back()))
|
if (!std::isblank(line.str().back()))
|
||||||
help += " ";
|
line += " ";
|
||||||
help += "(Choices: ";
|
line += "(Choices: ";
|
||||||
for (const auto& [i, v] : enumerate(*builder.m_choices))
|
for (const auto& [i, v] : enumerate(*builder.m_choices))
|
||||||
{
|
{
|
||||||
help += '\'';
|
line += '\'';
|
||||||
help += v;
|
line += v;
|
||||||
help += '\'';
|
line += '\'';
|
||||||
if (i != builder.m_choices->size() - 1)
|
if (i != builder.m_choices->size() - 1)
|
||||||
help += ", ";
|
line += ", ";
|
||||||
}
|
}
|
||||||
help += ')';
|
line += ')';
|
||||||
}
|
}
|
||||||
help.newline();
|
|
||||||
help.newline();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -508,14 +501,12 @@ namespace blt::argparse
|
||||||
}
|
}
|
||||||
const argument_string_t arg{flag_list.front(), allowed_flag_prefixes};
|
const argument_string_t arg{flag_list.front(), allowed_flag_prefixes};
|
||||||
auto metavar = builder->m_metavar.value_or(string::toUpperCase(arg.get_name()));
|
auto metavar = builder->m_metavar.value_or(string::toUpperCase(arg.get_name()));
|
||||||
auto lambda = [&]()
|
auto lambda = [&]() {
|
||||||
{
|
|
||||||
help += ' ';
|
help += ' ';
|
||||||
help += metavar;
|
help += metavar;
|
||||||
};
|
};
|
||||||
std::visit(lambda_visitor{
|
std::visit(lambda_visitor{
|
||||||
[&](const nargs_t type)
|
[&](const nargs_t type) {
|
||||||
{
|
|
||||||
lambda();
|
lambda();
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
@ -527,8 +518,7 @@ namespace blt::argparse
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[&](const int argc)
|
[&](const int argc) {
|
||||||
{
|
|
||||||
if (argc == 0)
|
if (argc == 0)
|
||||||
return;
|
return;
|
||||||
lambda();
|
lambda();
|
||||||
|
@ -552,13 +542,9 @@ namespace blt::argparse
|
||||||
if (!std::isblank(str.str().back()))
|
if (!std::isblank(str.str().back()))
|
||||||
str += " ";
|
str += " ";
|
||||||
str += "(Default: '";
|
str += "(Default: '";
|
||||||
std::visit(detail::arg_meta_type_helper_t::make_visitor(
|
std::visit(detail::arg_meta_type_helper_t::make_visitor([&](auto& value) {
|
||||||
[&](auto& value)
|
|
||||||
{
|
|
||||||
str += value;
|
str += value;
|
||||||
},
|
}, [&](auto& vec) {
|
||||||
[&](auto& vec)
|
|
||||||
{
|
|
||||||
if constexpr (!std::is_same_v<std::decay_t<meta::remove_cvref_t<decltype(vec)>>, std::vector<bool>>)
|
if constexpr (!std::is_same_v<std::decay_t<meta::remove_cvref_t<decltype(vec)>>, std::vector<bool>>)
|
||||||
{
|
{
|
||||||
str += '[';
|
str += '[';
|
||||||
|
@ -639,8 +625,7 @@ namespace blt::argparse
|
||||||
singleFlags[arg.get_flag()].emplace_back(arg.get_name());
|
singleFlags[arg.get_flag()].emplace_back(arg.get_name());
|
||||||
else
|
else
|
||||||
compoundFlags.emplace_back(arg, value);
|
compoundFlags.emplace_back(arg, value);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
compoundFlags.emplace_back(arg, value);
|
compoundFlags.emplace_back(arg, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,14 +646,12 @@ namespace blt::argparse
|
||||||
const auto& builder = kv.second;
|
const auto& builder = kv.second;
|
||||||
aligner += builder->m_required ? '<' : '[';
|
aligner += builder->m_required ? '<' : '[';
|
||||||
aligner += name.get_argument();
|
aligner += name.get_argument();
|
||||||
auto lambda = [&]()
|
auto lambda = [&]() {
|
||||||
{
|
|
||||||
aligner += ' ';
|
aligner += ' ';
|
||||||
aligner += builder->m_metavar.value_or(string::toUpperCase(name.get_name()));
|
aligner += builder->m_metavar.value_or(string::toUpperCase(name.get_name()));
|
||||||
};
|
};
|
||||||
std::visit(lambda_visitor{
|
std::visit(lambda_visitor{
|
||||||
[&](const nargs_t type)
|
[&](const nargs_t type) {
|
||||||
{
|
|
||||||
lambda();
|
lambda();
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
|
@ -680,8 +663,7 @@ namespace blt::argparse
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[&](const int argc)
|
[&](const int argc) {
|
||||||
{
|
|
||||||
for (int j = 0; j < argc; j++)
|
for (int j = 0; j < argc; j++)
|
||||||
lambda();
|
lambda();
|
||||||
}
|
}
|
||||||
|
@ -710,8 +692,8 @@ namespace blt::argparse
|
||||||
std::cout << m_name.value_or("NO NAME") << " " << m_version.value_or("NO VERSION") << std::endl;
|
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,
|
void argument_parser_t::handle_compound_flags(hashset_t<std::string>& found_flags, argument_storage_t& parsed_args, argument_consumer_t& consumer,
|
||||||
argument_consumer_t& consumer, const argument_string_t& arg)
|
const argument_string_t& arg)
|
||||||
{
|
{
|
||||||
// i kinda hate this, TODO?
|
// i kinda hate this, TODO?
|
||||||
std::vector<std::string> compound_flags;
|
std::vector<std::string> compound_flags;
|
||||||
|
@ -719,8 +701,7 @@ namespace blt::argparse
|
||||||
{
|
{
|
||||||
for (const auto c : arg.get_name())
|
for (const auto c : arg.get_name())
|
||||||
compound_flags.emplace_back(std::string{arg.get_flag()} + c);
|
compound_flags.emplace_back(std::string{arg.get_flag()} + c);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (arg.get_flag().size() > 2)
|
if (arg.get_flag().size() > 2)
|
||||||
throw detail::bad_flag(make_string("Error: Flag '", arg.get_argument(), "' is too long!"));
|
throw detail::bad_flag(make_string("Error: Flag '", arg.get_argument(), "' is too long!"));
|
||||||
|
@ -742,8 +723,7 @@ namespace blt::argparse
|
||||||
auto flag = m_flag_arguments.find(arg)->second;
|
auto flag = m_flag_arguments.find(arg)->second;
|
||||||
const auto dest = flag->m_dest.value_or(std::string{arg});
|
const auto dest = flag->m_dest.value_or(std::string{arg});
|
||||||
std::visit(lambda_visitor{
|
std::visit(lambda_visitor{
|
||||||
[&parsed_args, &consumer, &dest, &flag, arg](const nargs_t arg_enum)
|
[&parsed_args, &consumer, &dest, &flag, arg](const nargs_t arg_enum) {
|
||||||
{
|
|
||||||
switch (arg_enum)
|
switch (arg_enum)
|
||||||
{
|
{
|
||||||
case nargs_t::IF_POSSIBLE:
|
case nargs_t::IF_POSSIBLE:
|
||||||
|
@ -770,8 +750,7 @@ namespace blt::argparse
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[&parsed_args, &consumer, &dest, &flag, arg, this](const i32 argc)
|
[&parsed_args, &consumer, &dest, &flag, arg, this](const i32 argc) {
|
||||||
{
|
|
||||||
const auto args = consume_argc(argc, consumer, flag->m_choices ? &*flag->m_choices : nullptr, arg);
|
const auto args = consume_argc(argc, consumer, flag->m_choices ? &*flag->m_choices : nullptr, arg);
|
||||||
|
|
||||||
switch (flag->m_action)
|
switch (flag->m_action)
|
||||||
|
@ -800,22 +779,16 @@ namespace blt::argparse
|
||||||
make_string("Argument '", arg, "'s action is append const but takes in arguments."));
|
make_string("Argument '", arg, "'s action is append const but takes in arguments."));
|
||||||
if (!flag->m_const_value)
|
if (!flag->m_const_value)
|
||||||
{
|
{
|
||||||
throw detail::missing_value_error(
|
throw detail::missing_value_error(make_string(
|
||||||
make_string("Append const chosen as an action but const value not provided for argument '", arg,
|
"Append const chosen as an action but const value not provided for argument '", arg, '\''));
|
||||||
'\''));
|
|
||||||
}
|
}
|
||||||
if (parsed_args.contains(dest))
|
if (parsed_args.contains(dest))
|
||||||
{
|
{
|
||||||
auto& data = parsed_args.m_data[dest];
|
auto& data = parsed_args.m_data[dest];
|
||||||
std::visit(detail::arg_meta_type_helper_t::make_visitor(
|
std::visit(detail::arg_meta_type_helper_t::make_visitor([arg](auto& primitive) {
|
||||||
[arg](auto& primitive)
|
throw detail::type_error(make_string("Invalid type for argument '", arg, "' expected list type, found '",
|
||||||
{
|
|
||||||
throw detail::type_error(make_string(
|
|
||||||
"Invalid type for argument '", arg, "' expected list type, found '",
|
|
||||||
blt::type_string<decltype(primitive)>(), "' with value ", primitive));
|
blt::type_string<decltype(primitive)>(), "' with value ", primitive));
|
||||||
},
|
}, [&flag, arg](auto& vec) {
|
||||||
[&flag, arg](auto& vec)
|
|
||||||
{
|
|
||||||
using type = typename meta::remove_cvref_t<decltype(vec)>::value_type;
|
using type = typename meta::remove_cvref_t<decltype(vec)>::value_type;
|
||||||
if (!std::holds_alternative<type>(*flag->m_const_value))
|
if (!std::holds_alternative<type>(*flag->m_const_value))
|
||||||
{
|
{
|
||||||
|
@ -825,18 +798,13 @@ namespace blt::argparse
|
||||||
}
|
}
|
||||||
vec.push_back(std::get<type>(*flag->m_const_value));
|
vec.push_back(std::get<type>(*flag->m_const_value));
|
||||||
}), data);
|
}), data);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
{
|
|
||||||
std::visit(detail::arg_meta_type_helper_t::make_visitor(
|
|
||||||
[&parsed_args, &dest](auto& primitive)
|
|
||||||
{
|
{
|
||||||
|
std::visit(detail::arg_meta_type_helper_t::make_visitor([&parsed_args, &dest](auto& primitive) {
|
||||||
std::vector<meta::remove_cvref_t<decltype(primitive)>> vec;
|
std::vector<meta::remove_cvref_t<decltype(primitive)>> vec;
|
||||||
vec.emplace_back(primitive);
|
vec.emplace_back(primitive);
|
||||||
parsed_args.m_data.emplace(dest, std::move(vec));
|
parsed_args.m_data.emplace(dest, std::move(vec));
|
||||||
},
|
}, [](auto&) {
|
||||||
[](auto&)
|
|
||||||
{
|
|
||||||
throw detail::type_error("Append const should not be a list type!");
|
throw detail::type_error("Append const should not be a list type!");
|
||||||
}), *flag->m_const_value);
|
}), *flag->m_const_value);
|
||||||
}
|
}
|
||||||
|
@ -872,27 +840,20 @@ namespace blt::argparse
|
||||||
case action_t::COUNT:
|
case action_t::COUNT:
|
||||||
if (parsed_args.m_data.contains(dest))
|
if (parsed_args.m_data.contains(dest))
|
||||||
{
|
{
|
||||||
auto visitor = detail::arg_meta_type_helper_t::make_visitor(
|
auto visitor = detail::arg_meta_type_helper_t::make_visitor([](auto& primitive) -> detail::arg_data_t {
|
||||||
[](auto& primitive) -> detail::arg_data_t
|
|
||||||
{
|
|
||||||
using type = meta::remove_cvref_t<decltype(primitive)>;
|
using type = meta::remove_cvref_t<decltype(primitive)>;
|
||||||
if constexpr (std::is_convertible_v<decltype(1), type>)
|
if constexpr (std::is_convertible_v<decltype(1), type>)
|
||||||
{
|
{
|
||||||
return primitive + static_cast<type>(1);
|
return primitive + static_cast<type>(1);
|
||||||
}
|
} else
|
||||||
else
|
throw detail::type_error("Error: count called but stored type is " + blt::type_string<type>());
|
||||||
|
}, [](auto&) -> detail::arg_data_t {
|
||||||
throw detail::type_error(
|
throw detail::type_error(
|
||||||
"Error: count called but stored type is " + blt::type_string<type>());
|
"List present on count. This condition doesn't make any sense! "
|
||||||
},
|
|
||||||
[](auto&) -> detail::arg_data_t
|
|
||||||
{
|
|
||||||
throw detail::type_error("List present on count. This condition doesn't make any sense! "
|
|
||||||
"(How did we get here, please report this!)");
|
"(How did we get here, please report this!)");
|
||||||
}
|
});
|
||||||
);
|
|
||||||
parsed_args.m_data[dest] = std::visit(visitor, parsed_args.m_data[dest]);
|
parsed_args.m_data[dest] = std::visit(visitor, parsed_args.m_data[dest]);
|
||||||
}
|
} else // I also hate this!
|
||||||
else // I also hate this!
|
|
||||||
flag->m_dest_func(dest, parsed_args, "1");
|
flag->m_dest_func(dest, parsed_args, "1");
|
||||||
break;
|
break;
|
||||||
case action_t::HELP:
|
case action_t::HELP:
|
||||||
|
@ -914,8 +875,7 @@ namespace blt::argparse
|
||||||
auto& positional = storage.next();
|
auto& positional = storage.next();
|
||||||
const auto dest = positional.m_dest.value_or(std::string{arg});
|
const auto dest = positional.m_dest.value_or(std::string{arg});
|
||||||
std::visit(lambda_visitor{
|
std::visit(lambda_visitor{
|
||||||
[&consumer, &positional, &dest, &parsed_args, arg](const nargs_t arg_enum)
|
[&consumer, &positional, &dest, &parsed_args, arg](const nargs_t arg_enum) {
|
||||||
{
|
|
||||||
switch (arg_enum)
|
switch (arg_enum)
|
||||||
{
|
{
|
||||||
case nargs_t::IF_POSSIBLE:
|
case nargs_t::IF_POSSIBLE:
|
||||||
|
@ -927,8 +887,7 @@ namespace blt::argparse
|
||||||
make_string("Error expected at least one argument to be consumed by '", arg, '\''));
|
make_string("Error expected at least one argument to be consumed by '", arg, '\''));
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case nargs_t::ALL:
|
case nargs_t::ALL:
|
||||||
auto result = consume_until_flag_or_end(
|
auto result = consume_until_flag_or_end(consumer, positional.m_choices ? &*positional.m_choices : nullptr);
|
||||||
consumer, positional.m_choices ? &*positional.m_choices : nullptr);
|
|
||||||
if (!result)
|
if (!result)
|
||||||
throw detail::bad_choice_error(make_string('\'', consumer.peek().get_argument(),
|
throw detail::bad_choice_error(make_string('\'', consumer.peek().get_argument(),
|
||||||
"' is not a valid choice for argument '", arg,
|
"' is not a valid choice for argument '", arg,
|
||||||
|
@ -937,8 +896,7 @@ namespace blt::argparse
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[this, &consumer, &positional, &dest, &parsed_args, arg](const i32 argc)
|
[this, &consumer, &positional, &dest, &parsed_args, arg](const i32 argc) {
|
||||||
{
|
|
||||||
const auto args = consume_argc(argc, consumer, positional.m_choices ? &*positional.m_choices : nullptr, arg);
|
const auto args = consume_argc(argc, consumer, positional.m_choices ? &*positional.m_choices : nullptr, arg);
|
||||||
|
|
||||||
switch (positional.m_action)
|
switch (positional.m_action)
|
||||||
|
@ -1023,8 +981,7 @@ namespace blt::argparse
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> argument_parser_t::consume_argc(const int argc, argument_consumer_t& consumer,
|
std::vector<std::string> argument_parser_t::consume_argc(const int argc, argument_consumer_t& consumer, hashset_t<std::string>* allowed_choices,
|
||||||
hashset_t<std::string>* allowed_choices,
|
|
||||||
const std::string_view arg)
|
const std::string_view arg)
|
||||||
{
|
{
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
|
@ -1032,15 +989,13 @@ namespace blt::argparse
|
||||||
{
|
{
|
||||||
if (!consumer.can_consume())
|
if (!consumer.can_consume())
|
||||||
{
|
{
|
||||||
throw detail::missing_argument_error(
|
throw detail::missing_argument_error(make_string("Expected ", argc, " arguments to be consumed by '", arg, "' but found ", i));
|
||||||
make_string("Expected ", argc, " arguments to be consumed by '", arg, "' but found ", i));
|
|
||||||
}
|
}
|
||||||
if (consumer.peek().is_flag())
|
if (consumer.peek().is_flag())
|
||||||
{
|
{
|
||||||
std::cout << "Warning: arg '" << arg << "' expects " << argc <<
|
std::cout << "Warning: arg '" << arg << "' expects " << argc << " arguments to be consumed but we found a flag '" << consumer.peek().
|
||||||
" arguments to be consumed but we found a flag '" << consumer.peek().
|
get_argument()
|
||||||
get_argument() <<
|
<< "'. We will comply as this may be desired if this argument is a file." << std::endl;
|
||||||
"'. We will comply as this may be desired if this argument is a file." << std::endl;
|
|
||||||
}
|
}
|
||||||
if (allowed_choices != nullptr && !allowed_choices->contains(consumer.peek().get_argument()))
|
if (allowed_choices != nullptr && !allowed_choices->contains(consumer.peek().get_argument()))
|
||||||
{
|
{
|
||||||
|
@ -1052,8 +1007,7 @@ namespace blt::argparse
|
||||||
valid_choices += ", ";
|
valid_choices += ", ";
|
||||||
}
|
}
|
||||||
valid_choices += "}";
|
valid_choices += "}";
|
||||||
throw detail::bad_choice_error(make_string('\'', consumer.peek().get_argument(),
|
throw detail::bad_choice_error(make_string('\'', consumer.peek().get_argument(), "' is not a valid choice for argument '", arg,
|
||||||
"' is not a valid choice for argument '", arg,
|
|
||||||
"'! Expected one of ", valid_choices));
|
"'! Expected one of ", valid_choices));
|
||||||
}
|
}
|
||||||
args.emplace_back(consumer.consume().get_argument());
|
args.emplace_back(consumer.consume().get_argument());
|
||||||
|
@ -1061,8 +1015,7 @@ namespace blt::argparse
|
||||||
if (args.size() != static_cast<size_t>(argc))
|
if (args.size() != static_cast<size_t>(argc))
|
||||||
{
|
{
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"This error condition should not be possible. "
|
"This error condition should not be possible. " "Args consumed didn't equal the arguments requested and previous checks didn't fail. "
|
||||||
"Args consumed didn't equal the arguments requested and previous checks didn't fail. "
|
|
||||||
"Please report as an issue on the GitHub");
|
"Please report as an issue on the GitHub");
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
|
@ -1194,7 +1147,6 @@ namespace blt::argparse
|
||||||
BLT_ASSERT(arg.get_flag() == "++" && "Double plus value should match the input string.");
|
BLT_ASSERT(arg.get_flag() == "++" && "Double plus value should match the input string.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void run_all_tests_argument_string_t()
|
void run_all_tests_argument_string_t()
|
||||||
{
|
{
|
||||||
const hashset_t<char> prefixes = {'-', '+'};
|
const hashset_t<char> prefixes = {'-', '+'};
|
||||||
|
@ -1247,8 +1199,7 @@ namespace blt::argparse
|
||||||
{
|
{
|
||||||
parser.parse(args);
|
parser.parse(args);
|
||||||
BLT_ASSERT(false && "Parsing should fail with invalid flag prefix '!'");
|
BLT_ASSERT(false && "Parsing should fail with invalid flag prefix '!'");
|
||||||
}
|
} catch (...)
|
||||||
catch (...)
|
|
||||||
{
|
{
|
||||||
BLT_ASSERT(true && "Correctly threw on bad flag prefix");
|
BLT_ASSERT(true && "Correctly threw on bad flag prefix");
|
||||||
}
|
}
|
||||||
|
@ -1278,8 +1229,7 @@ namespace blt::argparse
|
||||||
{
|
{
|
||||||
parser.parse(args);
|
parser.parse(args);
|
||||||
BLT_ASSERT(false && "Parsing should fail due to invalid flag '!z'");
|
BLT_ASSERT(false && "Parsing should fail due to invalid flag '!z'");
|
||||||
}
|
} catch (...)
|
||||||
catch (...)
|
|
||||||
{
|
{
|
||||||
BLT_ASSERT(true && "Correctly threw an exception for invalid flag");
|
BLT_ASSERT(true && "Correctly threw an exception for invalid flag");
|
||||||
}
|
}
|
||||||
|
@ -1320,8 +1270,7 @@ namespace blt::argparse
|
||||||
{
|
{
|
||||||
auto parsed_args = parser.parse(consumer);
|
auto parsed_args = parser.parse(consumer);
|
||||||
return consumer.remaining() == 0;
|
return consumer.remaining() == 0;
|
||||||
}
|
} catch (const std::exception&)
|
||||||
catch (const std::exception&)
|
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1393,18 +1342,15 @@ namespace blt::argparse
|
||||||
|
|
||||||
// Valid case: No arguments
|
// Valid case: No arguments
|
||||||
const std::vector<std::string_view> valid_args_0 = {"./program"};
|
const std::vector<std::string_view> valid_args_0 = {"./program"};
|
||||||
BLT_ASSERT(!parse_arguments(valid_args_0, argparse::nargs_t::ALL) &&
|
BLT_ASSERT(!parse_arguments(valid_args_0, argparse::nargs_t::ALL) && "nargs=ALL: No arguments present. Should fail.)");
|
||||||
"nargs=ALL: No arguments present. Should fail.)");
|
|
||||||
|
|
||||||
// Valid case: Multiple arguments
|
// Valid case: Multiple arguments
|
||||||
const std::vector<std::string_view> valid_args_2 = {"./program", "arg1", "arg2"};
|
const std::vector<std::string_view> valid_args_2 = {"./program", "arg1", "arg2"};
|
||||||
BLT_ASSERT(parse_arguments(valid_args_2, argparse::nargs_t::ALL) &&
|
BLT_ASSERT(parse_arguments(valid_args_2, argparse::nargs_t::ALL) && "nargs=ALL: Should accept all remaining arguments");
|
||||||
"nargs=ALL: Should accept all remaining arguments");
|
|
||||||
|
|
||||||
// Valid case: Many arguments
|
// Valid case: Many arguments
|
||||||
const std::vector<std::string_view> valid_args_many = {"./program", "arg1", "arg2", "arg3", "arg4"};
|
const std::vector<std::string_view> valid_args_many = {"./program", "arg1", "arg2", "arg3", "arg4"};
|
||||||
BLT_ASSERT(parse_arguments(valid_args_many, argparse::nargs_t::ALL) &&
|
BLT_ASSERT(parse_arguments(valid_args_many, argparse::nargs_t::ALL) && "nargs=ALL: Should accept all remaining arguments");
|
||||||
"nargs=ALL: Should accept all remaining arguments");
|
|
||||||
|
|
||||||
std::cout << "Success: test_nargs_all\n";
|
std::cout << "Success: test_nargs_all\n";
|
||||||
}
|
}
|
||||||
|
@ -1497,20 +1443,16 @@ namespace blt::argparse
|
||||||
{
|
{
|
||||||
parser.parse(a2);
|
parser.parse(a2);
|
||||||
BLT_ASSERT(false && "Parsing should fail due to invalid flag '--hello'");
|
BLT_ASSERT(false && "Parsing should fail due to invalid flag '--hello'");
|
||||||
}
|
} catch (...)
|
||||||
catch (...)
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto a3 = make_arguments("--hello", "crazy", "not_a_choice");
|
const auto a3 = make_arguments("--hello", "crazy", "not_a_choice");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
parser.parse(a3);
|
parser.parse(a3);
|
||||||
BLT_ASSERT(false && "Parsing should fail due to invalid positional 'iam'");
|
BLT_ASSERT(false && "Parsing should fail due to invalid positional 'iam'");
|
||||||
}
|
} catch (...)
|
||||||
catch (...)
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << "Success: run_choice_test\n";
|
std::cout << "Success: run_choice_test\n";
|
||||||
}
|
}
|
||||||
|
@ -1541,20 +1483,16 @@ namespace blt::argparse
|
||||||
{
|
{
|
||||||
parser.parse(a1);
|
parser.parse(a1);
|
||||||
BLT_ASSERT(false && "Subparser should throw an error when positional not supplied");
|
BLT_ASSERT(false && "Subparser should throw an error when positional not supplied");
|
||||||
}
|
} catch (...)
|
||||||
catch (...)
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto a2 = make_arguments("--open");
|
const auto a2 = make_arguments("--open");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
parser.parse(a2);
|
parser.parse(a2);
|
||||||
BLT_ASSERT(false && "Subparser should throw an error when no subparser is supplied");
|
BLT_ASSERT(false && "Subparser should throw an error when no subparser is supplied");
|
||||||
}
|
} catch (...)
|
||||||
catch (...)
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto a3 = make_arguments("n1", "--silly", "path_n1");
|
const auto a3 = make_arguments("n1", "--silly", "path_n1");
|
||||||
const auto r3 = parser.parse(a3);
|
const auto r3 = parser.parse(a3);
|
||||||
|
@ -1568,10 +1506,8 @@ namespace blt::argparse
|
||||||
{
|
{
|
||||||
parser.parse(a4);
|
parser.parse(a4);
|
||||||
BLT_ASSERT(false && "Subparser should throw an error when second positional is not supplied");
|
BLT_ASSERT(false && "Subparser should throw an error when second positional is not supplied");
|
||||||
}
|
} catch (...)
|
||||||
catch (...)
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto a5 = make_arguments("--open", "n2", "path_n2", "output_n2");
|
const auto a5 = make_arguments("--open", "n2", "path_n2", "output_n2");
|
||||||
const auto r5 = parser.parse(a5);
|
const auto r5 = parser.parse(a5);
|
||||||
|
@ -1586,10 +1522,8 @@ namespace blt::argparse
|
||||||
{
|
{
|
||||||
parser.parse(a6);
|
parser.parse(a6);
|
||||||
BLT_ASSERT(false && "Subparser should throw an error when first positional is not a valid subparser");
|
BLT_ASSERT(false && "Subparser should throw an error when first positional is not a valid subparser");
|
||||||
}
|
} catch (const std::exception&)
|
||||||
catch (const std::exception&)
|
{}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto a7 = make_arguments("n3");
|
const auto a7 = make_arguments("n3");
|
||||||
const auto r7 = parser.parse(a7);
|
const auto r7 = parser.parse(a7);
|
||||||
|
|
Loading…
Reference in New Issue