From 53270aa5a565f414a35e63e422e629130661782e Mon Sep 17 00:00:00 2001 From: Teemu Murtola Date: Tue, 19 May 2015 12:20:40 +0300 Subject: [PATCH] Base to get all 'gmx help' contents to user guide Implement initial functionality to get all 'gmx help' contents to the reStructuredText user guide. Make 'gmx help -export rst' export also the help topics, and make minimal changes to the user guide and the selection help to get it go through Sphinx cleanly. Subsequent changes will clean up the documentation further. Part of #679. Change-Id: I66219110fac4f4acd9ff9c36a19ca10f9561ca29 --- docs/user-guide/tools.rst | 2 + src/gromacs/commandline/cmdlinehelpmodule.cpp | 191 +++++++++++------- src/gromacs/commandline/cmdlinehelpmodule.h | 6 +- .../commandline/cmdlinemodulemanager.cpp | 4 +- .../commandline/tests/cmdlinehelpmodule.cpp | 8 + .../tests/cmdlinemodulemanagertest.cpp | 4 - .../CommandLineHelpModuleTest_ExportsHelp.xml | 18 ++ src/gromacs/onlinehelp/helptopic.cpp | 38 ++-- src/gromacs/onlinehelp/tests/helpmanager.cpp | 14 +- .../onlinehelp/tests/mock_helptopic.cpp | 13 +- src/gromacs/onlinehelp/tests/mock_helptopic.h | 3 +- src/gromacs/selection/selhelp.cpp | 114 +++++++---- 12 files changed, 266 insertions(+), 149 deletions(-) diff --git a/docs/user-guide/tools.rst b/docs/user-guide/tools.rst index b34b48e169..ad3755ac6e 100644 --- a/docs/user-guide/tools.rst +++ b/docs/user-guide/tools.rst @@ -14,6 +14,8 @@ be found at the links below: /programs/byname /programs/bytopic + /programs/selections + .. toctree:: :hidden: :glob: diff --git a/src/gromacs/commandline/cmdlinehelpmodule.cpp b/src/gromacs/commandline/cmdlinehelpmodule.cpp index cbd5115d7e..e32e337cb2 100644 --- a/src/gromacs/commandline/cmdlinehelpmodule.cpp +++ b/src/gromacs/commandline/cmdlinehelpmodule.cpp @@ -108,6 +108,80 @@ class CommandLineHelpModuleImpl 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 */ @@ -142,14 +216,40 @@ class RootHelpTopic : public CompositeHelpTopic { } + //! 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 exportedTopics_; GMX_DISALLOW_COPY_AND_ASSIGN(RootHelpTopic); }; +void RootHelpTopic::exportHelp(HelpExportInterface *exporter) const +{ + std::vector::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) @@ -308,71 +408,8 @@ void ModuleHelpTopic::writeHelp(const HelpWriterContext & /*context*/) const } /******************************************************************** - * 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. @@ -407,10 +444,6 @@ void initProgramLinks(HelpLinks *links, const CommandLineHelpModuleImpl &helpMod } } -/******************************************************************** - * HelpExportReStructuredText - */ - /*! \internal \brief * Implements export for web pages as reStructuredText. * @@ -435,6 +468,8 @@ class HelpExportReStructuredText : public HelpExportInterface const ModuleGroupContents &modules); virtual void finishModuleGroupExport(); + virtual void exportTopic(const HelpTopicInterface &topic); + private: FileOutputRedirectorInterface *outputRedirector_; HelpLinks links_; @@ -571,6 +606,15 @@ void HelpExportReStructuredText::finishModuleGroupExport() 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 */ @@ -598,6 +642,8 @@ class HelpExportCompletion : public HelpExportInterface const ModuleGroupContents & /*modules*/) {} virtual void finishModuleGroupExport() {} + virtual void exportTopic(const HelpTopicInterface & /*topic*/) {} + private: ShellCompletionWriter bashWriter_; std::vector modules_; @@ -642,6 +688,7 @@ void HelpExportCompletion::finishModuleExport() /******************************************************************** * CommandLineHelpModuleImpl implementation */ + CommandLineHelpModuleImpl::CommandLineHelpModuleImpl( const ProgramContextInterface &programContext, const std::string &binaryName, @@ -681,6 +728,8 @@ void CommandLineHelpModuleImpl::exportHelp(HelpExportInterface *exporter) const exporter->exportModuleGroup((*group)->title(), (*group)->modules()); } exporter->finishModuleGroupExport(); + + rootTopic_->exportHelp(exporter); } /******************************************************************** @@ -706,9 +755,9 @@ HelpTopicPointer CommandLineHelpModule::createModuleHelpTopic( 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) @@ -731,7 +780,7 @@ void CommandLineHelpModule::setOutputRedirector( 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; diff --git a/src/gromacs/commandline/cmdlinehelpmodule.h b/src/gromacs/commandline/cmdlinehelpmodule.h index 42f25078d6..87214a2c01 100644 --- a/src/gromacs/commandline/cmdlinehelpmodule.h +++ b/src/gromacs/commandline/cmdlinehelpmodule.h @@ -100,10 +100,12 @@ class CommandLineHelpModule : public CommandLineModuleInterface /*! \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 diff --git a/src/gromacs/commandline/cmdlinemodulemanager.cpp b/src/gromacs/commandline/cmdlinemodulemanager.cpp index cd2c659575..95766c0ae7 100644 --- a/src/gromacs/commandline/cmdlinemodulemanager.cpp +++ b/src/gromacs/commandline/cmdlinemodulemanager.cpp @@ -319,7 +319,7 @@ void CommandLineModuleManager::Impl::addModule(CommandLineModulePointer module) 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() @@ -475,7 +475,7 @@ CommandLineModuleGroup CommandLineModuleManager::addModuleGroup( 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[]) diff --git a/src/gromacs/commandline/tests/cmdlinehelpmodule.cpp b/src/gromacs/commandline/tests/cmdlinehelpmodule.cpp index 3a2af802dc..e5b9a13962 100644 --- a/src/gromacs/commandline/tests/cmdlinehelpmodule.cpp +++ b/src/gromacs/commandline/tests/cmdlinehelpmodule.cpp @@ -139,10 +139,18 @@ TEST_F(CommandLineHelpModuleTest, ExportsHelp) 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); diff --git a/src/gromacs/commandline/tests/cmdlinemodulemanagertest.cpp b/src/gromacs/commandline/tests/cmdlinemodulemanagertest.cpp index 72816979c3..f85cabe057 100644 --- a/src/gromacs/commandline/tests/cmdlinemodulemanagertest.cpp +++ b/src/gromacs/commandline/tests/cmdlinemodulemanagertest.cpp @@ -177,10 +177,6 @@ MockHelpTopic & 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; } diff --git a/src/gromacs/commandline/tests/refdata/CommandLineHelpModuleTest_ExportsHelp.xml b/src/gromacs/commandline/tests/refdata/CommandLineHelpModuleTest_ExportsHelp.xml index d8b6126b9c..02a51bb3da 100644 --- a/src/gromacs/commandline/tests/refdata/CommandLineHelpModuleTest_ExportsHelp.xml +++ b/src/gromacs/commandline/tests/refdata/CommandLineHelpModuleTest_ExportsHelp.xml @@ -106,5 +106,23 @@ Group 2 +++++++ | ``test other`` - Second module +]]> + + diff --git a/src/gromacs/onlinehelp/helptopic.cpp b/src/gromacs/onlinehelp/helptopic.cpp index 1cf1585187..c2d88baf68 100644 --- a/src/gromacs/onlinehelp/helptopic.cpp +++ b/src/gromacs/onlinehelp/helptopic.cpp @@ -140,24 +140,32 @@ AbstractCompositeHelpTopic::writeSubTopicList(const HelpWriterContext &context, { 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(topic->first.length()); - if (nameLength > maxNameLength) + const char *const title = topic->second->title(); + if (!isNullOrEmpty(title)) { - maxNameLength = nameLength; + int nameLength = static_cast(topic->first.length()); + if (nameLength > maxNameLength) + { + maxNameLength = nameLength; + } } } if (maxNameLength == 0) @@ -172,9 +180,9 @@ AbstractCompositeHelpTopic::writeSubTopicList(const HelpWriterContext &context, 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); diff --git a/src/gromacs/onlinehelp/tests/helpmanager.cpp b/src/gromacs/onlinehelp/tests/helpmanager.cpp index 09b22225f1..f28b0f8e12 100644 --- a/src/gromacs/onlinehelp/tests/helpmanager.cpp +++ b/src/gromacs/onlinehelp/tests/helpmanager.cpp @@ -1,7 +1,7 @@ /* * 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. @@ -102,10 +102,10 @@ TEST_F(HelpManagerTest, HandlesRootTopic) 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(_)); @@ -117,9 +117,9 @@ TEST_F(HelpManagerTest, HandlesSubTopics) 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")); diff --git a/src/gromacs/onlinehelp/tests/mock_helptopic.cpp b/src/gromacs/onlinehelp/tests/mock_helptopic.cpp index 5d7484d1f9..3579fc7d82 100644 --- a/src/gromacs/onlinehelp/tests/mock_helptopic.cpp +++ b/src/gromacs/onlinehelp/tests/mock_helptopic.cpp @@ -1,7 +1,7 @@ /* * 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. @@ -46,6 +46,8 @@ #include #include +#include "gromacs/utility/stringutil.h" + namespace gmx { namespace test @@ -67,8 +69,15 @@ MockHelpTopic::addSubTopic(gmx::AbstractCompositeHelpTopic *parent, } 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() diff --git a/src/gromacs/onlinehelp/tests/mock_helptopic.h b/src/gromacs/onlinehelp/tests/mock_helptopic.h index 649ff921c3..d1996e0b6f 100644 --- a/src/gromacs/onlinehelp/tests/mock_helptopic.h +++ b/src/gromacs/onlinehelp/tests/mock_helptopic.h @@ -76,8 +76,7 @@ class MockHelpTopic : public AbstractCompositeHelpTopic * 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) { diff --git a/src/gromacs/selection/selhelp.cpp b/src/gromacs/selection/selhelp.cpp index 8487fafe69..02cdfcb45a 100644 --- a/src/gromacs/selection/selhelp.cpp +++ b/src/gromacs/selection/selhelp.cpp @@ -157,10 +157,10 @@ const char *const CmdLineHelpText::text[] = { "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.", }; @@ -227,7 +227,7 @@ const char *const ExamplesHelpText::text[] = { "", "Centers of mass of residues 1 to 5 and 10::", - "" + "", " res_com of resnr 1 to 5 10", "", @@ -418,25 +418,25 @@ const char *const SyntaxHelpText::text[] = { "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.", @@ -538,6 +538,17 @@ class KeywordsHelpTopic : public CompositeHelpTopic 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. * @@ -579,45 +590,60 @@ KeywordsHelpTopic::KeywordsHelpTopic() 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, -- 2.22.0