SeqAn3
format_man.hpp
Go to the documentation of this file.
1 // ============================================================================
2 // SeqAn - The Library for Sequence Analysis
3 // ============================================================================
4 //
5 // Copyright (c) 2006-2018, Knut Reinert & Freie Universitaet Berlin
6 // Copyright (c) 2016-2018, Knut Reinert & MPI Molekulare Genetik
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // * Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // * Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 // * Neither the name of Knut Reinert or the FU Berlin nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
25 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 // DAMAGE.
32 //
33 // ============================================================================
34 
40 #pragma once
41 
42 #include <iostream>
43 
46 #include <seqan3/version.hpp>
47 
48 namespace seqan3::detail
49 {
50 
62 class format_man : public format_base
63 {
64 public:
74  template <typename option_t, typename validator_type>
75  void add_option(option_t & value,
76  char const short_id,
77  std::string const & long_id,
78  std::string const & desc,
79  option_spec const & spec,
80  validator_type && validator)
81  {
82  parser_set_up_calls.push_back([=, &value]()
83  {
84  if (!(spec & option_spec::HIDDEN) && (!(spec & option_spec::ADVANCED)))
85  print_list_item(prep_id_for_help(short_id, long_id) + " " + option_type_and_list_info(value),
86  (desc + " " + validator.get_help_page_message()));
87  });
88  }
89 
97  void add_flag(bool & /*value*/,
98  char const short_id,
99  std::string const & long_id,
100  std::string const & desc,
101  option_spec const & spec)
102  {
103  parser_set_up_calls.push_back([=] ()
104  {
105  if (!(spec & option_spec::HIDDEN) && (!(spec & option_spec::ADVANCED)))
106  print_list_item(prep_id_for_help(short_id, long_id), desc);
107  });
108  }
109 
117  template <typename option_t, typename validator_type>
118  void add_positional_option(option_t & value,
119  std::string const & desc,
120  validator_type && validator)
121  {
122  ++positional_option_count;
123 
124  positional_option_calls.push_back([=, &value]()
125  {
126  std::string key{"\\fBARGUMENT-" + std::to_string(positional_option_count) +
127  "\\fP " + option_type_and_list_info(value)};
128  print_list_item(key, (desc + " " + validator.get_help_page_message()));
129  });
130  }
131 
135  void parse(argument_parser_meta_data const & parser_meta)
136  {
137  print_header();
138 
139  print_section("Synopsis");
140  print_synopsis();
141 
142  if (!parser_meta.description.empty())
143  {
144  print_section("Description");
145  for (auto desc : parser_meta.description)
146  print_line(desc);
147  }
148 
149  // add positional options if specified
150  if (!positional_option_calls.empty())
151  print_section("Positional Arguments");
152 
153  // each call will evaluate the function print_list_item()
154  for (auto f : positional_option_calls)
155  f();
156 
157  // add options and flags if specified
158  if (!parser_set_up_calls.empty())
159  print_section("Options");
160 
161  // each call will evaluate the function print_list_item()
162  for (auto f : parser_set_up_calls)
163  f();
164 
165  print_footer();
166 
167  throw parser_interruption();
168  }
169 
173  void add_section(std::string const & title)
174  {
175  parser_set_up_calls.push_back([&] ()
176  {
177  print_section(title);
178  });
179  }
180 
184  void add_subsection(std::string const & title)
185  {
186  parser_set_up_calls.push_back([&] ()
187  {
188  print_subsection(title);
189  });
190  }
191 
196  void add_line(std::string const & text, bool line_is_paragraph)
197  {
198  parser_set_up_calls.push_back([&] ()
199  {
200  print_line(text, line_is_paragraph);
201  });
202  }
203 
209  void add_list_item(std::string const & key, std::string const & description)
210  {
211  parser_set_up_calls.push_back([&] ()
212  {
213  print_list_item(key, description);
214  });
215  }
216 
217 private:
219  void print_header()
220  {
221  std::ostream_iterator<char> out(std::cout);
222 
223  // Print .TH line.
224  std::cout << ".TH ";
225  std::transform(meta.app_name.begin(), meta.app_name.end(), out, [] (unsigned char c) { return std::toupper(c); });
226  std::cout << " " << std::to_string(meta.man_page_section) << " \"" << meta.date << "\" \"";
227  std::transform(meta.app_name.begin(), meta.app_name.end(), out, [] (unsigned char c) { return std::tolower(c); });
228  std::cout << " " << meta.version << "\" \"" << meta.man_page_title << "\"\n";
229 
230  // Print NAME section.
231  std::cout << ".SH NAME\n"
232  << meta.app_name << " \\- " << meta.short_description << std::endl;
233  }
234 
236  void print_synopsis()
237  {
238  for (unsigned i = 0; i < meta.synopsis.size(); ++i)
239  {
240  std::string text = "\\fB";
241  text.append(meta.app_name);
242  text.append("\\fP ");
243  text.append(meta.synopsis[i]);
244 
245  print_line(text, false);
246  }
247  }
248 
252  void print_section(std::string const & title)
253  {
254  std::ostream_iterator<char> out(std::cout);
255  std::cout << ".SH ";
256  std::transform(title.begin(), title.end(), out, [] (unsigned char c) { return std::toupper(c); });
257  std::cout << "\n";
258  is_first_in_section = true;
259  }
260 
264  void print_subsection(std::string const & title)
265  {
266  std::cout << ".SS " << title << "\n";
267  is_first_in_section = true;
268  }
269 
276  void print_line(std::string const & text, bool const line_is_paragraph)
277  {
278  if (!is_first_in_section && line_is_paragraph)
279  std::cout << ".sp\n";
280  else if (!is_first_in_section && !line_is_paragraph)
281  std::cout << ".br\n";
282 
283  std::cout << text << "\n";
284  is_first_in_section = false;
285  }
286 
290  void print_line(std::string const & text)
291  {
292  print_line(text, true);
293  }
294 
304  void print_list_item(std::string const & term, std::string const & desc)
305  {
306  std::cout << ".TP\n"
307  << term << "\n"
308  << desc << "\n";
309  is_first_in_section = false;
310  }
311 
313  void print_footer()
314  {
315  // Print legal stuff
316  if ((!empty(meta.short_copyright)) || (!empty(meta.long_copyright)) || (!empty(meta.citation)))
317  {
318  std::cout << ".SH LEGAL\n";
319 
320  if (!empty(meta.short_copyright))
321  std::cout << "\\fB" << meta.app_name << " Copyright:\\fR " << meta.short_copyright << "\n.br\n";
322 
323  std::cout << "\\fBSeqAn Copyright:\\fR 2006-2015 Knut Reinert, FU-Berlin; released under the 3-clause BSDL.\n.br\n";
324 
325  if (!empty(meta.citation))
326  std::cout << "\\fBIn your academic works please cite:\\fR " << meta.citation << "\n.br\n";
327 
328  if (!empty(meta.long_copyright))
329  std::cout << "For full copyright and/or warranty information see \\fB--copyright\\fR.\n";
330  }
331  }
332 
347  argument_parser_meta_data meta;
349  std::vector<std::function<void()>> parser_set_up_calls;
351  std::vector<std::function<void()>> positional_option_calls; // singled out to be printed on top
353  bool is_first_in_section{true};
355  unsigned positional_option_count{0};
356 };
357 
358 } // namespace seqan3
Contains the format_base struct containing all helper functions that are needed in all formats...
constexpr auto transform
A range adaptor that takes a invocable and returns a view of the elements with the invocable applied...
Definition: transform.hpp:95
Definition: auxiliary.hpp:72
Checks if program is run interactively and retrieves dimensions of terminal (Transferred from seqan2)...
Definition: aligned_sequence_concept.hpp:288
Definition: auxiliary.hpp:68
::ranges::empty empty
Alias for ranges::empty. Checks whether a range is empty.
Definition: ranges:205
option_spec
Used to further specify argument_parser options/flags.
Definition: auxiliary.hpp:60
Contains SeqAn version macros and global variables.