Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / commandline / cmdlinehelpmodule.cpp
index 87f3ca9a076e4d2f0b3c26fdd4e988bbed01bf4f..3a67a1ff4ab4008f77a9d825c305bc561abca3ac 100644 (file)
  * \author Teemu Murtola <teemu.murtola@gmail.com>
  * \ingroup module_commandline
  */
-#include "gromacs/commandline/cmdlinehelpmodule.h"
+#include "gmxpre.h"
+
+#include "cmdlinehelpmodule.h"
 
-#include <algorithm>
 #include <string>
 #include <vector>
 
 #include <boost/scoped_ptr.hpp>
 
-#include "gromacs/legacyheaders/copyrite.h"
-
 #include "gromacs/commandline/cmdlinehelpcontext.h"
 #include "gromacs/commandline/cmdlinehelpwriter.h"
 #include "gromacs/commandline/cmdlineparser.h"
-#include "gromacs/commandline/shellcompletions.h"
 #include "gromacs/onlinehelp/helpformat.h"
 #include "gromacs/onlinehelp/helpmanager.h"
 #include "gromacs/onlinehelp/helptopic.h"
 #include "gromacs/onlinehelp/helpwritercontext.h"
 #include "gromacs/options/basicoptions.h"
 #include "gromacs/options/options.h"
+#include "gromacs/utility/baseversion.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/file.h"
 #include "gromacs/utility/gmxassert.h"
-#include "gromacs/utility/programinfo.h"
+#include "gromacs/utility/programcontext.h"
 #include "gromacs/utility/stringutil.h"
 
+#include "shellcompletions.h"
+
 namespace gmx
 {
 
@@ -81,7 +82,7 @@ class RootHelpTopic;
 class CommandLineHelpModuleImpl
 {
     public:
-        CommandLineHelpModuleImpl(const ProgramInfo                &programInfo,
+        CommandLineHelpModuleImpl(const ProgramContextInterface    &programContext,
                                   const std::string                &binaryName,
                                   const CommandLineModuleMap       &modules,
                                   const CommandLineModuleGroupList &groups);
@@ -89,7 +90,7 @@ class CommandLineHelpModuleImpl
         void exportHelp(HelpExportInterface *exporter) const;
 
         boost::scoped_ptr<RootHelpTopic>  rootTopic_;
-        const ProgramInfo                &programInfo_;
+        const ProgramContextInterface    &programContext_;
         std::string                       binaryName_;
         const CommandLineModuleMap       &modules_;
         const CommandLineModuleGroupList &groups_;
@@ -98,6 +99,8 @@ class CommandLineHelpModuleImpl
         const CommandLineModuleInterface *moduleOverride_;
         bool                              bHidden_;
 
+        File                             *outputOverride_;
+
         GMX_DISALLOW_COPY_AND_ASSIGN(CommandLineHelpModuleImpl);
 };
 
@@ -118,9 +121,7 @@ struct RootHelpText
 // The first two are not used.
 const char        RootHelpText::name[]  = "";
 const char        RootHelpText::title[] = "";
-const char *const RootHelpText::text[]  = {
-    "Usage: [PROGRAM] [<options>] <command> [<args>]",
-};
+const char *const RootHelpText::text[]  = { "" };
 
 /*! \brief
  * Help topic that forms the root of the help tree for the help subcommand.
@@ -133,28 +134,17 @@ class RootHelpTopic : public CompositeHelpTopic<RootHelpText>
         /*! \brief
          * Creates a root help topic.
          *
-         * \param[in] modules  List of modules for to use for module listings.
-         *
          * Does not throw.
          */
-        explicit RootHelpTopic(const CommandLineModuleMap &modules)
-            : modules_(modules), commonOptions_(NULL)
-        {
-        }
-
-        //! Sets the common options for the wrapper binary.
-        void setCommonOptions(const Options *options)
+        explicit RootHelpTopic(const CommandLineHelpModuleImpl &helpModule)
+            : helpModule_(helpModule)
         {
-            commonOptions_ = options;
         }
 
         virtual void writeHelp(const HelpWriterContext &context) const;
 
     private:
-        void printModuleList(const HelpWriterContext &context) const;
-
-        const CommandLineModuleMap &modules_;
-        const Options              *commonOptions_;
+        const CommandLineHelpModuleImpl  &helpModule_;
 
         GMX_DISALLOW_COPY_AND_ASSIGN(RootHelpTopic);
 };
@@ -168,38 +158,75 @@ void RootHelpTopic::writeHelp(const HelpWriterContext &context) const
         GMX_THROW(NotImplementedError(
                           "Root help is not implemented for this output format"));
     }
-    writeBasicHelpTopic(context, *this, helpText());
-    context.outputFile().writeLine();
     {
-        CommandLineHelpContext cmdlineContext(context);
-        // TODO: Propagate the -hidden option here.
-        CommandLineHelpWriter(*commonOptions_)
+        CommandLineCommonOptionsHolder optionsHolder;
+        CommandLineHelpContext         cmdlineContext(*helpModule_.context_);
+        cmdlineContext.setModuleDisplayName(helpModule_.binaryName_);
+        optionsHolder.initOptions();
+        // TODO: Add <command> [<args>] into the synopsis.
+        CommandLineHelpWriter(*optionsHolder.options())
             .writeHelp(cmdlineContext);
     }
-    // TODO: If/when this list becomes long, it may be better to only print
-    // "common" commands here, and have a separate topic (e.g.,
-    // "help commands") that prints the full list.
-    printModuleList(context);
-    context.writeTextBlock(
-            "For additional help on a command, use '[PROGRAM] help <command>'");
+    // TODO: Consider printing a list of "core" commands. Would require someone
+    // to determine such a set...
     writeSubTopicList(context,
-                      "\nAdditional help is available on the following topics:");
+                      "Additional help is available on the following topics:");
     context.writeTextBlock(
-            "To access the help, use '[PROGRAM] help <topic>'.");
+            "To access the help, use '[PROGRAM] help <topic>'.[BR]"
+            "For help on a command, use '[PROGRAM] help <command>'.");
 }
 
-void RootHelpTopic::printModuleList(const HelpWriterContext &context) const
+/********************************************************************
+ * CommandsHelpTopic
+ */
+
+/*! \brief
+ * Help topic for listing the commands.
+ *
+ * \ingroup module_commandline
+ */
+class CommandsHelpTopic : public HelpTopicInterface
+{
+    public:
+        /*! \brief
+         * Creates a command list help topic.
+         *
+         * \param[in]     helpModule Help module to get module information from.
+         *
+         * Does not throw.
+         */
+        explicit CommandsHelpTopic(const CommandLineHelpModuleImpl &helpModule)
+            : helpModule_(helpModule)
+        {
+        }
+
+        virtual const char *name() const { return "commands"; }
+        virtual const char *title() const { return "List of available commands"; }
+        virtual bool hasSubTopics() const { return false; }
+        virtual const HelpTopicInterface *findSubTopic(const char * /*name*/) const
+        {
+            return NULL;
+        }
+
+        virtual void writeHelp(const HelpWriterContext &context) const;
+
+    private:
+        const CommandLineHelpModuleImpl &helpModule_;
+
+        GMX_DISALLOW_COPY_AND_ASSIGN(CommandsHelpTopic);
+};
+
+void CommandsHelpTopic::writeHelp(const HelpWriterContext &context) const
 {
     if (context.outputFormat() != eHelpOutputFormat_Console)
     {
-        // TODO: Implement once the situation with Redmine issue #969 is more
-        // clear.
         GMX_THROW(NotImplementedError(
                           "Module list is not implemented for this output format"));
     }
     int maxNameLength = 0;
-    CommandLineModuleMap::const_iterator module;
-    for (module = modules_.begin(); module != modules_.end(); ++module)
+    const CommandLineModuleMap           &modules = helpModule_.modules_;
+    CommandLineModuleMap::const_iterator  module;
+    for (module = modules.begin(); module != modules.end(); ++module)
     {
         int nameLength = static_cast<int>(module->first.length());
         if (module->second->shortDescription() != NULL
@@ -208,14 +235,15 @@ void RootHelpTopic::printModuleList(const HelpWriterContext &context) const
             maxNameLength = nameLength;
         }
     }
+    context.writeTextBlock(
+            "Usage: [PROGRAM] [<options>] <command> [<args>][PAR]"
+            "Available commands:");
     File              &file = context.outputFile();
     TextTableFormatter formatter;
     formatter.addColumn(NULL, maxNameLength + 1, false);
     formatter.addColumn(NULL, 72 - maxNameLength, true);
     formatter.setFirstColumnIndent(4);
-    file.writeLine();
-    file.writeLine("Available commands:");
-    for (module = modules_.begin(); module != modules_.end(); ++module)
+    for (module = modules.begin(); module != modules.end(); ++module)
     {
         const char *name        = module->first.c_str();
         const char *description = module->second->shortDescription();
@@ -227,6 +255,8 @@ void RootHelpTopic::printModuleList(const HelpWriterContext &context) const
             file.writeString(formatter.formatRow());
         }
     }
+    context.writeTextBlock(
+            "For help on a command, use '[PROGRAM] help <command>'.");
 }
 
 /********************************************************************
@@ -422,8 +452,7 @@ void HelpExportMan::exportModuleHelp(
     // TODO: It would be nice to remove the VERSION prefix from the version
     // string to make it shorter.
     file.writeLine(formatString(".TH %s 1 \"\" \"%s\" \"GROMACS Manual\"\n",
-                                tag.c_str(),
-                                GromacsVersion()));
+                                tag.c_str(), gmx_version()));
     file.writeLine(".SH NAME");
     file.writeLine(formatString("%s - %s", tag.c_str(),
                                 module.shortDescription()));
@@ -449,7 +478,7 @@ void HelpExportMan::startModuleGroupExport()
                        "gromacs.7.in must contain a @PROGMANPAGES@ line");
     std::string header = man7Template.substr(0, index);
     man7Footer_ = man7Template.substr(index + std::strlen(programListPlaceholder));
-    header      = replaceAll(header, "@VERSION@", GromacsVersion());
+    header      = replaceAll(header, "@VERSION@", gmx_version());
     man7File_.reset(new File("man7/gromacs.7", "w"));
     man7File_->writeLine(header);
 }
@@ -521,7 +550,6 @@ class HelpExportHtml : public HelpExportInterface
 HelpExportHtml::HelpExportHtml(const CommandLineHelpModuleImpl &helpModule)
     : links_(eHelpOutputFormat_Html)
 {
-    initProgramLinks(&links_, helpModule);
     File             linksFile("links.dat", "r");
     std::string      line;
     while (linksFile.readLine(&line))
@@ -529,13 +557,14 @@ HelpExportHtml::HelpExportHtml(const CommandLineHelpModuleImpl &helpModule)
         links_.addLink(line, "../online/" + line, line);
     }
     linksFile.close();
+    initProgramLinks(&links_, helpModule);
     setupHeaderAndFooter();
 }
 
 void HelpExportHtml::setupHeaderAndFooter()
 {
     header_ = gmx::File::readToString("header.html.in");
-    header_ = replaceAll(header_, "@VERSION@", GromacsVersion());
+    header_ = replaceAll(header_, "@VERSION@", gmx_version());
     gmx::File::writeFileFromString("header.html", header_);
     header_ = replaceAll(header_, "@ROOTPATH@", "../");
     footer_ = gmx::File::readToString("footer.html");
@@ -591,7 +620,12 @@ void HelpExportHtml::exportModuleGroup(const char                *title,
     {
         const std::string     &tag(module->first);
         std::string            displayName(tag);
-        std::replace(displayName.begin(), displayName.end(), '-', ' ');
+        // TODO: This does not work if the binary name would contain a dash,
+        // but that is not currently the case.
+        size_t                 dashPos = displayName.find('-');
+        GMX_RELEASE_ASSERT(dashPos != std::string::npos,
+                           "There should always be at least one dash in the tag");
+        displayName[dashPos] = ' ';
         indexFile_->writeLine(formatString("<a href=\"%s.html\">%s</a> - %s<br>",
                                            tag.c_str(), displayName.c_str(),
                                            module->second));
@@ -674,7 +708,9 @@ void HelpExportCompletion::exportModuleHelp(
 
 void HelpExportCompletion::finishModuleExport()
 {
-    bashWriter_.writeWrapperCompletions(modules_);
+    CommandLineCommonOptionsHolder optionsHolder;
+    optionsHolder.initOptions();
+    bashWriter_.writeWrapperCompletions(modules_, *optionsHolder.options());
     bashWriter_.finishCompletions();
 }
 
@@ -684,13 +720,14 @@ void HelpExportCompletion::finishModuleExport()
  * CommandLineHelpModuleImpl implementation
  */
 CommandLineHelpModuleImpl::CommandLineHelpModuleImpl(
-        const ProgramInfo                &programInfo,
+        const ProgramContextInterface    &programContext,
         const std::string                &binaryName,
         const CommandLineModuleMap       &modules,
         const CommandLineModuleGroupList &groups)
-    : rootTopic_(new RootHelpTopic(modules)), programInfo_(programInfo),
+    : rootTopic_(new RootHelpTopic(*this)), programContext_(programContext),
       binaryName_(binaryName), modules_(modules), groups_(groups),
-      context_(NULL), moduleOverride_(NULL), bHidden_(false)
+      context_(NULL), moduleOverride_(NULL), bHidden_(false),
+      outputOverride_(NULL)
 {
 }
 
@@ -708,8 +745,7 @@ void CommandLineHelpModuleImpl::exportHelp(HelpExportInterface *exporter) const
         {
             const char *const moduleName = module->first.c_str();
             std::string       tag(formatString("%s-%s", program, moduleName));
-            std::string       displayName(tag);
-            std::replace(displayName.begin(), displayName.end(), '-', ' ');
+            std::string       displayName(formatString("%s %s", program, moduleName));
             exporter->exportModuleHelp(*module->second, tag, displayName);
         }
     }
@@ -729,11 +765,11 @@ void CommandLineHelpModuleImpl::exportHelp(HelpExportInterface *exporter) const
  */
 
 CommandLineHelpModule::CommandLineHelpModule(
-        const ProgramInfo                &programInfo,
+        const ProgramContextInterface    &programContext,
         const std::string                &binaryName,
         const CommandLineModuleMap       &modules,
         const CommandLineModuleGroupList &groups)
-    : impl_(new Impl(programInfo, binaryName, modules, groups))
+    : impl_(new Impl(programContext, binaryName, modules, groups))
 {
 }
 
@@ -757,19 +793,22 @@ void CommandLineHelpModule::setShowHidden(bool bHidden)
     impl_->bHidden_ = bHidden;
 }
 
-void CommandLineHelpModule::setCommonOptions(const Options *options)
-{
-    impl_->rootTopic_->setCommonOptions(options);
-}
-
 void CommandLineHelpModule::setModuleOverride(
         const CommandLineModuleInterface &module)
 {
     impl_->moduleOverride_ = &module;
 }
 
+void CommandLineHelpModule::setOutputRedirect(File *output)
+{
+    impl_->outputOverride_ = output;
+}
+
 int CommandLineHelpModule::run(int argc, char *argv[])
 {
+    // Add internal topics lazily here.
+    addTopic(HelpTopicPointer(new CommandsHelpTopic(*impl_)));
+
     const char *const exportFormats[] = { "man", "html", "completion" };
     std::string       exportFormat;
     Options           options(NULL, NULL);
@@ -799,15 +838,20 @@ int CommandLineHelpModule::run(int argc, char *argv[])
         return 0;
     }
 
+    File *outputFile = &File::standardOutput();
+    if (impl_->outputOverride_ != NULL)
+    {
+        outputFile = impl_->outputOverride_;
+    }
     HelpLinks                                 links(eHelpOutputFormat_Console);
     initProgramLinks(&links, *impl_);
     boost::scoped_ptr<CommandLineHelpContext> context(
-            new CommandLineHelpContext(&File::standardOutput(),
+            new CommandLineHelpContext(outputFile,
                                        eHelpOutputFormat_Console, &links));
     context->setShowHidden(impl_->bHidden_);
     if (impl_->moduleOverride_ != NULL)
     {
-        context->setModuleDisplayName(impl_->programInfo_.displayName());
+        context->setModuleDisplayName(impl_->programContext_.displayName());
         impl_->moduleOverride_->writeHelp(*context);
         return 0;
     }