SeqAn3 3.2.0
The Modern C++ library for sequence analysis.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
format_help.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
3// Copyright (c) 2016-2022, Knut Reinert & MPI für molekulare Genetik
4// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6// -----------------------------------------------------------------------------------------------------
7
15#pragma once
16
17#include <cassert>
18#include <iostream>
19
23
24namespace seqan3::detail
25{
26
39class format_help : public format_help_base<format_help>
40{
42 using base_type = format_help_base<format_help>;
43
45 friend base_type;
46
47public:
51 format_help() = default;
52 format_help(format_help const & pf) = default;
53 format_help & operator=(format_help const &) = default;
54 format_help(format_help &&) = default;
55 format_help & operator=(format_help &&) = default;
56 ~format_help() = default;
57
59 format_help(std::vector<std::string> const & names, bool const advanced = false) : base_type{names, advanced} {};
61
62protected:
65 struct console_layout_struct
66 {
68 uint32_t screenWidth;
70 uint32_t defaultScreenWidth;
72 uint32_t maximalScreenWidth;
74 uint32_t minimalScreenWidth;
76 uint32_t leftPadding;
78 uint32_t centerPadding;
80 uint32_t rightPadding;
82 uint32_t leftColumnWidth;
84 uint32_t rightColumnWidth;
86 uint32_t rightColumnTab;
87
90 console_layout_struct(uint32_t const terminal_width) :
91 screenWidth{0},
92 defaultScreenWidth{80},
93 maximalScreenWidth{120},
94 minimalScreenWidth{40},
95 leftPadding{4},
96 centerPadding{2},
97 rightPadding{2},
98 leftColumnWidth{4},
99 rightColumnWidth{0}
100 {
101 // Guess terminal screen width and set into layout.
102 screenWidth = (terminal_width > 0) ? terminal_width : defaultScreenWidth;
103 screenWidth = std::max(screenWidth, minimalScreenWidth);
104 screenWidth = std::min(screenWidth, maximalScreenWidth);
105 screenWidth -= rightPadding;
106
107 rightColumnWidth = screenWidth - leftPadding - leftColumnWidth - centerPadding - rightPadding;
108 rightColumnTab = leftPadding + leftColumnWidth + centerPadding;
109 }
110
112 console_layout_struct() : console_layout_struct{get_terminal_width()}
113 {}
114 };
115
117 void print_header()
118 {
120
121 std::cout << meta.app_name;
122 if (!empty(meta.short_description))
123 std::cout << " - " << meta.short_description;
124
125 std::cout << "\n";
126 unsigned len =
127 text_width(meta.app_name) + (empty(meta.short_description) ? 0 : 3) + text_width(meta.short_description);
128 std::fill_n(out, len, '=');
129 std::cout << '\n';
130 }
131
135 void print_section(std::string const & title)
136 {
138 std::cout << '\n' << to_text("\\fB");
139 std::transform(title.begin(),
140 title.end(),
141 out,
142 [](unsigned char c)
143 {
144 return std::toupper(c);
145 });
146 std::cout << to_text("\\fP") << '\n';
147 prev_was_paragraph = false;
148 }
149
153 void print_subsection(std::string const & title)
154 {
156 std::cout << '\n';
157 std::fill_n(out, layout.leftPadding / 2, ' ');
158 std::cout << in_bold(title) << '\n';
159 prev_was_paragraph = false;
160 }
161
167 void print_line(std::string const & text, bool const line_is_paragraph)
168 {
169 if (prev_was_paragraph)
170 std::cout << '\n';
171
173 std::fill_n(out, layout.leftPadding, ' ');
174 print_text(text, layout.leftPadding);
175 prev_was_paragraph = line_is_paragraph;
176 }
177
192 void print_list_item(std::string const & term, std::string const & desc)
193 {
194 if (prev_was_paragraph)
195 std::cout << '\n';
196
198
199 // Print term.
200 std::fill_n(out, layout.leftPadding, ' ');
201 std::cout << to_text(term);
202 unsigned pos = layout.leftPadding + term.size();
203 if (pos + layout.centerPadding > layout.rightColumnTab)
204 {
205 std::cout << '\n';
206 pos = 0;
207 }
208 std::fill_n(out, layout.rightColumnTab - pos, ' ');
209 print_text(desc, layout.rightColumnTab);
210
211 prev_was_paragraph = false;
212 }
213
215 void print_footer()
216 {
217 // no footer
218 }
219
223 std::string to_text(std::string const & str)
224 {
225 std::string result;
226
227 for (auto it = str.begin(); it != str.end(); ++it)
228 {
229 if (*it == '\\')
230 {
231 // Handle escape sequence, we interpret only "\-", "\fI", and "\fB".
232 ++it;
233 assert(it != str.end());
234 if (*it == '-')
235 {
236 result.push_back(*it);
237 }
238 else if (*it == 'f')
239 {
240 ++it;
241 assert(it != str.end());
242 if (*it == 'I')
243 {
244 if (is_terminal())
245 result.append("\033[4m");
246 }
247 else if (*it == 'B')
248 {
249 if (is_terminal())
250 result.append("\033[1m");
251 }
252 else if (*it == 'P')
253 {
254 if (is_terminal())
255 result.append("\033[0m");
256 }
257 else
258 {
259 result.append("\\f");
260 result.push_back(*it);
261 }
262 }
263 else
264 {
265 result.push_back('\\');
266 result.push_back(*it);
267 }
268 }
269 else
270 {
271 result.push_back(*it);
272 }
273 }
274
275 return result;
276 }
277
282 unsigned text_width(std::string const & text)
283 {
284 unsigned result = 0;
285
286 for (unsigned i = 0; i < text.size(); ++i)
287 {
288 if (text[i] != '\\')
289 {
290 result += 1;
291 continue;
292 }
293
294 if (i + 1 == text.size())
295 {
296 result += 1; // Will print "\\".
297 continue;
298 }
299
300 if (text[i + 1] == '\\' || text[i + 1] == '-')
301 {
302 i += 1;
303 result += 1;
304 continue; // Will print '\\' or '-'.
305 }
306
307 if (i + 2 == text.size())
308 {
309 i += 1;
310 result += 2; // Will print two chars.
311 continue;
312 }
313
314 if (text[i + 1] == 'f')
315 {
316 if (text[i + 2] == 'B' || text[i + 2] == 'I' || text[i + 2] == 'P')
317 i += 2; // Skip f and {B, I, P}.
318 else
319 result += 1;
320 }
321 }
322
323 return result;
324 }
325
330 void print_text(std::string const & text, unsigned const tab)
331 {
332 unsigned pos = tab;
334
335 // Tokenize the text.
336 std::istringstream iss(text.c_str());
340 std::back_inserter(tokens));
341
342 // Print the text.
343 assert(pos <= tab);
344 std::fill_n(out, tab - pos, ' '); // go to tab
345
346 pos = tab;
348 for (TConstIter it = tokens.begin(); it != tokens.end(); ++it)
349 {
350 if (it == tokens.begin())
351 {
352 std::cout << to_text(*it);
353 pos += text_width(*it);
354 if (pos > layout.screenWidth)
355 {
356 std::cout << '\n';
357 std::fill_n(out, tab, ' ');
358 pos = tab;
359 }
360 }
361 else
362 {
363 if (pos + 1 + text_width(*it) > layout.screenWidth)
364 {
365 // Would go over screen with next, print current word on next line.
366 std::cout << '\n';
367 fill_n(out, tab, ' ');
368 std::cout << to_text(*it);
369 pos = tab + text_width(*it);
370 }
371 else
372 {
373 std::cout << ' ';
374 std::cout << to_text(*it);
375 pos += text_width(*it) + 1;
376 }
377 }
378 }
379 if (!empty(tokens))
380 std::cout << '\n';
381 }
382
387 std::string in_bold(std::string const & str)
388 {
389 return to_text("\\fB") + str + to_text("\\fP");
390 }
391
393 bool prev_was_paragraph{false};
394
396 friend struct ::seqan3::detail::test_accessor;
397
399 console_layout_struct layout{};
400};
401
413class format_short_help : public format_help
414{
415public:
419 void parse(argument_parser_meta_data const & parser_meta)
420 {
421 meta = parser_meta;
422
423 print_header();
424
425 if (!parser_meta.synopsis.empty())
426 print_synopsis();
427
428 print_line("Try -h or --help for more information.\n", true);
429
430 std::exit(EXIT_SUCCESS);
431 }
432};
433
445class format_version : public format_help
446{
447public:
451 void parse(argument_parser_meta_data & parser_meta)
452 {
453 meta = parser_meta;
454
455 print_header();
456 print_version();
457
458 std::exit(EXIT_SUCCESS); // program should not continue from here
459 }
460};
461
473class format_copyright : public format_help
474{
475public:
479 void parse(argument_parser_meta_data const & parser_meta)
480 {
481 meta = parser_meta;
482 debug_stream_type stream{std::cout};
483 std::string seqan_license{
484 R"(Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
485Copyright (c) 2016-2022, Knut Reinert & MPI für molekulare Genetik
486All rights reserved.
487
488Redistribution and use in source and binary forms, with or without
489modification, are permitted provided that the following conditions are met:
490
491 * Redistributions of source code must retain the above copyright
492 notice, this list of conditions and the following disclaimer.
493 * Redistributions in binary form must reproduce the above copyright
494 notice, this list of conditions and the following disclaimer in the
495 documentation and/or other materials provided with the distribution.
496 * Neither the name of Knut Reinert or the FU Berlin nor the names of
497 its contributors may be used to endorse or promote products derived
498 from this software without specific prior written permission.
499
500THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
501AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
502IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
503ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
504FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
505DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
506SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
507CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
508LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
509OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
510DAMAGE.)"};
511
512 stream << std::string(80, '=') << "\n"
513 << in_bold("Copyright information for " + meta.app_name + ":\n") << std::string(80, '-') << '\n';
514
515 if (!empty(meta.long_copyright))
516 {
517 stream << to_text("\\fP") << meta.long_copyright << "\n";
518 }
519 else if (!empty(meta.short_copyright))
520 {
521 stream << in_bold(meta.app_name + " full copyright information not available. "
522 + "Displaying short copyright information instead:\n")
523 << meta.short_copyright << "\n";
524 }
525 else
526 {
527 stream << to_text("\\fP") << meta.app_name << " copyright information not available.\n";
528 }
529
530 stream << std::string(80, '=') << '\n'
531 << in_bold("This program contains SeqAn code licensed under the following terms:\n")
532 << std::string(80, '-') << '\n'
533 << seqan_license << '\n';
534
535 std::exit(EXIT_SUCCESS);
536 }
537};
538
539} // 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:255
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)