7 #include "arg_router/policy/default_help_formatter.hpp"
8 #include "arg_router/policy/description.hpp"
9 #include "arg_router/policy/flatten_help.hpp"
10 #include "arg_router/policy/long_name.hpp"
11 #include "arg_router/policy/min_max_count.hpp"
12 #include "arg_router/policy/no_result_value.hpp"
13 #include "arg_router/policy/short_name.hpp"
14 #include "arg_router/tree_node.hpp"
15 #include "arg_router/utility/string_to_policy.hpp"
24 template <
typename... Policies>
25 class add_missing_formatter_policy
27 using policies_tuple = std::tuple<std::decay_t<Policies>...>;
28 using default_formatter_type = policy::default_help_formatter_t<>;
31 constexpr
static auto has_formatter =
32 boost::mp11::mp_find_if<policies_tuple, traits::has_generate_help_method>::value !=
33 std::tuple_size_v<policies_tuple>;
35 using type = std::conditional_t<
37 boost::mp11::mp_rename<policies_tuple, tree_node>,
38 boost::mp11::mp_rename<boost::mp11::mp_push_front<policies_tuple, default_formatter_type>,
48 template <
typename... Policies>
50 public detail::add_missing_formatter_policy<
51 policy::no_result_value<>,
52 policy::min_max_count_t<traits::integral_constant<std::size_t{0}>,
53 traits::integral_constant<std::numeric_limits<std::size_t>::max()>>,
54 std::decay_t<Policies>...>::type
58 "Help must only contain policies (not other nodes)");
60 static_assert(traits::has_long_name_method_v<help_t> || traits::has_short_name_method_v<help_t>,
61 "Help must have a long and/or short name policy");
62 static_assert(!traits::has_display_name_method_v<help_t>,
63 "Help must not have a display name policy");
64 static_assert(!traits::has_none_name_method_v<help_t>,
"Help must not have a none name policy");
66 using parent_type =
typename detail::add_missing_formatter_policy<
70 std::decay_t<Policies>...>::type;
72 constexpr
static auto formatter_index =
73 boost::mp11::mp_find_if<
typename parent_type::policies_type,
75 static_assert(formatter_index != std::tuple_size_v<typename parent_type::policies_type>,
76 "Help node must have a formatter policy");
77 using formatter_type =
78 std::tuple_element_t<formatter_index, typename parent_type::policies_type>;
81 using typename parent_type::policies_type;
82 using parent_type::generate_help;
85 template <
bool Flatten>
86 using help_data_type =
typename parent_type::template default_leaf_help_data_type<Flatten>;
92 template <
auto has_formatter = detail::add_missing_formatter_policy<Policies...>::has_formatter>
93 constexpr
explicit help_t(Policies... policies,
95 std::enable_if_t<has_formatter>* =
nullptr) noexcept :
100 std::move(policies)...}
104 template <
auto has_formatter = detail::add_missing_formatter_policy<Policies...>::has_formatter>
105 constexpr
explicit help_t(Policies... policies,
107 std::enable_if_t<!has_formatter>* =
nullptr) noexcept :
109 policy::no_result_value<>{},
110 policy::min_max_count_t<
112 traits::integral_constant<std::numeric_limits<std::size_t>::max()>>{},
113 std::move(policies)...}
117 template <
typename Validator,
bool HasTarget,
typename... Parents>
118 [[nodiscard]] std::optional<parsing::parse_target> pre_parse(
119 parsing::pre_parse_data<Validator, HasTarget> pre_parse_data,
120 const Parents&... parents)
const
123 static_assert((
sizeof...(Parents) >= 1),
"At least one parent needed for help");
125 return parent_type::pre_parse(pre_parse_data, *
this, parents...);
135 template <
bool Flatten,
typename Node>
137 const Node& start_node)
const noexcept
141 const auto filter = [](
const auto& child) {
142 using child_type = std::decay_t<decltype(child)>;
143 if constexpr (traits::has_help_data_type_v<child_type>) {
144 if constexpr (traits::has_runtime_enabled_method_v<child_type>) {
145 return child.runtime_enabled();
154 auto rhd =
runtime_help_data{node_hdt::label::get(), node_hdt::description::get(), {}};
155 if constexpr (traits::has_runtime_children_method_v<node_hdt>) {
156 rhd.
children = node_hdt::runtime_children(start_node, filter);
159 parent_type::template default_leaf_help_data_type<Flatten>::runtime_children(
178 template <
typename... Parents>
182 std::get<
sizeof...(Parents) - 1>(std::tuple{std::cref(parents)...}).get();
184 find_help_target(target.tokens(),
root, [&](
const auto& target_node) {
185 using root_type = std::decay_t<decltype(root)>;
186 using node_type = std::decay_t<decltype(target_node)>;
190 constexpr auto flatten =
191 algorithm::has_specialisation_v<policy::flatten_help_t,
192 typename parent_type::policies_type> ||
193 !std::is_same_v<root_type, node_type>;
196 if constexpr (traits::has_runtime_generate_help_method_v<formatter_type>) {
197 const auto rhd = generate_runtime_help_data<flatten>(target_node);
201 using routing_policy =
202 typename parent_type::template phase_finder_t<policy::has_routing_phase_method>;
203 if constexpr (std::is_void_v<routing_policy>) {
204 formatter_type::template generate_help<node_type, help_t, flatten>(std::cout,
206 std::exit(EXIT_SUCCESS);
208 auto stream = ostringstream{};
209 formatter_type::template generate_help<node_type, help_t, flatten>(stream, rhd);
210 this->routing_policy::routing_phase(std::move(stream));
213 using routing_policy =
214 typename parent_type::template phase_finder_t<policy::has_routing_phase_method>;
215 if constexpr (std::is_void_v<routing_policy>) {
216 formatter_type::template generate_help<node_type, help_t, flatten>(std::cout);
217 std::exit(EXIT_SUCCESS);
219 auto stream = ostringstream{};
220 formatter_type::template generate_help<node_type, help_t, flatten>(stream);
221 this->routing_policy::routing_phase(std::move(stream));
229 !parent_type::template any_phases_v<
bool,
230 policy::has_parse_phase_method,
231 policy::has_validation_phase_method,
232 policy::has_missing_phase_method>,
233 "Help only supports policies with pre-parse and routing phases");
235 template <
typename Node,
typename TargetFn>
236 static void find_help_target(vector<parsing::token_type>& tokens,
240 if constexpr (traits::has_runtime_enabled_method_v<Node>) {
241 if (!node.runtime_enabled()) {
242 throw multi_lang_exception{error_code::unknown_argument, tokens.front()};
246 if (tokens.empty()) {
252 utility::tuple_iterator(
253 [&](
auto ,
const auto& child) {
254 using child_type = std::decay_t<decltype(child)>;
256 if (tokens.empty()) {
263 const auto token = parsing::get_token_type(child, tokens.front().name);
264 if (!result && parsing::match<child_type>(token)) {
266 tokens.erase(tokens.begin());
267 find_help_target(tokens, child, fn);
273 throw multi_lang_exception{error_code::unknown_argument, tokens.front()};
293 template <
typename... Policies>
294 [[nodiscard]] constexpr
auto help(Policies... policies) noexcept
297 [](
auto... converted_policies) {
298 return help_t<std::decay_t<decltype(converted_policies)>...>{
299 std::move(converted_policies)...};
301 utility::string_to_policy::convert<
305 std::move(policies)...));
constexpr help_t(Policies... policies, std::enable_if_t< has_formatter > *=nullptr) noexcept
typename parent_type::template default_leaf_help_data_type< Flatten > help_data_type
runtime_help_data generate_runtime_help_data(const Node &start_node) const noexcept
void parse(parsing::parse_target &&target, const Parents &... parents) const
constexpr auto default_help_formatter
constexpr auto is_all_policies_v
std::integral_constant< decltype(Value), Value > integral_constant
constexpr auto help(Policies... policies) noexcept
constexpr auto root(Params... params) noexcept
vector< runtime_help_data > children
Child node help data.