Introduce SimulatorBuilder
[gromacs.git] / src / gromacs / commandline / cmdlinehelpwriter.cpp
blob5963ed5085371793f226d2eed673ebb3e9a86c82
1 /*
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.
35 /*! \internal \file
36 * \brief
37 * Implements gmx::CommandLineHelpWriter.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_commandline
42 #include "gmxpre.h"
44 #include "cmdlinehelpwriter.h"
46 #include <cstring>
48 #include <algorithm>
49 #include <string>
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"
65 namespace gmx
68 namespace
71 //! \addtogroup module_commandline
72 //! \{
74 /********************************************************************
75 * IOptionsFormatter
78 /*! \brief
79 * Interface for output format specific formatting of options.
81 * \see OptionsFilter
83 class IOptionsFormatter
85 public:
86 virtual ~IOptionsFormatter() {}
88 //! Formats a single option option.
89 virtual void formatOption(const OptionInfo &option) = 0;
92 /********************************************************************
93 * OptionsFilter
96 /*! \brief
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
103 * format.
105 class OptionsFilter : public OptionsVisitor
107 public:
108 //! Specifies the type of output that formatSelected() produces.
109 enum FilterType
111 eSelectInputFileOptions,
112 eSelectInputOutputFileOptions,
113 eSelectOutputFileOptions,
114 eSelectOtherOptions
117 /*! \brief
118 * Creates a new filtering object.
120 * Does not throw.
122 OptionsFilter()
123 : formatter_(nullptr), filterType_(eSelectOtherOptions),
124 bShowHidden_(false)
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 &section) override;
140 void visitOption(const OptionInfo &option) override;
142 private:
143 IOptionsFormatter *formatter_;
144 FilterType filterType_;
145 bool bShowHidden_;
147 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsFilter);
150 void OptionsFilter::formatSelected(FilterType type,
151 IOptionsFormatter *formatter,
152 const Options &options)
154 formatter_ = formatter;
155 filterType_ = type;
156 visitSection(options.rootSection());
159 void OptionsFilter::visitSection(const OptionSectionInfo &section)
161 OptionsIterator iterator(section);
162 iterator.acceptSections(this);
163 iterator.acceptOptions(this);
166 void OptionsFilter::visitOption(const OptionInfo &option)
168 if (!bShowHidden_ && option.isHidden())
170 return;
172 const FileNameOptionInfo *const fileOption = option.toType<FileNameOptionInfo>();
173 if (fileOption != nullptr && fileOption->isInputFile())
175 if (filterType_ == eSelectInputFileOptions)
177 formatter_->formatOption(option);
179 return;
181 if (fileOption != nullptr && fileOption->isInputOutputFile())
183 if (filterType_ == eSelectInputOutputFileOptions)
185 formatter_->formatOption(option);
187 return;
189 if (fileOption != nullptr && fileOption->isOutputFile())
191 if (filterType_ == eSelectOutputFileOptions)
193 formatter_->formatOption(option);
195 return;
197 if (filterType_ == eSelectOtherOptions)
199 formatter_->formatOption(option);
200 return;
204 /********************************************************************
205 * CommonFormatterData
208 class CommonFormatterData
210 public:
211 explicit CommonFormatterData(const char *timeUnit)
212 : timeUnit(timeUnit)
216 const char *timeUnit;
219 /********************************************************************
220 * Helper functions
223 //! Formats option name and value.
224 void formatOptionNameAndValue(const OptionInfo &option, std::string *name,
225 std::string *value)
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)
234 *value += " [...]";
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 + "]";
246 value->clear();
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.
257 std::string
258 fileOptionFlagsAsString(const FileNameOptionInfo &option, bool bAbbrev)
260 std::string type;
261 if (!option.isRequired())
263 type = bAbbrev ? "Opt." : "Optional";
265 if (option.isLibraryFile())
267 if (!type.empty())
269 type.append(", ");
271 type.append(bAbbrev ? "Lib." : "Library");
273 return type;
276 //! Formats the description for an option as a string.
277 std::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);
292 return description;
295 /********************************************************************
296 * OptionsSynopsisFormatter
299 /*! \brief
300 * Formatter implementation for synopsis.
302 class SynopsisFormatter : public IOptionsFormatter
304 public:
305 //! Creates a helper object for formatting the synopsis.
306 explicit SynopsisFormatter(const HelpWriterContext &context)
307 : context_(context), bFormatted_(false), lineLength_(0), indent_(0),
308 currentLength_(0)
312 //! Starts formatting the synopsis.
313 void start(const char *name);
314 //! Finishes formatting the synopsis.
315 void finish();
317 void formatOption(const OptionInfo &option) override;
319 private:
320 const HelpWriterContext &context_;
321 bool bFormatted_;
322 int lineLength_;
323 int indent_;
324 int currentLength_;
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:
337 lineLength_ = 78;
338 file.writeString(name);
339 break;
340 case eHelpOutputFormat_Rst:
341 bFormatted_ = true;
342 lineLength_ = 74;
343 indent_ += 4;
344 file.writeLine(".. parsed-literal::");
345 file.writeLine();
346 file.writeString(" ");
347 file.writeString(name);
348 break;
349 default:
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());
366 if (!value.empty())
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
388 /*! \brief
389 * Formatter implementation for help export.
391 class OptionsListFormatter : public IOptionsFormatter
393 public:
394 //! Creates a helper object for formatting options.
395 OptionsListFormatter(const HelpWriterContext &context,
396 const CommonFormatterData &common,
397 const char *title);
399 //! Initiates a new section in the options list.
400 void startSection(const char *header)
402 header_ = header;
403 bDidOutput_ = false;
405 //! Finishes a section in the options list.
406 void finishSection()
408 if (bDidOutput_)
410 context_.writeOptionListEnd();
414 void formatOption(const OptionInfo &option) override;
416 private:
417 void writeSectionStartIfNecessary()
419 if (title_ != nullptr)
421 context_.writeTitle(title_);
422 title_ = nullptr;
424 if (!bDidOutput_)
426 if (header_ != nullptr)
428 context_.paragraphBreak();
429 context_.writeTextBlock(header_);
430 context_.paragraphBreak();
432 context_.writeOptionListStart();
434 bDidOutput_ = true;
437 const HelpWriterContext &context_;
438 const CommonFormatterData &common_;
439 const char *title_;
440 const char *header_;
441 bool bDidOutput_;
443 GMX_DISALLOW_COPY_AND_ASSIGN(OptionsListFormatter);
446 OptionsListFormatter::OptionsListFormatter(
447 const HelpWriterContext &context,
448 const CommonFormatterData &common,
449 const char *title)
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));
461 std::string info;
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);
472 //! \}
474 } // namespace
476 /********************************************************************
477 * CommandLineHelpWriter::Impl
480 /*! \internal \brief
481 * Private implementation class for CommandLineHelpWriter.
483 * \ingroup module_commandline
485 class CommandLineHelpWriter::Impl
487 public:
488 //! Sets the Options object to use for generating help.
489 explicit Impl(const Options &options)
490 : 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_;
499 //! Help text.
500 std::string helpText_;
501 //! List of bugs/knows issues.
502 std::vector<std::string> bugs_;
505 void CommandLineHelpWriter::Impl::formatBugs(const HelpWriterContext &context)
507 if (bugs_.empty())
509 return;
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;
537 return *this;
540 CommandLineHelpWriter &
541 CommandLineHelpWriter::setHelpText(const ArrayRef<const char *const> &help)
543 impl_->helpText_ = joinStrings(help, "\n");
544 return *this;
547 CommandLineHelpWriter &
548 CommandLineHelpWriter::setKnownIssues(ArrayRef<const std::string> bugs)
550 impl_->bugs_ = std::vector<std::string>(bugs.begin(), bugs.end());
551 return *this;
554 CommandLineHelpWriter &
555 CommandLineHelpWriter::setKnownIssues(const ArrayRef<const char *const> &bugs)
557 impl_->bugs_ = std::vector<std::string>(bugs.begin(), bugs.end());
558 return *this;
561 void CommandLineHelpWriter::writeHelp(const CommandLineHelpContext &context)
563 if (context.isCompletionExport())
565 context.shellCompletionWriter().writeModuleCompletions(
566 context.moduleDisplayName(), impl_->options_);
567 return;
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);
615 } // namespace gmx