2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012,2013,2014, 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.
37 * Implements gmx::CommandLineHelpWriter.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_commandline
42 #include "cmdlinehelpwriter.h"
49 #include <boost/scoped_ptr.hpp>
51 #include "gromacs/commandline/cmdlinehelpcontext.h"
52 #include "gromacs/commandline/shellcompletions.h"
53 #include "gromacs/onlinehelp/helpformat.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/file.h"
63 #include "gromacs/utility/stringutil.h"
71 //! \addtogroup module_commandline
74 /********************************************************************
75 * DescriptionsFormatter
78 class DescriptionsFormatter : public OptionsVisitor
82 * Creates a new description formatter.
84 * \param[in] context Help context to use to write the help.
86 explicit DescriptionsFormatter(const HelpWriterContext &context)
87 : context_(context), title_(NULL), bDidOutput_(false)
91 //! Formats all section descriptions from a given options.
92 void format(const Options &options, const char *title)
96 visitSubSection(options);
99 context_.outputFile().writeLine();
103 //! Formats the description for a single subsection and handles recursion.
104 virtual void visitSubSection(const Options §ion);
105 // This method is not used and never called.
106 virtual void visitOption(const OptionInfo & /*option*/) {}
109 const HelpWriterContext &context_;
113 GMX_DISALLOW_COPY_AND_ASSIGN(DescriptionsFormatter);
116 void DescriptionsFormatter::visitSubSection(const Options §ion)
118 if (!section.description().empty())
122 context_.outputFile().writeLine();
124 else if (title_ != NULL)
126 context_.writeTitle(title_);
128 // TODO: Print title for the section?
129 context_.writeTextBlock(section.description());
133 OptionsIterator iterator(section);
134 iterator.acceptSubSections(this);
137 /********************************************************************
138 * OptionsFormatterInterface
142 * Interface for output format specific formatting of options.
146 class OptionsFormatterInterface
149 virtual ~OptionsFormatterInterface() {}
151 //! Formats a single option option.
152 virtual void formatOption(const OptionInfo &option) = 0;
155 /********************************************************************
160 * Output format independent processing of options.
162 * Together with code in CommandLineHelpWriter::writeHelp(), this class
163 * implements the common logic for writing out the help.
164 * An object implementing the OptionsFormatterInterface must be provided to the
165 * constructor, and does the actual formatting that is specific to the output
168 class OptionsFilter : public OptionsVisitor
171 //! Specifies the type of output that formatSelected() produces.
179 * Creates a new filtering object.
184 : formatter_(NULL), filterType_(eSelectOtherOptions),
189 //! Sets whether hidden options will be shown.
190 void setShowHidden(bool bShowHidden)
192 bShowHidden_ = bShowHidden;
195 //! Formats selected options using the formatter.
196 void formatSelected(FilterType type,
197 OptionsFormatterInterface *formatter,
198 const Options &options);
200 virtual void visitSubSection(const Options §ion);
201 virtual void visitOption(const OptionInfo &option);
204 OptionsFormatterInterface *formatter_;
205 FilterType filterType_;
208 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsFilter);
211 void OptionsFilter::formatSelected(FilterType type,
212 OptionsFormatterInterface *formatter,
213 const Options &options)
215 formatter_ = formatter;
217 visitSubSection(options);
220 void OptionsFilter::visitSubSection(const Options §ion)
222 OptionsIterator iterator(section);
223 iterator.acceptSubSections(this);
224 iterator.acceptOptions(this);
227 void OptionsFilter::visitOption(const OptionInfo &option)
229 if (!bShowHidden_ && option.isHidden())
233 if (option.isType<FileNameOptionInfo>())
235 if (filterType_ == eSelectFileOptions)
237 formatter_->formatOption(option);
241 if (filterType_ == eSelectOtherOptions)
243 formatter_->formatOption(option);
248 /********************************************************************
249 * CommonFormatterData
252 class CommonFormatterData
255 explicit CommonFormatterData(const char *timeUnit)
260 const char *timeUnit;
263 /********************************************************************
267 //! Formats option name and value.
268 void formatOptionNameAndValue(const OptionInfo &option, std::string *name,
271 *name = option.name();
272 *value = "<" + option.type() + ">";
273 if (option.isType<FileNameOptionInfo>())
275 // TODO: Make these work also for other option types.
276 if (option.maxValueCount() != 1)
280 if (option.minValueCount() == 0)
282 *value = "[" + *value + "]";
285 if (option.isType<BooleanOptionInfo>())
287 *name = "[no]" + *name;
288 // Old command-line parser doesn't accept any values for these.
289 // value = "[" + value + "]";
294 //! Formats the default option value as a string.
296 defaultOptionValue(const OptionInfo &option)
298 if (option.valueCount() == 0
299 || (option.valueCount() == 1 && option.formatValue(0).empty()))
301 return option.formatDefaultValueIfSet();
306 for (int i = 0; i < option.valueCount(); ++i)
312 result.append(option.formatValue(i));
318 //! Formats the flags for a file option as a string.
320 fileOptionFlagsAsString(const FileNameOptionInfo &option, bool bAbbrev)
323 if (option.isInputOutputFile())
325 type = bAbbrev ? "In/Out" : "Input/Output";
327 else if (option.isInputFile())
331 else if (option.isOutputFile())
335 if (!option.isRequired())
337 type += bAbbrev ? ", Opt." : ", Optional";
339 if (option.isLibraryFile())
341 type += bAbbrev ? ", Lib." : ", Library";
346 //! Formats the description for an option as a string.
348 descriptionWithOptionDetails(const CommonFormatterData &common,
349 const OptionInfo &option)
351 std::string description(option.formatDescription());
353 const FloatOptionInfo *floatOption = option.toType<FloatOptionInfo>();
354 const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
355 if ((floatOption != NULL && floatOption->isTime())
356 || (doubleOption != NULL && doubleOption->isTime()))
358 // TODO: It could be nicer to have this in basicoptions.cpp.
359 description = replaceAll(description, "%t", common.timeUnit);
365 /********************************************************************
366 * OptionsSynopsisFormatter
370 * Formatter implementation for synopsis.
372 class SynopsisFormatter : public OptionsFormatterInterface
375 //! Creates a helper object for formatting the synopsis.
376 explicit SynopsisFormatter(const HelpWriterContext &context)
377 : context_(context), lineLength_(0), indent_(0), currentLength_(0)
381 //! Starts formatting the synopsis.
382 void start(const char *name);
383 //! Finishes formatting the synopsis.
386 virtual void formatOption(const OptionInfo &option);
389 const HelpWriterContext &context_;
394 GMX_DISALLOW_COPY_AND_ASSIGN(SynopsisFormatter);
397 void SynopsisFormatter::start(const char *name)
399 currentLength_ = std::strlen(name) + 1;
400 indent_ = std::min(currentLength_, 13);
401 File &file = context_.outputFile();
402 switch (context_.outputFormat())
404 case eHelpOutputFormat_Console:
406 file.writeString(name);
408 case eHelpOutputFormat_Man:
410 file.writeString(name);
412 case eHelpOutputFormat_Html:
414 file.writeLine("<pre>");
415 file.writeString(name);
418 GMX_THROW(NotImplementedError("Synopsis formatting not implemented for this output format"));
422 void SynopsisFormatter::finish()
424 File &file = context_.outputFile();
426 if (context_.outputFormat() == eHelpOutputFormat_Html)
428 file.writeLine("</pre>");
433 void SynopsisFormatter::formatOption(const OptionInfo &option)
435 std::string name, value;
436 formatOptionNameAndValue(option, &name, &value);
437 std::string fullOptionText(" [-" + name);
440 fullOptionText.append(" ");
441 fullOptionText.append(value);
443 fullOptionText.append("]");
444 const int totalLength = fullOptionText.size();
446 if (context_.outputFormat() == eHelpOutputFormat_Html)
448 value = replaceAll(value, "<", "<");
449 value = replaceAll(value, ">", ">");
452 File &file = context_.outputFile();
453 currentLength_ += totalLength;
454 if (currentLength_ >= lineLength_)
456 file.writeString(formatString("\n%*c", indent_ - 1, ' '));
457 currentLength_ = indent_ - 1 + totalLength;
459 file.writeString(fullOptionText);
462 /********************************************************************
463 * OptionsListFormatter
467 * Formatter implementation for help export.
469 class OptionsListFormatter : public OptionsFormatterInterface
472 //! Creates a helper object for formatting options.
473 OptionsListFormatter(const HelpWriterContext &context,
474 const CommonFormatterData &common,
477 //! Initiates a new section in the options list.
478 void startSection(const char *header)
483 //! Finishes a section in the options list.
488 context_.writeOptionListEnd();
489 context_.outputFile().writeLine();
493 virtual void formatOption(const OptionInfo &option);
496 void writeSectionStartIfNecessary()
500 context_.writeTitle(title_);
507 context_.writeTextBlock(header_);
509 context_.writeOptionListStart();
514 const HelpWriterContext &context_;
515 const CommonFormatterData &common_;
516 boost::scoped_ptr<TextTableFormatter> consoleFormatter_;
521 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsListFormatter);
524 OptionsListFormatter::OptionsListFormatter(
525 const HelpWriterContext &context,
526 const CommonFormatterData &common,
528 : context_(context), common_(common),
529 title_(title), header_(NULL), bDidOutput_(false)
531 if (context.outputFormat() == eHelpOutputFormat_Console)
533 consoleFormatter_.reset(new TextTableFormatter());
534 consoleFormatter_->setFirstColumnIndent(1);
535 consoleFormatter_->setFoldLastColumnToNextLine(4);
536 consoleFormatter_->addColumn(NULL, 6, false);
537 consoleFormatter_->addColumn(NULL, 8, false);
538 consoleFormatter_->addColumn(NULL, 10, false);
539 consoleFormatter_->addColumn(NULL, 50, true);
543 void OptionsListFormatter::formatOption(const OptionInfo &option)
545 writeSectionStartIfNecessary();
546 std::string name, value;
547 formatOptionNameAndValue(option, &name, &value);
548 std::string defaultValue(defaultOptionValue(option));
550 if (!defaultValue.empty())
552 info = "(" + defaultValue + ")";
554 const FileNameOptionInfo *fileOption = option.toType<FileNameOptionInfo>();
555 if (fileOption != NULL)
557 const bool bAbbrev = (context_.outputFormat() == eHelpOutputFormat_Console);
563 info.append(fileOptionFlagsAsString(*fileOption, bAbbrev));
566 std::string description(descriptionWithOptionDetails(common_, option));
567 if (context_.outputFormat() == eHelpOutputFormat_Console)
569 consoleFormatter_->clear();
570 consoleFormatter_->addColumnLine(0, "-" + name);
571 consoleFormatter_->addColumnLine(1, value);
574 consoleFormatter_->addColumnLine(2, info);
576 consoleFormatter_->addColumnHelpTextBlock(3, context_, description);
577 context_.outputFile().writeString(consoleFormatter_->formatRow());
586 context_.writeOptionItem("-" + name, value, description);
594 /********************************************************************
595 * CommandLineHelpWriter::Impl
599 * Private implementation class for CommandLineHelpWriter.
601 * \ingroup module_commandline
603 class CommandLineHelpWriter::Impl
606 //! Sets the Options object to use for generating help.
607 explicit Impl(const Options &options);
609 //! Format the list of known issues.
610 void formatBugs(const HelpWriterContext &context);
612 //! Options object to use for generating help.
613 const Options &options_;
614 //! List of bugs/knows issues.
615 ConstArrayRef<const char *> bugs_;
616 //! Time unit to show in descriptions.
617 std::string timeUnit_;
618 //! Whether to write descriptions to output.
619 bool bShowDescriptions_;
622 CommandLineHelpWriter::Impl::Impl(const Options &options)
623 : options_(options), timeUnit_(TimeUnitManager().timeUnitAsString()),
624 bShowDescriptions_(false)
628 void CommandLineHelpWriter::Impl::formatBugs(const HelpWriterContext &context)
634 context.writeTitle("Known Issues");
635 if (context.outputFormat() != eHelpOutputFormat_Console)
637 context.writeTextBlock("[UL]");
639 ConstArrayRef<const char *>::const_iterator i;
640 for (i = bugs_.begin(); i != bugs_.end(); ++i)
642 const char *const bug = *i;
643 // TODO: The context should be able to do this also for console output, but
644 // that requires a lot more elaborate parser for the markup.
645 if (context.outputFormat() == eHelpOutputFormat_Console)
647 TextLineWrapperSettings settings;
648 settings.setIndent(2);
649 settings.setFirstLineIndent(0);
650 settings.setLineLength(78);
651 context.outputFile().writeLine(
652 context.substituteMarkupAndWrapToString(
653 settings, formatString("* %s", bug)));
657 context.writeTextBlock(formatString("[LI]%s", bug));
660 if (context.outputFormat() != eHelpOutputFormat_Console)
662 context.writeTextBlock("[ul]");
667 /********************************************************************
668 * CommandLineHelpWriter
671 CommandLineHelpWriter::CommandLineHelpWriter(const Options &options)
672 : impl_(new Impl(options))
676 CommandLineHelpWriter::~CommandLineHelpWriter()
680 CommandLineHelpWriter &
681 CommandLineHelpWriter::setShowDescriptions(bool bSet)
683 impl_->bShowDescriptions_ = bSet;
687 CommandLineHelpWriter &
688 CommandLineHelpWriter::setTimeUnitString(const char *timeUnit)
690 impl_->timeUnit_ = timeUnit;
694 CommandLineHelpWriter &
695 CommandLineHelpWriter::setKnownIssues(const ConstArrayRef<const char *> &bugs)
701 void CommandLineHelpWriter::writeHelp(const CommandLineHelpContext &context)
703 if (context.isCompletionExport())
705 context.shellCompletionWriter().writeModuleCompletions(
706 context.moduleDisplayName(), impl_->options_);
709 const HelpWriterContext &writerContext = context.writerContext();
710 OptionsFilter filter;
711 filter.setShowHidden(context.showHidden());
714 writerContext.writeTitle("Synopsis");
715 SynopsisFormatter synopsisFormatter(writerContext);
716 synopsisFormatter.start(context.moduleDisplayName());
717 filter.formatSelected(OptionsFilter::eSelectFileOptions,
718 &synopsisFormatter, impl_->options_);
719 filter.formatSelected(OptionsFilter::eSelectOtherOptions,
720 &synopsisFormatter, impl_->options_);
721 synopsisFormatter.finish();
724 if (impl_->bShowDescriptions_)
726 DescriptionsFormatter descriptionFormatter(writerContext);
727 descriptionFormatter.format(impl_->options_, "Description");
729 CommonFormatterData common(impl_->timeUnit_.c_str());
730 OptionsListFormatter formatter(writerContext, common, "Options");
731 formatter.startSection("Options to specify input and output files:[PAR]");
732 filter.formatSelected(OptionsFilter::eSelectFileOptions,
733 &formatter, impl_->options_);
734 formatter.finishSection();
735 formatter.startSection("Other options:[PAR]");
736 filter.formatSelected(OptionsFilter::eSelectOtherOptions,
737 &formatter, impl_->options_);
738 formatter.finishSection();
740 impl_->formatBugs(writerContext);