Print list of modules with 'g_ana help'.
authorTeemu Murtola <teemu.murtola@gmail.com>
Tue, 8 May 2012 05:33:25 +0000 (08:33 +0300)
committerTeemu Murtola <teemu.murtola@gmail.com>
Tue, 8 May 2012 05:35:26 +0000 (08:35 +0300)
IssueIDs #666 and #672.

Change-Id: I001966ab3ba44c59b0186456a6467322b3b3d26d

src/gromacs/commandline/cmdlinemodule.h
src/gromacs/commandline/cmdlinemodulemanager.cpp
src/gromacs/commandline/cmdlinemodulemanager.h
src/gromacs/commandline/tests/cmdlinemodulemanager.cpp
src/gromacs/trajectoryanalysis/modules.cpp
src/gromacs/trajectoryanalysis/modules/angle.cpp
src/gromacs/trajectoryanalysis/modules/angle.h
src/gromacs/trajectoryanalysis/modules/distance.cpp
src/gromacs/trajectoryanalysis/modules/distance.h
src/gromacs/trajectoryanalysis/modules/select.cpp
src/gromacs/trajectoryanalysis/modules/select.h

index c62a097f002de72b2470c6728da60d784aa4b46a..b60a462bc6d3b1024d40d1d16453e5a76a5a572c 100644 (file)
@@ -57,6 +57,8 @@ class CommandLineModuleInterface
 
         //! Returns the name of the module.
         virtual const char *name() const = 0;
+        //! Returns a one-line description of the module.
+        virtual const char *shortDescription() const = 0;
 
         /*! \brief
          * Runs the module with the given arguments.
index bcd7736ba215d744ee68b1251711027d7e0c79b1..13a5e96a0266100e8cec46a0f24cf94fefc9a31f 100644 (file)
@@ -67,7 +67,9 @@ class CommandLineModuleManager::Impl
         typedef std::map<std::string, CommandLineModulePointer> ModuleMap;
 
         //! Prints usage message to stderr.
-        void printUsage() const;
+        void printUsage(bool bModuleList) const;
+        //! Prints the list of modules to stderr.
+        void printModuleList() const;
 
         /*! \brief
          * Maps module names to module objects.
@@ -77,12 +79,97 @@ class CommandLineModuleManager::Impl
         ModuleMap               modules_;
 };
 
-void CommandLineModuleManager::Impl::printUsage() const
+void CommandLineModuleManager::Impl::printUsage(bool bModuleList) const
+{
+    const char *program = ShortProgram();
+    fprintf(stderr, "Usage: %s <command> [<args>]\n\n", program);
+    if (bModuleList)
+    {
+        printModuleList();
+    }
+    else
+    {
+        fprintf(stderr, "See '%s help' for list of commands.\n", program);
+    }
+}
+
+void CommandLineModuleManager::Impl::printModuleList() const
+{
+    int maxNameLength = 0;
+    ModuleMap::const_iterator module;
+    for (module = modules_.begin(); module != modules_.end(); ++module)
+    {
+        int nameLength = static_cast<int>(module->first.length());
+        if (nameLength > maxNameLength)
+        {
+            maxNameLength = nameLength;
+        }
+    }
+    fprintf(stderr, "The following commands are available:\n");
+    for (module = modules_.begin(); module != modules_.end(); ++module)
+    {
+        const char *name = module->first.c_str();
+        const char *description = module->second->shortDescription();
+        fprintf(stderr, "    %*s  %s\n", -maxNameLength, name, description);
+    }
+}
+
+
+/********************************************************************
+ * CommandLineHelpModule
+ */
+
+namespace internal
+{
+
+/*! \internal \brief
+ * Command-line module for producing help.
+ *
+ * This module implements the 'help' subcommand that is automatically added by
+ * CommandLineModuleManager.
+ *
+ * \ingroup module_commandline
+ */
+class CommandLineHelpModule : public CommandLineModuleInterface
+{
+    public:
+        /*! \brief
+         * Creates a help module for the given module manager.
+         *
+         * \param[in] manager  Manager for which this module provides help.
+         *
+         * Does not throw.
+         */
+        explicit CommandLineHelpModule(const CommandLineModuleManager &manager);
+
+        virtual const char *name() const { return "help"; }
+        virtual const char *shortDescription() const
+        {
+            return "Print help information";
+        }
+
+        virtual int run(int argc, char *argv[]);
+
+    private:
+        const CommandLineModuleManager &manager_;
+
+        GMX_DISALLOW_COPY_AND_ASSIGN(CommandLineHelpModule);
+};
+
+CommandLineHelpModule::CommandLineHelpModule(const CommandLineModuleManager &manager)
+    : manager_(manager)
 {
-    fprintf(stderr, "Usage: %s <command> [<args>]\n",
-            ShortProgram());
 }
 
+int CommandLineHelpModule::run(int argc, char *argv[])
+{
+    manager_.impl_->printUsage(true);
+    return 0;
+}
+
+} // namespace internal
+
+
 /********************************************************************
  * CommandLineModuleManager
  */
@@ -90,6 +177,7 @@ void CommandLineModuleManager::Impl::printUsage() const
 CommandLineModuleManager::CommandLineModuleManager()
     : impl_(new Impl)
 {
+    addModule(CommandLineModulePointer(new internal::CommandLineHelpModule(*this)));
 }
 
 CommandLineModuleManager::~CommandLineModuleManager()
@@ -109,7 +197,7 @@ int CommandLineModuleManager::run(int argc, char *argv[])
     if (argc < 2)
     {
         fprintf(stderr, "\n");
-        impl_->printUsage();
+        impl_->printUsage(false);
         return 2;
     }
     // TODO: Accept unambiguous prefixes?
@@ -117,8 +205,8 @@ int CommandLineModuleManager::run(int argc, char *argv[])
     if (module == impl_->modules_.end())
     {
         fprintf(stderr, "\n");
-        fprintf(stderr, "Unknown command: %s\n", argv[1]);
-        impl_->printUsage();
+        fprintf(stderr, "Unknown command: '%s'\n", argv[1]);
+        impl_->printUsage(true);
         return 2;
     }
     return module->second->run(argc - 1, argv + 1);
index 6e3f7e3dcad11b9ea232abdcc5db0eef80b43eb9..2db11d3d2ed36fc8fa7d59eb1daeb448de8e7515 100644 (file)
@@ -51,6 +51,11 @@ class CommandLineModuleInterface;
 typedef gmx_unique_ptr<CommandLineModuleInterface>::type
         CommandLineModulePointer;
 
+namespace internal
+{
+class CommandLineHelpModule;
+}
+
 /*! \brief
  * Implements a wrapper command-line interface for multiple modules.
  *
@@ -136,6 +141,11 @@ class CommandLineModuleManager
         class Impl;
 
         PrivateImplPointer<Impl> impl_;
+
+        /*! \brief
+         * Needed to access information about registered modules etc.
+         */
+        friend class internal::CommandLineHelpModule;
 };
 
 } // namespace gmx
index 0f427c883a2cc1894c4bd2bbbefa1a21527feffe..19789066f7f1e20fc4e091d6a35997d76f0c9d00 100644 (file)
@@ -59,19 +59,21 @@ namespace
 class MockModule : public gmx::CommandLineModuleInterface
 {
     public:
-        //! Creates a mock module with the given name.
-        explicit MockModule(const char *name);
+        //! Creates a mock module with the given name and description.
+        MockModule(const char *name, const char *description);
 
         virtual const char *name() const { return name_; }
+        virtual const char *shortDescription() const { return descr_; }
 
         MOCK_METHOD2(run, int(int argc, char *argv[]));
 
     private:
         const char             *name_;
+        const char             *descr_;
 };
 
-MockModule::MockModule(const char *name)
-    : name_(name)
+MockModule::MockModule(const char *name, const char *description)
+    : name_(name), descr_(description)
 {
 }
 
@@ -82,15 +84,15 @@ MockModule::MockModule(const char *name)
 class CommandLineModuleManagerTest : public ::testing::Test
 {
     public:
-        MockModule &addModule(const char *name);
+        MockModule &addModule(const char *name, const char *description);
 
         gmx::CommandLineModuleManager manager_;
 };
 
 MockModule &
-CommandLineModuleManagerTest::addModule(const char *name)
+CommandLineModuleManagerTest::addModule(const char *name, const char *description)
 {
-    MockModule *module = new MockModule(name);
+    MockModule *module = new MockModule(name, description);
     manager_.addModule(gmx::CommandLineModulePointer(module));
     return *module;
 }
@@ -105,8 +107,8 @@ TEST_F(CommandLineModuleManagerTest, RunsModule)
         "test", "module", "-flag", "yes"
     };
     gmx::test::CommandLine args(cmdline);
-    MockModule &mod1 = addModule("module");
-    addModule("other");
+    MockModule &mod1 = addModule("module", "First module");
+    addModule("other", "Second module");
     using ::testing::_;
     using ::testing::Args;
     using ::testing::ElementsAreArray;
index e1ede11265b969453c95daa214fbd0873db9aa19..7b9087c9060794c12e4e02b4331bb866ebd9537a 100644 (file)
@@ -63,6 +63,7 @@ class AbstractTrajAnalysisCmdLineWrapper : public CommandLineModuleInterface
 {
     public:
         virtual const char *name() const = 0;
+        virtual const char *shortDescription() const = 0;
 
         virtual int run(int argc, char *argv[]);
 
@@ -85,8 +86,8 @@ int AbstractTrajAnalysisCmdLineWrapper::run(int argc, char *argv[])
  * \tparam Module  Trajectory analysis module to wrap.
  *
  * \p Module should be default-constructible, derive from
- * TrajectoryAnalysisModule, and have a static public member
- * \c "const char name[]".
+ * TrajectoryAnalysisModule, and have a static public members
+ * \c "const char name[]" and \c "const char shortDescription[]".
  *
  * \ingroup module_trajectoryanalysis
  */
@@ -98,6 +99,10 @@ class TrajAnalysisCmdLineWrapper : public AbstractTrajAnalysisCmdLineWrapper
         {
             return Module::name;
         }
+        virtual const char *shortDescription() const
+        {
+            return Module::shortDescription;
+        }
         virtual TrajectoryAnalysisModulePointer createModule()
         {
             return TrajectoryAnalysisModulePointer(new Module);
index 66d6c9f1fbf2bd595cff0e65febfd5d1f92cd8cf..6269f5fa69a9711bc177d5177aaf5a1c9db207da 100644 (file)
@@ -64,9 +64,11 @@ namespace analysismodules
 {
 
 const char Angle::name[] = "angle";
+const char Angle::shortDescription[] =
+    "Calculate angles";
 
 Angle::Angle()
-    : _options(name, "Angle calculation"),
+    : _options(name, shortDescription),
       _sel1info(NULL), _sel2info(NULL),
       _bSplit1(false), _bSplit2(false), _bMulti(false), _bAll(false),
       _bDumpDist(false), _natoms1(0), _natoms2(0), _vt0(NULL)
index 6b67dbb257c2cbc1b3948c9c95a1a3a6553c771d..ea18aec88eea2326f9b070e6fa0b90758d3ac36e 100644 (file)
@@ -57,6 +57,7 @@ class Angle : public TrajectoryAnalysisModule
 {
     public:
         static const char name[];
+        static const char shortDescription[];
 
         Angle();
         virtual ~Angle();
index 5932d66aed7aba5d05fb9126859c3e454fc9fd2a..f375fbc70513d6337a504bc05cebc4757740cc87 100644 (file)
@@ -62,9 +62,11 @@ namespace analysismodules
 {
 
 const char Distance::name[] = "distance";
+const char Distance::shortDescription[] =
+    "Calculate distances";
 
 Distance::Distance()
-    : _options(name, "Distance calculation"), _avem(new AnalysisDataAverageModule())
+    : _options(name, shortDescription), _avem(new AnalysisDataAverageModule())
 {
 }
 
index 0a1d48d43edbe1952ebab47be86d0da9af5c16b7..7035e1f21a69a3c1c800c97447b80e615a8820f3 100644 (file)
@@ -56,6 +56,7 @@ class Distance : public TrajectoryAnalysisModule
 {
     public:
         static const char name[];
+        static const char shortDescription[];
 
         Distance();
         virtual ~Distance();
index 42659e01f9869f9762704839e0a7ddeb993c6d5f..fab66e71c07c78336a13044efb8f1f63a19c8b23 100644 (file)
@@ -240,9 +240,11 @@ void IndexFileWriterModule::dataFinished()
  */
 
 const char Select::name[] = "select";
+const char Select::shortDescription[] =
+    "Print general information about selections";
 
 Select::Select()
-    : _options(name, "Selection information"),
+    : _options(name, shortDescription),
       _bDump(false), _bTotNorm(false), _bFracNorm(false), _bResInd(false),
       _top(NULL)
 {
index 5ab4be95a2b999755bd8af35caf8dec82a22a834..775f4c4e84520b826e069535a266cf2d1e6259ce 100644 (file)
@@ -56,6 +56,7 @@ class Select : public TrajectoryAnalysisModule
 {
     public:
         static const char name[];
+        static const char shortDescription[];
 
         Select();
         virtual ~Select();