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/exceptions.h"
61 #include "gromacs/utility/file.h"
62 #include "gromacs/utility/stringutil.h"
70 //! \addtogroup module_commandline
73 /********************************************************************
74 * DescriptionsFormatter
77 class DescriptionsFormatter : public OptionsVisitor
81 * Creates a new description formatter.
83 * \param[in] context Help context to use to write the help.
85 explicit DescriptionsFormatter(const HelpWriterContext &context)
86 : context_(context), title_(NULL), bDidOutput_(false)
90 //! Formats all section descriptions from a given options.
91 void format(const Options &options, const char *title)
95 visitSubSection(options);
98 context_.outputFile().writeLine();
102 //! Formats the description for a single subsection and handles recursion.
103 virtual void visitSubSection(const Options §ion);
104 // This method is not used and never called.
105 virtual void visitOption(const OptionInfo & /*option*/) {}
108 const HelpWriterContext &context_;
112 GMX_DISALLOW_COPY_AND_ASSIGN(DescriptionsFormatter);
115 void DescriptionsFormatter::visitSubSection(const Options §ion)
117 if (!section.description().empty())
121 context_.outputFile().writeLine();
123 else if (title_ != NULL)
125 context_.writeTitle(title_);
127 // TODO: Print title for the section?
128 context_.writeTextBlock(section.description());
132 OptionsIterator iterator(section);
133 iterator.acceptSubSections(this);
136 /********************************************************************
137 * OptionsFormatterInterface
141 * Interface for output format specific formatting of options.
145 class OptionsFormatterInterface
148 virtual ~OptionsFormatterInterface() {}
150 //! Formats a single option option.
151 virtual void formatOption(const OptionInfo &option) = 0;
154 /********************************************************************
159 * Output format independent processing of options.
161 * Together with code in CommandLineHelpWriter::writeHelp(), this class
162 * implements the common logic for writing out the help.
163 * An object implementing the OptionsFormatterInterface must be provided to the
164 * constructor, and does the actual formatting that is specific to the output
167 class OptionsFilter : public OptionsVisitor
170 //! Specifies the type of output that formatSelected() produces.
178 * Creates a new filtering object.
183 : formatter_(NULL), filterType_(eSelectOtherOptions),
188 //! Sets whether hidden options will be shown.
189 void setShowHidden(bool bShowHidden)
191 bShowHidden_ = bShowHidden;
194 //! Formats selected options using the formatter.
195 void formatSelected(FilterType type,
196 OptionsFormatterInterface *formatter,
197 const Options &options);
199 virtual void visitSubSection(const Options §ion);
200 virtual void visitOption(const OptionInfo &option);
203 OptionsFormatterInterface *formatter_;
204 FilterType filterType_;
207 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsFilter);
210 void OptionsFilter::formatSelected(FilterType type,
211 OptionsFormatterInterface *formatter,
212 const Options &options)
214 formatter_ = formatter;
216 visitSubSection(options);
219 void OptionsFilter::visitSubSection(const Options §ion)
221 OptionsIterator iterator(section);
222 iterator.acceptSubSections(this);
223 iterator.acceptOptions(this);
226 void OptionsFilter::visitOption(const OptionInfo &option)
228 if (!bShowHidden_ && option.isHidden())
232 if (option.isType<FileNameOptionInfo>())
234 if (filterType_ == eSelectFileOptions)
236 formatter_->formatOption(option);
240 if (filterType_ == eSelectOtherOptions)
242 formatter_->formatOption(option);
247 /********************************************************************
248 * CommonFormatterData
251 class CommonFormatterData
254 explicit CommonFormatterData(const char *timeUnit)
259 const char *timeUnit;
262 /********************************************************************
266 //! Formats option name and value.
267 void formatOptionNameAndValue(const OptionInfo &option, std::string *name,
270 *name = option.name();
271 *value = "<" + option.type() + ">";
272 if (option.isType<FileNameOptionInfo>())
274 // TODO: Make these work also for other option types.
275 if (option.maxValueCount() != 1)
279 if (option.minValueCount() == 0)
281 *value = "[" + *value + "]";
284 if (option.isType<BooleanOptionInfo>())
286 *name = "[no]" + *name;
287 // Old command-line parser doesn't accept any values for these.
288 // value = "[" + value + "]";
293 //! Formats the default option value as a string.
295 defaultOptionValue(const OptionInfo &option)
297 if (option.valueCount() == 0
298 || (option.valueCount() == 1 && option.formatValue(0).empty()))
300 return option.formatDefaultValueIfSet();
305 for (int i = 0; i < option.valueCount(); ++i)
311 result.append(option.formatValue(i));
317 //! Formats the flags for a file option as a string.
319 fileOptionFlagsAsString(const FileNameOptionInfo &option, bool bAbbrev)
322 if (option.isInputOutputFile())
324 type = bAbbrev ? "In/Out" : "Input/Output";
326 else if (option.isInputFile())
330 else if (option.isOutputFile())
334 if (!option.isRequired())
336 type += bAbbrev ? ", Opt." : ", Optional";
338 if (option.isLibraryFile())
340 type += bAbbrev ? ", Lib." : ", Library";
345 //! Formats the description for an option as a string.
347 descriptionWithOptionDetails(const CommonFormatterData &common,
348 const OptionInfo &option)
350 std::string description(option.formatDescription());
352 const FloatOptionInfo *floatOption = option.toType<FloatOptionInfo>();
353 const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
354 if ((floatOption != NULL && floatOption->isTime())
355 || (doubleOption != NULL && doubleOption->isTime()))
357 // TODO: It could be nicer to have this in basicoptions.cpp.
358 description = replaceAll(description, "%t", common.timeUnit);
364 /********************************************************************
365 * OptionsSynopsisFormatter
369 * Formatter implementation for synopsis.
371 class SynopsisFormatter : public OptionsFormatterInterface
374 //! Creates a helper object for formatting the synopsis.
375 explicit SynopsisFormatter(const HelpWriterContext &context)
376 : context_(context), lineLength_(0), indent_(0), currentLength_(0)
380 //! Starts formatting the synopsis.
381 void start(const char *name);
382 //! Finishes formatting the synopsis.
385 virtual void formatOption(const OptionInfo &option);
388 const HelpWriterContext &context_;
393 GMX_DISALLOW_COPY_AND_ASSIGN(SynopsisFormatter);
396 void SynopsisFormatter::start(const char *name)
398 currentLength_ = std::strlen(name) + 1;
399 indent_ = std::min(currentLength_, 13);
400 File &file = context_.outputFile();
401 switch (context_.outputFormat())
403 case eHelpOutputFormat_Console:
405 file.writeString(name);
407 case eHelpOutputFormat_Man:
409 file.writeString(name);
411 case eHelpOutputFormat_Html:
413 file.writeLine("<pre>");
414 file.writeString(name);
417 GMX_THROW(NotImplementedError("Synopsis formatting not implemented for this output format"));
421 void SynopsisFormatter::finish()
423 File &file = context_.outputFile();
425 if (context_.outputFormat() == eHelpOutputFormat_Html)
427 file.writeLine("</pre>");
432 void SynopsisFormatter::formatOption(const OptionInfo &option)
434 std::string name, value;
435 formatOptionNameAndValue(option, &name, &value);
436 std::string fullOptionText(" [-" + name);
439 fullOptionText.append(" ");
440 fullOptionText.append(value);
442 fullOptionText.append("]");
443 const int totalLength = fullOptionText.size();
445 if (context_.outputFormat() == eHelpOutputFormat_Html)
447 value = replaceAll(value, "<", "<");
448 value = replaceAll(value, ">", ">");
451 File &file = context_.outputFile();
452 currentLength_ += totalLength;
453 if (currentLength_ >= lineLength_)
455 file.writeString(formatString("\n%*c", indent_ - 1, ' '));
456 currentLength_ = indent_ - 1 + totalLength;
458 file.writeString(fullOptionText);
461 /********************************************************************
462 * OptionsListFormatter
466 * Formatter implementation for help export.
468 class OptionsListFormatter : public OptionsFormatterInterface
471 //! Creates a helper object for formatting options.
472 OptionsListFormatter(const HelpWriterContext &context,
473 const CommonFormatterData &common,
476 //! Initiates a new section in the options list.
477 void startSection(const char *title)
482 //! Finishes a section in the options list.
487 context_.writeOptionListEnd();
488 context_.outputFile().writeLine();
492 virtual void formatOption(const OptionInfo &option);
495 void writeSectionStartIfNecessary()
501 context_.writeTitle(title_);
503 context_.writeOptionListStart();
508 const HelpWriterContext &context_;
509 const CommonFormatterData &common_;
510 boost::scoped_ptr<TextTableFormatter> consoleFormatter_;
514 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsListFormatter);
517 OptionsListFormatter::OptionsListFormatter(
518 const HelpWriterContext &context,
519 const CommonFormatterData &common,
521 : context_(context), common_(common), title_(NULL), bDidOutput_(false)
525 consoleFormatter_.reset(new TextTableFormatter());
526 consoleFormatter_->setFirstColumnIndent(1);
527 consoleFormatter_->setFoldLastColumnToNextLine(4);
528 consoleFormatter_->addColumn(NULL, 6, false);
529 consoleFormatter_->addColumn(NULL, 8, false);
530 consoleFormatter_->addColumn(NULL, 10, false);
531 consoleFormatter_->addColumn(NULL, 50, true);
535 void OptionsListFormatter::formatOption(const OptionInfo &option)
537 writeSectionStartIfNecessary();
538 std::string name, value;
539 formatOptionNameAndValue(option, &name, &value);
540 std::string defaultValue(defaultOptionValue(option));
542 if (!defaultValue.empty())
544 info = "(" + defaultValue + ")";
546 const FileNameOptionInfo *fileOption = option.toType<FileNameOptionInfo>();
547 if (fileOption != NULL)
549 const bool bAbbrev = (context_.outputFormat() == eHelpOutputFormat_Console);
555 info.append(fileOptionFlagsAsString(*fileOption, bAbbrev));
558 std::string description(descriptionWithOptionDetails(common_, option));
559 if (context_.outputFormat() == eHelpOutputFormat_Console)
561 consoleFormatter_->clear();
562 consoleFormatter_->addColumnLine(0, "-" + name);
563 consoleFormatter_->addColumnLine(1, value);
566 consoleFormatter_->addColumnLine(2, info);
568 consoleFormatter_->addColumnHelpTextBlock(3, context_, description);
569 context_.outputFile().writeString(consoleFormatter_->formatRow());
578 context_.writeOptionItem("-" + name, value, description);
586 /********************************************************************
587 * CommandLineHelpWriter::Impl
591 * Private implementation class for CommandLineHelpWriter.
593 * \ingroup module_commandline
595 class CommandLineHelpWriter::Impl
598 //! Sets the Options object to use for generating help.
599 explicit Impl(const Options &options);
601 //! Options object to use for generating help.
602 const Options &options_;
603 //! Time unit to show in descriptions.
604 std::string timeUnit_;
605 //! Whether to write descriptions to output.
606 bool bShowDescriptions_;
609 CommandLineHelpWriter::Impl::Impl(const Options &options)
610 : options_(options), timeUnit_(TimeUnitManager().timeUnitAsString()),
611 bShowDescriptions_(false)
615 /********************************************************************
616 * CommandLineHelpWriter
619 CommandLineHelpWriter::CommandLineHelpWriter(const Options &options)
620 : impl_(new Impl(options))
624 CommandLineHelpWriter::~CommandLineHelpWriter()
628 CommandLineHelpWriter &CommandLineHelpWriter::setShowDescriptions(bool bSet)
630 impl_->bShowDescriptions_ = bSet;
634 CommandLineHelpWriter &CommandLineHelpWriter::setTimeUnitString(const char *timeUnit)
636 impl_->timeUnit_ = timeUnit;
640 void CommandLineHelpWriter::writeHelp(const CommandLineHelpContext &context)
642 if (context.isCompletionExport())
644 context.shellCompletionWriter().writeModuleCompletions(
645 context.moduleDisplayName(), impl_->options_);
648 const HelpWriterContext &writerContext = context.writerContext();
650 = (writerContext.outputFormat() == eHelpOutputFormat_Console);
651 OptionsFilter filter;
652 filter.setShowHidden(context.showHidden());
655 writerContext.writeTitle("Synopsis");
656 SynopsisFormatter synopsisFormatter(writerContext);
657 synopsisFormatter.start(context.moduleDisplayName());
658 filter.formatSelected(OptionsFilter::eSelectFileOptions,
659 &synopsisFormatter, impl_->options_);
660 filter.formatSelected(OptionsFilter::eSelectOtherOptions,
661 &synopsisFormatter, impl_->options_);
662 synopsisFormatter.finish();
665 if (impl_->bShowDescriptions_)
667 DescriptionsFormatter descriptionFormatter(writerContext);
668 descriptionFormatter.format(impl_->options_, "Description");
670 CommonFormatterData common(impl_->timeUnit_.c_str());
671 OptionsListFormatter formatter(writerContext, common, bConsole);
672 formatter.startSection("File Options");
673 filter.formatSelected(OptionsFilter::eSelectFileOptions,
674 &formatter, impl_->options_);
675 formatter.finishSection();
676 formatter.startSection("Options");
677 filter.formatSelected(OptionsFilter::eSelectOtherOptions,
678 &formatter, impl_->options_);
679 formatter.finishSection();