3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
9 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11 * Copyright (c) 2001-2009, The GROMACS development team,
12 * check out http://www.gromacs.org for more information.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * If you want to redistribute modifications, please consider that
20 * scientific software is very special. Version control is crucial -
21 * bugs must be traceable. We will be happy to consider code for
22 * inclusion in the official distribution, but derived work must not
23 * be called official GROMACS. Details are found in the README & COPYING
24 * files - if they are missing, get the official version at www.gromacs.org.
26 * To help us fund GROMACS development, we humbly ask that you cite
27 * the papers on the package - you can find them in the top README file.
29 * For more info, check our website at http://www.gromacs.org
33 * Implements gmx::CommandLineHelpWriter.
35 * \author Teemu Murtola <teemu.murtola@gmail.com>
36 * \ingroup module_commandline
38 #include "cmdlinehelpwriter.h"
42 #include "gromacs/onlinehelp/helpformat.h"
43 #include "gromacs/onlinehelp/helpwritercontext.h"
44 #include "gromacs/options/basicoptions.h"
45 #include "gromacs/options/filenameoption.h"
46 #include "gromacs/options/options.h"
47 #include "gromacs/options/optionsvisitor.h"
48 #include "gromacs/options/timeunitmanager.h"
49 #include "gromacs/selection/selectionfileoption.h"
50 #include "gromacs/selection/selectionoption.h"
51 #include "gromacs/utility/exceptions.h"
52 #include "gromacs/utility/file.h"
53 #include "gromacs/utility/stringutil.h"
61 /********************************************************************
62 * OptionsFormatterInterface
66 * Interface for output format specific formatting of options.
70 * \ingroup module_commandline
72 class OptionsFormatterInterface
75 virtual ~OptionsFormatterInterface() {}
77 //! Formats the description text block for a section.
78 virtual void formatDescription(const HelpWriterContext &context,
79 const Options §ion) = 0;
80 //! Formats a single file option.
81 virtual void formatFileOption(const HelpWriterContext &context,
82 const FileNameOptionInfo &option) = 0;
83 //! Formats a single non-file, non-selection option.
84 virtual void formatOption(const HelpWriterContext &context,
85 const OptionInfo &option) = 0;
86 //! Formats a single selection option.
87 virtual void formatSelectionOption(const HelpWriterContext &context,
88 const OptionInfo &option) = 0;
91 /********************************************************************
96 * Output format independent processing of options.
98 * Together with code in CommandLineHelpWriter::writeHelp(), this class
99 * implements the common logic for writing out the help.
100 * An object implementing the OptionsFormatterInterface must be provided to the
101 * constructor, and does the actual formatting that is specific to the output
104 * \ingroup module_commandline
106 class OptionsFilter : public OptionsVisitor
109 //! Specifies the type of output that formatSelected() produces.
114 eSelectSelectionOptions,
119 * Creates a new filtering object.
121 * \param[in] context Help context to use to write the help.
122 * \param[in] formatter Output format specific formatter.
126 OptionsFilter(const HelpWriterContext &context,
127 OptionsFormatterInterface *formatter)
128 : context_(context), formatter_(*formatter),
129 filterType_(eSelectOtherOptions), bShowHidden_(false),
134 //! Sets whether hidden options will be shown.
135 void setShowHidden(bool bShowHidden)
137 bShowHidden_ = bShowHidden;
140 //! Formats selected options using the formatter.
141 void formatSelected(FilterType type, const Options &options);
143 virtual void visitSubSection(const Options §ion);
144 virtual void visitOption(const OptionInfo &option);
147 const HelpWriterContext &context_;
148 OptionsFormatterInterface &formatter_;
149 FilterType filterType_;
154 void OptionsFilter::formatSelected(FilterType type, const Options &options)
158 visitSubSection(options);
161 context_.outputFile().writeLine();
165 void OptionsFilter::visitSubSection(const Options §ion)
167 if (filterType_ == eSelectDescriptions)
171 context_.outputFile().writeLine();
173 formatter_.formatDescription(context_, section);
177 OptionsIterator iterator(section);
178 iterator.acceptSubSections(this);
179 iterator.acceptOptions(this);
182 void OptionsFilter::visitOption(const OptionInfo &option)
184 if (!bShowHidden_ && option.isHidden())
188 if (option.isType<FileNameOptionInfo>())
190 if (filterType_ == eSelectFileOptions)
192 formatter_.formatFileOption(context_,
193 *option.toType<FileNameOptionInfo>());
198 if (option.isType<SelectionFileOptionInfo>()
199 || option.isType<SelectionOptionInfo>())
201 if (filterType_ == eSelectSelectionOptions)
203 formatter_.formatSelectionOption(context_, option);
208 if (filterType_ == eSelectOtherOptions)
210 formatter_.formatOption(context_, option);
216 /********************************************************************
217 * CommonFormatterData
220 class CommonFormatterData
223 explicit CommonFormatterData(const char *timeUnit)
228 const char *timeUnit;
231 /********************************************************************
232 * OptionsConsoleFormatter
236 * Formatter implementation for console help.
238 * \ingroup module_commandline
240 class OptionsConsoleFormatter : public OptionsFormatterInterface
243 //! Creates a helper object for formatting options help for console.
244 explicit OptionsConsoleFormatter(const CommonFormatterData &common);
246 virtual void formatDescription(const HelpWriterContext &context,
247 const Options §ion);
248 virtual void formatFileOption(const HelpWriterContext &context,
249 const FileNameOptionInfo &option);
250 virtual void formatOption(const HelpWriterContext &context,
251 const OptionInfo &option);
252 virtual void formatSelectionOption(const HelpWriterContext &context,
253 const OptionInfo &option);
256 const CommonFormatterData &common_;
257 TextTableFormatter fileOptionFormatter_;
258 TextTableFormatter genericOptionFormatter_;
259 TextTableFormatter selectionOptionFormatter_;
262 OptionsConsoleFormatter::OptionsConsoleFormatter(const CommonFormatterData &common)
265 fileOptionFormatter_.addColumn("Option", 6, false);
266 fileOptionFormatter_.addColumn("Filename", 12, false);
267 fileOptionFormatter_.addColumn("Type", 12, false);
268 fileOptionFormatter_.addColumn("Description", 45, true);
270 genericOptionFormatter_.addColumn("Option", 12, false);
271 genericOptionFormatter_.addColumn("Type", 6, false);
272 genericOptionFormatter_.addColumn("Value", 6, false);
273 genericOptionFormatter_.addColumn("Description", 51, true);
275 selectionOptionFormatter_.addColumn("Selection", 10, false);
276 selectionOptionFormatter_.addColumn("Description", 67, true);
279 void OptionsConsoleFormatter::formatDescription(
280 const HelpWriterContext &context, const Options §ion)
282 if (!section.description().empty())
284 File &file = context.outputFile();
285 const std::string &title = section.title();
288 file.writeLine(title);
291 context.writeTextBlock(section.description());
295 void OptionsConsoleFormatter::formatFileOption(
296 const HelpWriterContext &context, const FileNameOptionInfo &option)
298 int firstShortValue = 0; // The first value after which the type fits.
299 int firstLongValue = -1; // First value that overlaps description column.
300 int lastLongValue = -1; // Last value like the above.
302 // Get the values to write and check where text overflows the columns.
303 fileOptionFormatter_.clear();
304 std::string name(formatString("-%s", option.name().c_str()));
305 fileOptionFormatter_.addColumnLine(0, name);
306 for (int i = 0; i < option.valueCount() || i == 0; ++i)
309 if (option.valueCount() == 0
310 || (option.valueCount() == 1 && option.formatValue(0).empty()))
312 value = option.formatDefaultValueIfSet();
316 value = option.formatValue(i);
318 fileOptionFormatter_.addColumnLine(1, value);
319 if (value.length() > 12U && i == firstShortValue)
321 firstShortValue = i + 1;
323 if (value.length() > 25U)
325 if (firstLongValue == -1)
333 if (option.isInputOutputFile())
337 else if (option.isInputFile())
341 else if (option.isOutputFile())
345 if (!option.isRequired())
349 if (option.isLibraryFile())
353 bool bLongType = (type.length() > 12U);
354 fileOptionFormatter_.addColumnLine(2, type);
355 fileOptionFormatter_.addColumnLine(3, context.substituteMarkup(option.description()));
358 if (name.length() > 6U || firstShortValue > 0)
360 fileOptionFormatter_.setColumnFirstLineOffset(1, 1);
361 // Assume that the name is <20 chars, so that the type fits
362 if (firstLongValue >= 0)
368 int firstDescriptionLine = 0;
371 firstDescriptionLine = 1;
373 fileOptionFormatter_.setColumnFirstLineOffset(3, firstDescriptionLine);
374 if (firstLongValue >= 0
375 && fileOptionFormatter_.lastColumnLine(3) >= firstLongValue)
377 firstDescriptionLine = lastLongValue + 1;
378 fileOptionFormatter_.setColumnFirstLineOffset(3, firstDescriptionLine);
381 // Do the formatting.
382 context.outputFile().writeString(fileOptionFormatter_.formatRow());
385 void OptionsConsoleFormatter::formatOption(
386 const HelpWriterContext &context, const OptionInfo &option)
388 genericOptionFormatter_.clear();
389 bool bIsBool = option.isType<BooleanOptionInfo>();
390 std::string name(formatString("-%s%s", bIsBool ? "[no]" : "",
391 option.name().c_str()));
392 genericOptionFormatter_.addColumnLine(0, name);
393 genericOptionFormatter_.addColumnLine(1, option.type());
394 if (name.length() > 12U)
396 genericOptionFormatter_.setColumnFirstLineOffset(1, 1);
398 // TODO: Better handling of multiple long values
400 for (int i = 0; i < option.valueCount(); ++i)
406 values.append(option.formatValue(i));
408 genericOptionFormatter_.addColumnLine(2, values);
409 std::string description(context.substituteMarkup(option.description()));
410 const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
411 if (doubleOption != NULL && doubleOption->isTime())
413 description = replaceAll(description, "%t", common_.timeUnit);
415 genericOptionFormatter_.addColumnLine(3, description);
416 if (values.length() > 6U)
418 genericOptionFormatter_.setColumnFirstLineOffset(3, 1);
421 context.outputFile().writeString(genericOptionFormatter_.formatRow());
424 void OptionsConsoleFormatter::formatSelectionOption(
425 const HelpWriterContext &context, const OptionInfo &option)
427 File &file = context.outputFile();
429 selectionOptionFormatter_.clear();
430 std::string name(formatString("-%s", option.name().c_str()));
431 selectionOptionFormatter_.addColumnLine(0, name);
432 selectionOptionFormatter_.addColumnLine(1, context.substituteMarkup(option.description()));
433 file.writeString(selectionOptionFormatter_.formatRow());
435 TextLineWrapper wrapper;
436 wrapper.settings().setLineLength(77);
437 wrapper.settings().setFirstLineIndent(4);
438 wrapper.settings().setIndent(8);
439 wrapper.settings().setContinuationChar('\\');
440 // TODO: What to do with selection variables?
441 // They are not printed as values for any option.
442 for (int i = 0; i < option.valueCount(); ++i)
444 std::string value(option.formatValue(i));
445 file.writeLine(wrapper.wrapToString(value));
451 /********************************************************************
452 * CommandLineHelpWriter::Impl
456 * Private implementation class for CommandLineHelpWriter.
458 * \ingroup module_commandline
460 class CommandLineHelpWriter::Impl
463 //! Sets the Options object to use for generating help.
464 explicit Impl(const Options &options);
466 //! Options object to use for generating help.
467 const Options &options_;
468 //! Time unit to show in descriptions.
469 std::string timeUnit_;
470 //! Whether to write descriptions to output.
471 bool bShowDescriptions_;
472 //! Whether to write hidden options to output.
476 CommandLineHelpWriter::Impl::Impl(const Options &options)
477 : options_(options), timeUnit_(TimeUnitManager().timeUnitAsString()),
478 bShowDescriptions_(false), bShowHidden_(false)
482 /********************************************************************
483 * CommandLineHelpWriter
486 CommandLineHelpWriter::CommandLineHelpWriter(const Options &options)
487 : impl_(new Impl(options))
491 CommandLineHelpWriter::~CommandLineHelpWriter()
495 CommandLineHelpWriter &CommandLineHelpWriter::setShowHidden(bool bSet)
497 impl_->bShowHidden_ = bSet;
501 CommandLineHelpWriter &CommandLineHelpWriter::setShowDescriptions(bool bSet)
503 impl_->bShowDescriptions_ = bSet;
507 CommandLineHelpWriter &CommandLineHelpWriter::setTimeUnitString(const char *timeUnit)
509 impl_->timeUnit_ = timeUnit;
513 void CommandLineHelpWriter::writeHelp(const HelpWriterContext &context)
515 boost::scoped_ptr<OptionsFormatterInterface> formatter;
516 CommonFormatterData common(impl_->timeUnit_.c_str());
517 switch (context.outputFormat())
519 case eHelpOutputFormat_Console:
520 formatter.reset(new OptionsConsoleFormatter(common));
523 // TODO: Implement once the situation with Redmine issue #969 is
525 GMX_THROW(NotImplementedError(
526 "Command-line help is not implemented for this output format"));
528 OptionsFilter filter(context, formatter.get());
529 filter.setShowHidden(impl_->bShowHidden_);
531 if (impl_->bShowDescriptions_)
533 File &file = context.outputFile();
534 file.writeLine("DESCRIPTION");
535 file.writeLine("-----------");
537 filter.formatSelected(OptionsFilter::eSelectDescriptions,
540 filter.formatSelected(OptionsFilter::eSelectFileOptions,
542 filter.formatSelected(OptionsFilter::eSelectOtherOptions,
544 filter.formatSelected(OptionsFilter::eSelectSelectionOptions,