Change naming convention for C++ interfaces
[alexxy/gromacs.git] / src / gromacs / selection / selhelp.cpp
index 02cdfcb45a8f6ed53be911b24b4d15c6d8ca7d87..0a29722728ae9fce6cf1803696842c0e80750bbd 100644 (file)
@@ -43,6 +43,7 @@
 
 #include "selhelp.h"
 
+#include <set>
 #include <string>
 #include <utility>
 #include <vector>
@@ -52,8 +53,9 @@
 #include "gromacs/onlinehelp/helptopic.h"
 #include "gromacs/onlinehelp/helpwritercontext.h"
 #include "gromacs/utility/exceptions.h"
-#include "gromacs/utility/file.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/stringutil.h"
+#include "gromacs/utility/textwriter.h"
 
 #include "selmethod.h"
 #include "symrec.h"
@@ -125,7 +127,7 @@ const char *const CmdLineHelpText::text[] = {
     "if they are complex or for scripting.[PAR]",
 
     "Each tool has different command-line arguments for specifying selections",
-    "(listed by [TT][PROGRAM] help <tool>[tt]).",
+    "(see the help for the individual tools).",
     "You can either pass a single string containing all selections (separated",
     "by semicolons), or multiple strings, each containing one selection.",
     "Note that you need to quote the selections to protect them from the",
@@ -150,10 +152,9 @@ const char *const CmdLineHelpText::text[] = {
     "To use groups from a traditional index file, use argument [TT]-n[tt]",
     "to provide a file. See the \"syntax\" subtopic for how to use them.",
     "If this option is not provided, default groups are generated.",
-    "The default groups are generated by reading selections from a file",
-    "[TT]defselection.dat[tt]. If such a file is found in the current",
-    "directory, it is used instead of the one provided by default.[PAR]",
-
+    "The default groups are generated with the same logic as for",
+    "non-selection tools.",
+    "",
     "Depending on the tool, two additional command-line arguments may be",
     "available to control the behavior:",
     "",
@@ -217,44 +218,90 @@ const char        ExamplesHelpText::name[]  = "examples";
 const char        ExamplesHelpText::title[] =
     "Selection examples";
 const char *const ExamplesHelpText::text[] = {
-    // TODO: Once there are more tools available, use examples that invoke
-    // tools and explain what the selections do in those tools.
-    "Below, examples of increasingly complex selections are given.[PAR]",
-
-    "Selection of all water oxygens::",
+    "Below, examples of different types of selections are given.",
     "",
-    "  resname SOL and name OW",
+    "* Selection of all water oxygens::",
     "",
-
-    "Centers of mass of residues 1 to 5 and 10::",
+    "    resname SOL and name OW",
     "",
-    "  res_com of resnr 1 to 5 10",
+    "* Centers of mass of residues 1 to 5 and 10::",
     "",
-
-    "All atoms farther than 1 nm of a fixed position::",
+    "    res_com of resnr 1 to 5 10",
     "",
-    "  not within 1 of [1.2, 3.1, 2.4]",
+    "* All atoms farther than 1 nm of a fixed position::",
     "",
-
-    "All atoms of a residue LIG within 0.5 nm of a protein (with a custom name)::",
+    "    not within 1 of [1.2, 3.1, 2.4]",
     "",
-    "  \"Close to protein\" resname LIG and within 0.5 of group \"Protein\"",
+    "* All atoms of a residue LIG within 0.5 nm of a protein (with a custom name)::",
     "",
-
-    "All protein residues that have at least one atom within 0.5 nm of a residue LIG::",
+    "    \"Close to protein\" resname LIG and within 0.5 of group \"Protein\"",
     "",
-    "  group \"Protein\" and same residue as within 0.5 of resname LIG",
+    "* All protein residues that have at least one atom within 0.5 nm of a residue LIG::",
     "",
-
-    "All RES residues whose COM is between 2 and 4 nm from the COM of all of them::",
+    "    group \"Protein\" and same residue as within 0.5 of resname LIG",
     "",
-    "  rdist = res_com distance from com of resname RES",
-    "  resname RES and rdist >= 2 and rdist <= 4",
+    "* All RES residues whose COM is between 2 and 4 nm from the COM of all of them::",
     "",
-
-    "Selection like C1 C2 C2 C3 C3 C4 ... C8 C9 (e.g., for g_bond)::",
+    "    rdist = res_com distance from com of resname RES",
+    "    resname RES and rdist >= 2 and rdist <= 4",
+    "",
+    // TODO: Make it possible to use links below.
+    "* Selection like with duplicate atoms like C1 C2 C2 C3 C3 C4 ... C8 C9::",
+    "",
+    "    name \"C[1-8]\" merge name \"C[2-9]\"",
+    "",
+    "  This can be used with [TT]gmx distance[tt] to compute C1-C2, C2-C3 etc.",
+    "  distances.",
+    "",
+    "* Selection with atoms in order C2 C1::",
+    "",
+    "    name C1 C2 permute 2 1",
+    "",
+    "  This can be used with [TT]gmx gangle[tt] to get C2->C1 vectors instead of",
+    "  C1->C2.",
+    "",
+    "* Selection with COMs of two index groups::",
+    "",
+    "    com of group 1 plus com of group 2",
+    "",
+    "  This can be used with [TT]gmx distance[tt] to compute the distance between",
+    "  these two COMs.",
+    "",
+    "* Fixed vector along x (can be used as a reference with [TT]gmx gangle[tt])::",
     "",
-    "  name \"C[1-8]\" merge name \"C[2-9]\"",
+    "    [0, 0, 0] plus [1, 0, 0]",
+    "",
+    "* The following examples explain the difference between the various",
+    "  position types.  This selection selects a position for each residue",
+    "  where any of the three atoms C[123] has [TT]x < 2[tt].  The positions",
+    "  are computed as the COM of all three atoms.",
+    "  This is the default behavior if you just write [TT]res_com of[tt]. ::",
+    "",
+    "    part_res_com of name C1 C2 C3 and x < 2",
+    "",
+    "  This selection does the same, but the positions are computed as COM",
+    "  positions of whole residues::",
+    "",
+    "    whole_res_com of name C1 C2 C3 and x < 2",
+    "",
+    "  Finally, this selection selects the same residues, but the positions",
+    "  are computed as COM of exactly those atoms atoms that match the",
+    "  [TT]x < 2[tt] criterion::",
+    "",
+    "    dyn_res_com of name C1 C2 C3 and x < 2",
+    "",
+    "* Without the [TT]of[tt] keyword, the default behavior is different from",
+    "  above, but otherwise the rules are the same::",
+    "",
+    "    name C1 C2 C3 and res_com x < 2",
+    "",
+    "  works as if [TT]whole_res_com[tt] was specified, and selects the three",
+    "  atoms from residues whose COM satisfiex [TT]x < 2[tt].",
+    "  Using ::",
+    "",
+    "    name C1 C2 C3 and part_res_com x < 2",
+    "",
+    "  instead selects residues based on the COM computed from the C[123] atoms.",
 };
 
 struct KeywordsHelpText
@@ -269,7 +316,7 @@ const char        KeywordsHelpText::title[] =
     "Selection keywords";
 const char *const KeywordsHelpText::text[] = {
     "The following selection keywords are currently available.",
-    "For keywords marked with a star, additional help is available through",
+    "For keywords marked with a plus, additional help is available through",
     "a subtopic KEYWORD, where KEYWORD is the name of the keyword.",
 };
 
@@ -342,39 +389,39 @@ const char        PositionsHelpText::name[]  = "positions";
 const char        PositionsHelpText::title[] =
     "Specifying positions in selections";
 const char *const PositionsHelpText::text[] = {
-    "Possible ways of specifying positions in selections are:[PAR]",
-
+    "Possible ways of specifying positions in selections are:",
+    "",
     "1. A constant position can be defined as [TT][XX, YY, ZZ][tt], where",
-    "[TT]XX[tt], [TT]YY[tt] and [TT]ZZ[tt] are real numbers.[PAR]",
-
+    "   [TT]XX[tt], [TT]YY[tt] and [TT]ZZ[tt] are real numbers.[PAR]",
+    "",
     "2. [TT]com of ATOM_EXPR [pbc][tt] or [TT]cog of ATOM_EXPR [pbc][tt]",
-    "calculate the center of mass/geometry of [TT]ATOM_EXPR[tt]. If",
-    "[TT]pbc[tt] is specified, the center is calculated iteratively to try",
-    "to deal with cases where [TT]ATOM_EXPR[tt] wraps around periodic",
-    "boundary conditions.[PAR]",
-
+    "   calculate the center of mass/geometry of [TT]ATOM_EXPR[tt]. If",
+    "   [TT]pbc[tt] is specified, the center is calculated iteratively to try",
+    "   to deal with cases where [TT]ATOM_EXPR[tt] wraps around periodic",
+    "   boundary conditions.",
+    "",
     "3. [TT]POSTYPE of ATOM_EXPR[tt] calculates the specified positions for",
-    "the atoms in [TT]ATOM_EXPR[tt].",
-    "[TT]POSTYPE[tt] can be [TT]atom[tt], [TT]res_com[tt], [TT]res_cog[tt],",
-    "[TT]mol_com[tt] or [TT]mol_cog[tt], with an optional prefix [TT]whole_[tt]",
-    "[TT]part_[tt] or [TT]dyn_[tt].",
-    "[TT]whole_[tt] calculates the centers for the whole residue/molecule,",
-    "even if only part of it is selected.",
-    "[TT]part_[tt] prefix calculates the centers for the selected atoms, but",
-    "uses always the same atoms for the same residue/molecule. The used atoms",
-    "are determined from the the largest group allowed by the selection.",
-    "[TT]dyn_[tt] calculates the centers strictly only for the selected atoms.",
-    "If no prefix is specified, whole selections default to [TT]part_[tt] and",
-    "other places default to [TT]whole_[tt].",
-    "The latter is often desirable to select the same molecules in different",
-    "tools, while the first is a compromise between speed ([TT]dyn_[tt]",
-    "positions can be slower to evaluate than [TT]part_[tt]) and intuitive",
-    "behavior.[PAR]",
-
+    "   the atoms in [TT]ATOM_EXPR[tt].",
+    "   [TT]POSTYPE[tt] can be [TT]atom[tt], [TT]res_com[tt], [TT]res_cog[tt],",
+    "   [TT]mol_com[tt] or [TT]mol_cog[tt], with an optional prefix [TT]whole_[tt]",
+    "   [TT]part_[tt] or [TT]dyn_[tt].",
+    "   [TT]whole_[tt] calculates the centers for the whole residue/molecule,",
+    "   even if only part of it is selected.",
+    "   [TT]part_[tt] prefix calculates the centers for the selected atoms, but",
+    "   uses always the same atoms for the same residue/molecule. The used atoms",
+    "   are determined from the the largest group allowed by the selection.",
+    "   [TT]dyn_[tt] calculates the centers strictly only for the selected atoms.",
+    "   If no prefix is specified, whole selections default to [TT]part_[tt] and",
+    "   other places default to [TT]whole_[tt].",
+    "   The latter is often desirable to select the same molecules in different",
+    "   tools, while the first is a compromise between speed ([TT]dyn_[tt]",
+    "   positions can be slower to evaluate than [TT]part_[tt]) and intuitive",
+    "   behavior.",
+    "",
     "4. [TT]ATOM_EXPR[tt], when given for whole selections, is handled as 3.",
-    "above, using the position type from the command-line argument",
-    "[TT]-seltype[tt].[PAR]",
-
+    "   above, using the position type from the command-line argument",
+    "   [TT]-seltype[tt].",
+    "",
     "Selection keywords that select atoms based on their positions, such as",
     "[TT]dist from[tt], use by default the positions defined by the",
     "[TT]-selrpos[tt] command-line option.",
@@ -495,7 +542,7 @@ class KeywordDetailsHelpTopic : public AbstractSimpleHelpTopic
         }
         virtual const char *title() const
         {
-            return NULL;
+            return method_.help.helpTitle;
         }
 
     protected:
@@ -560,6 +607,11 @@ class KeywordsHelpTopic : public CompositeHelpTopic<KeywordsHelpText>
         void printKeywordList(const HelpWriterContext &context,
                               e_selvalue_t type, bool bModifiers) const;
 
+        /*! \brief
+         * Prints the detailed help for keywords for rst export.
+         */
+        void writeKeywordSubTopics(const HelpWriterContext &context) const;
+
         MethodList              methods_;
 };
 
@@ -618,16 +670,20 @@ void KeywordsHelpTopic::writeHelp(const HelpWriterContext &context) const
     printKeywordList(context, POS_VALUE, true);
     printKeywordList(context, NO_VALUE, true);
     writeKeywordListEnd(context, NULL);
+
+    writeKeywordSubTopics(context);
 }
 
 void KeywordsHelpTopic::writeKeywordListStart(const HelpWriterContext &context,
                                               const char              *heading) const
 {
-    context.writeTextBlock(heading);
+    std::string fullHeading("* ");
+    fullHeading.append(heading);
+    context.writeTextBlock(fullHeading);
     if (context.outputFormat() == eHelpOutputFormat_Rst)
     {
         context.writeTextBlock("");
-        context.writeTextBlock("::");
+        context.writeTextBlock("  ::");
         context.writeTextBlock("");
     }
 }
@@ -641,7 +697,9 @@ void KeywordsHelpTopic::writeKeywordListEnd(const HelpWriterContext &context,
     }
     if (!isNullOrEmpty(extraInfo))
     {
-        context.writeTextBlock(extraInfo);
+        std::string fullInfo("  ");
+        fullInfo.append(extraInfo);
+        context.writeTextBlock(fullInfo);
     }
     context.writeTextBlock("");
 }
@@ -650,16 +708,19 @@ void KeywordsHelpTopic::printKeywordList(const HelpWriterContext &context,
                                          e_selvalue_t             type,
                                          bool                     bModifiers) const
 {
-    File &file = context.outputFile();
+    TextWriter                &file = context.outputFile();
     MethodList::const_iterator iter;
     for (iter = methods_.begin(); iter != methods_.end(); ++iter)
     {
         const gmx_ana_selmethod_t &method = *iter->second;
-        bool bIsModifier                  = (method.flags & SMETH_MODIFIER) != 0;
+        const bool                 bIsModifier
+            = (method.flags & SMETH_MODIFIER) != 0;
         if (method.type == type && bModifiers == bIsModifier)
         {
-            bool bHasHelp = (method.help.nlhelp > 0 && method.help.help != NULL);
-            file.writeString(formatString(" %c ", bHasHelp ? '*' : ' '));
+            const bool bHasHelp = (method.help.nlhelp > 0 && method.help.help != NULL);
+            const bool bPrintHelpMark
+                = bHasHelp && context.outputFormat() == eHelpOutputFormat_Console;
+            file.writeString(formatString("   %c ", bPrintHelpMark ? '+' : ' '));
             if (method.help.syntax != NULL)
             {
                 file.writeLine(method.help.syntax);
@@ -677,20 +738,65 @@ void KeywordsHelpTopic::printKeywordList(const HelpWriterContext &context,
     }
 }
 
+void KeywordsHelpTopic::writeKeywordSubTopics(const HelpWriterContext &context) const
+{
+    if (context.outputFormat() != eHelpOutputFormat_Rst)
+    {
+        return;
+    }
+    std::set<std::string>      usedSymbols;
+    MethodList::const_iterator iter;
+    for (iter = methods_.begin(); iter != methods_.end(); ++iter)
+    {
+        const gmx_ana_selmethod_t &method = *iter->second;
+        const bool                 bHasHelp
+            = (method.help.nlhelp > 0 && method.help.help != NULL);
+        if (!bHasHelp || usedSymbols.count(iter->first) > 0)
+        {
+            continue;
+        }
+
+        std::string                title;
+        if (method.help.helpTitle != NULL)
+        {
+            title = method.help.helpTitle;
+            title.append(" - ");
+        }
+        title.append(iter->first);
+        MethodList::const_iterator mergeIter = iter;
+        for (++mergeIter; mergeIter != methods_.end(); ++mergeIter)
+        {
+            if (mergeIter->second->help.help == method.help.help)
+            {
+                title.append(", ");
+                title.append(mergeIter->first);
+                usedSymbols.insert(mergeIter->first);
+            }
+        }
+
+        const IHelpTopic         *subTopic = findSubTopic(iter->first.c_str());
+        GMX_RELEASE_ASSERT(subTopic != NULL, "Keyword subtopic no longer exists");
+        HelpWriterContext         subContext(context);
+        subContext.enterSubSection(title);
+        subTopic->writeHelp(subContext);
+        context.writeTextBlock("");
+    }
+}
+
 }   // namespace
 
 //! \cond libapi */
 HelpTopicPointer createSelectionHelpTopic()
 {
     CompositeHelpTopicPointer root(new CompositeHelpTopic<CommonHelpText>);
-    root->registerSubTopic<SimpleHelpTopic<ArithmeticHelpText> >();
     root->registerSubTopic<SimpleHelpTopic<CmdLineHelpText> >();
-    root->registerSubTopic<SimpleHelpTopic<EvaluationHelpText> >();
-    root->registerSubTopic<SimpleHelpTopic<ExamplesHelpText> >();
+    root->registerSubTopic<SimpleHelpTopic<SyntaxHelpText> >();
+    root->registerSubTopic<SimpleHelpTopic<PositionsHelpText> >();
+    root->registerSubTopic<SimpleHelpTopic<ArithmeticHelpText> >();
     root->registerSubTopic<KeywordsHelpTopic>();
+    root->registerSubTopic<SimpleHelpTopic<EvaluationHelpText> >();
     root->registerSubTopic<SimpleHelpTopic<LimitationsHelpText> >();
-    root->registerSubTopic<SimpleHelpTopic<PositionsHelpText> >();
-    root->registerSubTopic<SimpleHelpTopic<SyntaxHelpText> >();
+    root->registerSubTopic<SimpleHelpTopic<ExamplesHelpText> >();
     return move(root);
 }
 //! \endcond