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
44 #include "cmdlinehelpwriter.h"
51 #include <boost/scoped_ptr.hpp>
53 #include "gromacs/commandline/cmdlinehelpcontext.h"
54 #include "gromacs/onlinehelp/helpformat.h"
55 #include "gromacs/onlinehelp/helpwritercontext.h"
56 #include "gromacs/options/basicoptions.h"
57 #include "gromacs/options/filenameoption.h"
58 #include "gromacs/options/options.h"
59 #include "gromacs/options/optionsvisitor.h"
60 #include "gromacs/options/timeunitmanager.h"
61 #include "gromacs/utility/arrayref.h"
62 #include "gromacs/utility/exceptions.h"
63 #include "gromacs/utility/file.h"
64 #include "gromacs/utility/stringutil.h"
66 #include "shellcompletions.h"
74 //! \addtogroup module_commandline
77 /********************************************************************
78 * DescriptionsFormatter
81 class DescriptionsFormatter : public OptionsVisitor
85 * Creates a new description formatter.
87 * \param[in] context Help context to use to write the help.
89 explicit DescriptionsFormatter(const HelpWriterContext &context)
90 : context_(context), title_(NULL), bDidOutput_(false)
94 //! Formats all section descriptions from a given options.
95 void format(const Options &options, const char *title)
99 visitSubSection(options);
102 context_.outputFile().writeLine();
106 //! Formats the description for a single subsection and handles recursion.
107 virtual void visitSubSection(const Options §ion);
108 // This method is not used and never called.
109 virtual void visitOption(const OptionInfo & /*option*/) {}
112 const HelpWriterContext &context_;
116 GMX_DISALLOW_COPY_AND_ASSIGN(DescriptionsFormatter);
119 void DescriptionsFormatter::visitSubSection(const Options §ion)
121 if (!section.description().empty())
125 context_.outputFile().writeLine();
127 else if (title_ != NULL)
129 context_.writeTitle(title_);
131 // TODO: Print title for the section?
132 context_.writeTextBlock(section.description());
136 OptionsIterator iterator(section);
137 iterator.acceptSubSections(this);
140 /********************************************************************
141 * OptionsFormatterInterface
145 * Interface for output format specific formatting of options.
149 class OptionsFormatterInterface
152 virtual ~OptionsFormatterInterface() {}
154 //! Formats a single option option.
155 virtual void formatOption(const OptionInfo &option) = 0;
158 /********************************************************************
163 * Output format independent processing of options.
165 * Together with code in CommandLineHelpWriter::writeHelp(), this class
166 * implements the common logic for writing out the help.
167 * An object implementing the OptionsFormatterInterface must be provided to the
168 * constructor, and does the actual formatting that is specific to the output
171 class OptionsFilter : public OptionsVisitor
174 //! Specifies the type of output that formatSelected() produces.
182 * Creates a new filtering object.
187 : formatter_(NULL), filterType_(eSelectOtherOptions),
192 //! Sets whether hidden options will be shown.
193 void setShowHidden(bool bShowHidden)
195 bShowHidden_ = bShowHidden;
198 //! Formats selected options using the formatter.
199 void formatSelected(FilterType type,
200 OptionsFormatterInterface *formatter,
201 const Options &options);
203 virtual void visitSubSection(const Options §ion);
204 virtual void visitOption(const OptionInfo &option);
207 OptionsFormatterInterface *formatter_;
208 FilterType filterType_;
211 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsFilter);
214 void OptionsFilter::formatSelected(FilterType type,
215 OptionsFormatterInterface *formatter,
216 const Options &options)
218 formatter_ = formatter;
220 visitSubSection(options);
223 void OptionsFilter::visitSubSection(const Options §ion)
225 OptionsIterator iterator(section);
226 iterator.acceptSubSections(this);
227 iterator.acceptOptions(this);
230 void OptionsFilter::visitOption(const OptionInfo &option)
232 if (!bShowHidden_ && option.isHidden())
236 if (option.isType<FileNameOptionInfo>())
238 if (filterType_ == eSelectFileOptions)
240 formatter_->formatOption(option);
244 if (filterType_ == eSelectOtherOptions)
246 formatter_->formatOption(option);
251 /********************************************************************
252 * CommonFormatterData
255 class CommonFormatterData
258 explicit CommonFormatterData(const char *timeUnit)
263 const char *timeUnit;
266 /********************************************************************
270 //! Formats option name and value.
271 void formatOptionNameAndValue(const OptionInfo &option, std::string *name,
274 *name = option.name();
275 *value = "<" + option.type() + ">";
276 if (option.isType<FileNameOptionInfo>())
278 // TODO: Make these work also for other option types.
279 if (option.maxValueCount() != 1)
283 if (option.minValueCount() == 0)
285 *value = "[" + *value + "]";
288 if (option.isType<BooleanOptionInfo>())
290 *name = "[no]" + *name;
291 // Old command-line parser doesn't accept any values for these.
292 // value = "[" + value + "]";
297 //! Formats the default option value as a string.
299 defaultOptionValue(const OptionInfo &option)
301 if (option.valueCount() == 0
302 || (option.valueCount() == 1 && option.formatValue(0).empty()))
304 return option.formatDefaultValueIfSet();
309 for (int i = 0; i < option.valueCount(); ++i)
315 result.append(option.formatValue(i));
321 //! Formats the flags for a file option as a string.
323 fileOptionFlagsAsString(const FileNameOptionInfo &option, bool bAbbrev)
326 if (option.isInputOutputFile())
328 type = bAbbrev ? "In/Out" : "Input/Output";
330 else if (option.isInputFile())
334 else if (option.isOutputFile())
338 if (!option.isRequired())
340 type += bAbbrev ? ", Opt." : ", Optional";
342 if (option.isLibraryFile())
344 type += bAbbrev ? ", Lib." : ", Library";
349 //! Formats the description for an option as a string.
351 descriptionWithOptionDetails(const CommonFormatterData &common,
352 const OptionInfo &option)
354 std::string description(option.formatDescription());
356 const FloatOptionInfo *floatOption = option.toType<FloatOptionInfo>();
357 const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
358 if ((floatOption != NULL && floatOption->isTime())
359 || (doubleOption != NULL && doubleOption->isTime()))
361 // TODO: It could be nicer to have this in basicoptions.cpp.
362 description = replaceAll(description, "%t", common.timeUnit);
368 /********************************************************************
369 * OptionsSynopsisFormatter
373 * Formatter implementation for synopsis.
375 class SynopsisFormatter : public OptionsFormatterInterface
378 //! Creates a helper object for formatting the synopsis.
379 explicit SynopsisFormatter(const HelpWriterContext &context)
380 : context_(context), lineLength_(0), indent_(0), currentLength_(0)
384 //! Starts formatting the synopsis.
385 void start(const char *name);
386 //! Finishes formatting the synopsis.
389 virtual void formatOption(const OptionInfo &option);
392 const HelpWriterContext &context_;
397 GMX_DISALLOW_COPY_AND_ASSIGN(SynopsisFormatter);
400 void SynopsisFormatter::start(const char *name)
402 currentLength_ = std::strlen(name) + 1;
403 indent_ = std::min(currentLength_, 13);
404 File &file = context_.outputFile();
405 switch (context_.outputFormat())
407 case eHelpOutputFormat_Console:
409 file.writeString(name);
411 case eHelpOutputFormat_Man:
413 file.writeString(name);
415 case eHelpOutputFormat_Html:
417 file.writeLine("<pre>");
418 file.writeString(name);
421 GMX_THROW(NotImplementedError("Synopsis formatting not implemented for this output format"));
425 void SynopsisFormatter::finish()
427 File &file = context_.outputFile();
429 if (context_.outputFormat() == eHelpOutputFormat_Html)
431 file.writeLine("</pre>");
436 void SynopsisFormatter::formatOption(const OptionInfo &option)
438 std::string name, value;
439 formatOptionNameAndValue(option, &name, &value);
440 std::string fullOptionText(" [-" + name);
443 fullOptionText.append(" ");
444 fullOptionText.append(value);
446 fullOptionText.append("]");
447 const int totalLength = fullOptionText.size();
449 if (context_.outputFormat() == eHelpOutputFormat_Html)
451 value = replaceAll(value, "<", "<");
452 value = replaceAll(value, ">", ">");
455 File &file = context_.outputFile();
456 currentLength_ += totalLength;
457 if (currentLength_ >= lineLength_)
459 file.writeString(formatString("\n%*c", indent_ - 1, ' '));
460 currentLength_ = indent_ - 1 + totalLength;
462 file.writeString(fullOptionText);
465 /********************************************************************
466 * OptionsListFormatter
470 * Formatter implementation for help export.
472 class OptionsListFormatter : public OptionsFormatterInterface
475 //! Creates a helper object for formatting options.
476 OptionsListFormatter(const HelpWriterContext &context,
477 const CommonFormatterData &common,
480 //! Initiates a new section in the options list.
481 void startSection(const char *header)
486 //! Finishes a section in the options list.
491 context_.writeOptionListEnd();
492 context_.outputFile().writeLine();
496 virtual void formatOption(const OptionInfo &option);
499 void writeSectionStartIfNecessary()
503 context_.writeTitle(title_);
510 context_.writeTextBlock(header_);
512 context_.writeOptionListStart();
517 const HelpWriterContext &context_;
518 const CommonFormatterData &common_;
519 boost::scoped_ptr<TextTableFormatter> consoleFormatter_;
524 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsListFormatter);
527 OptionsListFormatter::OptionsListFormatter(
528 const HelpWriterContext &context,
529 const CommonFormatterData &common,
531 : context_(context), common_(common),
532 title_(title), header_(NULL), bDidOutput_(false)
534 if (context.outputFormat() == eHelpOutputFormat_Console)
536 consoleFormatter_.reset(new TextTableFormatter());
537 consoleFormatter_->setFirstColumnIndent(1);
538 consoleFormatter_->setFoldLastColumnToNextLine(4);
539 consoleFormatter_->addColumn(NULL, 6, false);
540 consoleFormatter_->addColumn(NULL, 8, false);
541 consoleFormatter_->addColumn(NULL, 10, false);
542 consoleFormatter_->addColumn(NULL, 50, true);
546 void OptionsListFormatter::formatOption(const OptionInfo &option)
548 writeSectionStartIfNecessary();
549 std::string name, value;
550 formatOptionNameAndValue(option, &name, &value);
551 std::string defaultValue(defaultOptionValue(option));
553 if (!defaultValue.empty())
555 info = "(" + defaultValue + ")";
557 const FileNameOptionInfo *fileOption = option.toType<FileNameOptionInfo>();
558 if (fileOption != NULL)
560 const bool bAbbrev = (context_.outputFormat() == eHelpOutputFormat_Console);
566 info.append(fileOptionFlagsAsString(*fileOption, bAbbrev));
569 std::string description(descriptionWithOptionDetails(common_, option));
570 if (context_.outputFormat() == eHelpOutputFormat_Console)
572 consoleFormatter_->clear();
573 consoleFormatter_->addColumnLine(0, "-" + name);
574 consoleFormatter_->addColumnLine(1, value);
577 consoleFormatter_->addColumnLine(2, info);
579 consoleFormatter_->addColumnHelpTextBlock(3, context_, description);
580 context_.outputFile().writeString(consoleFormatter_->formatRow());
589 context_.writeOptionItem("-" + name, value, description);
597 /********************************************************************
598 * CommandLineHelpWriter::Impl
602 * Private implementation class for CommandLineHelpWriter.
604 * \ingroup module_commandline
606 class CommandLineHelpWriter::Impl
609 //! Sets the Options object to use for generating help.
610 explicit Impl(const Options &options);
612 //! Format the list of known issues.
613 void formatBugs(const HelpWriterContext &context);
615 //! Options object to use for generating help.
616 const Options &options_;
617 //! List of bugs/knows issues.
618 ConstArrayRef<const char *> bugs_;
619 //! Time unit to show in descriptions.
620 std::string timeUnit_;
621 //! Whether to write descriptions to output.
622 bool bShowDescriptions_;
625 CommandLineHelpWriter::Impl::Impl(const Options &options)
626 : options_(options), timeUnit_(TimeUnitManager().timeUnitAsString()),
627 bShowDescriptions_(false)
631 void CommandLineHelpWriter::Impl::formatBugs(const HelpWriterContext &context)
637 context.writeTitle("Known Issues");
638 if (context.outputFormat() != eHelpOutputFormat_Console)
640 context.writeTextBlock("[UL]");
642 ConstArrayRef<const char *>::const_iterator i;
643 for (i = bugs_.begin(); i != bugs_.end(); ++i)
645 const char *const bug = *i;
646 // TODO: The context should be able to do this also for console output, but
647 // that requires a lot more elaborate parser for the markup.
648 if (context.outputFormat() == eHelpOutputFormat_Console)
650 TextLineWrapperSettings settings;
651 settings.setIndent(2);
652 settings.setFirstLineIndent(0);
653 settings.setLineLength(78);
654 context.outputFile().writeLine(
655 context.substituteMarkupAndWrapToString(
656 settings, formatString("* %s", bug)));
660 context.writeTextBlock(formatString("[LI]%s", bug));
663 if (context.outputFormat() != eHelpOutputFormat_Console)
665 context.writeTextBlock("[ul]");
670 /********************************************************************
671 * CommandLineHelpWriter
674 CommandLineHelpWriter::CommandLineHelpWriter(const Options &options)
675 : impl_(new Impl(options))
679 CommandLineHelpWriter::~CommandLineHelpWriter()
683 CommandLineHelpWriter &
684 CommandLineHelpWriter::setShowDescriptions(bool bSet)
686 impl_->bShowDescriptions_ = bSet;
690 CommandLineHelpWriter &
691 CommandLineHelpWriter::setTimeUnitString(const char *timeUnit)
693 impl_->timeUnit_ = timeUnit;
697 CommandLineHelpWriter &
698 CommandLineHelpWriter::setKnownIssues(const ConstArrayRef<const char *> &bugs)
704 void CommandLineHelpWriter::writeHelp(const CommandLineHelpContext &context)
706 if (context.isCompletionExport())
708 context.shellCompletionWriter().writeModuleCompletions(
709 context.moduleDisplayName(), impl_->options_);
712 const HelpWriterContext &writerContext = context.writerContext();
713 OptionsFilter filter;
714 filter.setShowHidden(context.showHidden());
717 writerContext.writeTitle("Synopsis");
718 SynopsisFormatter synopsisFormatter(writerContext);
719 synopsisFormatter.start(context.moduleDisplayName());
720 filter.formatSelected(OptionsFilter::eSelectFileOptions,
721 &synopsisFormatter, impl_->options_);
722 filter.formatSelected(OptionsFilter::eSelectOtherOptions,
723 &synopsisFormatter, impl_->options_);
724 synopsisFormatter.finish();
727 if (impl_->bShowDescriptions_)
729 DescriptionsFormatter descriptionFormatter(writerContext);
730 descriptionFormatter.format(impl_->options_, "Description");
732 CommonFormatterData common(impl_->timeUnit_.c_str());
733 OptionsListFormatter formatter(writerContext, common, "Options");
734 formatter.startSection("Options to specify input and output files:[PAR]");
735 filter.formatSelected(OptionsFilter::eSelectFileOptions,
736 &formatter, impl_->options_);
737 formatter.finishSection();
738 formatter.startSection("Other options:[PAR]");
739 filter.formatSelected(OptionsFilter::eSelectOtherOptions,
740 &formatter, impl_->options_);
741 formatter.finishSection();
743 impl_->formatBugs(writerContext);