SeqAn3 3.4.0-rc.1
The Modern C++ library for sequence analysis.
Loading...
Searching...
No Matches
format_help.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
3// SPDX-License-Identifier: BSD-3-Clause
4
12#pragma once
13
14#include <cassert>
15#include <iostream>
16
20
21namespace seqan3::detail
22{
23
36class format_help : public format_help_base<format_help>
37{
39 using base_type = format_help_base<format_help>;
40
42 friend base_type;
43
44public:
48 format_help() = default;
49 format_help(format_help const & pf) = default;
50 format_help & operator=(format_help const &) = default;
51 format_help(format_help &&) = default;
52 format_help & operator=(format_help &&) = default;
53 ~format_help() = default;
54
56 format_help(std::vector<std::string> const & names, bool const advanced = false) : base_type{names, advanced} {};
58
59protected:
62 struct console_layout_struct
63 {
65 uint32_t screenWidth;
67 uint32_t defaultScreenWidth;
69 uint32_t maximalScreenWidth;
71 uint32_t minimalScreenWidth;
73 uint32_t leftPadding;
75 uint32_t centerPadding;
77 uint32_t rightPadding;
79 uint32_t leftColumnWidth;
81 uint32_t rightColumnWidth;
83 uint32_t rightColumnTab;
84
87 console_layout_struct(uint32_t const terminal_width) :
88 screenWidth{0},
89 defaultScreenWidth{80},
90 maximalScreenWidth{120},
91 minimalScreenWidth{40},
92 leftPadding{4},
93 centerPadding{2},
94 rightPadding{2},
95 leftColumnWidth{4},
96 rightColumnWidth{0}
97 {
98 // Guess terminal screen width and set into layout.
99 screenWidth = (terminal_width > 0) ? terminal_width : defaultScreenWidth;
100 screenWidth = std::max(screenWidth, minimalScreenWidth);
101 screenWidth = std::min(screenWidth, maximalScreenWidth);
102 screenWidth -= rightPadding;
103
104 rightColumnWidth = screenWidth - leftPadding - leftColumnWidth - centerPadding - rightPadding;
105 rightColumnTab = leftPadding + leftColumnWidth + centerPadding;
106 }
107
109 console_layout_struct() : console_layout_struct{get_terminal_width()}
110 {}
111 };
112
114 void print_header()
115 {
117
118 std::cout << meta.app_name;
119 if (!empty(meta.short_description))
120 std::cout << " - " << meta.short_description;
121
122 std::cout << "\n";
123 unsigned len =
124 text_width(meta.app_name) + (empty(meta.short_description) ? 0 : 3) + text_width(meta.short_description);
125 std::fill_n(out, len, '=');
126 std::cout << '\n';
127 }
128
132 void print_section(std::string const & title)
133 {
135 std::cout << '\n' << to_text("\\fB");
136 std::transform(title.begin(),
137 title.end(),
138 out,
139 [](unsigned char c)
140 {
141 return std::toupper(c);
142 });
143 std::cout << to_text("\\fP") << '\n';
144 prev_was_paragraph = false;
145 }
146
150 void print_subsection(std::string const & title)
151 {
153 std::cout << '\n';
154 std::fill_n(out, layout.leftPadding / 2, ' ');
155 std::cout << in_bold(title) << '\n';
156 prev_was_paragraph = false;
157 }
158
164 void print_line(std::string const & text, bool const line_is_paragraph)
165 {
166 if (prev_was_paragraph)
167 std::cout << '\n';
168
170 std::fill_n(out, layout.leftPadding, ' ');
171 print_text(text, layout.leftPadding);
172 prev_was_paragraph = line_is_paragraph;
173 }
174
189 void print_list_item(std::string const & term, std::string const & desc)
190 {
191 if (prev_was_paragraph)
192 std::cout << '\n';
193
195
196 // Print term.
197 std::fill_n(out, layout.leftPadding, ' ');
198 std::cout << to_text(term);
199 unsigned pos = layout.leftPadding + term.size();
200 if (pos + layout.centerPadding > layout.rightColumnTab)
201 {
202 std::cout << '\n';
203 pos = 0;
204 }
205 std::fill_n(out, layout.rightColumnTab - pos, ' ');
206 print_text(desc, layout.rightColumnTab);
207
208 prev_was_paragraph = false;
209 }
210
212 void print_footer()
213 {
214 // no footer
215 }
216
220 std::string to_text(std::string const & str)
221 {
222 std::string result;
223
224 for (auto it = str.begin(); it != str.end(); ++it)
225 {
226 if (*it == '\\')
227 {
228 // Handle escape sequence, we interpret only "\-", "\fI", and "\fB".
229 ++it;
230 assert(it != str.end());
231 if (*it == '-')
232 {
233 result.push_back(*it);
234 }
235 else if (*it == 'f')
236 {
237 ++it;
238 assert(it != str.end());
239 if (*it == 'I')
240 {
241 if (is_terminal())
242 result.append("\033[4m");
243 }
244 else if (*it == 'B')
245 {
246 if (is_terminal())
247 result.append("\033[1m");
248 }
249 else if (*it == 'P')
250 {
251 if (is_terminal())
252 result.append("\033[0m");
253 }
254 else
255 {
256 result.append("\\f");
257 result.push_back(*it);
258 }
259 }
260 else
261 {
262 result.push_back('\\');
263 result.push_back(*it);
264 }
265 }
266 else
267 {
268 result.push_back(*it);
269 }
270 }
271
272 return result;
273 }
274
279 unsigned text_width(std::string const & text)
280 {
281 unsigned result = 0;
282
283 for (unsigned i = 0; i < text.size(); ++i)
284 {
285 if (text[i] != '\\')
286 {
287 result += 1;
288 continue;
289 }
290
291 if (i + 1 == text.size())
292 {
293 result += 1; // Will print "\\".
294 continue;
295 }
296
297 if (text[i + 1] == '\\' || text[i + 1] == '-')
298 {
299 i += 1;
300 result += 1;
301 continue; // Will print '\\' or '-'.
302 }
303
304 if (i + 2 == text.size())
305 {
306 i += 1;
307 result += 2; // Will print two chars.
308 continue;
309 }
310
311 if (text[i + 1] == 'f')
312 {
313 if (text[i + 2] == 'B' || text[i + 2] == 'I' || text[i + 2] == 'P')
314 i += 2; // Skip f and {B, I, P}.
315 else
316 result += 1;
317 }
318 }
319
320 return result;
321 }
322
327 void print_text(std::string const & text, unsigned const tab)
328 {
329 unsigned pos = tab;
331
332 // Tokenize the text.
333 std::istringstream iss(text.c_str());
337 std::back_inserter(tokens));
338
339 // Print the text.
340 assert(pos <= tab);
341 std::fill_n(out, tab - pos, ' '); // go to tab
342
343 pos = tab;
345 for (TConstIter it = tokens.begin(); it != tokens.end(); ++it)
346 {
347 if (it == tokens.begin())
348 {
349 std::cout << to_text(*it);
350 pos += text_width(*it);
351 if (pos > layout.screenWidth)
352 {
353 std::cout << '\n';
354 std::fill_n(out, tab, ' ');
355 pos = tab;
356 }
357 }
358 else
359 {
360 if (pos + 1 + text_width(*it) > layout.screenWidth)
361 {
362 // Would go over screen with next, print current word on next line.
363 std::cout << '\n';
364 fill_n(out, tab, ' ');
365 std::cout << to_text(*it);
366 pos = tab + text_width(*it);
367 }
368 else
369 {
370 std::cout << ' ';
371 std::cout << to_text(*it);
372 pos += text_width(*it) + 1;
373 }
374 }
375 }
376 if (!empty(tokens))
377 std::cout << '\n';
378 }
379
384 std::string in_bold(std::string const & str)
385 {
386 return to_text("\\fB") + str + to_text("\\fP");
387 }
388
390 bool prev_was_paragraph{false};
391
393 friend struct ::seqan3::detail::test_accessor;
394
396 console_layout_struct layout{};
397};
398
410class format_short_help : public format_help
411{
412public:
416 void parse(argument_parser_meta_data const & parser_meta)
417 {
418 meta = parser_meta;
419
420 print_header();
421
422 if (!parser_meta.synopsis.empty())
423 print_synopsis();
424
425 print_line("Try -h or --help for more information.\n", true);
426
427 std::exit(EXIT_SUCCESS);
428 }
429};
430
442class format_version : public format_help
443{
444public:
448 void parse(argument_parser_meta_data & parser_meta)
449 {
450 meta = parser_meta;
451
452 print_header();
453 print_version();
454
455 std::exit(EXIT_SUCCESS); // program should not continue from here
456 }
457};
458
470class format_copyright : public format_help
471{
472public:
476 void parse(argument_parser_meta_data const & parser_meta)
477 {
478 meta = parser_meta;
479 debug_stream_type stream{std::cout};
480 std::string seqan_license{
481 R"(Copyright (c) 2006-2023, Knut Reinert & Freie Universität Berlin
482Copyright (c) 2016-2023, Knut Reinert & MPI für molekulare Genetik
483All rights reserved.
484
485Redistribution and use in source and binary forms, with or without
486modification, are permitted provided that the following conditions are met:
487
488 * Redistributions of source code must retain the above copyright
489 notice, this list of conditions and the following disclaimer.
490 * Redistributions in binary form must reproduce the above copyright
491 notice, this list of conditions and the following disclaimer in the
492 documentation and/or other materials provided with the distribution.
493 * Neither the name of Knut Reinert or the FU Berlin nor the names of
494 its contributors may be used to endorse or promote products derived
495 from this software without specific prior written permission.
496
497THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
498AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
499IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
500ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
501FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
502DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
503SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
504CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
505LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
506OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
507DAMAGE.)"};
508
509 stream << std::string(80, '=') << "\n"
510 << in_bold("Copyright information for " + meta.app_name + ":\n") << std::string(80, '-') << '\n';
511
512 if (!empty(meta.long_copyright))
513 {
514 stream << to_text("\\fP") << meta.long_copyright << "\n";
515 }
516 else if (!empty(meta.short_copyright))
517 {
518 stream << in_bold(meta.app_name + " full copyright information not available. "
519 + "Displaying short copyright information instead:\n")
520 << meta.short_copyright << "\n";
521 }
522 else
523 {
524 stream << to_text("\\fP") << meta.app_name << " copyright information not available.\n";
525 }
526
527 stream << std::string(80, '=') << '\n'
528 << in_bold("This program contains SeqAn code licensed under the following terms:\n")
529 << std::string(80, '-') << '\n'
530 << seqan_license << '\n';
531
532 std::exit(EXIT_SUCCESS);
533 }
534};
535
536} // namespace seqan3::detail
T append(T... args)
T back_inserter(T... args)
T begin(T... args)
T c_str(T... args)
T copy(T... args)
T empty(T... args)
T end(T... args)
T exit(T... args)
T fill_n(T... args)
Provides the format_base struct containing all helper functions that are needed in all formats.
@ advanced
Definition auxiliary.hpp:254
T max(T... args)
T min(T... args)
T parse(T... args)
T push_back(T... args)
T size(T... args)
Checks if program is run interactively and retrieves dimensions of terminal (Transferred from seqan2)...
Forward declares seqan3::detail::test_accessor.
T transform(T... args)
Hide me