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 /********************************************************************
77 * DescriptionsFormatter
80 class DescriptionsFormatter
: public OptionsVisitor
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
)
98 visitSubSection(options
);
101 context_
.outputFile().writeLine();
105 //! Formats the description for a single subsection and handles recursion.
106 virtual void visitSubSection(const Options
§ion
);
107 // This method is not used and never called.
108 virtual void visitOption(const OptionInfo
& /*option*/) {}
111 const HelpWriterContext
&context_
;
115 GMX_DISALLOW_COPY_AND_ASSIGN(DescriptionsFormatter
);
118 void DescriptionsFormatter::visitSubSection(const Options
§ion
)
120 if (!section
.description().empty())
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());
135 OptionsIterator
iterator(section
);
136 iterator
.acceptSubSections(this);
139 /********************************************************************
144 * Interface for output format specific formatting of options.
148 class IOptionsFormatter
151 virtual ~IOptionsFormatter() {}
153 //! Formats a single option option.
154 virtual void formatOption(const OptionInfo
&option
) = 0;
157 /********************************************************************
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
170 class OptionsFilter
: public OptionsVisitor
173 //! Specifies the type of output that formatSelected() produces.
176 eSelectInputFileOptions
,
177 eSelectInputOutputFileOptions
,
178 eSelectOutputFileOptions
,
183 * Creates a new filtering object.
188 : formatter_(NULL
), filterType_(eSelectOtherOptions
),
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
§ion
);
205 virtual void visitOption(const OptionInfo
&option
);
208 IOptionsFormatter
*formatter_
;
209 FilterType filterType_
;
212 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsFilter
);
215 void OptionsFilter::formatSelected(FilterType type
,
216 IOptionsFormatter
*formatter
,
217 const Options
&options
)
219 formatter_
= formatter
;
221 visitSubSection(options
);
224 void OptionsFilter::visitSubSection(const Options
§ion
)
226 OptionsIterator
iterator(section
);
227 iterator
.acceptSubSections(this);
228 iterator
.acceptOptions(this);
231 void OptionsFilter::visitOption(const OptionInfo
&option
)
233 if (!bShowHidden_
&& option
.isHidden())
237 const FileNameOptionInfo
*const fileOption
= option
.toType
<FileNameOptionInfo
>();
238 if (fileOption
!= NULL
&& fileOption
->isInputFile())
240 if (filterType_
== eSelectInputFileOptions
)
242 formatter_
->formatOption(option
);
246 if (fileOption
!= NULL
&& fileOption
->isInputOutputFile())
248 if (filterType_
== eSelectInputOutputFileOptions
)
250 formatter_
->formatOption(option
);
254 if (fileOption
!= NULL
&& fileOption
->isOutputFile())
256 if (filterType_
== eSelectOutputFileOptions
)
258 formatter_
->formatOption(option
);
262 if (filterType_
== eSelectOtherOptions
)
264 formatter_
->formatOption(option
);
269 /********************************************************************
270 * CommonFormatterData
273 class CommonFormatterData
276 explicit CommonFormatterData(const char *timeUnit
)
281 const char *timeUnit
;
284 /********************************************************************
288 //! Formats option name and value.
289 void formatOptionNameAndValue(const OptionInfo
&option
, std::string
*name
,
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)
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 + "]";
315 //! Formats the default option value as a string.
317 defaultOptionValue(const OptionInfo
&option
)
319 if (option
.valueCount() == 0
320 || (option
.valueCount() == 1 && option
.formatValue(0).empty()))
322 return option
.formatDefaultValueIfSet();
327 for (int i
= 0; i
< option
.valueCount(); ++i
)
333 result
.append(option
.formatValue(i
));
339 //! Formats the flags for a file option as a string.
341 fileOptionFlagsAsString(const FileNameOptionInfo
&option
, bool bAbbrev
)
344 if (!option
.isRequired())
346 type
= bAbbrev
? "Opt." : "Optional";
348 if (option
.isLibraryFile())
354 type
.append(bAbbrev
? "Lib." : "Library");
359 //! Formats the description for an option as a 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
);
378 /********************************************************************
379 * OptionsSynopsisFormatter
383 * Formatter implementation for synopsis.
385 class SynopsisFormatter
: public IOptionsFormatter
388 //! Creates a helper object for formatting the synopsis.
389 explicit SynopsisFormatter(const HelpWriterContext
&context
)
390 : context_(context
), bFormatted_(false), lineLength_(0), indent_(0),
395 //! Starts formatting the synopsis.
396 void start(const char *name
);
397 //! Finishes formatting the synopsis.
400 virtual void formatOption(const OptionInfo
&option
);
403 const HelpWriterContext
&context_
;
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
:
421 file
.writeString(name
);
423 case eHelpOutputFormat_Rst
:
427 file
.writeLine(".. parsed-literal::");
429 file
.writeString(" ");
430 file
.writeString(name
);
433 GMX_THROW(NotImplementedError("Synopsis formatting not implemented for this output format"));
437 void SynopsisFormatter::finish()
439 TextWriter
&file
= context_
.outputFile();
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());
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
474 * Formatter implementation for help export.
476 class OptionsListFormatter
: public IOptionsFormatter
479 //! Creates a helper object for formatting options.
480 OptionsListFormatter(const HelpWriterContext
&context
,
481 const CommonFormatterData
&common
,
484 //! Initiates a new section in the options list.
485 void startSection(const char *header
)
490 //! Finishes a section in the options list.
495 context_
.writeOptionListEnd();
496 context_
.outputFile().writeLine();
500 virtual void formatOption(const OptionInfo
&option
);
503 void writeSectionStartIfNecessary()
507 context_
.writeTitle(title_
);
514 context_
.writeTextBlock(header_
);
515 context_
.writeTextBlock("");
517 context_
.writeOptionListStart();
522 const HelpWriterContext
&context_
;
523 const CommonFormatterData
&common_
;
528 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsListFormatter
);
531 OptionsListFormatter::OptionsListFormatter(
532 const HelpWriterContext
&context
,
533 const CommonFormatterData
&common
,
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
));
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
);
561 /********************************************************************
562 * CommandLineHelpWriter::Impl
566 * Private implementation class for CommandLineHelpWriter.
568 * \ingroup module_commandline
570 class CommandLineHelpWriter::Impl
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
)
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
;
631 CommandLineHelpWriter
&
632 CommandLineHelpWriter::setTimeUnitString(const char *timeUnit
)
634 impl_
->timeUnit_
= timeUnit
;
638 CommandLineHelpWriter
&
639 CommandLineHelpWriter::setKnownIssues(const ConstArrayRef
<const char *> &bugs
)
645 void CommandLineHelpWriter::writeHelp(const CommandLineHelpContext
&context
)
647 if (context
.isCompletionExport())
649 context
.shellCompletionWriter().writeModuleCompletions(
650 context
.moduleDisplayName(), impl_
->options_
);
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
);