2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019, 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 "gromacs/commandline/cmdlinehelpcontext.h"
52 #include "gromacs/onlinehelp/helpwritercontext.h"
53 #include "gromacs/options/basicoptions.h"
54 #include "gromacs/options/filenameoption.h"
55 #include "gromacs/options/options.h"
56 #include "gromacs/options/optionsvisitor.h"
57 #include "gromacs/options/timeunitmanager.h"
58 #include "gromacs/utility/arrayref.h"
59 #include "gromacs/utility/exceptions.h"
60 #include "gromacs/utility/stringutil.h"
61 #include "gromacs/utility/textwriter.h"
63 #include "shellcompletions.h"
71 //! \addtogroup module_commandline
74 /********************************************************************
79 * Interface for output format specific formatting of options.
83 class IOptionsFormatter
86 virtual ~IOptionsFormatter() {}
88 //! Formats a single option option.
89 virtual void formatOption(const OptionInfo
&option
) = 0;
92 /********************************************************************
97 * Output format independent processing of options.
99 * Together with code in CommandLineHelpWriter::writeHelp(), this class
100 * implements the common logic for writing out the help.
101 * An object implementing the IOptionsFormatter must be provided to the
102 * constructor, and does the actual formatting that is specific to the output
105 class OptionsFilter
: public OptionsVisitor
108 //! Specifies the type of output that formatSelected() produces.
111 eSelectInputFileOptions
,
112 eSelectInputOutputFileOptions
,
113 eSelectOutputFileOptions
,
118 * Creates a new filtering object.
123 : formatter_(nullptr), filterType_(eSelectOtherOptions
),
128 //! Sets whether hidden options will be shown.
129 void setShowHidden(bool bShowHidden
)
131 bShowHidden_
= bShowHidden
;
134 //! Formats selected options using the formatter.
135 void formatSelected(FilterType type
,
136 IOptionsFormatter
*formatter
,
137 const Options
&options
);
139 void visitSection(const OptionSectionInfo
§ion
) override
;
140 void visitOption(const OptionInfo
&option
) override
;
143 IOptionsFormatter
*formatter_
;
144 FilterType filterType_
;
147 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsFilter
);
150 void OptionsFilter::formatSelected(FilterType type
,
151 IOptionsFormatter
*formatter
,
152 const Options
&options
)
154 formatter_
= formatter
;
156 visitSection(options
.rootSection());
159 void OptionsFilter::visitSection(const OptionSectionInfo
§ion
)
161 OptionsIterator
iterator(section
);
162 iterator
.acceptSections(this);
163 iterator
.acceptOptions(this);
166 void OptionsFilter::visitOption(const OptionInfo
&option
)
168 if (!bShowHidden_
&& option
.isHidden())
172 const FileNameOptionInfo
*const fileOption
= option
.toType
<FileNameOptionInfo
>();
173 if (fileOption
!= nullptr && fileOption
->isInputFile())
175 if (filterType_
== eSelectInputFileOptions
)
177 formatter_
->formatOption(option
);
181 if (fileOption
!= nullptr && fileOption
->isInputOutputFile())
183 if (filterType_
== eSelectInputOutputFileOptions
)
185 formatter_
->formatOption(option
);
189 if (fileOption
!= nullptr && fileOption
->isOutputFile())
191 if (filterType_
== eSelectOutputFileOptions
)
193 formatter_
->formatOption(option
);
197 if (filterType_
== eSelectOtherOptions
)
199 formatter_
->formatOption(option
);
204 /********************************************************************
205 * CommonFormatterData
208 class CommonFormatterData
211 explicit CommonFormatterData(const char *timeUnit
)
216 const char *timeUnit
;
219 /********************************************************************
223 //! Formats option name and value.
224 void formatOptionNameAndValue(const OptionInfo
&option
, std::string
*name
,
227 *name
= option
.name();
228 *value
= "<" + option
.type() + ">";
229 if (option
.isType
<FileNameOptionInfo
>())
231 // TODO: Make these work also for other option types.
232 if (option
.maxValueCount() != 1)
236 if (option
.minValueCount() == 0)
238 *value
= "[" + *value
+ "]";
241 if (option
.isType
<BooleanOptionInfo
>())
243 *name
= "[no]" + *name
;
244 // Old command-line parser doesn't accept any values for these.
245 // value = "[" + value + "]";
250 //! Formats the default option value as a string.
251 std::string
defaultOptionValue(const OptionInfo
&option
)
253 return joinStrings(option
.defaultValuesAsStrings(), " ");
256 //! Formats the flags for a file option as a string.
258 fileOptionFlagsAsString(const FileNameOptionInfo
&option
, bool bAbbrev
)
261 if (!option
.isRequired())
263 type
= bAbbrev
? "Opt." : "Optional";
265 if (option
.isLibraryFile())
271 type
.append(bAbbrev
? "Lib." : "Library");
276 //! Formats the description for an option as a string.
278 descriptionWithOptionDetails(const CommonFormatterData
&common
,
279 const OptionInfo
&option
)
281 std::string
description(option
.formatDescription());
283 const FloatOptionInfo
*floatOption
= option
.toType
<FloatOptionInfo
>();
284 const DoubleOptionInfo
*doubleOption
= option
.toType
<DoubleOptionInfo
>();
285 if ((floatOption
!= nullptr && floatOption
->isTime())
286 || (doubleOption
!= nullptr && doubleOption
->isTime()))
288 // TODO: It could be nicer to have this in basicoptions.cpp.
289 description
= replaceAll(description
, "%t", common
.timeUnit
);
295 /********************************************************************
296 * OptionsSynopsisFormatter
300 * Formatter implementation for synopsis.
302 class SynopsisFormatter
: public IOptionsFormatter
305 //! Creates a helper object for formatting the synopsis.
306 explicit SynopsisFormatter(const HelpWriterContext
&context
)
307 : context_(context
), bFormatted_(false), lineLength_(0), indent_(0),
312 //! Starts formatting the synopsis.
313 void start(const char *name
);
314 //! Finishes formatting the synopsis.
317 void formatOption(const OptionInfo
&option
) override
;
320 const HelpWriterContext
&context_
;
326 GMX_DISALLOW_COPY_AND_ASSIGN(SynopsisFormatter
);
329 void SynopsisFormatter::start(const char *name
)
331 currentLength_
= std::strlen(name
) + 1;
332 indent_
= std::min(currentLength_
, 13);
333 TextWriter
&file
= context_
.outputFile();
334 switch (context_
.outputFormat())
336 case eHelpOutputFormat_Console
:
338 file
.writeString(name
);
340 case eHelpOutputFormat_Rst
:
344 file
.writeLine(".. parsed-literal::");
346 file
.writeString(" ");
347 file
.writeString(name
);
350 GMX_THROW(NotImplementedError("Synopsis formatting not implemented for this output format"));
354 void SynopsisFormatter::finish()
356 context_
.outputFile().ensureLineBreak();
359 void SynopsisFormatter::formatOption(const OptionInfo
&option
)
361 std::string name
, value
;
362 formatOptionNameAndValue(option
, &name
, &value
);
363 int totalLength
= name
.length() + 4;
364 std::string fullOptionText
365 = formatString(" [%s-%s", bFormatted_
? ":strong:`" : "", name
.c_str());
368 fullOptionText
.append(bFormatted_
? "` :emphasis:`" : " ");
369 fullOptionText
.append(value
);
370 totalLength
+= value
.length() + 1;
372 fullOptionText
.append(bFormatted_
? "`]" : "]");
374 TextWriter
&file
= context_
.outputFile();
375 currentLength_
+= totalLength
;
376 if (currentLength_
>= lineLength_
)
378 file
.writeString(formatString("\n%*c", indent_
- 1, ' '));
379 currentLength_
= indent_
- 1 + totalLength
;
381 file
.writeString(fullOptionText
);
384 /********************************************************************
385 * OptionsListFormatter
389 * Formatter implementation for help export.
391 class OptionsListFormatter
: public IOptionsFormatter
394 //! Creates a helper object for formatting options.
395 OptionsListFormatter(const HelpWriterContext
&context
,
396 const CommonFormatterData
&common
,
399 //! Initiates a new section in the options list.
400 void startSection(const char *header
)
405 //! Finishes a section in the options list.
410 context_
.writeOptionListEnd();
414 void formatOption(const OptionInfo
&option
) override
;
417 void writeSectionStartIfNecessary()
419 if (title_
!= nullptr)
421 context_
.writeTitle(title_
);
426 if (header_
!= nullptr)
428 context_
.paragraphBreak();
429 context_
.writeTextBlock(header_
);
430 context_
.paragraphBreak();
432 context_
.writeOptionListStart();
437 const HelpWriterContext
&context_
;
438 const CommonFormatterData
&common_
;
443 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsListFormatter
);
446 OptionsListFormatter::OptionsListFormatter(
447 const HelpWriterContext
&context
,
448 const CommonFormatterData
&common
,
450 : context_(context
), common_(common
),
451 title_(title
), header_(nullptr), bDidOutput_(false)
455 void OptionsListFormatter::formatOption(const OptionInfo
&option
)
457 writeSectionStartIfNecessary();
458 std::string name
, value
;
459 formatOptionNameAndValue(option
, &name
, &value
);
460 std::string
defaultValue(defaultOptionValue(option
));
462 const FileNameOptionInfo
*fileOption
= option
.toType
<FileNameOptionInfo
>();
463 if (fileOption
!= nullptr)
465 const bool bAbbrev
= (context_
.outputFormat() == eHelpOutputFormat_Console
);
466 info
= fileOptionFlagsAsString(*fileOption
, bAbbrev
);
468 std::string
description(descriptionWithOptionDetails(common_
, option
));
469 context_
.writeOptionItem("-" + name
, value
, defaultValue
, info
, description
);
476 /********************************************************************
477 * CommandLineHelpWriter::Impl
481 * Private implementation class for CommandLineHelpWriter.
483 * \ingroup module_commandline
485 class CommandLineHelpWriter::Impl
488 //! Sets the Options object to use for generating help.
489 explicit Impl(const Options
&options
)
494 //! Format the list of known issues.
495 void formatBugs(const HelpWriterContext
&context
);
497 //! Options object to use for generating help.
498 const Options
&options_
;
500 std::string helpText_
;
501 //! List of bugs/knows issues.
502 std::vector
<std::string
> bugs_
;
505 void CommandLineHelpWriter::Impl::formatBugs(const HelpWriterContext
&context
)
511 context
.writeTitle("Known Issues");
512 for (const auto &i
: bugs_
)
514 const char *const bug
= i
.c_str();
515 context
.writeTextBlock(formatString("* %s", bug
));
520 /********************************************************************
521 * CommandLineHelpWriter
524 CommandLineHelpWriter::CommandLineHelpWriter(const Options
&options
)
525 : impl_(new Impl(options
))
529 CommandLineHelpWriter::~CommandLineHelpWriter()
533 CommandLineHelpWriter
&
534 CommandLineHelpWriter::setHelpText(const std::string
&help
)
536 impl_
->helpText_
= help
;
540 CommandLineHelpWriter
&
541 CommandLineHelpWriter::setHelpText(const ArrayRef
<const char *const> &help
)
543 impl_
->helpText_
= joinStrings(help
, "\n");
547 CommandLineHelpWriter
&
548 CommandLineHelpWriter::setKnownIssues(ArrayRef
<const std::string
> bugs
)
550 impl_
->bugs_
= std::vector
<std::string
>(bugs
.begin(), bugs
.end());
554 CommandLineHelpWriter
&
555 CommandLineHelpWriter::setKnownIssues(const ArrayRef
<const char *const> &bugs
)
557 impl_
->bugs_
= std::vector
<std::string
>(bugs
.begin(), bugs
.end());
561 void CommandLineHelpWriter::writeHelp(const CommandLineHelpContext
&context
)
563 if (context
.isCompletionExport())
565 context
.shellCompletionWriter().writeModuleCompletions(
566 context
.moduleDisplayName(), impl_
->options_
);
569 const HelpWriterContext
&writerContext
= context
.writerContext();
570 OptionsFilter filter
;
571 filter
.setShowHidden(context
.showHidden());
574 writerContext
.writeTitle("Synopsis");
575 SynopsisFormatter
synopsisFormatter(writerContext
);
576 synopsisFormatter
.start(context
.moduleDisplayName());
577 filter
.formatSelected(OptionsFilter::eSelectInputFileOptions
,
578 &synopsisFormatter
, impl_
->options_
);
579 filter
.formatSelected(OptionsFilter::eSelectInputOutputFileOptions
,
580 &synopsisFormatter
, impl_
->options_
);
581 filter
.formatSelected(OptionsFilter::eSelectOutputFileOptions
,
582 &synopsisFormatter
, impl_
->options_
);
583 filter
.formatSelected(OptionsFilter::eSelectOtherOptions
,
584 &synopsisFormatter
, impl_
->options_
);
585 synopsisFormatter
.finish();
588 if (!impl_
->helpText_
.empty())
590 writerContext
.writeTitle("Description");
591 writerContext
.writeTextBlock(impl_
->helpText_
);
593 CommonFormatterData
common(TimeUnitManager().timeUnitAsString());
594 OptionsListFormatter
formatter(writerContext
, common
, "Options");
595 formatter
.startSection("Options to specify input files:");
596 filter
.formatSelected(OptionsFilter::eSelectInputFileOptions
,
597 &formatter
, impl_
->options_
);
598 formatter
.finishSection();
599 formatter
.startSection("Options to specify input/output files:");
600 filter
.formatSelected(OptionsFilter::eSelectInputOutputFileOptions
,
601 &formatter
, impl_
->options_
);
602 formatter
.finishSection();
603 formatter
.startSection("Options to specify output files:");
604 filter
.formatSelected(OptionsFilter::eSelectOutputFileOptions
,
605 &formatter
, impl_
->options_
);
606 formatter
.finishSection();
607 formatter
.startSection("Other options:");
608 filter
.formatSelected(OptionsFilter::eSelectOtherOptions
,
609 &formatter
, impl_
->options_
);
610 formatter
.finishSection();
612 impl_
->formatBugs(writerContext
);