arg_router  1.4.0
C++ command line argument parsing and routing
colour_help_formatter.hpp
1 // Copyright (C) 2022-2023 by Camden Mannett.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
4 
5 #pragma once
6 
7 #include "arg_router/policy/default_help_formatter.hpp"
8 
9 namespace arg_router::policy
10 {
11 namespace help_formatter_component
12 {
19 template <std::size_t Indent>
21 {
22  static_assert(Indent > 0, "Indent must be greater than zero");
23 
24  constexpr static auto reset_colour = std::string_view{"\033[0m"};
25  constexpr static auto red_colour = std::string_view{"\033[31m"};
26  constexpr static auto green_colour = std::string_view{"\033[32m"};
27 
28 public:
37  template <std::size_t DescStart, std::size_t Depth, typename HelpData>
38  void format(std::ostream& stream, std::size_t columns)
39  {
40  if constexpr (!HelpData::label::empty()) {
41  constexpr auto indent = indent_size<Depth>();
42  stream << red_colour << utility::create_sequence_cts_t<indent, ' '>::get()
43  << HelpData::label::get();
44 
45  if constexpr (!HelpData::description::empty()) {
46  static_assert(HelpData::description::get().find('\t') == std::string_view::npos,
47  "Help descriptions cannot contain tabs");
48 
49  constexpr auto gap =
50  DescStart - indent - utility::utf8::terminal_width(HelpData::label::get());
51 
52  // Spacing between the end of the args label and start of description
53  stream << green_colour << utility::create_sequence_cts_t<gap, ' '>::get();
54 
55  // Print the description, breaking if a word will exceed the terminal width
56  for (auto it = utility::utf8::line_iterator{HelpData::description::get(),
57  columns - DescStart};
59  stream << *it;
60 
61  // If there's more data to follow, then add the offset
62  if (++it != utility::utf8::line_iterator{}) {
63  stream << '\n' << utility::create_sequence_cts_t<DescStart, ' '>::get();
64  }
65  }
66  }
67 
68  stream << "\n" << reset_colour;
69  }
70  }
71 
81  void format(std::ostream& stream,
82  std::size_t desc_start,
83  std::size_t depth,
84  std::size_t columns,
85  const runtime_help_data& help_data)
86  {
87  if (!help_data.label.empty()) {
88  const auto indent = depth * Indent;
89  stream << red_colour << std::setw(indent) << ' ' << help_data.label;
90 
91  if (!help_data.description.empty()) {
92  const auto gap =
93  desc_start - indent - utility::utf8::terminal_width(help_data.label);
94 
95  // Spacing between the end of the args label and start of description
96  stream << green_colour << std::setw(gap) << ' ';
97 
98  // Print the description, breaking if a word will exceed the terminal width
99  for (auto it =
100  utility::utf8::line_iterator{help_data.description, columns - desc_start};
101  it != utility::utf8::line_iterator{};) {
102  stream << *it;
103 
104  // If there's more data to follow, then add the offset
105  if (++it != utility::utf8::line_iterator{}) {
106  stream << '\n' << std::setw(desc_start) << ' ';
107  }
108  }
109  }
110 
111  stream << "\n" << reset_colour;
112  }
113  }
114 
115 private:
116  template <std::size_t Depth>
117  [[nodiscard]] constexpr static std::size_t indent_size() noexcept
118  {
119  return Depth * Indent;
120  }
121 };
122 } // namespace help_formatter_component
123 
136 template <typename Indent = traits::integral_constant<std::size_t{4}>,
137  typename DescColumnOffset = traits::integral_constant<Indent{} * 2>,
138  typename PreambleFormatter = help_formatter_component::default_preamble_formatter,
139  typename AddendumFormatter = help_formatter_component::default_addendum_formatter>
142  DescColumnOffset,
144  PreambleFormatter,
145  AddendumFormatter>;
146 
149 } // namespace arg_router::policy
void format(std::ostream &stream, std::size_t desc_start, std::size_t depth, std::size_t columns, const runtime_help_data &help_data)
constexpr auto colour_help_formatter
std::integral_constant< decltype(Value), Value > integral_constant
Definition: traits.hpp:210
constexpr std::size_t terminal_width(std::string_view str) noexcept
Definition: utf8.hpp:321
utility::dynamic_string_view label
Node name.
utility::dynamic_string_view description
Node description.