koutil
Loading...
Searching...
No Matches
help_impl.h
Go to the documentation of this file.
1#ifndef KOUTIL_ARGS_HELP_IMPL_H
2#define KOUTIL_ARGS_HELP_IMPL_H
3
5#include "koutil/args/help.h"
7#include <algorithm>
8#include <cstddef>
9#include <iomanip>
10#include <ios>
11#include <ostream>
12#include <sstream>
13#include <string>
14#include <string_view>
15#include <vector>
16
17namespace koutil::args {
18
19template <extends_result Result> void help_printer_t<Result>::print(std::ostream& out) {
20 // clang-format off
21 out << m_cmd.description() << '\n'
22 << '\n'
23 << "Usage: ";
24 // clang-format on
25
26 if (!m_cmd.path().empty()) {
27 out << m_cmd.path() << ' ';
28 }
29 out << m_cmd.name();
30
31 const auto& options = m_cmd.options();
32 const auto& args = m_cmd.arguments();
33 const auto& cmds = m_cmd.commands();
34
35 if (!options.empty()) {
36 out << " [OPTIONS]";
37 }
38
39 if (!args.empty()) {
40 out << " <ARGUMENTS>";
41 }
42
43 if (!cmds.empty()) {
44 out << " [COMMANDS]";
45 }
46
47 out << '\n';
48
49 print_arguments(out, args);
50 print_options(out, options);
51 print_commands(out, cmds);
52}
53
54template <extends_result Result>
55void help_printer_t<Result>::print_arguments(std::ostream& out, const std::vector<argument_t>& args) {
56 if (args.empty()) {
57 return;
58 }
59
60 std::size_t max_size = 0;
61
62 for (const auto& arg : args) {
63 max_size = std::max(max_size, arg.name().size() + 2);
64 }
65
66 out << "Arguments:\n";
67
68 for (const auto& arg : args) {
69 print_item(out, max_size, "", arg.name(), arg.description());
70 }
71}
72
73template <extends_result Result>
74void help_printer_t<Result>::print_options(std::ostream& out, const std::vector<option_t>& options) {
75 if (options.empty()) {
76 return;
77 }
78
79 std::size_t max_size = 0;
80
81 for (const auto& opt : options) {
82 std::size_t size = 0;
83
84 if (opt.long_name() && opt.short_name()) {
85 // ", "
86 size += 2;
87 }
88
89 if (opt.short_name()) {
90 // "-x"
91 size += 2;
92 }
93
94 if (opt.long_name()) {
95 // "--name"
96 size += 2 + opt.long_name()->size();
97 }
98
99 if (opt.has_value()) {
100 // " <name>"
101 size += 3 + opt.value_name().size();
102 }
103
104 max_size = std::max(max_size, size);
105 }
106
107 out << "Options:\n";
108 for (const auto& opt : options) {
109 std::string name;
110
111 bool has_short_name = opt.short_name().has_value();
112
113 if (has_short_name) {
114 name += '-';
115 name += *opt.short_name();
116 }
117
118 if (opt.long_name()) {
119 if (has_short_name) {
120 name += ", ";
121 }
122
123 name += "--";
124 name += *opt.long_name();
125 }
126
127 if (opt.has_value()) {
128 name += " <";
129 name += opt.value_name();
130 name += '>';
131 }
132
133 std::string_view prefix;
134 if (opt.required()) {
135 prefix = "(required) ";
136 }
137
138 print_item(out, max_size, prefix, name, opt.description());
139 }
140}
141
142template <extends_result Result>
143void help_printer_t<Result>::print_commands(std::ostream& out, const std::vector<command_t>& cmds) {
144 if (cmds.empty()) {
145 return;
146 }
147
148 std::size_t max_size = 0;
149
150 for (const auto& cmd : cmds) {
151 max_size = std::max(max_size, cmd.name().size());
152 }
153
154 out << "Commands:\n";
155
156 for (const auto& cmd : cmds) {
157 print_item(out, max_size, "", cmd.name(), cmd.description());
158 }
159}
160
161template <extends_result Result>
163 std::ostream& out,
164 std::size_t max_size,
165 std::string_view prefix,
166 std::string_view name,
167 std::string_view description
168) {
169 const std::size_t indent = 2;
170 const std::size_t name_width = indent + max_size;
171 const std::size_t desc_start = name_width + indent;
172
173 out << " " << std::left << std::setw(name_width) << name;
174 const std::size_t available_width = m_term_size - desc_start;
175
176 if (description.size() + prefix.size() <= available_width) {
177 out << prefix << description << '\n';
178 return;
179 }
180
181 std::string desc(prefix);
182 desc += description;
183
184 std::istringstream stream(desc);
185 std::string word;
186
187 std::size_t line_len = 0;
188 bool first_line = true;
189
190 while (stream >> word) {
191 if (!first_line && line_len + word.size() + 1 > available_width) {
192 out << '\n' << std::setw(desc_start) << "";
193 line_len = 0;
194 }
195
196 if (line_len > 0) {
197 out << ' ';
198 line_len += 1;
199 }
200
201 out << word;
202 line_len += word.size();
203 first_line = false;
204 }
205
206 out << '\n';
207}
208}
209
210#endif
void print_options(std::ostream &out, const std::vector< option_t > &options)
Definition help_impl.h:74
void print_item(std::ostream &out, std::size_t max_size, std::string_view prefix, std::string_view name, std::string_view description)
Definition help_impl.h:162
void print_arguments(std::ostream &out, const std::vector< argument_t > &args)
Definition help_impl.h:55
void print(std::ostream &out)
Definition help_impl.h:19
void print_commands(std::ostream &out, const std::vector< command_t > &cmds)
Definition help_impl.h:143
Definition argument.h:9