SeqAn3  3.0.2
The Modern C++ library for sequence analysis.
format_help.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2020, 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 #include <seqan3/version.hpp>
24 
25 namespace seqan3::detail
26 {
27 
38 class format_help : public format_help_base<format_help>
39 {
41  using base_type = format_help_base<format_help>;
42 
44  friend base_type;
45 public:
49  format_help() = default;
50  format_help(format_help const & pf) = default;
51  format_help & operator=(format_help const &) = default;
52  format_help(format_help &&) = default;
53  format_help & operator=(format_help &&) = default;
54  ~format_help() = default;
55 
57  format_help(std::vector<std::string> const & names, bool const advanced = false) : base_type{names, advanced}
58  {};
60 
61 protected:
64  struct console_layout_struct
65  {
67  uint32_t screenWidth;
69  uint32_t defaultScreenWidth;
71  uint32_t maximalScreenWidth;
73  uint32_t minimalScreenWidth;
75  uint32_t leftPadding;
77  uint32_t centerPadding;
79  uint32_t rightPadding;
81  uint32_t leftColumnWidth;
83  uint32_t rightColumnWidth;
85  uint32_t rightColumnTab;
86 
89  console_layout_struct(uint32_t const terminal_width) :
90  screenWidth{0}, defaultScreenWidth{80}, maximalScreenWidth{120}, minimalScreenWidth{40},
91  leftPadding{4}, centerPadding{2}, rightPadding{2}, leftColumnWidth{4}, rightColumnWidth{0}
92  {
93  // Guess terminal screen width and set into layout.
94  screenWidth = (terminal_width > 0) ? terminal_width : defaultScreenWidth;
95  screenWidth = std::max(screenWidth, minimalScreenWidth);
96  screenWidth = std::min(screenWidth, maximalScreenWidth);
97  screenWidth -= rightPadding;
98 
99  rightColumnWidth = screenWidth - leftPadding - leftColumnWidth - centerPadding - rightPadding;
100  rightColumnTab = leftPadding + leftColumnWidth + centerPadding;
101  }
102 
104  console_layout_struct() : console_layout_struct{get_terminal_width()} {}
105  };
106 
108  void print_header()
109  {
111 
112  std::cout << meta.app_name;
113  if (!empty(meta.short_description))
114  std::cout << " - " << meta.short_description;
115 
116  std::cout << "\n";
117  unsigned len = text_width(meta.app_name) + (empty(meta.short_description) ? 0 : 3) +
118  text_width(meta.short_description);
119  std::fill_n(out, len, '=');
120  std::cout << '\n';
121  }
122 
126  void print_section(std::string const & title)
127  {
129  std::cout << '\n' << to_text("\\fB");
130  std::transform(title.begin(), title.end(), out, [] (unsigned char c) { return std::toupper(c); });
131  std::cout << to_text("\\fP") << '\n';
132  prev_was_paragraph = false;
133  }
134 
138  void print_subsection(std::string const & title)
139  {
141  std::cout << '\n' << to_text("\\fB");
142  std::fill_n(out, layout.leftPadding / 2, ' ');
143  std::cout << title << to_text("\\fP") << '\n';
144  prev_was_paragraph = false;
145  }
146 
152  void print_line(std::string const & text, bool const line_is_paragraph)
153  {
154  if (prev_was_paragraph)
155  std::cout << '\n';
156 
158  std::fill_n(out, layout.leftPadding, ' ');
159  print_text(text, layout.leftPadding);
160  prev_was_paragraph = line_is_paragraph;
161  }
162 
177  void print_list_item(std::string const & term, std::string const & desc)
178  {
179  if (prev_was_paragraph)
180  std::cout << '\n';
181 
183 
184  // Print term.
185  std::fill_n(out, layout.leftPadding, ' ');
186  std::cout << to_text(term);
187  unsigned pos = layout.leftPadding + term.size();
188  if (pos + layout.centerPadding > layout.rightColumnTab)
189  {
190  std::cout << '\n';
191  pos = 0;
192  }
193  std::fill_n(out, layout.rightColumnTab - pos, ' ');
194  print_text(desc, layout.rightColumnTab);
195 
196  prev_was_paragraph = false;
197  }
198 
200  void print_version()
201  {
203 
204  // Print version, date and url.
205  std::cout << "\n" << to_text("\\fB") << "VERSION" << to_text("\\fP") << "\n";
206  std::fill_n(out, layout.leftPadding, ' ');
207  std::cout << to_text("\\fB") << "Last update: " << to_text("\\fP") << meta.date << "\n";
208  std::fill_n(out, layout.leftPadding, ' ');
209  std::cout << to_text("\\fB") << meta.app_name << " version: " << to_text("\\fP") << meta.version << "\n";
210  std::fill_n(out, layout.leftPadding, ' ');
211  std::cout << to_text("\\fB") << "SeqAn version: " << to_text("\\fP") << SEQAN3_VERSION_MAJOR << '.'
213 
214  if (!empty(meta.url))
215  {
216  std::cout << "\n" << to_text("\\fB") << "URL" << to_text("\\fP") << "\n";
217  std::fill_n(out, layout.leftPadding, ' ');
218  std::cout << meta.url << "\n";
219  }
220  std::cout << "\n";
221  }
222 
224  void print_footer()
225  {
226  print_version();
227 
229 
230  // Print legal stuff
231  if ((!empty(meta.short_copyright)) || (!empty(meta.long_copyright)) || (!empty(meta.citation)))
232  {
233  std::cout << "\n" << to_text("\\fB") << "LEGAL" << to_text("\\fP") << "\n";
234 
235  if (!empty(meta.short_copyright))
236  {
237  std::fill_n(out, layout.leftPadding, ' ');
238  std::cout << to_text("\\fB") << meta.app_name << " Copyright: "
239  << to_text("\\fP") << meta.short_copyright << "\n";
240  }
241  std::fill_n(out, layout.leftPadding, ' ');
242  std::cout << to_text("\\fB") << "SeqAn Copyright: " << to_text("\\fP")
243  << "2006-2015 Knut Reinert, FU-Berlin; released under the 3-clause BSDL.\n";
244  if (!empty(meta.citation))
245  {
246  std::fill_n(out, layout.leftPadding, ' ');
247  std::cout << to_text("\\fB") << "In your academic works please cite: " << to_text("\\fP")
248  << meta.citation << "\n";
249  }
250  if (!empty(meta.long_copyright))
251  {
252  std::fill_n(out, layout.leftPadding, ' ');
253  std::cout << "For full copyright and/or warranty information see " << to_text("\\fB")
254  << "--copyright" << to_text("\\fP") << ".\n";
255  }
256  }
257  }
258 
262  std::string to_text(std::string const & str)
263  {
264  std::string result;
265 
266  for (auto it = str.begin(); it != str.end(); ++it)
267  {
268  if (*it == '\\')
269  {
270  // Handle escape sequence, we interpret only "\-", "\fI", and "\fB".
271  ++it;
272  assert(it != str.end());
273  if (*it == '-')
274  {
275  result.push_back(*it);
276  }
277  else if (*it == 'f')
278  {
279  ++it;
280  assert(it != str.end());
281  if (*it == 'I')
282  {
283  if (is_terminal())
284  result.append("\033[4m");
285  }
286  else if (*it == 'B')
287  {
288  if (is_terminal())
289  result.append("\033[1m");
290  }
291  else if (*it == 'P')
292  {
293  if (is_terminal())
294  result.append("\033[0m");
295  }
296  else
297  {
298  result.append("\\f");
299  result.push_back(*it);
300  }
301  }
302  else
303  {
304  result.push_back('\\');
305  result.push_back(*it);
306  }
307  }
308  else
309  {
310  result.push_back(*it);
311  }
312  }
313 
314  return result;
315  }
316 
321  unsigned text_width(std::string const & text)
322  {
323  unsigned result = 0;
324 
325  for (unsigned i = 0; i < text.size(); ++i)
326  {
327  if (text[i] != '\\')
328  {
329  result += 1;
330  continue;
331  }
332 
333  if (i + 1 == text.size())
334  {
335  result += 1; // Will print "\\".
336  continue;
337  }
338 
339  if (text[i + 1] == '\\' || text[i + 1] == '-')
340  {
341  i += 1;
342  result += 1;
343  continue; // Will print '\\' or '-'.
344  }
345 
346  if (i + 2 == text.size())
347  {
348  i += 1;
349  result += 2; // Will print two chars.
350  continue;
351  }
352 
353  if (text[i + 1] == 'f')
354  {
355  if (text[i + 2] == 'B' || text[i + 2] == 'I' || text[i + 2] == 'P')
356  i += 2; // Skip f and {B, I, P}.
357  else
358  result += 1;
359  }
360  }
361 
362  return result;
363  }
364 
369  void print_text(std::string const & text, unsigned const tab)
370  {
371  unsigned pos = tab;
373 
374  // Tokenize the text.
375  std::istringstream iss(text.c_str());
378  std::cpp20::back_inserter(tokens));
379 
380  // Print the text.
381  assert(pos <= tab);
382  std::fill_n(out, tab - pos, ' '); // go to tab
383 
384  pos = tab;
385  typedef std::vector<std::string>::const_iterator TConstIter;
386  for (TConstIter it = tokens.begin(); it != tokens.end(); ++it)
387  {
388  if (it == tokens.begin())
389  {
390  std::cout << to_text(*it);
391  pos += text_width(*it);
392  if (pos > layout.screenWidth)
393  {
394  std::cout << '\n';
395  std::fill_n(out, tab, ' ');
396  pos = tab;
397  }
398  }
399  else
400  {
401  if (pos + 1 + text_width(*it) > layout.screenWidth)
402  {
403  // Would go over screen with next, print current word on next line.
404  std::cout << '\n';
405  fill_n(out, tab, ' ');
406  std::cout << to_text(*it);
407  pos = tab + text_width(*it);
408  }
409  else
410  {
411  std::cout << ' ';
412  std::cout << to_text(*it);
413  pos += text_width(*it) + 1;
414  }
415  }
416  }
417  if (!empty(tokens))
418  std::cout << '\n';
419  }
420 
422  bool prev_was_paragraph{false};
423 
425  friend struct ::seqan3::detail::test_accessor;
426 
428  console_layout_struct layout{};
429 };
430 
440 class format_short_help : public format_help
441 {
442 public:
446  void parse(argument_parser_meta_data const & parser_meta)
447  {
448  meta = parser_meta;
449 
450  print_header();
451 
452  if (!parser_meta.synopsis.empty())
453  print_synopsis();
454 
455  print_line("Try -h or --help for more information.\n", true);
456 
457  std::exit(EXIT_SUCCESS);
458  }
459 };
460 
470 class format_version : public format_help
471 {
472 public:
476  void parse(argument_parser_meta_data & parser_meta)
477  {
478  meta = parser_meta;
479 
480  print_header();
481  print_version();
482 
483  std::exit(EXIT_SUCCESS); // program should not continue from here
484  }
485 };
486 
496 class format_copyright : public format_help
497 {
498 public:
502  void parse(argument_parser_meta_data const & parser_meta)
503  {
504  meta = parser_meta;
505  debug_stream_type stream{std::cout};
506  std::string seqan_license{
507 R"(Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
508 Copyright (c) 2016-2020, Knut Reinert & MPI für molekulare Genetik
509 All rights reserved.
510 
511 Redistribution and use in source and binary forms, with or without
512 modification, are permitted provided that the following conditions are met:
513 
514  * Redistributions of source code must retain the above copyright
515  notice, this list of conditions and the following disclaimer.
516  * Redistributions in binary form must reproduce the above copyright
517  notice, this list of conditions and the following disclaimer in the
518  documentation and/or other materials provided with the distribution.
519  * Neither the name of Knut Reinert or the FU Berlin nor the names of
520  its contributors may be used to endorse or promote products derived
521  from this software without specific prior written permission.
522 
523 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
524 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
525 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
526 ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
527 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
528 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
529 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
530 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
531 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
532 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
533 DAMAGE.)"};
534 
535  stream << std::string(80, '=') << to_text("\n\\fB") << "Copyright information for "
536  << meta.app_name << ":\n" << to_text("\\fP") << std::string(80, '-') << '\n';
537 
538  if (!empty(meta.long_copyright))
539  {
540  stream << to_text("\\fP") << meta.long_copyright << "\n";
541  }
542  else if (!empty(meta.short_copyright))
543  {
544  stream << to_text("\\fP") << meta.app_name << " full copyright information not available. Displaying"
545  << " short copyright information instead:\n" << to_text("\\fP") << meta.short_copyright << "\n";
546  }
547  else
548  {
549  stream << to_text("\\fP") << meta.app_name << " copyright information not available.\n";
550  }
551 
552  stream << std::string(80, '=') << to_text("\n\\fB")
553  << "This program contains SeqAn code licensed under the following terms:\n" << to_text("\\fP")
554  << std::string(80, '-') << '\n' << seqan_license << '\n';
555 
556  std::exit(EXIT_SUCCESS);
557  }
558 };
559 
560 } // namespace seqan3::detail
std::string
std::vector< std::string >
std::string::size
T size(T... args)
SEQAN3_VERSION_MINOR
#define SEQAN3_VERSION_MINOR
The minor version as MACRO.
Definition: version.hpp:22
std::istringstream
version.hpp
Provides SeqAn version macros and global variables.
iostream
terminal.hpp
Checks if program is run interactively and retrieves dimensions of terminal (Transferred from seqan2)...
std::string::push_back
T push_back(T... args)
std::cout
std::string::c_str
T c_str(T... args)
std::transform
T transform(T... args)
std::string::append
T append(T... args)
std::min
T min(T... args)
format_base.hpp
Provides the format_base struct containing all helper functions that are needed in all formats.
std::ostream_iterator
SEQAN3_VERSION_MAJOR
#define SEQAN3_VERSION_MAJOR
The major version as MACRO.
Definition: version.hpp:20
std::istream_iterator
std::string::begin
T begin(T... args)
cassert
std::empty
T empty(T... args)
SEQAN3_VERSION_PATCH
#define SEQAN3_VERSION_PATCH
The patch version as MACRO.
Definition: version.hpp:24
std::string::end
T end(T... args)
std::max
T max(T... args)
std::fill_n
T fill_n(T... args)
std::exit
T exit(T... args)
test_accessor.hpp
Forward declares seqan3::detail::test_accessor.