this doesn't work rn

v2
Brett 2025-02-27 01:53:22 -05:00
parent 17e6b507ea
commit 6935ae4785
3 changed files with 78 additions and 38 deletions

View File

@ -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 4.0.30) set(BLT_VERSION 4.0.31)
set(BLT_TARGET BLT) set(BLT_TARGET BLT)

View File

@ -231,8 +231,11 @@ namespace blt::argparse
template <typename T> template <typename T>
auto ensure_is_string(T&& t) auto ensure_is_string(T&& t)
{ {
if constexpr (std::is_arithmetic_v<meta::remove_cvref_t<T>> && !(std::is_same_v<T, char> using NO_REF = meta::remove_cvref_t<T>;
|| std::is_same_v<T, unsigned char> || std::is_same_v<T, signed char>)) if constexpr (std::is_same_v<NO_REF, bool>)
return t ? "true" : "false";
else if constexpr (std::is_arithmetic_v<NO_REF> && !(std::is_same_v<NO_REF, char>
|| std::is_same_v<NO_REF, unsigned char> || std::is_same_v<NO_REF, signed char>))
return std::to_string(std::forward<T>(t)); return std::to_string(std::forward<T>(t));
else else
return std::forward<T>(t); return std::forward<T>(t);
@ -582,7 +585,9 @@ namespace blt::argparse
class argument_parser_t class argument_parser_t
{ {
friend argument_subparser_t; friend argument_subparser_t;
explicit argument_parser_t(const argument_subparser_t* parent): m_parent(parent)
{
}
public: public:
explicit argument_parser_t(const std::optional<std::string_view> description = {}, const std::optional<std::string_view> 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> version = {},
@ -739,6 +744,7 @@ namespace blt::argparse
std::optional<std::string> m_description; std::optional<std::string> m_description;
std::optional<std::string> m_epilogue; std::optional<std::string> m_epilogue;
std::optional<std::string> m_version; std::optional<std::string> m_version;
const argument_subparser_t* m_parent = nullptr;
std::vector<std::pair<std::string_view, argument_subparser_t>> m_subparsers; std::vector<std::pair<std::string_view, argument_subparser_t>> m_subparsers;
std::vector<std::unique_ptr<argument_builder_t>> m_argument_builders; std::vector<std::unique_ptr<argument_builder_t>> m_argument_builders;
hashmap_t<std::string_view, argument_builder_t*> m_flag_arguments; hashmap_t<std::string_view, argument_builder_t*> m_flag_arguments;
@ -748,6 +754,7 @@ namespace blt::argparse
class argument_subparser_t class argument_subparser_t
{ {
friend argument_parser_t;
public: public:
explicit argument_subparser_t(const argument_parser_t& parent): m_parent(&parent) explicit argument_subparser_t(const argument_parser_t& parent): m_parent(&parent)
{ {
@ -760,9 +767,16 @@ namespace blt::argparse
std::conjunction_v<std::disjunction<std::is_convertible<Aliases, std::string_view>, std::is_constructible< std::conjunction_v<std::disjunction<std::is_convertible<Aliases, std::string_view>, std::is_constructible<
std::string_view, Aliases>>...>, std::string_view, Aliases>>...>,
"Arguments must be of type string_view, convertible to string_view or be string_view constructable"); "Arguments must be of type string_view, convertible to string_view or be string_view constructable");
m_parsers.emplace(name, argument_parser_t{}); m_parsers.emplace_back(new argument_parser_t{this});
((m_aliases[std::string_view{aliases}] = &m_parsers[name]), ...); m_aliases[name] = m_parsers.back().get();
return &m_parsers[name]; ((m_aliases[std::string_view{aliases}] = m_parsers.back().get()), ...);
return m_parsers.back().get();
}
argument_subparser_t* set_help(const std::optional<std::string>& help)
{
m_help = help;
return this;
} }
@ -781,10 +795,15 @@ namespace blt::argparse
std::pair<argument_string_t, argument_storage_t> parse(argument_consumer_t& consumer); // NOLINT std::pair<argument_string_t, argument_storage_t> parse(argument_consumer_t& consumer); // NOLINT
private: private:
[[nodiscard]] std::vector<std::vector<std::string_view>> get_allowed_strings() const; [[nodiscard]] hashmap_t<argument_parser_t*, std::vector<std::string_view>> get_allowed_strings() const;
// annoying compatability because im lazy
static std::vector<std::vector<std::string_view>> to_vec(const hashmap_t<argument_parser_t*, std::vector<std::string_view>>& map);
const argument_parser_t* m_parent; const argument_parser_t* m_parent;
hashmap_t<std::string_view, argument_parser_t> m_parsers; std::optional<std::string> m_last_parsed_parser; // bad hack
std::optional<std::string> m_help;
std::vector<std::unique_ptr<argument_parser_t>> m_parsers;
hashmap_t<std::string_view, argument_parser_t*> m_aliases; hashmap_t<std::string_view, argument_parser_t*> m_aliases;
}; };
} }

View File

@ -76,7 +76,9 @@ namespace blt::argparse
} }
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 std::string() + t; std::string str;
str += t;
return str;
} }
else else
{ {
@ -400,7 +402,23 @@ namespace blt::argparse
{ {
help += "Subcommands:"; help += "Subcommands:";
help.newline(); help.newline();
for (const auto& [key, value] : m_subparsers)
{
help += '\t';
auto map = value.get_allowed_strings();
// TODO: make an unzip?
for (const auto& [parser, strings] : map)
{
for (const auto& [i, str] : enumerate(strings))
{
help += str;
if (i != strings.size() - 1)
help += ", ";
}
help += parser.he
help.newline();
}
}
} }
if (!m_flag_arguments.empty()) if (!m_flag_arguments.empty())
@ -461,7 +479,7 @@ namespace blt::argparse
{ {
auto& [builder, flag_list] = pair; auto& [builder, flag_list] = pair;
str += builder->m_help.value_or(""); str += builder->m_help.value_or("");
if (builder->m_default_value) if (builder->m_default_value && !(builder->m_action == action_t::STORE_TRUE || builder->m_action == action_t::STORE_FALSE))
{ {
if (!std::isblank(str.str().back())) if (!std::isblank(str.str().back()))
str += " "; str += " ";
@ -514,6 +532,17 @@ namespace blt::argparse
aligner += m_name.value_or(""); aligner += m_name.value_or("");
aligner += ' '; aligner += ' ';
auto parent = m_parent;
while (parent != nullptr)
{
if (!parent->m_last_parsed_parser)
throw detail::missing_value_error(
"Error: Help called on subparser but unable to find parser chain. This condition should be impossible.");
aligner += parent->m_last_parsed_parser.value();
aligner += ' ';
parent = parent->m_parent->m_parent;
}
hashmap_t<std::string, std::vector<std::string>> singleFlags; hashmap_t<std::string, std::vector<std::string>> singleFlags;
std::vector<std::pair<argument_string_t, argument_builder_t*>> compoundFlags; std::vector<std::pair<argument_string_t, argument_builder_t*>> compoundFlags;
@ -960,36 +989,28 @@ namespace blt::argparse
throw detail::missing_argument_error("Subparser requires an argument."); throw detail::missing_argument_error("Subparser requires an argument.");
const auto key = consumer.consume(); const auto key = consumer.consume();
if (key.is_flag()) if (key.is_flag())
throw detail::subparse_error(key.get_argument(), get_allowed_strings()); throw detail::subparse_error(key.get_argument(), to_vec(get_allowed_strings()));
const auto it = m_parsers.find(key.get_name()); const auto it = m_aliases.find(key.get_name());
argument_parser_t* parser; if (it == m_aliases.end())
if (it == m_parsers.end()) throw detail::subparse_error(key.get_argument(), to_vec(get_allowed_strings()));
{ it->second->m_name = m_parent->m_name;
const auto it2 = m_aliases.find(key.get_name()); m_last_parsed_parser = key.get_name();
if (it2 == m_aliases.end()) return {key, it->second->parse(consumer)};
throw detail::subparse_error(key.get_argument(), get_allowed_strings());
parser = it2->second;
}
else
parser = &it->second;
parser->m_name = m_parent->m_name;
return {key, parser->parse(consumer)};
} }
std::vector<std::vector<std::string_view>> argument_subparser_t::get_allowed_strings() const hashmap_t<argument_parser_t*, std::vector<std::string_view>> argument_subparser_t::get_allowed_strings() const
{
hashmap_t<argument_parser_t*, std::vector<std::string_view>> map;
for (const auto& [key, value] : m_aliases)
map[value].emplace_back(key);
return map;
}
std::vector<std::vector<std::string_view>> argument_subparser_t::to_vec(const hashmap_t<argument_parser_t*, std::vector<std::string_view>>& map)
{ {
std::vector<std::vector<std::string_view>> vec; std::vector<std::vector<std::string_view>> vec;
for (const auto& [key, value] : m_parsers) for (const auto& [key, value] : map)
{ vec.push_back(value);
std::vector<std::string_view> aliases;
aliases.push_back(key);
for (const auto& [alias, parser] : m_aliases)
{
if (parser == &value)
aliases.push_back(alias);
}
vec.emplace_back(std::move(aliases));
}
return vec; return vec;
} }