From cb8f1bd87724dd5fd4d21bb15e7f6a543e0d7dcd Mon Sep 17 00:00:00 2001 From: Teemu Murtola Date: Sun, 24 May 2015 06:33:08 +0300 Subject: [PATCH] Improve lists in user guide for selections - Support enumerated list formatting in console output to make it possible to use reStructuredText enumerated lists in help texts. - Make the keyword list use a bullet list for the keyword groups, providing some visual structure for the HTML output. The extra stars do not hurt in the console output, either, but changed the extra help indicator to be a + instead of * to reduce confusion with these other stars. Change-Id: I4d5063d4f117a31ea31d8d78cd799dfbd0f1eac8 --- src/gromacs/onlinehelp/helpwritercontext.cpp | 48 ++++++++++-- .../onlinehelp/tests/helpwritercontext.cpp | 27 ++++++- ...elpWriterContextTest_FormatsBulletList.xml | 26 +++---- ...riterContextTest_FormatsEnumeratedList.xml | 46 ++++++++++++ src/gromacs/selection/selhelp.cpp | 74 ++++++++++--------- 5 files changed, 165 insertions(+), 56 deletions(-) create mode 100644 src/gromacs/onlinehelp/tests/refdata/HelpWriterContextTest_FormatsEnumeratedList.xml diff --git a/src/gromacs/onlinehelp/helpwritercontext.cpp b/src/gromacs/onlinehelp/helpwritercontext.cpp index 8d5a44903b..415f2602f7 100644 --- a/src/gromacs/onlinehelp/helpwritercontext.cpp +++ b/src/gromacs/onlinehelp/helpwritercontext.cpp @@ -309,8 +309,7 @@ std::string toUpperCase(const std::string &text) * \param[in] text Input text. * \returns \p text with all sequences of more than two newlines replaced * with just two newlines. - * - * Does not throw. + * \throws std::bad_alloc if out of memory. */ std::string removeExtraNewlinesRst(const std::string &text) { @@ -342,6 +341,36 @@ std::string removeExtraNewlinesRst(const std::string &text) return result; } +/*! \brief + * Returns `true` if a list item starts in \p text at \p index. + * + * Does not throw. + */ +bool startsListItem(const std::string &text, size_t index) +{ + if (text.length() <= index + 1) + { + return false; + } + if (text[index] == '*' && std::isspace(text[index+1])) + { + return true; + } + if (std::isdigit(text[index])) + { + while (index < text.length() && std::isdigit(text[index])) + { + ++index; + } + if (text.length() > index + 1 && text[index] == '.' + && std::isspace(text[index+1])) + { + return true; + } + } + return false; +} + //! \} } // namespace @@ -606,8 +635,7 @@ void HelpWriterContext::Impl::processMarkup(const std::string &text, ++currentIndent; continue; } - else if (i + 1 < result.length() - && result[i] == '*' && result[i + 1] == ' ') + else if (startsListItem(result, i)) { if (currentLine > 0) { @@ -619,7 +647,17 @@ void HelpWriterContext::Impl::processMarkup(const std::string &text, nextBreakSize = 1; break; } - indent = currentIndent + 2; + int prefixLength = 0; + while (!std::isspace(result[i + prefixLength])) + { + ++prefixLength; + } + while (i + prefixLength < result.length() + && std::isspace(result[i + prefixLength])) + { + ++prefixLength; + } + indent = currentIndent + prefixLength; } bLineStart = false; } diff --git a/src/gromacs/onlinehelp/tests/helpwritercontext.cpp b/src/gromacs/onlinehelp/tests/helpwritercontext.cpp index 4216fccf0b..9db5f0e340 100644 --- a/src/gromacs/onlinehelp/tests/helpwritercontext.cpp +++ b/src/gromacs/onlinehelp/tests/helpwritercontext.cpp @@ -173,10 +173,31 @@ TEST_F(HelpWriterContextTest, FormatsBulletList) const char *const text[] = { "Sample list:", "", - " * first item", - " * second item that", + "* first item", + "* second item that", + " spans multiple lines", + "* third item that has a single long line", + "", + "Normal paragraph" + }; + // Wrapping to rst with a fixed line length does not currently work + // correctly, but it is not used, either. + settings_.setLineLength(15); + testFormatting(text); +} + +TEST_F(HelpWriterContextTest, FormatsEnumeratedList) +{ + const char *const text[] = { + "Sample list:", + "", + "1. first item", + "2. second item that", " spans multiple lines", - " * third item that has a single long line", + "3. third item that has a single long line", + "", + "9. Item with extra indentation", + "10. Double digit item", "", "Normal paragraph" }; diff --git a/src/gromacs/onlinehelp/tests/refdata/HelpWriterContextTest_FormatsBulletList.xml b/src/gromacs/onlinehelp/tests/refdata/HelpWriterContextTest_FormatsBulletList.xml index 2bceed2aaf..2acdee1880 100644 --- a/src/gromacs/onlinehelp/tests/refdata/HelpWriterContextTest_FormatsBulletList.xml +++ b/src/gromacs/onlinehelp/tests/refdata/HelpWriterContextTest_FormatsBulletList.xml @@ -4,27 +4,27 @@ + + + + + diff --git a/src/gromacs/selection/selhelp.cpp b/src/gromacs/selection/selhelp.cpp index 746b4394ef..891e927509 100644 --- a/src/gromacs/selection/selhelp.cpp +++ b/src/gromacs/selection/selhelp.cpp @@ -316,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.", }; @@ -389,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.", @@ -677,11 +677,13 @@ void KeywordsHelpTopic::writeHelp(const HelpWriterContext &context) const 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(""); } } @@ -695,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(""); } @@ -714,9 +718,9 @@ void KeywordsHelpTopic::printKeywordList(const HelpWriterContext &context, if (method.type == type && bModifiers == bIsModifier) { const bool bHasHelp = (method.help.nlhelp > 0 && method.help.help != NULL); - const bool bPrintStar + const bool bPrintHelpMark = bHasHelp && context.outputFormat() == eHelpOutputFormat_Console; - file.writeString(formatString(" %c ", bPrintStar ? '*' : ' ')); + file.writeString(formatString(" %c ", bPrintHelpMark ? '+' : ' ')); if (method.help.syntax != NULL) { file.writeLine(method.help.syntax); -- 2.22.0