Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / commandline / cmdlinehelpwriter.cpp
index 494e02072fae3806e52d500da6ddfc75fac3de5f..0c79bd393451006b0e4c5161ced2b0ab4170a1dd 100644 (file)
 /*
+ * This file is part of the GROMACS molecular simulation package.
  *
- *                This source code is part of
+ * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
  *
- *                 G   R   O   M   A   C   S
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
  *
- *          GROningen MAchine for Chemical Simulations
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
  *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
  *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
  *
  * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
+ * the research papers on the package. Check out http://www.gromacs.org.
  */
 /*! \internal \file
  * \brief
  * Implements gmx::CommandLineHelpWriter.
  *
- * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
  * \ingroup module_commandline
  */
+#include "gmxpre.h"
+
 #include "cmdlinehelpwriter.h"
 
+#include <cstring>
+
+#include <algorithm>
 #include <string>
 
+#include <boost/scoped_ptr.hpp>
+
+#include "gromacs/commandline/cmdlinehelpcontext.h"
 #include "gromacs/onlinehelp/helpformat.h"
-#include "gromacs/options/basicoptioninfo.h"
-#include "gromacs/options/filenameoptioninfo.h"
+#include "gromacs/onlinehelp/helpwritercontext.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/filenameoption.h"
 #include "gromacs/options/options.h"
 #include "gromacs/options/optionsvisitor.h"
 #include "gromacs/options/timeunitmanager.h"
-#include "gromacs/selection/selectionfileoptioninfo.h"
-#include "gromacs/selection/selectionoptioninfo.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/file.h"
 #include "gromacs/utility/stringutil.h"
 
+#include "shellcompletions.h"
+
 namespace gmx
 {
 
 namespace
 {
 
+//! \addtogroup module_commandline
+//! \{
+
 /********************************************************************
- * DescriptionWriter
+ * DescriptionsFormatter
  */
 
-/*! \internal \brief
- * Helper object for writing section descriptions to help.
- *
- * \ingroup module_commandline
- */
-class DescriptionWriter : public OptionsVisitor
+class DescriptionsFormatter : public OptionsVisitor
 {
     public:
-        //! Creates a helper object for writing section descriptions.
-        explicit DescriptionWriter(File *file) : file_(*file) {}
+        /*! \brief
+         * Creates a new description formatter.
+         *
+         * \param[in] context   Help context to use to write the help.
+         */
+        explicit DescriptionsFormatter(const HelpWriterContext &context)
+            : context_(context), title_(NULL), bDidOutput_(false)
+        {
+        }
+
+        //! Formats all section descriptions from a given options.
+        void format(const Options &options, const char *title)
+        {
+            title_      = title;
+            bDidOutput_ = false;
+            visitSubSection(options);
+            if (bDidOutput_)
+            {
+                context_.outputFile().writeLine();
+            }
+        }
 
+        //! Formats the description for a single subsection and handles recursion.
         virtual void visitSubSection(const Options &section);
-        virtual void visitOption(const OptionInfo & /*option*/) { }
+        // This method is not used and never called.
+        virtual void visitOption(const OptionInfo & /*option*/) {}
 
     private:
-        File                   &file_;
+        const HelpWriterContext &context_;
+        const char              *title_;
+        bool                     bDidOutput_;
+
+        GMX_DISALLOW_COPY_AND_ASSIGN(DescriptionsFormatter);
 };
 
-void DescriptionWriter::visitSubSection(const Options &section)
+void DescriptionsFormatter::visitSubSection(const Options &section)
 {
     if (!section.description().empty())
     {
-        const std::string &title = section.title();
-        if (!title.empty())
+        if (bDidOutput_)
+        {
+            context_.outputFile().writeLine();
+        }
+        else if (title_ != NULL)
         {
-            file_.writeLine(title);
-            file_.writeLine();
+            context_.writeTitle(title_);
         }
-        writeHelpTextForConsole(&file_, section.description());
-        file_.writeLine();
+        // TODO: Print title for the section?
+        context_.writeTextBlock(section.description());
+        bDidOutput_ = true;
     }
-    OptionsIterator(section).acceptSubSections(this);
+
+    OptionsIterator iterator(section);
+    iterator.acceptSubSections(this);
 }
 
+/********************************************************************
+ * OptionsFormatterInterface
+ */
+
+/*! \brief
+ * Interface for output format specific formatting of options.
+ *
+ * \see OptionsFilter
+ */
+class OptionsFormatterInterface
+{
+    public:
+        virtual ~OptionsFormatterInterface() {}
+
+        //! Formats a single option option.
+        virtual void formatOption(const OptionInfo &option) = 0;
+};
 
 /********************************************************************
- * FileParameterWriter
+ * OptionsFilter
  */
 
-/*! \internal \brief
- * Helper object for writing help for file parameters.
+/*! \brief
+ * Output format independent processing of options.
  *
- * \ingroup module_commandline
+ * Together with code in CommandLineHelpWriter::writeHelp(), this class
+ * implements the common logic for writing out the help.
+ * An object implementing the OptionsFormatterInterface must be provided to the
+ * constructor, and does the actual formatting that is specific to the output
+ * format.
  */
-class FileParameterWriter : public OptionsTypeVisitor<FileNameOptionInfo>
+class OptionsFilter : public OptionsVisitor
 {
     public:
-        //! Creates a helper object for writing file parameters.
-        explicit FileParameterWriter(File *file);
+        //! Specifies the type of output that formatSelected() produces.
+        enum FilterType
+        {
+            eSelectFileOptions,
+            eSelectOtherOptions
+        };
+
+        /*! \brief
+         * Creates a new filtering object.
+         *
+         * Does not throw.
+         */
+        OptionsFilter()
+            : formatter_(NULL), filterType_(eSelectOtherOptions),
+              bShowHidden_(false)
+        {
+        }
+
+        //! Sets whether hidden options will be shown.
+        void setShowHidden(bool bShowHidden)
+        {
+            bShowHidden_ = bShowHidden;
+        }
 
-        //! Returns true if anything was written out.
-        bool didOutput() const { return formatter_.didOutput(); }
+        //! Formats selected options using the formatter.
+        void formatSelected(FilterType                 type,
+                            OptionsFormatterInterface *formatter,
+                            const Options             &options);
 
         virtual void visitSubSection(const Options &section);
-        virtual void visitOptionType(const FileNameOptionInfo &option);
+        virtual void visitOption(const OptionInfo &option);
 
     private:
-        File                   &file_;
-        TextTableFormatter      formatter_;
+        OptionsFormatterInterface      *formatter_;
+        FilterType                      filterType_;
+        bool                            bShowHidden_;
+
+        GMX_DISALLOW_COPY_AND_ASSIGN(OptionsFilter);
 };
 
-FileParameterWriter::FileParameterWriter(File *file)
-    : file_(*file)
+void OptionsFilter::formatSelected(FilterType                 type,
+                                   OptionsFormatterInterface *formatter,
+                                   const Options             &options)
 {
-    formatter_.addColumn("Option",      6, false);
-    formatter_.addColumn("Filename",    12, false);
-    formatter_.addColumn("Type",        12, false);
-    formatter_.addColumn("Description", 45, true);
+    formatter_  = formatter;
+    filterType_ = type;
+    visitSubSection(options);
 }
 
-void FileParameterWriter::visitSubSection(const Options &section)
+void OptionsFilter::visitSubSection(const Options &section)
 {
     OptionsIterator iterator(section);
     iterator.acceptSubSections(this);
     iterator.acceptOptions(this);
 }
 
-void FileParameterWriter::visitOptionType(const FileNameOptionInfo &option)
+void OptionsFilter::visitOption(const OptionInfo &option)
 {
-    int firstShortValue = 0; // The first value after which the type fits.
-    int firstLongValue = -1; // First value that overlaps description column.
-    int lastLongValue = -1;  // Last value like the above.
-
-    // Get the values to write and check where text overflows the columns.
-    formatter_.clear();
-    std::string name(formatString("-%s", option.name().c_str()));
-    formatter_.addColumnLine(0, name);
-    for (int i = 0; i < option.valueCount() || i == 0; ++i)
+    if (!bShowHidden_ && option.isHidden())
+    {
+        return;
+    }
+    if (option.isType<FileNameOptionInfo>())
     {
-        std::string value;
-        if (option.valueCount() == 0)
+        if (filterType_ == eSelectFileOptions)
         {
-            value = option.formatDefaultValueIfSet();
+            formatter_->formatOption(option);
         }
-        else
+        return;
+    }
+    if (filterType_ == eSelectOtherOptions)
+    {
+        formatter_->formatOption(option);
+        return;
+    }
+}
+
+/********************************************************************
+ * CommonFormatterData
+ */
+
+class CommonFormatterData
+{
+    public:
+        explicit CommonFormatterData(const char *timeUnit)
+            : timeUnit(timeUnit)
         {
-            value = option.formatValue(i);
         }
-        formatter_.addColumnLine(1, value);
-        if (value.length() > 12U && i == firstShortValue)
+
+        const char             *timeUnit;
+};
+
+/********************************************************************
+ * Helper functions
+ */
+
+//! Formats option name and value.
+void formatOptionNameAndValue(const OptionInfo &option, std::string *name,
+                              std::string *value)
+{
+    *name  = option.name();
+    *value = "<" + option.type() + ">";
+    if (option.isType<FileNameOptionInfo>())
+    {
+        // TODO: Make these work also for other option types.
+        if (option.maxValueCount() != 1)
         {
-            firstShortValue = i + 1;
+            *value += " [...]";
         }
-        if (value.length() > 25U)
+        if (option.minValueCount() == 0)
         {
-            if (firstLongValue == -1)
+            *value = "[" + *value + "]";
+        }
+    }
+    if (option.isType<BooleanOptionInfo>())
+    {
+        *name = "[no]" + *name;
+        // Old command-line parser doesn't accept any values for these.
+        // value = "[" + value + "]";
+        value->clear();
+    }
+}
+
+//! Formats the default option value as a string.
+std::string
+defaultOptionValue(const OptionInfo &option)
+{
+    if (option.valueCount() == 0
+        || (option.valueCount() == 1 && option.formatValue(0).empty()))
+    {
+        return option.formatDefaultValueIfSet();
+    }
+    else
+    {
+        std::string result;
+        for (int i = 0; i < option.valueCount(); ++i)
+        {
+            if (i != 0)
             {
-                firstLongValue = i;
+                result.append(" ");
             }
-            lastLongValue = i;
+            result.append(option.formatValue(i));
         }
+        return result;
     }
+}
+
+//! Formats the flags for a file option as a string.
+std::string
+fileOptionFlagsAsString(const FileNameOptionInfo &option, bool bAbbrev)
+{
     std::string type;
     if (option.isInputOutputFile())
     {
-        type = "In/Out";
+        type = bAbbrev ? "In/Out" : "Input/Output";
     }
     else if (option.isInputFile())
     {
@@ -187,202 +337,262 @@ void FileParameterWriter::visitOptionType(const FileNameOptionInfo &option)
     }
     if (!option.isRequired())
     {
-        type += ", Opt.";
+        type += bAbbrev ? ", Opt." : ", Optional";
     }
     if (option.isLibraryFile())
     {
-        type += ", Lib.";
+        type += bAbbrev ? ", Lib." : ", Library";
     }
-    bool bLongType = (type.length() > 12U);
-    formatter_.addColumnLine(2, type);
-    formatter_.addColumnLine(3, substituteMarkupForConsole(option.description()));
+    return type;
+}
 
-    // Compute layout.
-    if (name.length() > 6U || firstShortValue > 0)
-    {
-        formatter_.setColumnFirstLineOffset(1, 1);
-        // Assume that the name is <20 chars, so that the type fits
-        if (firstLongValue >= 0)
-        {
-            ++firstLongValue;
-            ++lastLongValue;
-        }
-    }
-    int firstDescriptionLine = 0;
-    if (bLongType)
-    {
-        firstDescriptionLine = 1;
-    }
-    formatter_.setColumnFirstLineOffset(3, firstDescriptionLine);
-    if (firstLongValue >= 0 && formatter_.lastColumnLine(3) >= firstLongValue)
+//! Formats the description for an option as a string.
+std::string
+descriptionWithOptionDetails(const CommonFormatterData &common,
+                             const OptionInfo          &option)
+{
+    std::string             description(option.formatDescription());
+
+    const FloatOptionInfo  *floatOption  = option.toType<FloatOptionInfo>();
+    const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
+    if ((floatOption != NULL && floatOption->isTime())
+        || (doubleOption != NULL && doubleOption->isTime()))
     {
-        firstDescriptionLine = lastLongValue + 1;
-        formatter_.setColumnFirstLineOffset(3, firstDescriptionLine);
+        // TODO: It could be nicer to have this in basicoptions.cpp.
+        description = replaceAll(description, "%t", common.timeUnit);
     }
 
-    // Do the formatting.
-    file_.writeString(formatter_.formatRow());
+    return description;
 }
 
-
 /********************************************************************
- * ParameterWriter
+ * OptionsSynopsisFormatter
  */
 
-/*! \internal \brief
- * Helper object for writing help for non-file parameters.
- *
- * \ingroup module_commandline
+/*! \brief
+ * Formatter implementation for synopsis.
  */
-class ParameterWriter : public OptionsVisitor
+class SynopsisFormatter : public OptionsFormatterInterface
 {
     public:
-        //! Creates a helper object for writing non-file parameters.
-        ParameterWriter(File *file, const char *timeUnit);
+        //! Creates a helper object for formatting the synopsis.
+        explicit SynopsisFormatter(const HelpWriterContext &context)
+            : context_(context), lineLength_(0), indent_(0), currentLength_(0)
+        {
+        }
 
-        //! Sets the writer to show hidden options.
-        void setShowHidden(bool bSet) { bShowHidden_ = bSet; }
-        //! Returns true if anything was written out.
-        bool didOutput() const { return formatter_.didOutput(); }
+        //! Starts formatting the synopsis.
+        void start(const char *name);
+        //! Finishes formatting the synopsis.
+        void finish();
 
-        virtual void visitSubSection(const Options &section);
-        virtual void visitOption(const OptionInfo &option);
+        virtual void formatOption(const OptionInfo &option);
 
     private:
-        File                   &file_;
-        TextTableFormatter      formatter_;
-        const char             *timeUnit_;
-        bool                    bShowHidden_;
+        const HelpWriterContext &context_;
+        int                      lineLength_;
+        int                      indent_;
+        int                      currentLength_;
+
+        GMX_DISALLOW_COPY_AND_ASSIGN(SynopsisFormatter);
 };
 
-ParameterWriter::ParameterWriter(File *file, const char *timeUnit)
-    : file_(*file), timeUnit_(timeUnit), bShowHidden_(false)
+void SynopsisFormatter::start(const char *name)
 {
-    formatter_.addColumn("Option",      12, false);
-    formatter_.addColumn("Type",         6, false);
-    formatter_.addColumn("Value",        6, false);
-    formatter_.addColumn("Description", 51, true);
+    currentLength_ = std::strlen(name) + 1;
+    indent_        = std::min(currentLength_, 13);
+    File &file = context_.outputFile();
+    switch (context_.outputFormat())
+    {
+        case eHelpOutputFormat_Console:
+            lineLength_ = 78;
+            file.writeString(name);
+            break;
+        case eHelpOutputFormat_Man:
+            lineLength_ = 70;
+            file.writeString(name);
+            break;
+        case eHelpOutputFormat_Html:
+            lineLength_ = 78;
+            file.writeLine("<pre>");
+            file.writeString(name);
+            break;
+        default:
+            GMX_THROW(NotImplementedError("Synopsis formatting not implemented for this output format"));
+    }
 }
 
-void ParameterWriter::visitSubSection(const Options &section)
+void SynopsisFormatter::finish()
 {
-    OptionsIterator iterator(section);
-    iterator.acceptSubSections(this);
-    iterator.acceptOptions(this);
+    File &file = context_.outputFile();
+    file.writeLine();
+    if (context_.outputFormat() == eHelpOutputFormat_Html)
+    {
+        file.writeLine("</pre>");
+    }
+    file.writeLine();
 }
 
-void ParameterWriter::visitOption(const OptionInfo &option)
+void SynopsisFormatter::formatOption(const OptionInfo &option)
 {
-    if (option.isType<FileNameOptionInfo>()
-        || option.isType<SelectionFileOptionInfo>()
-        || option.isType<SelectionOptionInfo>()
-        || (!bShowHidden_ && option.isHidden()))
+    std::string name, value;
+    formatOptionNameAndValue(option, &name, &value);
+    std::string fullOptionText(" [-" + name);
+    if (!value.empty())
     {
-        return;
+        fullOptionText.append(" ");
+        fullOptionText.append(value);
     }
+    fullOptionText.append("]");
+    const int   totalLength = fullOptionText.size();
 
-    formatter_.clear();
-    bool bIsBool = option.isType<BooleanOptionInfo>();
-    std::string name(formatString("-%s%s", bIsBool ? "[no]" : "",
-                                           option.name().c_str()));
-    formatter_.addColumnLine(0, name);
-    formatter_.addColumnLine(1, option.type());
-    if (name.length() > 12U)
+    if (context_.outputFormat() == eHelpOutputFormat_Html)
     {
-        formatter_.setColumnFirstLineOffset(1, 1);
+        value = replaceAll(value, "<", "&lt;");
+        value = replaceAll(value, ">", "&gt;");
     }
-    // TODO: Better handling of multiple long values
-    std::string values;
-    for (int i = 0; i < option.valueCount(); ++i)
-    {
-        if (i != 0)
-        {
-            values.append(" ");
-        }
-        values.append(option.formatValue(i));
-    }
-    formatter_.addColumnLine(2, values);
-    std::string description(substituteMarkupForConsole(option.description()));
-    const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
-    if (doubleOption != NULL && doubleOption->isTime())
-    {
-        description = replaceAll(description, "%t", timeUnit_);
-    }
-    formatter_.addColumnLine(3, description);
-    if (values.length() > 6U)
+
+    File &file = context_.outputFile();
+    currentLength_ += totalLength;
+    if (currentLength_ >= lineLength_)
     {
-        formatter_.setColumnFirstLineOffset(3, 1);
+        file.writeString(formatString("\n%*c", indent_ - 1, ' '));
+        currentLength_ = indent_ - 1 + totalLength;
     }
-
-    file_.writeString(formatter_.formatRow());
+    file.writeString(fullOptionText);
 }
 
-
 /********************************************************************
- * SelectionParameterWriter
+ * OptionsListFormatter
  */
 
-/*! \internal \brief
- * Helper object for writing help for selection parameters.
- *
- * \ingroup module_commandline
+/*! \brief
+ * Formatter implementation for help export.
  */
-class SelectionParameterWriter : public OptionsVisitor
+class OptionsListFormatter : public OptionsFormatterInterface
 {
     public:
-        //! Creates a helper object for writing selection parameters.
-        explicit SelectionParameterWriter(File *file);
+        //! Creates a helper object for formatting options.
+        OptionsListFormatter(const HelpWriterContext   &context,
+                             const CommonFormatterData &common,
+                             const char                *title);
 
-        //! Returns true if anything was written out.
-        bool didOutput() const { return formatter_.didOutput(); }
+        //! Initiates a new section in the options list.
+        void startSection(const char *header)
+        {
+            header_     = header;
+            bDidOutput_ = false;
+        }
+        //! Finishes a section in the options list.
+        void finishSection()
+        {
+            if (bDidOutput_)
+            {
+                context_.writeOptionListEnd();
+                context_.outputFile().writeLine();
+            }
+        }
 
-        virtual void visitSubSection(const Options &section);
-        virtual void visitOption(const OptionInfo &option);
+        virtual void formatOption(const OptionInfo &option);
 
     private:
-        File                   &file_;
-        TextTableFormatter      formatter_;
-};
+        void writeSectionStartIfNecessary()
+        {
+            if (title_ != NULL)
+            {
+                context_.writeTitle(title_);
+                title_ = NULL;
+            }
+            if (!bDidOutput_)
+            {
+                if (header_ != NULL)
+                {
+                    context_.writeTextBlock(header_);
+                }
+                context_.writeOptionListStart();
+            }
+            bDidOutput_ = true;
+        }
 
-SelectionParameterWriter::SelectionParameterWriter(File *file)
-    : file_(*file)
-{
-    formatter_.addColumn("Selection",   10, false);
-    formatter_.addColumn("Description", 67, true);
-}
+        const HelpWriterContext               &context_;
+        const CommonFormatterData             &common_;
+        boost::scoped_ptr<TextTableFormatter>  consoleFormatter_;
+        const char                            *title_;
+        const char                            *header_;
+        bool                                   bDidOutput_;
+
+        GMX_DISALLOW_COPY_AND_ASSIGN(OptionsListFormatter);
+};
 
-void SelectionParameterWriter::visitSubSection(const Options &section)
+OptionsListFormatter::OptionsListFormatter(
+        const HelpWriterContext   &context,
+        const CommonFormatterData &common,
+        const char                *title)
+    : context_(context), common_(common),
+      title_(title), header_(NULL), bDidOutput_(false)
 {
-    OptionsIterator iterator(section);
-    iterator.acceptSubSections(this);
-    iterator.acceptOptions(this);
+    if (context.outputFormat() == eHelpOutputFormat_Console)
+    {
+        consoleFormatter_.reset(new TextTableFormatter());
+        consoleFormatter_->setFirstColumnIndent(1);
+        consoleFormatter_->setFoldLastColumnToNextLine(4);
+        consoleFormatter_->addColumn(NULL, 6, false);
+        consoleFormatter_->addColumn(NULL, 8, false);
+        consoleFormatter_->addColumn(NULL, 10, false);
+        consoleFormatter_->addColumn(NULL, 50, true);
+    }
 }
 
-void SelectionParameterWriter::visitOption(const OptionInfo &option)
+void OptionsListFormatter::formatOption(const OptionInfo &option)
 {
-    if (!option.isType<SelectionFileOptionInfo>()
-        && !option.isType<SelectionOptionInfo>())
+    writeSectionStartIfNecessary();
+    std::string name, value;
+    formatOptionNameAndValue(option, &name, &value);
+    std::string defaultValue(defaultOptionValue(option));
+    std::string info;
+    if (!defaultValue.empty())
     {
-        return;
+        info = "(" + defaultValue + ")";
     }
-
-    formatter_.clear();
-    std::string name(formatString("-%s", option.name().c_str()));
-    formatter_.addColumnLine(0, name);
-    formatter_.addColumnLine(1, substituteMarkupForConsole(option.description()));
-    file_.writeString(formatter_.formatRow());
-
-    // TODO: What to do with selection variables?
-    // They are not printed as values for any option.
-    for (int i = 0; i < option.valueCount(); ++i)
+    const FileNameOptionInfo *fileOption = option.toType<FileNameOptionInfo>();
+    if (fileOption != NULL)
     {
-        std::string value(option.formatValue(i));
-        // TODO: Wrapping
-        file_.writeLine(formatString("    %s", value.c_str()));
+        const bool bAbbrev = (context_.outputFormat() == eHelpOutputFormat_Console);
+        if (!info.empty())
+        {
+            info.append(" ");
+        }
+        info.append("(");
+        info.append(fileOptionFlagsAsString(*fileOption, bAbbrev));
+        info.append(")");
+    }
+    std::string description(descriptionWithOptionDetails(common_, option));
+    if (context_.outputFormat() == eHelpOutputFormat_Console)
+    {
+        consoleFormatter_->clear();
+        consoleFormatter_->addColumnLine(0, "-" + name);
+        consoleFormatter_->addColumnLine(1, value);
+        if (!info.empty())
+        {
+            consoleFormatter_->addColumnLine(2, info);
+        }
+        consoleFormatter_->addColumnHelpTextBlock(3, context_, description);
+        context_.outputFile().writeString(consoleFormatter_->formatRow());
+    }
+    else
+    {
+        if (!info.empty())
+        {
+            value.append(" ");
+            value.append(info);
+        }
+        context_.writeOptionItem("-" + name, value, description);
     }
 }
 
-} // namespace
+//! \}
+
+}   // namespace
 
 /********************************************************************
  * CommandLineHelpWriter::Impl
@@ -399,22 +609,64 @@ class CommandLineHelpWriter::Impl
         //! Sets the Options object to use for generating help.
         explicit Impl(const Options &options);
 
+        //! Format the list of known issues.
+        void formatBugs(const HelpWriterContext &context);
+
         //! Options object to use for generating help.
-        const Options          &options_;
+        const Options               &options_;
+        //! List of bugs/knows issues.
+        ConstArrayRef<const char *>  bugs_;
         //! Time unit to show in descriptions.
-        std::string             timeUnit_;
+        std::string                  timeUnit_;
         //! Whether to write descriptions to output.
-        bool                    bShowDescriptions_;
-        //! Whether to write hidden options to output.
-        bool                    bShowHidden_;
+        bool                         bShowDescriptions_;
 };
 
 CommandLineHelpWriter::Impl::Impl(const Options &options)
     : options_(options), timeUnit_(TimeUnitManager().timeUnitAsString()),
-      bShowDescriptions_(false), bShowHidden_(false)
+      bShowDescriptions_(false)
 {
 }
 
+void CommandLineHelpWriter::Impl::formatBugs(const HelpWriterContext &context)
+{
+    if (bugs_.empty())
+    {
+        return;
+    }
+    context.writeTitle("Known Issues");
+    if (context.outputFormat() != eHelpOutputFormat_Console)
+    {
+        context.writeTextBlock("[UL]");
+    }
+    ConstArrayRef<const char *>::const_iterator i;
+    for (i = bugs_.begin(); i != bugs_.end(); ++i)
+    {
+        const char *const bug = *i;
+        // TODO: The context should be able to do this also for console output, but
+        // that requires a lot more elaborate parser for the markup.
+        if (context.outputFormat() == eHelpOutputFormat_Console)
+        {
+            TextLineWrapperSettings settings;
+            settings.setIndent(2);
+            settings.setFirstLineIndent(0);
+            settings.setLineLength(78);
+            context.outputFile().writeLine(
+                    context.substituteMarkupAndWrapToString(
+                            settings, formatString("* %s", bug)));
+        }
+        else
+        {
+            context.writeTextBlock(formatString("[LI]%s", bug));
+        }
+    }
+    if (context.outputFormat() != eHelpOutputFormat_Console)
+    {
+        context.writeTextBlock("[ul]");
+    }
+}
+
+
 /********************************************************************
  * CommandLineHelpWriter
  */
@@ -428,58 +680,67 @@ CommandLineHelpWriter::~CommandLineHelpWriter()
 {
 }
 
-CommandLineHelpWriter &CommandLineHelpWriter::setShowHidden(bool bSet)
+CommandLineHelpWriter &
+CommandLineHelpWriter::setShowDescriptions(bool bSet)
 {
-    impl_->bShowHidden_ = bSet;
+    impl_->bShowDescriptions_ = bSet;
     return *this;
 }
 
-CommandLineHelpWriter &CommandLineHelpWriter::setShowDescriptions(bool bSet)
+CommandLineHelpWriter &
+CommandLineHelpWriter::setTimeUnitString(const char *timeUnit)
 {
-    impl_->bShowDescriptions_ = bSet;
+    impl_->timeUnit_ = timeUnit;
     return *this;
 }
 
-CommandLineHelpWriter &CommandLineHelpWriter::setTimeUnitString(const char *timeUnit)
+CommandLineHelpWriter &
+CommandLineHelpWriter::setKnownIssues(const ConstArrayRef<const char *> &bugs)
 {
-    impl_->timeUnit_ = timeUnit;
+    impl_->bugs_ = bugs;
     return *this;
 }
 
-void CommandLineHelpWriter::writeHelp(File *file)
+void CommandLineHelpWriter::writeHelp(const CommandLineHelpContext &context)
 {
-    if (impl_->bShowDescriptions_)
+    if (context.isCompletionExport())
     {
-        file->writeLine("DESCRIPTION");
-        file->writeLine("-----------");
-        file->writeLine();
-        DescriptionWriter(file).visitSubSection(impl_->options_);
-    }
-    {
-        FileParameterWriter writer(file);
-        writer.visitSubSection(impl_->options_);
-        if (writer.didOutput())
-        {
-            file->writeLine();
-        }
+        context.shellCompletionWriter().writeModuleCompletions(
+                context.moduleDisplayName(), impl_->options_);
+        return;
     }
+    const HelpWriterContext &writerContext = context.writerContext();
+    OptionsFilter            filter;
+    filter.setShowHidden(context.showHidden());
+
     {
-        ParameterWriter writer(file, impl_->timeUnit_.c_str());
-        writer.setShowHidden(impl_->bShowHidden_);
-        writer.visitSubSection(impl_->options_);
-        if (writer.didOutput())
-        {
-            file->writeLine();
-        }
+        writerContext.writeTitle("Synopsis");
+        SynopsisFormatter synopsisFormatter(writerContext);
+        synopsisFormatter.start(context.moduleDisplayName());
+        filter.formatSelected(OptionsFilter::eSelectFileOptions,
+                              &synopsisFormatter, impl_->options_);
+        filter.formatSelected(OptionsFilter::eSelectOtherOptions,
+                              &synopsisFormatter, impl_->options_);
+        synopsisFormatter.finish();
     }
+
+    if (impl_->bShowDescriptions_)
     {
-        SelectionParameterWriter writer(file);
-        writer.visitSubSection(impl_->options_);
-        if (writer.didOutput())
-        {
-            file->writeLine();
-        }
+        DescriptionsFormatter descriptionFormatter(writerContext);
+        descriptionFormatter.format(impl_->options_, "Description");
     }
+    CommonFormatterData    common(impl_->timeUnit_.c_str());
+    OptionsListFormatter   formatter(writerContext, common, "Options");
+    formatter.startSection("Options to specify input and output files:[PAR]");
+    filter.formatSelected(OptionsFilter::eSelectFileOptions,
+                          &formatter, impl_->options_);
+    formatter.finishSection();
+    formatter.startSection("Other options:[PAR]");
+    filter.formatSelected(OptionsFilter::eSelectOtherOptions,
+                          &formatter, impl_->options_);
+    formatter.finishSection();
+
+    impl_->formatBugs(writerContext);
 }
 
 } // namespace gmx