/programs/byname
/programs/bytopic
+ /programs/selections
+
.. toctree::
:hidden:
:glob:
namespace
{
+/********************************************************************
+ * HelpExportInterface
+ */
+
+/*! \brief
+ * Callbacks for exporting help information for command-line modules.
+ *
+ * \ingroup module_commandline
+ */
+class HelpExportInterface
+{
+ public:
+ //! Shorthand for a list of modules contained in a group.
+ typedef CommandLineModuleGroupData::ModuleList ModuleGroupContents;
+
+ virtual ~HelpExportInterface() {};
+
+ /*! \brief
+ * Called once before exporting individual modules.
+ *
+ * Can, e.g., open shared output files (e.g., if the output is written
+ * into a single file, or if a separate index is required) and write
+ * headers into them.
+ */
+ virtual void startModuleExport() = 0;
+ /*! \brief
+ * Called to export the help for each module.
+ *
+ * \param[in] module Module for which the help should be exported.
+ * \param[in] tag Unique tag for the module (gmx-something).
+ * \param[in] displayName Display name for the module (gmx something).
+ */
+ virtual void exportModuleHelp(
+ const CommandLineModuleInterface &module,
+ const std::string &tag,
+ const std::string &displayName) = 0;
+ /*! \brief
+ * Called after all modules have been exported.
+ *
+ * Can close files opened in startModuleExport(), write footers to them
+ * etc.
+ */
+ virtual void finishModuleExport() = 0;
+
+ /*! \brief
+ * Called once before exporting module groups.
+ *
+ * Can, e.g., open a single output file for listing all the groups.
+ */
+ virtual void startModuleGroupExport() = 0;
+ /*! \brief
+ * Called to export the help for each module group.
+ *
+ * \param[in] title Title for the group.
+ * \param[in] modules List of modules in the group.
+ */
+ virtual void exportModuleGroup(const char *title,
+ const ModuleGroupContents &modules) = 0;
+ /*! \brief
+ * Called after all module groups have been exported.
+ *
+ * Can close files opened in startModuleGroupExport(), write footers to them
+ * etc.
+ */
+ virtual void finishModuleGroupExport() = 0;
+
+ /*! \brief
+ * Called to export the help for a top-level topic.
+ *
+ * \param[in] topic Topic to export.
+ */
+ virtual void exportTopic(const HelpTopicInterface &topic) = 0;
+};
+
/********************************************************************
* RootHelpTopic
*/
{
}
+ //! Adds a top-level topic and optionally marks it as exported.
+ void addTopic(HelpTopicPointer topic, bool bExported)
+ {
+ if (bExported)
+ {
+ exportedTopics_.push_back(topic->name());
+ }
+ addSubTopic(move(topic));
+ }
+ //! Exports all the top-level topics with the given exporter.
+ void exportHelp(HelpExportInterface *exporter) const;
+
virtual void writeHelp(const HelpWriterContext &context) const;
private:
const CommandLineHelpModuleImpl &helpModule_;
+ std::vector<std::string> exportedTopics_;
GMX_DISALLOW_COPY_AND_ASSIGN(RootHelpTopic);
};
+void RootHelpTopic::exportHelp(HelpExportInterface *exporter) const
+{
+ std::vector<std::string>::const_iterator topicName;
+ for (topicName = exportedTopics_.begin();
+ topicName != exportedTopics_.end();
+ ++topicName)
+ {
+ const HelpTopicInterface *topic = findSubTopic(topicName->c_str());
+ GMX_RELEASE_ASSERT(topic != NULL, "Exported help topic no longer found");
+ exporter->exportTopic(*topic);
+ }
+}
+
void RootHelpTopic::writeHelp(const HelpWriterContext &context) const
{
if (context.outputFormat() != eHelpOutputFormat_Console)
}
/********************************************************************
- * HelpExportInterface
- */
-
-/*! \brief
- * Callbacks for exporting help information for command-line modules.
- *
- * \ingroup module_commandline
+ * HelpExportReStructuredText
*/
-class HelpExportInterface
-{
- public:
- //! Shorthand for a list of modules contained in a group.
- typedef CommandLineModuleGroupData::ModuleList ModuleGroupContents;
-
- virtual ~HelpExportInterface() {};
-
- /*! \brief
- * Called once before exporting individual modules.
- *
- * Can, e.g., open shared output files (e.g., if the output is written
- * into a single file, or if a separate index is required) and write
- * headers into them.
- */
- virtual void startModuleExport() = 0;
- /*! \brief
- * Called to export the help for each module.
- *
- * \param[in] module Module for which the help should be exported.
- * \param[in] tag Unique tag for the module (gmx-something).
- * \param[in] displayName Display name for the module (gmx something).
- */
- virtual void exportModuleHelp(
- const CommandLineModuleInterface &module,
- const std::string &tag,
- const std::string &displayName) = 0;
- /*! \brief
- * Called after all modules have been exported.
- *
- * Can close files opened in startModuleExport(), write footers to them
- * etc.
- */
- virtual void finishModuleExport() = 0;
-
- /*! \brief
- * Called once before exporting module groups.
- *
- * Can, e.g., open a single output file for listing all the groups.
- */
- virtual void startModuleGroupExport() = 0;
- /*! \brief
- * Called to export the help for each module group.
- *
- * \param[in] title Title for the group.
- * \param[in] modules List of modules in the group.
- */
- virtual void exportModuleGroup(const char *title,
- const ModuleGroupContents &modules) = 0;
- /*! \brief
- * Called after all module groups have been exported.
- *
- * Can close files opened in startModuleGroupExport(), write footers to them
- * etc.
- */
- virtual void finishModuleGroupExport() = 0;
-};
/*! \internal \brief
* Adds hyperlinks to modules within this binary.
}
}
-/********************************************************************
- * HelpExportReStructuredText
- */
-
/*! \internal \brief
* Implements export for web pages as reStructuredText.
*
const ModuleGroupContents &modules);
virtual void finishModuleGroupExport();
+ virtual void exportTopic(const HelpTopicInterface &topic);
+
private:
FileOutputRedirectorInterface *outputRedirector_;
HelpLinks links_;
manPagesFile_.reset();
}
+void HelpExportReStructuredText::exportTopic(const HelpTopicInterface &topic)
+{
+ const std::string path("programs/" + std::string(topic.name()) + ".rst");
+ File file(outputRedirector_->openFileForWriting(path));
+ HelpWriterContext context(&file, eHelpOutputFormat_Rst, &links_);
+ HelpManager manager(topic, context);
+ manager.writeCurrentTopic();
+}
+
/********************************************************************
* HelpExportCompletion
*/
const ModuleGroupContents & /*modules*/) {}
virtual void finishModuleGroupExport() {}
+ virtual void exportTopic(const HelpTopicInterface & /*topic*/) {}
+
private:
ShellCompletionWriter bashWriter_;
std::vector<std::string> modules_;
/********************************************************************
* CommandLineHelpModuleImpl implementation
*/
+
CommandLineHelpModuleImpl::CommandLineHelpModuleImpl(
const ProgramContextInterface &programContext,
const std::string &binaryName,
exporter->exportModuleGroup((*group)->title(), (*group)->modules());
}
exporter->finishModuleGroupExport();
+
+ rootTopic_->exportHelp(exporter);
}
/********************************************************************
return HelpTopicPointer(new ModuleHelpTopic(module, *impl_));
}
-void CommandLineHelpModule::addTopic(HelpTopicPointer topic)
+void CommandLineHelpModule::addTopic(HelpTopicPointer topic, bool bExported)
{
- impl_->rootTopic_->addSubTopic(move(topic));
+ impl_->rootTopic_->addTopic(move(topic), bExported);
}
void CommandLineHelpModule::setShowHidden(bool bHidden)
int CommandLineHelpModule::run(int argc, char *argv[])
{
// Add internal topics lazily here.
- addTopic(HelpTopicPointer(new CommandsHelpTopic(*impl_)));
+ addTopic(HelpTopicPointer(new CommandsHelpTopic(*impl_)), false);
const char *const exportFormats[] = { "rst", "completion" };
std::string exportFormat;
/*! \brief
* Adds a top-level help topic.
*
- * \param[in] topic Help topic to add.
+ * \param[in] topic Help topic to add.
+ * \param[in] bExported Whether this topic will be directly exported to
+ * the user guide.
* \throws std::bad_alloc if out of memory.
*/
- void addTopic(HelpTopicPointer topic);
+ void addTopic(HelpTopicPointer topic, bool bExported);
//! Sets whether hidden options will be shown in help.
void setShowHidden(bool bHidden);
/*! \brief
HelpTopicPointer helpTopic(helpModule_->createModuleHelpTopic(*module));
modules_.insert(std::make_pair(std::string(module->name()),
move(module)));
- helpModule_->addTopic(move(helpTopic));
+ helpModule_->addTopic(move(helpTopic), false);
}
void CommandLineModuleManager::Impl::ensureHelpModuleExists()
void CommandLineModuleManager::addHelpTopic(HelpTopicPointer topic)
{
impl_->ensureHelpModuleExists();
- impl_->helpModule_->addTopic(move(topic));
+ impl_->helpModule_->addTopic(move(topic), true);
}
int CommandLineModuleManager::run(int argc, char *argv[])
gmx::CommandLineModuleGroup group = manager().addModuleGroup("Group 2");
group.addModule("other");
}
+ MockHelpTopic &topic1 = addHelpTopic("topic1", "Test topic");
+ MockHelpTopic &sub1 = topic1.addSubTopic("sub1", "Subtopic 1", "Sub text");
+ MockHelpTopic &sub2 = topic1.addSubTopic("sub2", "Subtopic 2", "Sub text");
+ MockHelpTopic &topic2 = addHelpTopic("topic2", "Another topic");
using ::testing::_;
using ::testing::Invoke;
EXPECT_CALL(mod1, initOptions(_)).WillOnce(Invoke(&initOptionsBasic));
EXPECT_CALL(mod2, initOptions(_));
+ EXPECT_CALL(topic1, writeHelp(_));
+ EXPECT_CALL(sub1, writeHelp(_));
+ EXPECT_CALL(sub2, writeHelp(_));
+ EXPECT_CALL(topic2, writeHelp(_));
int rc = 0;
ASSERT_NO_THROW_GMX(rc = manager().run(args.argc(), args.argv()));
ASSERT_EQ(0, rc);
CommandLineModuleManagerTestBase::addHelpTopic(const char *name, const char *title)
{
MockHelpTopic *topic = new MockHelpTopic(name, title, "Help text");
- using ::testing::_;
- using ::testing::Invoke;
- ON_CALL(*topic, writeHelp(_))
- .WillByDefault(Invoke(topic, &MockHelpTopic::writeHelpBase));
manager().addHelpTopic(gmx::HelpTopicPointer(topic));
return *topic;
}
+++++++
| ``test other`` - Second module
+]]></String>
+ <String Name="programs/topic1.rst"><![CDATA[
+Test topic
+==========
+Help text
+
+Subtopic 1
+----------
+Sub text
+
+Subtopic 2
+----------
+Sub text
+]]></String>
+ <String Name="programs/topic2.rst"><![CDATA[
+Another topic
+=============
+Help text
]]></String>
</ReferenceData>
{
if (context.outputFormat() != eHelpOutputFormat_Console)
{
- // TODO: Implement once the situation with Redmine issue #969 is more
- // clear.
- GMX_THROW(NotImplementedError(
- "Subtopic listing is not implemented for this output format"));
+ Impl::SubTopicMap::const_iterator topic;
+ for (topic = impl_->subtopics_.begin(); topic != impl_->subtopics_.end(); ++topic)
+ {
+ const char *const title = topic->second->title();
+ if (!isNullOrEmpty(title))
+ {
+ context.outputFile().writeLine();
+ HelpWriterContext subContext(context);
+ subContext.enterSubSection(title);
+ topic->second->writeHelp(subContext);
+ }
+ }
+ return true;
}
int maxNameLength = 0;
Impl::SubTopicMap::const_iterator topic;
for (topic = impl_->subtopics_.begin(); topic != impl_->subtopics_.end(); ++topic)
{
- const char *title = topic->second->title();
- if (title == NULL || title[0] == '\0')
- {
- continue;
- }
- int nameLength = static_cast<int>(topic->first.length());
- if (nameLength > maxNameLength)
+ const char *const title = topic->second->title();
+ if (!isNullOrEmpty(title))
{
- maxNameLength = nameLength;
+ int nameLength = static_cast<int>(topic->first.length());
+ if (nameLength > maxNameLength)
+ {
+ maxNameLength = nameLength;
+ }
}
}
if (maxNameLength == 0)
file.writeLine(title);
for (topic = impl_->subtopics_.begin(); topic != impl_->subtopics_.end(); ++topic)
{
- const char *name = topic->first.c_str();
- const char *title = topic->second->title();
- if (title != NULL && title[0] != '\0')
+ const char *const name = topic->first.c_str();
+ const char *const title = topic->second->title();
+ if (!isNullOrEmpty(title))
{
formatter.clear();
formatter.addColumnLine(0, name);
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2012,2013,2014, by the GROMACS development team, led by
+ * Copyright (c) 2012,2013,2014,2015, 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.
TEST_F(HelpManagerTest, HandlesSubTopics)
{
MockHelpTopic &first =
- rootTopic_.addSubTopic("first", "First topic", "First topic text");
+ rootTopic_.addSubTopic("first", "First topic", NULL);
MockHelpTopic &firstSub =
- first.addSubTopic("firstsub", "First subtopic", "First subtopic text");
- rootTopic_.addSubTopic("second", "Second topic", "Second topic text");
+ first.addSubTopic("firstsub", "First subtopic", NULL);
+ rootTopic_.addSubTopic("second", "Second topic", NULL);
using ::testing::_;
EXPECT_CALL(firstSub, writeHelp(_));
TEST_F(HelpManagerTest, HandlesInvalidTopics)
{
MockHelpTopic &first =
- rootTopic_.addSubTopic("first", "First topic", "First topic text");
- first.addSubTopic("firstsub", "First subtopic", "First subtopic text");
- rootTopic_.addSubTopic("second", "Second topic", "Second topic text");
+ rootTopic_.addSubTopic("first", "First topic", NULL);
+ first.addSubTopic("firstsub", "First subtopic", NULL);
+ rootTopic_.addSubTopic("second", "Second topic", NULL);
ASSERT_THROW_GMX(manager_.enterTopic("unknown"), gmx::InvalidInputError);
ASSERT_NO_THROW_GMX(manager_.enterTopic("first"));
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2012,2014, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015, 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.
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+#include "gromacs/utility/stringutil.h"
+
namespace gmx
{
namespace test
}
MockHelpTopic::MockHelpTopic(const char *name, const char *title, const char *text)
- : name_(name), title_(title), text_(text)
+ : name_(name), title_(title), text_(text != NULL ? text : "")
{
+ if (!isNullOrEmpty(text))
+ {
+ using ::testing::_;
+ using ::testing::Invoke;
+ ON_CALL(*this, writeHelp(_))
+ .WillByDefault(Invoke(this, &MockHelpTopic::writeHelpBase));
+ }
}
MockHelpTopic::~MockHelpTopic()
* Calls base class writeHelp() method.
*
* This provides the possibility for the mock to do the actual help
- * writing. The caller must set this as the writeHelp() action, as
- * most tests do not want to get the output.
+ * writing.
*/
void writeHelpBase(const HelpWriterContext &context)
{
"Depending on the tool, two additional command-line arguments may be",
"available to control the behavior:",
"",
- " * [TT]-seltype[tt] can be used to specify the default type of",
- " positions to calculate for each selection.",
- " * [TT]-selrpos[tt] can be used to specify the default type of",
- " positions used in selecting atoms by coordinates.",
+ "* [TT]-seltype[tt] can be used to specify the default type of",
+ " positions to calculate for each selection.",
+ "* [TT]-selrpos[tt] can be used to specify the default type of",
+ " positions used in selecting atoms by coordinates.",
"",
"See the \"positions\" subtopic for more information on these options.",
};
"",
"Centers of mass of residues 1 to 5 and 10::",
- ""
+ "",
" res_com of resnr 1 to 5 10",
"",
"would be valid.[PAR]",
"Selections are composed of three main types of expressions, those that",
- "define atoms ([TT]ATOM_EXPR[tt]s), those that define positions",
- "([TT]POS_EXPR[tt]s), and those that evaluate to numeric values",
- "([TT]NUM_EXPR[tt]s). Each selection should be a [TT]POS_EXPR[tt]",
+ "define atoms ([TT]ATOM_EXPR[tt]), those that define positions",
+ "([TT]POS_EXPR[tt]), and those that evaluate to numeric values",
+ "([TT]NUM_EXPR[tt]). Each selection should be a [TT]POS_EXPR[tt]",
"or a [TT]ATOM_EXPR[tt] (the latter is automatically converted to",
"positions). The basic rules are as follows:",
"",
- " * An expression like [TT]NUM_EXPR1 < NUM_EXPR2[tt] evaluates to an",
- " [TT]ATOM_EXPR[tt] that selects all the atoms for which the comparison",
- " is true.",
- " * Atom expressions can be combined with boolean operations such as",
- " [TT]not ATOM_EXPR[tt], [TT]ATOM_EXPR and ATOM_EXPR[tt], or",
- " [TT]ATOM_EXPR or ATOM_EXPR[tt]. Parentheses can be used to alter the",
- " evaluation order.",
- " * [TT]ATOM_EXPR[tt] expressions can be converted into [TT]POS_EXPR[tt]",
- " expressions in various ways, see the \"positions\" subtopic for more",
- " details.",
- " * [TT]POS_EXPR[tt] can be converted into [TT]NUM_EXPR[tt] using syntax",
- " like \"x of POS_EXPR\". Currently, this is only supported for single",
- " positions like in expression \"x of cog of ATOM_EXPR\".",
+ "* An expression like [TT]NUM_EXPR1 < NUM_EXPR2[tt] evaluates to an",
+ " [TT]ATOM_EXPR[tt] that selects all the atoms for which the comparison",
+ " is true.",
+ "* Atom expressions can be combined with boolean operations such as",
+ " [TT]not ATOM_EXPR[tt], [TT]ATOM_EXPR and ATOM_EXPR[tt], or",
+ " [TT]ATOM_EXPR or ATOM_EXPR[tt]. Parentheses can be used to alter the",
+ " evaluation order.",
+ "* [TT]ATOM_EXPR[tt] expressions can be converted into [TT]POS_EXPR[tt]",
+ " expressions in various ways, see the \"positions\" subtopic for more",
+ " details.",
+ "* [TT]POS_EXPR[tt] can be converted into [TT]NUM_EXPR[tt] using syntax",
+ " like \"[TT]x of POS_EXPR[tt]\". Currently, this is only supported for single",
+ " positions like in expression \"[TT]x of cog of ATOM_EXPR[tt]\".",
"",
"Some keywords select atoms based on string values such as the atom name.",
const gmx_ana_selmethod_t *> >
MethodList;
+ /*! \brief
+ * Prints markup for starting a list of keywords.
+ */
+ void writeKeywordListStart(const HelpWriterContext &context,
+ const char *heading) const;
+ /*! \brief
+ * Prints markup for ending a list of keywords.
+ */
+ void writeKeywordListEnd(const HelpWriterContext &context,
+ const char *extraInfo) const;
+
/*! \brief
* Prints a brief list of keywords (selection methods) available.
*
void KeywordsHelpTopic::writeHelp(const HelpWriterContext &context) const
{
- if (context.outputFormat() != eHelpOutputFormat_Console)
- {
- GMX_THROW(NotImplementedError(
- "Selection help is not implemented for this output format"));
- }
- // TODO: The markup here is not really appropriate, and printKeywordList()
- // still prints raw text, but these are waiting for discussion of the
- // markup format in #969.
context.writeTextBlock(helpText());
context.writeTextBlock("");
// Print the list of keywords
- context.writeTextBlock("Keywords that select atoms by an integer property:");
- context.writeTextBlock("(use in expressions or like \"atomnr 1 to 5 7 9\")");
+ writeKeywordListStart(context, "Keywords that select atoms by an integer property:");
printKeywordList(context, INT_VALUE, false);
- context.writeTextBlock("");
+ writeKeywordListEnd(context, "(use in expressions or like \"atomnr 1 to 5 7 9\")");
- context.writeTextBlock("Keywords that select atoms by a numeric property:");
- context.writeTextBlock("(use in expressions or like \"occupancy 0.5 to 1\")");
+ writeKeywordListStart(context, "Keywords that select atoms by a numeric property:");
printKeywordList(context, REAL_VALUE, false);
- context.writeTextBlock("");
+ writeKeywordListEnd(context, "(use in expressions or like \"occupancy 0.5 to 1\")");
- context.writeTextBlock("Keywords that select atoms by a string property:");
- context.writeTextBlock("(use like \"name PATTERN [PATTERN] ...\")");
+ writeKeywordListStart(context, "Keywords that select atoms by a string property:");
printKeywordList(context, STR_VALUE, false);
- context.writeTextBlock("");
+ writeKeywordListEnd(context, "(use like \"name PATTERN [PATTERN] ...\")");
- context.writeTextBlock("Additional keywords that directly select atoms:");
+ writeKeywordListStart(context, "Additional keywords that directly select atoms:");
printKeywordList(context, GROUP_VALUE, false);
- context.writeTextBlock("");
+ writeKeywordListEnd(context, NULL);
- context.writeTextBlock("Keywords that directly evaluate to positions:");
- context.writeTextBlock("(see also \"positions\" subtopic)");
+ writeKeywordListStart(context, "Keywords that directly evaluate to positions:");
printKeywordList(context, POS_VALUE, false);
- context.writeTextBlock("");
+ writeKeywordListEnd(context, "(see also \"positions\" subtopic)");
- context.writeTextBlock("Additional keywords:");
+ writeKeywordListStart(context, "Additional keywords:");
printKeywordList(context, POS_VALUE, true);
printKeywordList(context, NO_VALUE, true);
+ writeKeywordListEnd(context, NULL);
+}
+
+void KeywordsHelpTopic::writeKeywordListStart(const HelpWriterContext &context,
+ const char *heading) const
+{
+ context.writeTextBlock(heading);
+ if (context.outputFormat() == eHelpOutputFormat_Rst)
+ {
+ context.writeTextBlock("");
+ context.writeTextBlock("::");
+ context.writeTextBlock("");
+ }
+}
+
+void KeywordsHelpTopic::writeKeywordListEnd(const HelpWriterContext &context,
+ const char *extraInfo) const
+{
+ if (context.outputFormat() == eHelpOutputFormat_Rst)
+ {
+ context.writeTextBlock("");
+ }
+ if (!isNullOrEmpty(extraInfo))
+ {
+ context.writeTextBlock(extraInfo);
+ }
+ context.writeTextBlock("");
}
void KeywordsHelpTopic::printKeywordList(const HelpWriterContext &context,