2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012,2013, by the GROMACS development team, led by
5 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
6 * others, as listed in the AUTHORS file in the top-level source
7 * 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"
46 #include "gromacs/onlinehelp/helpformat.h"
47 #include "gromacs/onlinehelp/helpwritercontext.h"
48 #include "gromacs/options/basicoptions.h"
49 #include "gromacs/options/filenameoption.h"
50 #include "gromacs/options/options.h"
51 #include "gromacs/options/optionsvisitor.h"
52 #include "gromacs/options/timeunitmanager.h"
53 #include "gromacs/selection/selectionfileoption.h"
54 #include "gromacs/selection/selectionoption.h"
55 #include "gromacs/utility/exceptions.h"
56 #include "gromacs/utility/file.h"
57 #include "gromacs/utility/stringutil.h"
65 /********************************************************************
66 * OptionsFormatterInterface
70 * Interface for output format specific formatting of options.
74 * \ingroup module_commandline
76 class OptionsFormatterInterface
79 virtual ~OptionsFormatterInterface() {}
81 //! Formats the description text block for a section.
82 virtual void formatDescription(const HelpWriterContext &context,
83 const Options §ion) = 0;
84 //! Formats a single file option.
85 virtual void formatFileOption(const HelpWriterContext &context,
86 const FileNameOptionInfo &option) = 0;
87 //! Formats a single non-file, non-selection option.
88 virtual void formatOption(const HelpWriterContext &context,
89 const OptionInfo &option) = 0;
90 //! Formats a single selection option.
91 virtual void formatSelectionOption(const HelpWriterContext &context,
92 const OptionInfo &option) = 0;
95 /********************************************************************
100 * Output format independent processing of options.
102 * Together with code in CommandLineHelpWriter::writeHelp(), this class
103 * implements the common logic for writing out the help.
104 * An object implementing the OptionsFormatterInterface must be provided to the
105 * constructor, and does the actual formatting that is specific to the output
108 * \ingroup module_commandline
110 class OptionsFilter : public OptionsVisitor
113 //! Specifies the type of output that formatSelected() produces.
118 eSelectSelectionOptions,
123 * Creates a new filtering object.
125 * \param[in] context Help context to use to write the help.
126 * \param[in] formatter Output format specific formatter.
130 OptionsFilter(const HelpWriterContext &context,
131 OptionsFormatterInterface *formatter)
132 : context_(context), formatter_(*formatter),
133 filterType_(eSelectOtherOptions), bShowHidden_(false),
138 //! Sets whether hidden options will be shown.
139 void setShowHidden(bool bShowHidden)
141 bShowHidden_ = bShowHidden;
144 //! Formats selected options using the formatter.
145 void formatSelected(FilterType type, const Options &options);
147 virtual void visitSubSection(const Options §ion);
148 virtual void visitOption(const OptionInfo &option);
151 const HelpWriterContext &context_;
152 OptionsFormatterInterface &formatter_;
153 FilterType filterType_;
158 void OptionsFilter::formatSelected(FilterType type, const Options &options)
162 visitSubSection(options);
165 context_.outputFile().writeLine();
169 void OptionsFilter::visitSubSection(const Options §ion)
171 if (filterType_ == eSelectDescriptions)
175 context_.outputFile().writeLine();
177 formatter_.formatDescription(context_, section);
181 OptionsIterator iterator(section);
182 iterator.acceptSubSections(this);
183 iterator.acceptOptions(this);
186 void OptionsFilter::visitOption(const OptionInfo &option)
188 if (!bShowHidden_ && option.isHidden())
192 if (option.isType<FileNameOptionInfo>())
194 if (filterType_ == eSelectFileOptions)
196 formatter_.formatFileOption(context_,
197 *option.toType<FileNameOptionInfo>());
202 if (option.isType<SelectionFileOptionInfo>()
203 || option.isType<SelectionOptionInfo>())
205 if (filterType_ == eSelectSelectionOptions)
207 formatter_.formatSelectionOption(context_, option);
212 if (filterType_ == eSelectOtherOptions)
214 formatter_.formatOption(context_, option);
220 /********************************************************************
221 * CommonFormatterData
224 class CommonFormatterData
227 explicit CommonFormatterData(const char *timeUnit)
232 const char *timeUnit;
235 /********************************************************************
236 * OptionsConsoleFormatter
240 * Formatter implementation for console help.
242 * \ingroup module_commandline
244 class OptionsConsoleFormatter : public OptionsFormatterInterface
247 //! Creates a helper object for formatting options help for console.
248 explicit OptionsConsoleFormatter(const CommonFormatterData &common);
250 virtual void formatDescription(const HelpWriterContext &context,
251 const Options §ion);
252 virtual void formatFileOption(const HelpWriterContext &context,
253 const FileNameOptionInfo &option);
254 virtual void formatOption(const HelpWriterContext &context,
255 const OptionInfo &option);
256 virtual void formatSelectionOption(const HelpWriterContext &context,
257 const OptionInfo &option);
260 const CommonFormatterData &common_;
261 TextTableFormatter fileOptionFormatter_;
262 TextTableFormatter genericOptionFormatter_;
263 TextTableFormatter selectionOptionFormatter_;
266 OptionsConsoleFormatter::OptionsConsoleFormatter(const CommonFormatterData &common)
269 fileOptionFormatter_.addColumn("Option", 6, false);
270 fileOptionFormatter_.addColumn("Filename", 12, false);
271 fileOptionFormatter_.addColumn("Type", 12, false);
272 fileOptionFormatter_.addColumn("Description", 45, true);
274 genericOptionFormatter_.addColumn("Option", 12, false);
275 genericOptionFormatter_.addColumn("Type", 6, false);
276 genericOptionFormatter_.addColumn("Value", 6, false);
277 genericOptionFormatter_.addColumn("Description", 51, true);
279 selectionOptionFormatter_.addColumn("Selection", 10, false);
280 selectionOptionFormatter_.addColumn("Description", 67, true);
283 void OptionsConsoleFormatter::formatDescription(
284 const HelpWriterContext &context, const Options §ion)
286 if (!section.description().empty())
288 File &file = context.outputFile();
289 const std::string &title = section.title();
292 file.writeLine(title);
295 context.writeTextBlock(section.description());
299 void OptionsConsoleFormatter::formatFileOption(
300 const HelpWriterContext &context, const FileNameOptionInfo &option)
302 int firstShortValue = 0; // The first value after which the type fits.
303 int firstLongValue = -1; // First value that overlaps description column.
304 int lastLongValue = -1; // Last value like the above.
306 // Get the values to write and check where text overflows the columns.
307 fileOptionFormatter_.clear();
308 std::string name(formatString("-%s", option.name().c_str()));
309 fileOptionFormatter_.addColumnLine(0, name);
310 for (int i = 0; i < option.valueCount() || i == 0; ++i)
313 if (option.valueCount() == 0
314 || (option.valueCount() == 1 && option.formatValue(0).empty()))
316 value = option.formatDefaultValueIfSet();
320 value = option.formatValue(i);
322 fileOptionFormatter_.addColumnLine(1, value);
323 if (value.length() > 12U && i == firstShortValue)
325 firstShortValue = i + 1;
327 if (value.length() > 25U)
329 if (firstLongValue == -1)
337 if (option.isInputOutputFile())
341 else if (option.isInputFile())
345 else if (option.isOutputFile())
349 if (!option.isRequired())
353 if (option.isLibraryFile())
357 bool bLongType = (type.length() > 12U);
358 fileOptionFormatter_.addColumnLine(2, type);
359 fileOptionFormatter_.addColumnLine(3, context.substituteMarkup(option.description()));
362 if (name.length() > 6U || firstShortValue > 0)
364 fileOptionFormatter_.setColumnFirstLineOffset(1, 1);
365 // Assume that the name is <20 chars, so that the type fits
366 if (firstLongValue >= 0)
372 int firstDescriptionLine = 0;
375 firstDescriptionLine = 1;
377 fileOptionFormatter_.setColumnFirstLineOffset(3, firstDescriptionLine);
378 if (firstLongValue >= 0
379 && fileOptionFormatter_.lastColumnLine(3) >= firstLongValue)
381 firstDescriptionLine = lastLongValue + 1;
382 fileOptionFormatter_.setColumnFirstLineOffset(3, firstDescriptionLine);
385 // Do the formatting.
386 context.outputFile().writeString(fileOptionFormatter_.formatRow());
389 void OptionsConsoleFormatter::formatOption(
390 const HelpWriterContext &context, const OptionInfo &option)
392 genericOptionFormatter_.clear();
393 bool bIsBool = option.isType<BooleanOptionInfo>();
394 std::string name(formatString("-%s%s", bIsBool ? "[no]" : "",
395 option.name().c_str()));
396 genericOptionFormatter_.addColumnLine(0, name);
397 genericOptionFormatter_.addColumnLine(1, option.type());
398 if (name.length() > 12U)
400 genericOptionFormatter_.setColumnFirstLineOffset(1, 1);
403 // TODO: Better handling of multiple long values
405 for (int i = 0; i < option.valueCount(); ++i)
411 values.append(option.formatValue(i));
413 genericOptionFormatter_.addColumnLine(2, values);
415 std::string description(context.substituteMarkup(option.description()));
416 const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
417 if (doubleOption != NULL && doubleOption->isTime())
419 description = replaceAll(description, "%t", common_.timeUnit);
421 const StringOptionInfo *stringOption = option.toType<StringOptionInfo>();
422 if (stringOption != NULL && stringOption->isEnumerated())
424 const std::vector<std::string> &allowedValues
425 = stringOption->allowedValues();
426 description.append(": ");
427 for (size_t i = 0; i < allowedValues.size(); ++i)
431 description.append(i + 1 < allowedValues.size()
434 description.append(allowedValues[i]);
437 genericOptionFormatter_.addColumnLine(3, description);
438 if (values.length() > 6U)
440 genericOptionFormatter_.setColumnFirstLineOffset(3, 1);
443 context.outputFile().writeString(genericOptionFormatter_.formatRow());
446 void OptionsConsoleFormatter::formatSelectionOption(
447 const HelpWriterContext &context, const OptionInfo &option)
449 File &file = context.outputFile();
451 selectionOptionFormatter_.clear();
452 std::string name(formatString("-%s", option.name().c_str()));
453 selectionOptionFormatter_.addColumnLine(0, name);
454 selectionOptionFormatter_.addColumnLine(1, context.substituteMarkup(option.description()));
455 file.writeString(selectionOptionFormatter_.formatRow());
457 TextLineWrapper wrapper;
458 wrapper.settings().setLineLength(77);
459 wrapper.settings().setFirstLineIndent(4);
460 wrapper.settings().setIndent(8);
461 wrapper.settings().setContinuationChar('\\');
462 // TODO: What to do with selection variables?
463 // They are not printed as values for any option.
464 for (int i = 0; i < option.valueCount(); ++i)
466 std::string value(option.formatValue(i));
467 file.writeLine(wrapper.wrapToString(value));
473 /********************************************************************
474 * CommandLineHelpWriter::Impl
478 * Private implementation class for CommandLineHelpWriter.
480 * \ingroup module_commandline
482 class CommandLineHelpWriter::Impl
485 //! Sets the Options object to use for generating help.
486 explicit Impl(const Options &options);
488 //! Options object to use for generating help.
489 const Options &options_;
490 //! Time unit to show in descriptions.
491 std::string timeUnit_;
492 //! Whether to write descriptions to output.
493 bool bShowDescriptions_;
494 //! Whether to write hidden options to output.
498 CommandLineHelpWriter::Impl::Impl(const Options &options)
499 : options_(options), timeUnit_(TimeUnitManager().timeUnitAsString()),
500 bShowDescriptions_(false), bShowHidden_(false)
504 /********************************************************************
505 * CommandLineHelpWriter
508 CommandLineHelpWriter::CommandLineHelpWriter(const Options &options)
509 : impl_(new Impl(options))
513 CommandLineHelpWriter::~CommandLineHelpWriter()
517 CommandLineHelpWriter &CommandLineHelpWriter::setShowHidden(bool bSet)
519 impl_->bShowHidden_ = bSet;
523 CommandLineHelpWriter &CommandLineHelpWriter::setShowDescriptions(bool bSet)
525 impl_->bShowDescriptions_ = bSet;
529 CommandLineHelpWriter &CommandLineHelpWriter::setTimeUnitString(const char *timeUnit)
531 impl_->timeUnit_ = timeUnit;
535 void CommandLineHelpWriter::writeHelp(const HelpWriterContext &context)
537 boost::scoped_ptr<OptionsFormatterInterface> formatter;
538 CommonFormatterData common(impl_->timeUnit_.c_str());
539 switch (context.outputFormat())
541 case eHelpOutputFormat_Console:
542 formatter.reset(new OptionsConsoleFormatter(common));
545 // TODO: Implement once the situation with Redmine issue #969 is
547 GMX_THROW(NotImplementedError(
548 "Command-line help is not implemented for this output format"));
550 OptionsFilter filter(context, formatter.get());
551 filter.setShowHidden(impl_->bShowHidden_);
553 if (impl_->bShowDescriptions_)
555 File &file = context.outputFile();
556 file.writeLine("DESCRIPTION");
557 file.writeLine("-----------");
559 filter.formatSelected(OptionsFilter::eSelectDescriptions,
562 filter.formatSelected(OptionsFilter::eSelectFileOptions,
564 filter.formatSelected(OptionsFilter::eSelectOtherOptions,
566 filter.formatSelected(OptionsFilter::eSelectSelectionOptions,