7 #include "arg_router/algorithm.hpp"
8 #include "arg_router/policy/program_addendum.hpp"
9 #include "arg_router/policy/program_intro.hpp"
10 #include "arg_router/policy/program_name.hpp"
11 #include "arg_router/policy/program_version.hpp"
12 #include "arg_router/tree_node_fwd.hpp"
14 #include "arg_router/utility/terminal.hpp"
15 #include "arg_router/utility/tuple_iterator.hpp"
28 namespace help_formatter_component
35 template <std::
size_t Indent>
38 static_assert(Indent > 0,
"Indent must be greater than zero");
50 template <std::
size_t DescStart, std::
size_t Depth,
typename HelpData>
51 void format(std::ostream& stream, std::size_t columns)
53 if constexpr (!HelpData::label::empty()) {
54 constexpr
auto indent = indent_size<Depth>();
55 stream << utility::create_sequence_cts_t<indent, ' '>::get() << HelpData::label::get();
57 if constexpr (!HelpData::description::empty()) {
58 static_assert(HelpData::description::get().find(
'\t') == std::string_view::npos,
59 "Help descriptions cannot contain tabs");
65 stream << utility::create_sequence_cts_t<gap, ' '>::get();
75 stream << '\n' << utility::create_sequence_cts_t<DescStart, ' '>::get();
94 std::size_t desc_start,
100 const auto indent = depth * Indent;
101 set_gap(stream, indent);
102 stream << help_data.
label;
109 set_gap(stream, gap);
120 set_gap(stream, desc_start);
130 template <std::
size_t Depth>
131 [[nodiscard]] constexpr
static std::size_t indent_size() noexcept
133 return Depth * Indent;
136 static void set_gap(std::ostream& stream, std::size_t num_chars)
139 stream << std::setw(num_chars) <<
' ';
154 template <
typename HelpNode>
157 [[maybe_unused]] constexpr
auto name_index =
159 typename HelpNode::policies_type>;
160 [[maybe_unused]] constexpr
auto version_index =
162 typename HelpNode::policies_type>;
163 [[maybe_unused]] constexpr
auto intro_index =
165 typename HelpNode::policies_type>;
168 if constexpr (name_index != std::tuple_size_v<typename HelpNode::policies_type>) {
169 stream << std::tuple_element_t<name_index,
171 if constexpr (version_index != std::tuple_size_v<typename HelpNode::policies_type>) {
173 << std::tuple_element_t<version_index,
179 if constexpr (intro_index != std::tuple_size_v<typename HelpNode::policies_type>) {
180 stream << std::tuple_element_t<intro_index,
198 template <
typename HelpNode>
201 [[maybe_unused]] constexpr
auto addendum_index =
203 typename HelpNode::policies_type>;
205 if constexpr (addendum_index != std::tuple_size_v<typename HelpNode::policies_type>) {
207 << std::tuple_element_t<addendum_index,
229 typename LineFormatter = help_formatter_component::default_line_formatter<Indent{}>,
230 typename PreambleFormatter = help_formatter_component::default_preamble_formatter,
231 typename AddendumFormatter = help_formatter_component::default_addendum_formatter>
234 static_assert(traits::has_value_type_v<Indent>,
"Indent must have a value_type");
235 static_assert(Indent{} > 0,
"Indent value_type must be greater than zero");
236 static_assert(traits::has_value_type_v<DescColumnOffset>,
237 "DescColumnOffset must have a value_type");
238 static_assert(DescColumnOffset{} > 0,
"DescColumnOffset value_type must be greater than zero");
251 template <
typename Node,
typename HelpNode,
bool Flatten>
254 generate_help_impl<Node, HelpNode, Flatten>(stream);
265 template <
typename Node,
typename HelpNode,
bool Flatten>
268 generate_help_impl<Node, HelpNode, Flatten>(stream, &help_data);
272 template <
typename Node,
typename HelpNode,
bool Flatten>
273 static void generate_help_impl(std::ostream& stream,
276 static_assert(traits::has_help_data_type_v<Node>,
277 "Node must have a help_data_type to generate help from");
279 using help_data_type =
typename Node::template help_data_type<Flatten>;
282 auto preamble_formatter = PreambleFormatter{};
283 preamble_formatter.template format<HelpNode>(stream);
286 constexpr
auto desc_column = description_column_start<0, help_data_type>(0);
294 auto line_formatter = LineFormatter{};
296 line_formatter_dispatch(stream,
299 columns >= (desc_column + DescColumnOffset{}) ?
301 std::numeric_limits<std::size_t>::max(),
305 line_formatter_dispatch<desc_column, 0, help_data_type>(
307 columns >= (desc_column + DescColumnOffset{}) ?
309 std::numeric_limits<std::size_t>::max(),
314 auto addendum_formatter = AddendumFormatter{};
315 addendum_formatter.template format<HelpNode>(stream);
318 template <std::
size_t Depth,
typename HelpData>
319 [[nodiscard]] constexpr
static std::size_t description_column_start(
320 std::size_t current_max) noexcept
322 constexpr
auto this_row_start =
324 current_max = std::max(current_max, this_row_start);
326 utility::tuple_type_iterator<typename HelpData::children>([&](
auto i) {
327 using child_type = std::tuple_element_t<i, typename HelpData::children>;
329 current_max = description_column_start<Depth + 1, child_type>(current_max);
335 template <std::
size_t DescStart, std::
size_t Depth,
typename HelpData>
336 static void line_formatter_dispatch(std::ostream& stream,
338 LineFormatter& line_formatter)
340 line_formatter.template format<DescStart, Depth, HelpData>(stream, columns);
342 utility::tuple_type_iterator<typename HelpData::children>([&](
auto i) {
343 using child_type = std::tuple_element_t<i, typename HelpData::children>;
345 line_formatter_dispatch<DescStart, Depth + 1, child_type>(stream,
351 static void line_formatter_dispatch(std::ostream& stream,
352 std::size_t desc_start,
355 LineFormatter& line_formatter,
356 const runtime_help_data& help_data)
358 line_formatter.format(stream, desc_start, depth, columns, help_data);
360 for (
const auto& child_help_data : help_data.children) {
361 line_formatter_dispatch(stream,
374 template <
typename Indent,
375 typename DescColumnOffset,
376 typename LineFormatter,
377 typename PreambleFormatter>
379 default_help_formatter_t<Indent, DescColumnOffset, LineFormatter, PreambleFormatter>> :
bool empty() const noexcept
constexpr auto find_specialisation_v
constexpr auto program_version
constexpr auto program_addendum
constexpr auto default_help_formatter
constexpr auto program_name
constexpr auto program_intro
std::integral_constant< decltype(Value), Value > integral_constant
constexpr std::size_t terminal_width(std::string_view str) noexcept
utility::dynamic_string_view label
Node name.
utility::dynamic_string_view description
Node description.