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.
37 * Implements gmx::CommandLineHelpWriter.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_commandline
44 #include "cmdlinehelpwriter.h"
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"
73 //! \addtogroup module_commandline
76 /********************************************************************
81 * Interface for output format specific formatting of options.
85 class IOptionsFormatter
88 virtual ~IOptionsFormatter() {}
90 //! Formats a single option option.
91 virtual void formatOption(const OptionInfo &option) = 0;
94 /********************************************************************
99 * Output format independent processing of options.
101 * Together with code in CommandLineHelpWriter::writeHelp(), this class
102 * implements the common logic for writing out the help.
103 * An object implementing the IOptionsFormatter must be provided to the
104 * constructor, and does the actual formatting that is specific to the output
107 class OptionsFilter : public OptionsVisitor
110 //! Specifies the type of output that formatSelected() produces.
113 eSelectInputFileOptions,
114 eSelectInputOutputFileOptions,
115 eSelectOutputFileOptions,
120 * Creates a new filtering object.
125 : formatter_(NULL), filterType_(eSelectOtherOptions),
130 //! Sets whether hidden options will be shown.
131 void setShowHidden(bool bShowHidden)
133 bShowHidden_ = bShowHidden;
136 //! Formats selected options using the formatter.
137 void formatSelected(FilterType type,
138 IOptionsFormatter *formatter,
139 const Options &options);
141 virtual void visitSubSection(const Options §ion);
142 virtual void visitOption(const OptionInfo &option);
145 IOptionsFormatter *formatter_;
146 FilterType filterType_;
149 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsFilter);
152 void OptionsFilter::formatSelected(FilterType type,
153 IOptionsFormatter *formatter,
154 const Options &options)
156 formatter_ = formatter;
158 visitSubSection(options);
161 void OptionsFilter::visitSubSection(const Options §ion)
163 OptionsIterator iterator(section);
164 iterator.acceptSubSections(this);
165 iterator.acceptOptions(this);
168 void OptionsFilter::visitOption(const OptionInfo &option)
170 if (!bShowHidden_ && option.isHidden())
174 const FileNameOptionInfo *const fileOption = option.toType<FileNameOptionInfo>();
175 if (fileOption != NULL && fileOption->isInputFile())
177 if (filterType_ == eSelectInputFileOptions)
179 formatter_->formatOption(option);
183 if (fileOption != NULL && fileOption->isInputOutputFile())
185 if (filterType_ == eSelectInputOutputFileOptions)
187 formatter_->formatOption(option);
191 if (fileOption != NULL && fileOption->isOutputFile())
193 if (filterType_ == eSelectOutputFileOptions)
195 formatter_->formatOption(option);
199 if (filterType_ == eSelectOtherOptions)
201 formatter_->formatOption(option);
206 /********************************************************************
207 * CommonFormatterData
210 class CommonFormatterData
213 explicit CommonFormatterData(const char *timeUnit)
218 const char *timeUnit;
221 /********************************************************************
225 //! Formats option name and value.
226 void formatOptionNameAndValue(const OptionInfo &option, std::string *name,
229 *name = option.name();
230 *value = "<" + option.type() + ">";
231 if (option.isType<FileNameOptionInfo>())
233 // TODO: Make these work also for other option types.
234 if (option.maxValueCount() != 1)
238 if (option.minValueCount() == 0)
240 *value = "[" + *value + "]";
243 if (option.isType<BooleanOptionInfo>())
245 *name = "[no]" + *name;
246 // Old command-line parser doesn't accept any values for these.
247 // value = "[" + value + "]";
252 //! Formats the default option value as a string.
254 defaultOptionValue(const OptionInfo &option)
256 if (option.valueCount() == 0
257 || (option.valueCount() == 1 && option.formatValue(0).empty()))
259 return option.formatDefaultValueIfSet();
264 for (int i = 0; i < option.valueCount(); ++i)
270 result.append(option.formatValue(i));
276 //! Formats the flags for a file option as a string.
278 fileOptionFlagsAsString(const FileNameOptionInfo &option, bool bAbbrev)
281 if (!option.isRequired())
283 type = bAbbrev ? "Opt." : "Optional";
285 if (option.isLibraryFile())
291 type.append(bAbbrev ? "Lib." : "Library");
296 //! Formats the description for an option as a string.
298 descriptionWithOptionDetails(const CommonFormatterData &common,
299 const OptionInfo &option)
301 std::string description(option.formatDescription());
303 const FloatOptionInfo *floatOption = option.toType<FloatOptionInfo>();
304 const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
305 if ((floatOption != NULL && floatOption->isTime())
306 || (doubleOption != NULL && doubleOption->isTime()))
308 // TODO: It could be nicer to have this in basicoptions.cpp.
309 description = replaceAll(description, "%t", common.timeUnit);
315 /********************************************************************
316 * OptionsSynopsisFormatter
320 * Formatter implementation for synopsis.
322 class SynopsisFormatter : public IOptionsFormatter
325 //! Creates a helper object for formatting the synopsis.
326 explicit SynopsisFormatter(const HelpWriterContext &context)
327 : context_(context), bFormatted_(false), lineLength_(0), indent_(0),
332 //! Starts formatting the synopsis.
333 void start(const char *name);
334 //! Finishes formatting the synopsis.
337 virtual void formatOption(const OptionInfo &option);
340 const HelpWriterContext &context_;
346 GMX_DISALLOW_COPY_AND_ASSIGN(SynopsisFormatter);
349 void SynopsisFormatter::start(const char *name)
351 currentLength_ = std::strlen(name) + 1;
352 indent_ = std::min(currentLength_, 13);
353 TextWriter &file = context_.outputFile();
354 switch (context_.outputFormat())
356 case eHelpOutputFormat_Console:
358 file.writeString(name);
360 case eHelpOutputFormat_Rst:
364 file.writeLine(".. parsed-literal::");
366 file.writeString(" ");
367 file.writeString(name);
370 GMX_THROW(NotImplementedError("Synopsis formatting not implemented for this output format"));
374 void SynopsisFormatter::finish()
376 TextWriter &file = context_.outputFile();
381 void SynopsisFormatter::formatOption(const OptionInfo &option)
383 std::string name, value;
384 formatOptionNameAndValue(option, &name, &value);
385 int totalLength = name.length() + 4;
386 std::string fullOptionText
387 = formatString(" [%s-%s", bFormatted_ ? ":strong:`" : "", name.c_str());
390 fullOptionText.append(bFormatted_ ? "` :emphasis:`" : " ");
391 fullOptionText.append(value);
392 totalLength += value.length() + 1;
394 fullOptionText.append(bFormatted_ ? "`]" : "]");
396 TextWriter &file = context_.outputFile();
397 currentLength_ += totalLength;
398 if (currentLength_ >= lineLength_)
400 file.writeString(formatString("\n%*c", indent_ - 1, ' '));
401 currentLength_ = indent_ - 1 + totalLength;
403 file.writeString(fullOptionText);
406 /********************************************************************
407 * OptionsListFormatter
411 * Formatter implementation for help export.
413 class OptionsListFormatter : public IOptionsFormatter
416 //! Creates a helper object for formatting options.
417 OptionsListFormatter(const HelpWriterContext &context,
418 const CommonFormatterData &common,
421 //! Initiates a new section in the options list.
422 void startSection(const char *header)
427 //! Finishes a section in the options list.
432 context_.writeOptionListEnd();
433 context_.outputFile().writeLine();
437 virtual void formatOption(const OptionInfo &option);
440 void writeSectionStartIfNecessary()
444 context_.writeTitle(title_);
451 context_.writeTextBlock(header_);
452 context_.writeTextBlock("");
454 context_.writeOptionListStart();
459 const HelpWriterContext &context_;
460 const CommonFormatterData &common_;
465 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsListFormatter);
468 OptionsListFormatter::OptionsListFormatter(
469 const HelpWriterContext &context,
470 const CommonFormatterData &common,
472 : context_(context), common_(common),
473 title_(title), header_(NULL), bDidOutput_(false)
477 void OptionsListFormatter::formatOption(const OptionInfo &option)
479 writeSectionStartIfNecessary();
480 std::string name, value;
481 formatOptionNameAndValue(option, &name, &value);
482 std::string defaultValue(defaultOptionValue(option));
484 const FileNameOptionInfo *fileOption = option.toType<FileNameOptionInfo>();
485 if (fileOption != NULL)
487 const bool bAbbrev = (context_.outputFormat() == eHelpOutputFormat_Console);
488 info = fileOptionFlagsAsString(*fileOption, bAbbrev);
490 std::string description(descriptionWithOptionDetails(common_, option));
491 context_.writeOptionItem("-" + name, value, defaultValue, info, description);
498 /********************************************************************
499 * CommandLineHelpWriter::Impl
503 * Private implementation class for CommandLineHelpWriter.
505 * \ingroup module_commandline
507 class CommandLineHelpWriter::Impl
510 //! Sets the Options object to use for generating help.
511 explicit Impl(const Options &options);
513 //! Format the list of known issues.
514 void formatBugs(const HelpWriterContext &context);
516 //! Options object to use for generating help.
517 const Options &options_;
519 std::string helpText_;
520 //! List of bugs/knows issues.
521 ConstArrayRef<const char *> bugs_;
522 //! Time unit to show in descriptions.
523 std::string timeUnit_;
526 CommandLineHelpWriter::Impl::Impl(const Options &options)
527 : options_(options), timeUnit_(TimeUnitManager().timeUnitAsString())
531 void CommandLineHelpWriter::Impl::formatBugs(const HelpWriterContext &context)
537 context.writeTitle("Known Issues");
538 ConstArrayRef<const char *>::const_iterator i;
539 for (i = bugs_.begin(); i != bugs_.end(); ++i)
541 const char *const bug = *i;
542 context.writeTextBlock(formatString("* %s", bug));
547 /********************************************************************
548 * CommandLineHelpWriter
551 CommandLineHelpWriter::CommandLineHelpWriter(const Options &options)
552 : impl_(new Impl(options))
556 CommandLineHelpWriter::~CommandLineHelpWriter()
560 CommandLineHelpWriter &
561 CommandLineHelpWriter::setTimeUnitString(const char *timeUnit)
563 impl_->timeUnit_ = timeUnit;
567 CommandLineHelpWriter &
568 CommandLineHelpWriter::setHelpText(const std::string &help)
570 impl_->helpText_ = help;
574 CommandLineHelpWriter &
575 CommandLineHelpWriter::setHelpText(const ConstArrayRef<const char *> &help)
577 impl_->helpText_ = joinStrings(help, "\n");
581 CommandLineHelpWriter &
582 CommandLineHelpWriter::setKnownIssues(const ConstArrayRef<const char *> &bugs)
588 void CommandLineHelpWriter::writeHelp(const CommandLineHelpContext &context)
590 if (context.isCompletionExport())
592 context.shellCompletionWriter().writeModuleCompletions(
593 context.moduleDisplayName(), impl_->options_);
596 const HelpWriterContext &writerContext = context.writerContext();
597 OptionsFilter filter;
598 filter.setShowHidden(context.showHidden());
601 writerContext.writeTitle("Synopsis");
602 SynopsisFormatter synopsisFormatter(writerContext);
603 synopsisFormatter.start(context.moduleDisplayName());
604 filter.formatSelected(OptionsFilter::eSelectInputFileOptions,
605 &synopsisFormatter, impl_->options_);
606 filter.formatSelected(OptionsFilter::eSelectInputOutputFileOptions,
607 &synopsisFormatter, impl_->options_);
608 filter.formatSelected(OptionsFilter::eSelectOutputFileOptions,
609 &synopsisFormatter, impl_->options_);
610 filter.formatSelected(OptionsFilter::eSelectOtherOptions,
611 &synopsisFormatter, impl_->options_);
612 synopsisFormatter.finish();
615 if (!impl_->helpText_.empty())
617 writerContext.writeTitle("Description");
618 writerContext.writeTextBlock(impl_->helpText_);
619 writerContext.outputFile().writeLine();
621 CommonFormatterData common(impl_->timeUnit_.c_str());
622 OptionsListFormatter formatter(writerContext, common, "Options");
623 formatter.startSection("Options to specify input files:");
624 filter.formatSelected(OptionsFilter::eSelectInputFileOptions,
625 &formatter, impl_->options_);
626 formatter.finishSection();
627 formatter.startSection("Options to specify input/output files:");
628 filter.formatSelected(OptionsFilter::eSelectInputOutputFileOptions,
629 &formatter, impl_->options_);
630 formatter.finishSection();
631 formatter.startSection("Options to specify output files:");
632 filter.formatSelected(OptionsFilter::eSelectOutputFileOptions,
633 &formatter, impl_->options_);
634 formatter.finishSection();
635 formatter.startSection("Other options:");
636 filter.formatSelected(OptionsFilter::eSelectOtherOptions,
637 &formatter, impl_->options_);
638 formatter.finishSection();
640 impl_->formatBugs(writerContext);