Change naming convention for C++ interfaces
[gromacs.git] / src / gromacs / commandline / cmdlinehelpwriter.cpp
blob69448c4bd780d8ae8a8c3d1f44ae1769f0639602
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012,2013,2014,2015, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
35 /*! \internal \file
36 * \brief
37 * Implements gmx::CommandLineHelpWriter.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_commandline
42 #include "gmxpre.h"
44 #include "cmdlinehelpwriter.h"
46 #include <cstring>
48 #include <algorithm>
49 #include <string>
51 #include <boost/scoped_ptr.hpp>
53 #include "gromacs/commandline/cmdlinehelpcontext.h"
54 #include "gromacs/onlinehelp/helpwritercontext.h"
55 #include "gromacs/options/basicoptions.h"
56 #include "gromacs/options/filenameoption.h"
57 #include "gromacs/options/options.h"
58 #include "gromacs/options/optionsvisitor.h"
59 #include "gromacs/options/timeunitmanager.h"
60 #include "gromacs/utility/arrayref.h"
61 #include "gromacs/utility/exceptions.h"
62 #include "gromacs/utility/stringutil.h"
63 #include "gromacs/utility/textwriter.h"
65 #include "shellcompletions.h"
67 namespace gmx
70 namespace
73 //! \addtogroup module_commandline
74 //! \{
76 /********************************************************************
77 * DescriptionsFormatter
80 class DescriptionsFormatter : public OptionsVisitor
82 public:
83 /*! \brief
84 * Creates a new description formatter.
86 * \param[in] context Help context to use to write the help.
88 explicit DescriptionsFormatter(const HelpWriterContext &context)
89 : context_(context), title_(NULL), bDidOutput_(false)
93 //! Formats all section descriptions from a given options.
94 void format(const Options &options, const char *title)
96 title_ = title;
97 bDidOutput_ = false;
98 visitSubSection(options);
99 if (bDidOutput_)
101 context_.outputFile().writeLine();
105 //! Formats the description for a single subsection and handles recursion.
106 virtual void visitSubSection(const Options &section);
107 // This method is not used and never called.
108 virtual void visitOption(const OptionInfo & /*option*/) {}
110 private:
111 const HelpWriterContext &context_;
112 const char *title_;
113 bool bDidOutput_;
115 GMX_DISALLOW_COPY_AND_ASSIGN(DescriptionsFormatter);
118 void DescriptionsFormatter::visitSubSection(const Options &section)
120 if (!section.description().empty())
122 if (bDidOutput_)
124 context_.outputFile().writeLine();
126 else if (title_ != NULL)
128 context_.writeTitle(title_);
130 // TODO: Print title for the section?
131 context_.writeTextBlock(section.description());
132 bDidOutput_ = true;
135 OptionsIterator iterator(section);
136 iterator.acceptSubSections(this);
139 /********************************************************************
140 * IOptionsFormatter
143 /*! \brief
144 * Interface for output format specific formatting of options.
146 * \see OptionsFilter
148 class IOptionsFormatter
150 public:
151 virtual ~IOptionsFormatter() {}
153 //! Formats a single option option.
154 virtual void formatOption(const OptionInfo &option) = 0;
157 /********************************************************************
158 * OptionsFilter
161 /*! \brief
162 * Output format independent processing of options.
164 * Together with code in CommandLineHelpWriter::writeHelp(), this class
165 * implements the common logic for writing out the help.
166 * An object implementing the IOptionsFormatter must be provided to the
167 * constructor, and does the actual formatting that is specific to the output
168 * format.
170 class OptionsFilter : public OptionsVisitor
172 public:
173 //! Specifies the type of output that formatSelected() produces.
174 enum FilterType
176 eSelectInputFileOptions,
177 eSelectInputOutputFileOptions,
178 eSelectOutputFileOptions,
179 eSelectOtherOptions
182 /*! \brief
183 * Creates a new filtering object.
185 * Does not throw.
187 OptionsFilter()
188 : formatter_(NULL), filterType_(eSelectOtherOptions),
189 bShowHidden_(false)
193 //! Sets whether hidden options will be shown.
194 void setShowHidden(bool bShowHidden)
196 bShowHidden_ = bShowHidden;
199 //! Formats selected options using the formatter.
200 void formatSelected(FilterType type,
201 IOptionsFormatter *formatter,
202 const Options &options);
204 virtual void visitSubSection(const Options &section);
205 virtual void visitOption(const OptionInfo &option);
207 private:
208 IOptionsFormatter *formatter_;
209 FilterType filterType_;
210 bool bShowHidden_;
212 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsFilter);
215 void OptionsFilter::formatSelected(FilterType type,
216 IOptionsFormatter *formatter,
217 const Options &options)
219 formatter_ = formatter;
220 filterType_ = type;
221 visitSubSection(options);
224 void OptionsFilter::visitSubSection(const Options &section)
226 OptionsIterator iterator(section);
227 iterator.acceptSubSections(this);
228 iterator.acceptOptions(this);
231 void OptionsFilter::visitOption(const OptionInfo &option)
233 if (!bShowHidden_ && option.isHidden())
235 return;
237 const FileNameOptionInfo *const fileOption = option.toType<FileNameOptionInfo>();
238 if (fileOption != NULL && fileOption->isInputFile())
240 if (filterType_ == eSelectInputFileOptions)
242 formatter_->formatOption(option);
244 return;
246 if (fileOption != NULL && fileOption->isInputOutputFile())
248 if (filterType_ == eSelectInputOutputFileOptions)
250 formatter_->formatOption(option);
252 return;
254 if (fileOption != NULL && fileOption->isOutputFile())
256 if (filterType_ == eSelectOutputFileOptions)
258 formatter_->formatOption(option);
260 return;
262 if (filterType_ == eSelectOtherOptions)
264 formatter_->formatOption(option);
265 return;
269 /********************************************************************
270 * CommonFormatterData
273 class CommonFormatterData
275 public:
276 explicit CommonFormatterData(const char *timeUnit)
277 : timeUnit(timeUnit)
281 const char *timeUnit;
284 /********************************************************************
285 * Helper functions
288 //! Formats option name and value.
289 void formatOptionNameAndValue(const OptionInfo &option, std::string *name,
290 std::string *value)
292 *name = option.name();
293 *value = "<" + option.type() + ">";
294 if (option.isType<FileNameOptionInfo>())
296 // TODO: Make these work also for other option types.
297 if (option.maxValueCount() != 1)
299 *value += " [...]";
301 if (option.minValueCount() == 0)
303 *value = "[" + *value + "]";
306 if (option.isType<BooleanOptionInfo>())
308 *name = "[no]" + *name;
309 // Old command-line parser doesn't accept any values for these.
310 // value = "[" + value + "]";
311 value->clear();
315 //! Formats the default option value as a string.
316 std::string
317 defaultOptionValue(const OptionInfo &option)
319 if (option.valueCount() == 0
320 || (option.valueCount() == 1 && option.formatValue(0).empty()))
322 return option.formatDefaultValueIfSet();
324 else
326 std::string result;
327 for (int i = 0; i < option.valueCount(); ++i)
329 if (i != 0)
331 result.append(" ");
333 result.append(option.formatValue(i));
335 return result;
339 //! Formats the flags for a file option as a string.
340 std::string
341 fileOptionFlagsAsString(const FileNameOptionInfo &option, bool bAbbrev)
343 std::string type;
344 if (!option.isRequired())
346 type = bAbbrev ? "Opt." : "Optional";
348 if (option.isLibraryFile())
350 if (!type.empty())
352 type.append(", ");
354 type.append(bAbbrev ? "Lib." : "Library");
356 return type;
359 //! Formats the description for an option as a string.
360 std::string
361 descriptionWithOptionDetails(const CommonFormatterData &common,
362 const OptionInfo &option)
364 std::string description(option.formatDescription());
366 const FloatOptionInfo *floatOption = option.toType<FloatOptionInfo>();
367 const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
368 if ((floatOption != NULL && floatOption->isTime())
369 || (doubleOption != NULL && doubleOption->isTime()))
371 // TODO: It could be nicer to have this in basicoptions.cpp.
372 description = replaceAll(description, "%t", common.timeUnit);
375 return description;
378 /********************************************************************
379 * OptionsSynopsisFormatter
382 /*! \brief
383 * Formatter implementation for synopsis.
385 class SynopsisFormatter : public IOptionsFormatter
387 public:
388 //! Creates a helper object for formatting the synopsis.
389 explicit SynopsisFormatter(const HelpWriterContext &context)
390 : context_(context), bFormatted_(false), lineLength_(0), indent_(0),
391 currentLength_(0)
395 //! Starts formatting the synopsis.
396 void start(const char *name);
397 //! Finishes formatting the synopsis.
398 void finish();
400 virtual void formatOption(const OptionInfo &option);
402 private:
403 const HelpWriterContext &context_;
404 bool bFormatted_;
405 int lineLength_;
406 int indent_;
407 int currentLength_;
409 GMX_DISALLOW_COPY_AND_ASSIGN(SynopsisFormatter);
412 void SynopsisFormatter::start(const char *name)
414 currentLength_ = std::strlen(name) + 1;
415 indent_ = std::min(currentLength_, 13);
416 TextWriter &file = context_.outputFile();
417 switch (context_.outputFormat())
419 case eHelpOutputFormat_Console:
420 lineLength_ = 78;
421 file.writeString(name);
422 break;
423 case eHelpOutputFormat_Rst:
424 bFormatted_ = true;
425 lineLength_ = 74;
426 indent_ += 4;
427 file.writeLine(".. parsed-literal::");
428 file.writeLine();
429 file.writeString(" ");
430 file.writeString(name);
431 break;
432 default:
433 GMX_THROW(NotImplementedError("Synopsis formatting not implemented for this output format"));
437 void SynopsisFormatter::finish()
439 TextWriter &file = context_.outputFile();
440 file.writeLine();
441 file.writeLine();
444 void SynopsisFormatter::formatOption(const OptionInfo &option)
446 std::string name, value;
447 formatOptionNameAndValue(option, &name, &value);
448 int totalLength = name.length() + 4;
449 std::string fullOptionText
450 = formatString(" [%s-%s", bFormatted_ ? ":strong:`" : "", name.c_str());
451 if (!value.empty())
453 fullOptionText.append(bFormatted_ ? "` :emphasis:`" : " ");
454 fullOptionText.append(value);
455 totalLength += value.length() + 1;
457 fullOptionText.append(bFormatted_ ? "`]" : "]");
459 TextWriter &file = context_.outputFile();
460 currentLength_ += totalLength;
461 if (currentLength_ >= lineLength_)
463 file.writeString(formatString("\n%*c", indent_ - 1, ' '));
464 currentLength_ = indent_ - 1 + totalLength;
466 file.writeString(fullOptionText);
469 /********************************************************************
470 * OptionsListFormatter
473 /*! \brief
474 * Formatter implementation for help export.
476 class OptionsListFormatter : public IOptionsFormatter
478 public:
479 //! Creates a helper object for formatting options.
480 OptionsListFormatter(const HelpWriterContext &context,
481 const CommonFormatterData &common,
482 const char *title);
484 //! Initiates a new section in the options list.
485 void startSection(const char *header)
487 header_ = header;
488 bDidOutput_ = false;
490 //! Finishes a section in the options list.
491 void finishSection()
493 if (bDidOutput_)
495 context_.writeOptionListEnd();
496 context_.outputFile().writeLine();
500 virtual void formatOption(const OptionInfo &option);
502 private:
503 void writeSectionStartIfNecessary()
505 if (title_ != NULL)
507 context_.writeTitle(title_);
508 title_ = NULL;
510 if (!bDidOutput_)
512 if (header_ != NULL)
514 context_.writeTextBlock(header_);
515 context_.writeTextBlock("");
517 context_.writeOptionListStart();
519 bDidOutput_ = true;
522 const HelpWriterContext &context_;
523 const CommonFormatterData &common_;
524 const char *title_;
525 const char *header_;
526 bool bDidOutput_;
528 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsListFormatter);
531 OptionsListFormatter::OptionsListFormatter(
532 const HelpWriterContext &context,
533 const CommonFormatterData &common,
534 const char *title)
535 : context_(context), common_(common),
536 title_(title), header_(NULL), bDidOutput_(false)
540 void OptionsListFormatter::formatOption(const OptionInfo &option)
542 writeSectionStartIfNecessary();
543 std::string name, value;
544 formatOptionNameAndValue(option, &name, &value);
545 std::string defaultValue(defaultOptionValue(option));
546 std::string info;
547 const FileNameOptionInfo *fileOption = option.toType<FileNameOptionInfo>();
548 if (fileOption != NULL)
550 const bool bAbbrev = (context_.outputFormat() == eHelpOutputFormat_Console);
551 info = fileOptionFlagsAsString(*fileOption, bAbbrev);
553 std::string description(descriptionWithOptionDetails(common_, option));
554 context_.writeOptionItem("-" + name, value, defaultValue, info, description);
557 //! \}
559 } // namespace
561 /********************************************************************
562 * CommandLineHelpWriter::Impl
565 /*! \internal \brief
566 * Private implementation class for CommandLineHelpWriter.
568 * \ingroup module_commandline
570 class CommandLineHelpWriter::Impl
572 public:
573 //! Sets the Options object to use for generating help.
574 explicit Impl(const Options &options);
576 //! Format the list of known issues.
577 void formatBugs(const HelpWriterContext &context);
579 //! Options object to use for generating help.
580 const Options &options_;
581 //! List of bugs/knows issues.
582 ConstArrayRef<const char *> bugs_;
583 //! Time unit to show in descriptions.
584 std::string timeUnit_;
585 //! Whether to write descriptions to output.
586 bool bShowDescriptions_;
589 CommandLineHelpWriter::Impl::Impl(const Options &options)
590 : options_(options), timeUnit_(TimeUnitManager().timeUnitAsString()),
591 bShowDescriptions_(false)
595 void CommandLineHelpWriter::Impl::formatBugs(const HelpWriterContext &context)
597 if (bugs_.empty())
599 return;
601 context.writeTitle("Known Issues");
602 ConstArrayRef<const char *>::const_iterator i;
603 for (i = bugs_.begin(); i != bugs_.end(); ++i)
605 const char *const bug = *i;
606 context.writeTextBlock(formatString("* %s", bug));
611 /********************************************************************
612 * CommandLineHelpWriter
615 CommandLineHelpWriter::CommandLineHelpWriter(const Options &options)
616 : impl_(new Impl(options))
620 CommandLineHelpWriter::~CommandLineHelpWriter()
624 CommandLineHelpWriter &
625 CommandLineHelpWriter::setShowDescriptions(bool bSet)
627 impl_->bShowDescriptions_ = bSet;
628 return *this;
631 CommandLineHelpWriter &
632 CommandLineHelpWriter::setTimeUnitString(const char *timeUnit)
634 impl_->timeUnit_ = timeUnit;
635 return *this;
638 CommandLineHelpWriter &
639 CommandLineHelpWriter::setKnownIssues(const ConstArrayRef<const char *> &bugs)
641 impl_->bugs_ = bugs;
642 return *this;
645 void CommandLineHelpWriter::writeHelp(const CommandLineHelpContext &context)
647 if (context.isCompletionExport())
649 context.shellCompletionWriter().writeModuleCompletions(
650 context.moduleDisplayName(), impl_->options_);
651 return;
653 const HelpWriterContext &writerContext = context.writerContext();
654 OptionsFilter filter;
655 filter.setShowHidden(context.showHidden());
658 writerContext.writeTitle("Synopsis");
659 SynopsisFormatter synopsisFormatter(writerContext);
660 synopsisFormatter.start(context.moduleDisplayName());
661 filter.formatSelected(OptionsFilter::eSelectInputFileOptions,
662 &synopsisFormatter, impl_->options_);
663 filter.formatSelected(OptionsFilter::eSelectInputOutputFileOptions,
664 &synopsisFormatter, impl_->options_);
665 filter.formatSelected(OptionsFilter::eSelectOutputFileOptions,
666 &synopsisFormatter, impl_->options_);
667 filter.formatSelected(OptionsFilter::eSelectOtherOptions,
668 &synopsisFormatter, impl_->options_);
669 synopsisFormatter.finish();
672 if (impl_->bShowDescriptions_)
674 DescriptionsFormatter descriptionFormatter(writerContext);
675 descriptionFormatter.format(impl_->options_, "Description");
677 CommonFormatterData common(impl_->timeUnit_.c_str());
678 OptionsListFormatter formatter(writerContext, common, "Options");
679 formatter.startSection("Options to specify input files:");
680 filter.formatSelected(OptionsFilter::eSelectInputFileOptions,
681 &formatter, impl_->options_);
682 formatter.finishSection();
683 formatter.startSection("Options to specify input/output files:");
684 filter.formatSelected(OptionsFilter::eSelectInputOutputFileOptions,
685 &formatter, impl_->options_);
686 formatter.finishSection();
687 formatter.startSection("Options to specify output files:");
688 filter.formatSelected(OptionsFilter::eSelectOutputFileOptions,
689 &formatter, impl_->options_);
690 formatter.finishSection();
691 formatter.startSection("Other options:");
692 filter.formatSelected(OptionsFilter::eSelectOtherOptions,
693 &formatter, impl_->options_);
694 formatter.finishSection();
696 impl_->formatBugs(writerContext);
699 } // namespace gmx