#include <string>
#include "gromacs/onlinehelp/helpformat.h"
+#include "gromacs/onlinehelp/helpwritercontext.h"
#include "gromacs/options/basicoptioninfo.h"
#include "gromacs/options/filenameoptioninfo.h"
#include "gromacs/options/options.h"
#include "gromacs/options/timeunitmanager.h"
#include "gromacs/selection/selectionfileoptioninfo.h"
#include "gromacs/selection/selectionoptioninfo.h"
+#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/file.h"
#include "gromacs/utility/stringutil.h"
{
public:
//! Creates a helper object for writing section descriptions.
- explicit DescriptionWriter(File *file) : file_(*file) {}
+ explicit DescriptionWriter(const HelpWriterContext &context)
+ : context_(context)
+ {
+ }
virtual void visitSubSection(const Options §ion);
virtual void visitOption(const OptionInfo & /*option*/) { }
private:
- File &file_;
+ const HelpWriterContext &context_;
};
void DescriptionWriter::visitSubSection(const Options §ion)
{
if (!section.description().empty())
{
+ File &file = context_.outputFile();
const std::string &title = section.title();
if (!title.empty())
{
- file_.writeLine(title);
- file_.writeLine();
+ file.writeLine(title);
+ file.writeLine();
}
- writeHelpTextForConsole(&file_, section.description());
- file_.writeLine();
+ context_.writeTextBlock(section.description());
+ file.writeLine();
}
OptionsIterator(section).acceptSubSections(this);
}
{
public:
//! Creates a helper object for writing file parameters.
- explicit FileParameterWriter(File *file);
+ explicit FileParameterWriter(const HelpWriterContext &context);
//! Returns true if anything was written out.
bool didOutput() const { return formatter_.didOutput(); }
virtual void visitOptionType(const FileNameOptionInfo &option);
private:
- File &file_;
- TextTableFormatter formatter_;
+ const HelpWriterContext &context_;
+ TextTableFormatter formatter_;
};
-FileParameterWriter::FileParameterWriter(File *file)
- : file_(*file)
+FileParameterWriter::FileParameterWriter(const HelpWriterContext &context)
+ : context_(context)
{
formatter_.addColumn("Option", 6, false);
formatter_.addColumn("Filename", 12, false);
}
bool bLongType = (type.length() > 12U);
formatter_.addColumnLine(2, type);
- formatter_.addColumnLine(3, substituteMarkupForConsole(option.description()));
+ formatter_.addColumnLine(3, context_.substituteMarkup(option.description()));
// Compute layout.
if (name.length() > 6U || firstShortValue > 0)
}
// Do the formatting.
- file_.writeString(formatter_.formatRow());
+ context_.outputFile().writeString(formatter_.formatRow());
}
{
public:
//! Creates a helper object for writing non-file parameters.
- ParameterWriter(File *file, const char *timeUnit);
+ ParameterWriter(const HelpWriterContext &context,
+ const char *timeUnit);
//! Sets the writer to show hidden options.
void setShowHidden(bool bSet) { bShowHidden_ = bSet; }
virtual void visitOption(const OptionInfo &option);
private:
- File &file_;
- TextTableFormatter formatter_;
- const char *timeUnit_;
- bool bShowHidden_;
+ const HelpWriterContext &context_;
+ TextTableFormatter formatter_;
+ const char *timeUnit_;
+ bool bShowHidden_;
};
-ParameterWriter::ParameterWriter(File *file, const char *timeUnit)
- : file_(*file), timeUnit_(timeUnit), bShowHidden_(false)
+ParameterWriter::ParameterWriter(const HelpWriterContext &context,
+ const char *timeUnit)
+ : context_(context), timeUnit_(timeUnit), bShowHidden_(false)
{
formatter_.addColumn("Option", 12, false);
formatter_.addColumn("Type", 6, false);
values.append(option.formatValue(i));
}
formatter_.addColumnLine(2, values);
- std::string description(substituteMarkupForConsole(option.description()));
+ std::string description(context_.substituteMarkup(option.description()));
const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
if (doubleOption != NULL && doubleOption->isTime())
{
formatter_.setColumnFirstLineOffset(3, 1);
}
- file_.writeString(formatter_.formatRow());
+ context_.outputFile().writeString(formatter_.formatRow());
}
{
public:
//! Creates a helper object for writing selection parameters.
- explicit SelectionParameterWriter(File *file);
+ explicit SelectionParameterWriter(const HelpWriterContext &context);
//! Returns true if anything was written out.
bool didOutput() const { return formatter_.didOutput(); }
virtual void visitOption(const OptionInfo &option);
private:
- File &file_;
- TextTableFormatter formatter_;
+ const HelpWriterContext &context_;
+ TextTableFormatter formatter_;
};
-SelectionParameterWriter::SelectionParameterWriter(File *file)
- : file_(*file)
+SelectionParameterWriter::SelectionParameterWriter(const HelpWriterContext &context)
+ : context_(context)
{
formatter_.addColumn("Selection", 10, false);
formatter_.addColumn("Description", 67, true);
return;
}
+ File &file = context_.outputFile();
+
formatter_.clear();
std::string name(formatString("-%s", option.name().c_str()));
formatter_.addColumnLine(0, name);
- formatter_.addColumnLine(1, substituteMarkupForConsole(option.description()));
- file_.writeString(formatter_.formatRow());
+ formatter_.addColumnLine(1, context_.substituteMarkup(option.description()));
+ file.writeString(formatter_.formatRow());
// TODO: What to do with selection variables?
// They are not printed as values for any option.
{
std::string value(option.formatValue(i));
// TODO: Wrapping
- file_.writeLine(formatString(" %s", value.c_str()));
+ file.writeLine(formatString(" %s", value.c_str()));
}
}
return *this;
}
-void CommandLineHelpWriter::writeHelp(File *file)
+void CommandLineHelpWriter::writeHelp(const HelpWriterContext &context)
{
+ if (context.outputFormat() != eHelpOutputFormat_Console)
+ {
+ // TODO: Implement once the situation with Redmine issue #969 is more
+ // clear.
+ GMX_THROW(NotImplementedError(
+ "Command-line help is not implemented for this output format"));
+ }
+ File &file = context.outputFile();
if (impl_->bShowDescriptions_)
{
- file->writeLine("DESCRIPTION");
- file->writeLine("-----------");
- file->writeLine();
- DescriptionWriter(file).visitSubSection(impl_->options_);
+ file.writeLine("DESCRIPTION");
+ file.writeLine("-----------");
+ file.writeLine();
+ DescriptionWriter(context).visitSubSection(impl_->options_);
}
{
- FileParameterWriter writer(file);
+ FileParameterWriter writer(context);
writer.visitSubSection(impl_->options_);
if (writer.didOutput())
{
- file->writeLine();
+ file.writeLine();
}
}
{
- ParameterWriter writer(file, impl_->timeUnit_.c_str());
+ ParameterWriter writer(context, impl_->timeUnit_.c_str());
writer.setShowHidden(impl_->bShowHidden_);
writer.visitSubSection(impl_->options_);
if (writer.didOutput())
{
- file->writeLine();
+ file.writeLine();
}
}
{
- SelectionParameterWriter writer(file);
+ SelectionParameterWriter writer(context);
writer.visitSubSection(impl_->options_);
if (writer.didOutput())
{
- file->writeLine();
+ file.writeLine();
}
}
}
namespace gmx
{
-class File;
+class HelpWriterContext;
class Options;
/*! \brief
/*! \brief
* Writes the help.
*
- * \param[in] file File to write the help to.
+ * \param[in] context Context object for writing the help.
+ * \throws std::bad_alloc if out of memory.
+ * \throws FileIOError on any I/O error.
*/
- void writeHelp(File *file);
+ void writeHelp(const HelpWriterContext &context);
private:
class Impl;
namespace gmx
{
-class File;
+class HelpWriterContext;
/*! \brief
* Module that can be run from command line using CommandLineModuleManager.
/*! \brief
* Prints help for the module.
*
- * \param[in] file File to write the help to.
+ * \param[in] context Context object for writing the help.
* \throws std::bad_alloc if out of memory.
+ * \throws FileIOError on any I/O error.
*/
- virtual void writeHelp(File *file) const = 0;
+ virtual void writeHelp(const HelpWriterContext &context) const = 0;
};
} // namespace gmx
#include "gromacs/onlinehelp/helpformat.h"
#include "gromacs/onlinehelp/helpmanager.h"
#include "gromacs/onlinehelp/helptopic.h"
+#include "gromacs/onlinehelp/helpwritercontext.h"
#include "gromacs/utility/file.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/gmxassert.h"
{
}
- virtual void writeHelp(File *file) const;
+ virtual void writeHelp(const HelpWriterContext &context) const;
private:
- void printModuleList(File *file) const;
+ void printModuleList(const HelpWriterContext &context) const;
const CommandLineModuleMap &modules_;
GMX_DISALLOW_COPY_AND_ASSIGN(RootHelpTopic);
};
-void RootHelpTopic::writeHelp(File *file) const
+void RootHelpTopic::writeHelp(const HelpWriterContext &context) const
{
- writeBasicHelpTopic(file, *this, helpText());
+ if (context.outputFormat() != eHelpOutputFormat_Console)
+ {
+ // TODO: Implement once the situation with Redmine issue #969 is more
+ // clear.
+ GMX_THROW(NotImplementedError(
+ "Root help is not implemented for this output format"));
+ }
+ writeBasicHelpTopic(context, *this, helpText());
// TODO: If/when this list becomes long, it may be better to only print
// "common" commands here, and have a separate topic (e.g.,
// "help commands") that prints the full list.
- printModuleList(file);
- writeHelpTextForConsole(file,
+ printModuleList(context);
+ context.writeTextBlock(
"For additional help on a command, use '[PROGRAM] help <command>'");
- writeSubTopicList(file, "\nAdditional help is available on the following topics:");
- writeHelpTextForConsole(file,
+ writeSubTopicList(context,
+ "\nAdditional help is available on the following topics:");
+ context.writeTextBlock(
"To access the help, use '[PROGRAM] help <topic>'.");
}
-void RootHelpTopic::printModuleList(File *file) const
+void RootHelpTopic::printModuleList(const HelpWriterContext &context) const
{
+ if (context.outputFormat() != eHelpOutputFormat_Console)
+ {
+ // TODO: Implement once the situation with Redmine issue #969 is more
+ // clear.
+ GMX_THROW(NotImplementedError(
+ "Module list is not implemented for this output format"));
+ }
int maxNameLength = 0;
CommandLineModuleMap::const_iterator module;
for (module = modules_.begin(); module != modules_.end(); ++module)
maxNameLength = nameLength;
}
}
+ File &file = context.outputFile();
TextTableFormatter formatter;
formatter.addColumn(NULL, maxNameLength + 1, false);
formatter.addColumn(NULL, 72 - maxNameLength, true);
formatter.setFirstColumnIndent(4);
- file->writeLine();
- file->writeLine("Available commands:");
+ file.writeLine();
+ file.writeLine("Available commands:");
for (module = modules_.begin(); module != modules_.end(); ++module)
{
const char *name = module->first.c_str();
formatter.clear();
formatter.addColumnLine(0, name);
formatter.addColumnLine(1, description);
- file->writeString(formatter.formatRow());
+ file.writeString(formatter.formatRow());
}
}
{
return NULL;
}
- virtual void writeHelp(File *file) const;
+ virtual void writeHelp(const HelpWriterContext &context) const;
private:
const CommandLineModuleInterface &module_;
GMX_DISALLOW_COPY_AND_ASSIGN(ModuleHelpTopic);
};
-void ModuleHelpTopic::writeHelp(File *file) const
+void ModuleHelpTopic::writeHelp(const HelpWriterContext &context) const
{
- module_.writeHelp(file);
+ module_.writeHelp(context);
}
} // namespace
}
virtual int run(int argc, char *argv[]);
- virtual void writeHelp(File *file) const;
+ virtual void writeHelp(const HelpWriterContext &context) const;
//! Prints usage message to stderr.
void printUsage() const;
int CommandLineHelpModule::run(int argc, char *argv[])
{
- HelpManager helpManager(*rootTopic_);
+ HelpWriterContext context(&File::standardOutput(),
+ eHelpOutputFormat_Console);
+ HelpManager helpManager(*rootTopic_, context);
try
{
for (int i = 1; i < argc; ++i)
fprintf(stderr, "%s\n", ex.what());
return 2;
}
- helpManager.writeCurrentTopic(&File::standardOutput());
+ helpManager.writeCurrentTopic();
fprintf(stderr, "\n");
return 0;
}
-void CommandLineHelpModule::writeHelp(File *file) const
+void CommandLineHelpModule::writeHelp(const HelpWriterContext &context) const
{
- writeHelpTextForConsole(file,
+ context.writeTextBlock(
"Usage: [PROGRAM] help [<command>|<topic> [<subtopic> [...]]]");
// TODO: More information.
}
void CommandLineHelpModule::printUsage() const
{
- rootTopic_->writeHelp(&File::standardError());
+ HelpWriterContext context(&File::standardError(),
+ eHelpOutputFormat_Console);
+ rootTopic_->writeHelp(context);
}
/********************************************************************
CommandLineModuleMap::const_iterator
findModuleFromBinaryName(const ProgramInfo &programInfo) const;
- //! Prints usage message to stderr.
- void printUsage(bool bModuleList) const;
- //! Prints the list of modules to stderr.
- void printModuleList() const;
-
/*! \brief
* Maps module names to module objects.
*
#include "gromacs/legacyheaders/types/simple.h"
#include "gromacs/commandline/cmdlinehelpwriter.h"
+#include "gromacs/onlinehelp/helpwritercontext.h"
#include "gromacs/options/basicoptions.h"
#include "gromacs/options/filenameoption.h"
#include "gromacs/options/options.h"
{
std::string filename = tempFiles_.getTemporaryFilePath("helptext.txt");
gmx::File file(filename, "w");
- writer->writeHelp(&file);
+ gmx::HelpWriterContext context(&file, gmx::eHelpOutputFormat_Console);
+ writer->writeHelp(context);
file.close();
checkFileContents(filename, "HelpText");
virtual const char *shortDescription() const { return descr_; }
MOCK_METHOD2(run, int(int argc, char *argv[]));
- MOCK_CONST_METHOD1(writeHelp, void(gmx::File *));
+ MOCK_CONST_METHOD1(writeHelp, void(const gmx::HelpWriterContext &context));
private:
const char *name_;
*/
#include "helpformat.h"
-#include <cctype>
-
#include <algorithm>
#include <string>
#include <vector>
-#include "gromacs/legacyheaders/smalloc.h"
-#include "gromacs/legacyheaders/wman.h"
-
-#include "gromacs/utility/file.h"
#include "gromacs/utility/gmxassert.h"
-#include "gromacs/utility/programinfo.h"
#include "gromacs/utility/stringutil.h"
namespace gmx
{
-/*! \cond libapi */
-std::string toUpperCase(const std::string &text)
-{
- std::string result(text);
- transform(result.begin(), result.end(), result.begin(), toupper);
- return result;
-}
-
-std::string substituteMarkupForConsole(const std::string &text)
-{
- char *resultStr = check_tty(text.c_str());
- try
- {
- std::string result(resultStr);
- sfree(resultStr);
- return result;
- }
- catch (...)
- {
- sfree(resultStr);
- throw;
- }
-}
-
-void writeHelpTextForConsole(File *file, const std::string &text)
-{
- TextLineWrapper wrapper;
- wrapper.setLineLength(78);
- const char *program = ProgramInfo::getInstance().programName().c_str();
- std::string newText = replaceAll(text, "[PROGRAM]", program);
- file->writeLine(wrapper.wrapToString(substituteMarkupForConsole(newText)));
-}
-//! \endcond
-
/********************************************************************
* TextTableFormatter::Impl
*/
class File;
-/*! \cond libapi */
-/*! \libinternal \brief
- * Make the string uppercase.
- *
- * \param[in] text Input text.
- * \returns \p text with all characters transformed to uppercase.
- * \throws std::bad_alloc if out of memory.
- *
- * \inlibraryapi
- */
-std::string toUpperCase(const std::string &text);
-
-/*! \libinternal \brief
- * Substitute markup used in help text for console output.
- *
- * \param[in] text Text to substitute.
- * \returns \p text with markup substituted.
- * \throws std::bad_alloc if out of memory.
- *
- * \inlibraryapi
- */
-std::string substituteMarkupForConsole(const std::string &text);
-/*! \libinternal \brief
- * Format a help text block for console output.
- *
- * \param file File to write the formatted text to.
- * \param[in] text Text to format.
- * \throws std::bad_alloc if out of memory.
- * \throws FileIOError on any I/O error.
- *
- * Calls substituteMarkupForConsole(), and also wraps the lines to 78
- * characters.
- *
- * \inlibraryapi
- */
-void writeHelpTextForConsole(File *file, const std::string &text);
-//! \endcond
-
/*! \libinternal \brief
* Formats rows of a table for text output.
*
*/
#include "helpmanager.h"
-#include <cstdio>
-
#include <string>
#include <vector>
//! Container type for keeping the stack of active topics.
typedef std::vector<const HelpTopicInterface *> TopicStack;
+ //! Initializes a new manager with the given context.
+ explicit Impl(const HelpWriterContext &context)
+ : rootContext_(context)
+ {
+ }
+
//! Whether the active topic is the root topic.
bool isAtRootTopic() const { return topicStack_.size() == 1; }
//! Returns the active topic.
//! Formats the active topic as a string, including its parent topics.
std::string currentTopicAsString() const;
+ //! Context with which the manager was initialized.
+ const HelpWriterContext &rootContext_;
/*! \brief
* Stack of active topics.
*
* The first item is always the root topic, and each item is a subtopic
* of the preceding item. The last item is the currently active topic.
*/
- TopicStack topicStack_;
+ TopicStack topicStack_;
};
std::string HelpManager::Impl::currentTopicAsString() const
* HelpManager
*/
-HelpManager::HelpManager(const HelpTopicInterface &rootTopic)
- : impl_(new Impl)
+HelpManager::HelpManager(const HelpTopicInterface &rootTopic,
+ const HelpWriterContext &context)
+ : impl_(new Impl(context))
{
impl_->topicStack_.push_back(&rootTopic);
}
impl_->topicStack_.push_back(newTopic);
}
-void HelpManager::writeCurrentTopic(File *file) const
+void HelpManager::writeCurrentTopic() const
{
const HelpTopicInterface &topic = impl_->currentTopic();
- topic.writeHelp(file);
+ topic.writeHelp(impl_->rootContext_);
}
} // namespace gmx
namespace gmx
{
-class File;
class HelpTopicInterface;
+class HelpWriterContext;
/*! \libinternal \brief
* Helper for providing interactive online help.
*
* \param[in] rootTopic Help topic that can be accessed through this
* manager.
+ * \param[in] context Context object for writing the help.
* \throws std::bad_alloc if out of memory.
*
- * The provided topic must remain valid for the lifetime of this
- * manager object.
+ * The provided topic and context objects must remain valid for the
+ * lifetime of this manager object.
*/
- explicit HelpManager(const HelpTopicInterface &rootTopic);
+ HelpManager(const HelpTopicInterface &rootTopic,
+ const HelpWriterContext &context);
~HelpManager();
/*! \brief
/*! \brief
* Writes out the help for the currently active topic.
*
- * \param file File to write the help text to.
* \throws std::bad_alloc if out of memory.
* \throws FileIOError on any I/O error.
*/
- void writeCurrentTopic(File *file) const;
+ void writeCurrentTopic() const;
private:
class Impl;
#include <utility>
#include "gromacs/onlinehelp/helpformat.h"
+#include "gromacs/onlinehelp/helpwritercontext.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/file.h"
#include "gromacs/utility/gmxassert.h"
{
/*! \cond libapi */
-void writeBasicHelpTopic(File *file, const HelpTopicInterface &topic,
+void writeBasicHelpTopic(const HelpWriterContext &context,
+ const HelpTopicInterface &topic,
const std::string &text)
{
const char *title = topic.title();
if (title != NULL && title[0] != '\0')
{
- file->writeLine(toUpperCase(title));
- file->writeLine();
+ context.writeTitle(title);
}
- writeHelpTextForConsole(file, text);
+ context.writeTextBlock(text);
}
//! \endcond
return NULL;
}
-void AbstractSimpleHelpTopic::writeHelp(File *file) const
+void AbstractSimpleHelpTopic::writeHelp(const HelpWriterContext &context) const
{
- writeBasicHelpTopic(file, *this, helpText());
+ writeBasicHelpTopic(context, *this, helpText());
}
/********************************************************************
return topic->second.get();
}
-void AbstractCompositeHelpTopic::writeHelp(File *file) const
+void AbstractCompositeHelpTopic::writeHelp(const HelpWriterContext &context) const
{
- writeBasicHelpTopic(file, *this, helpText());
- writeSubTopicList(file, "\nAvailable subtopics:");
+ writeBasicHelpTopic(context, *this, helpText());
+ writeSubTopicList(context, "\nAvailable subtopics:");
}
bool
-AbstractCompositeHelpTopic::writeSubTopicList(File *file,
+AbstractCompositeHelpTopic::writeSubTopicList(const HelpWriterContext &context,
const std::string &title) const
{
+ 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"));
+ }
int maxNameLength = 0;
Impl::SubTopicMap::const_iterator topic;
for (topic = impl_->subtopics_.begin(); topic != impl_->subtopics_.end(); ++topic)
{
return false;
}
+ File &file = context.outputFile();
TextTableFormatter formatter;
formatter.addColumn(NULL, maxNameLength + 1, false);
formatter.addColumn(NULL, 72 - maxNameLength, true);
formatter.setFirstColumnIndent(4);
- file->writeLine(title);
+ file.writeLine(title);
for (topic = impl_->subtopics_.begin(); topic != impl_->subtopics_.end(); ++topic)
{
const char *name = topic->first.c_str();
formatter.clear();
formatter.addColumnLine(0, name);
formatter.addColumnLine(1, title);
- file->writeString(formatter.formatRow());
+ file.writeString(formatter.formatRow());
}
}
return true;
/*! \libinternal \brief
* Helper for writing simple help text.
*
- * \param file File to write the help to.
- * \param[in] topic Topic to write the help for (used for title).
- * \param[in] text Text to write for the topic.
+ * \param[in] context Context for writing the help.
+ * \param[in] topic Topic to write the help for (used for title).
+ * \param[in] text Text to write for the topic.
+ * \throws std::bad_alloc if out of memory.
+ * \throws FileIOError on any I/O error.
*
* Formats basic help by writing a title (obtained from \p topic), followed by
* \p text with markup substituted and lines properly wrapped.
*
* \inlibraryapi
*/
-void writeBasicHelpTopic(File *file, const HelpTopicInterface &topic,
+void writeBasicHelpTopic(const HelpWriterContext &context,
+ const HelpTopicInterface &topic,
const std::string &text);
//! \endcond
virtual bool hasSubTopics() const;
virtual const HelpTopicInterface *findSubTopic(const char *name) const;
- virtual void writeHelp(File *file) const;
+ virtual void writeHelp(const HelpWriterContext &context) const;
protected:
/*! \brief
virtual bool hasSubTopics() const;
virtual const HelpTopicInterface *findSubTopic(const char *name) const;
- virtual void writeHelp(File *file) const;
+ virtual void writeHelp(const HelpWriterContext &context) const;
/*! \brief
* Adds a given topic as a subtopic of this topic.
/*! \brief
* Writes the list of subtopics.
*
- * \param file File to write the list to.
+ * \param[in] context Context for writing the help.
* \param[in] title Title for the written list.
* \returns true if anything was printed.
+ * \throws std::bad_alloc if out of memory.
+ * \throws FileIOError on any I/O error.
*
* Subtopics with empty titles are skipped from the list.
* If there would be no subtopics in the list, \p title is not printed
* subtopic list that is printed by the default writeHelp()
* implementation.
*/
- bool writeSubTopicList(File *file, const std::string &title) const;
+ bool writeSubTopicList(const HelpWriterContext &context,
+ const std::string &title) const;
private:
class Impl;
namespace gmx
{
-class File;
+class HelpWriterContext;
/*! \brief
* Provides a single online help topic.
/*! \brief
* Prints the help text for this topic.
*
- * \param file File to write the help text to.
- * \throws std::bad_alloc if out of memory.
- * \throws FileIOError on any I/O error.
+ * \param[in] context Context object for writing the help.
+ * \throws std::bad_alloc if out of memory.
+ * \throws FileIOError on any I/O error.
*/
- virtual void writeHelp(File *file) const = 0;
+ virtual void writeHelp(const HelpWriterContext &context) const = 0;
};
//! Smart pointer type to manage a HelpTopicInterface object.
--- /dev/null
+/*
+ *
+ * This source code is part of
+ *
+ * G R O M A C S
+ *
+ * GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::HelpWriterContext.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_onlinehelp
+ */
+#include "helpwritercontext.h"
+
+#include <cctype>
+
+#include <algorithm>
+
+#include "gromacs/legacyheaders/smalloc.h"
+#include "gromacs/legacyheaders/wman.h"
+
+#include "gromacs/onlinehelp/helpformat.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/file.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/programinfo.h"
+#include "gromacs/utility/stringutil.h"
+
+namespace
+{
+
+/*! \internal \brief
+ * Make the string uppercase.
+ *
+ * \param[in] text Input text.
+ * \returns \p text with all characters transformed to uppercase.
+ * \throws std::bad_alloc if out of memory.
+ */
+std::string toUpperCase(const std::string &text)
+{
+ std::string result(text);
+ transform(result.begin(), result.end(), result.begin(), toupper);
+ return result;
+}
+
+} // namespace
+
+namespace gmx
+{
+
+/********************************************************************
+ * HelpWriterContext::Impl
+ */
+
+/*! \internal \brief
+ * Private implementation class for HelpWriterContext.
+ *
+ * \ingroup module_onlinehelp
+ */
+class HelpWriterContext::Impl
+{
+ public:
+ //! Initializes the context with the given output file and format.
+ explicit Impl(File *file, HelpOutputFormat format)
+ : file_(*file), format_(format)
+ {
+ }
+
+ //! Output file to which the help is written.
+ File &file_;
+ //! Output format for the help output.
+ HelpOutputFormat format_;
+};
+
+/********************************************************************
+ * HelpWriterContext
+ */
+
+HelpWriterContext::HelpWriterContext(File *file, HelpOutputFormat format)
+ : impl_(new Impl(file, format))
+{
+ if (format != eHelpOutputFormat_Console)
+ {
+ // TODO: Implement once the situation with Redmine issue #969 is more
+ // clear.
+ GMX_THROW(NotImplementedError(
+ "This output format is not implemented"));
+ }
+}
+
+HelpWriterContext::~HelpWriterContext()
+{
+}
+
+HelpOutputFormat HelpWriterContext::outputFormat() const
+{
+ return impl_->format_;
+}
+
+File &HelpWriterContext::outputFile() const
+{
+ return impl_->file_;
+}
+
+std::string HelpWriterContext::substituteMarkup(const std::string &text) const
+{
+ char *resultStr = check_tty(text.c_str());
+ try
+ {
+ std::string result(resultStr);
+ sfree(resultStr);
+ return result;
+ }
+ catch (...)
+ {
+ sfree(resultStr);
+ throw;
+ }
+}
+
+void HelpWriterContext::writeTitle(const std::string &title) const
+{
+ File &file = outputFile();
+ file.writeLine(toUpperCase(title));
+ file.writeLine();
+}
+
+void HelpWriterContext::writeTextBlock(const std::string &text) const
+{
+ TextLineWrapper wrapper;
+ wrapper.setLineLength(78);
+ const char *program = ProgramInfo::getInstance().programName().c_str();
+ std::string newText = replaceAll(text, "[PROGRAM]", program);
+ outputFile().writeLine(wrapper.wrapToString(substituteMarkup(newText)));
+}
+
+} // namespace gmx
--- /dev/null
+/*
+ *
+ * This source code is part of
+ *
+ * G R O M A C S
+ *
+ * GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \libinternal \file
+ * \brief
+ * Declares gmx::HelpWriterContext.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inlibraryapi
+ * \ingroup module_onlinehelp
+ */
+#ifndef GMX_ONLINEHELP_HELPWRITERCONTEXT_H
+#define GMX_ONLINEHELP_HELPWRITERCONTEXT_H
+
+#include <string>
+
+#include "../utility/common.h"
+
+namespace gmx
+{
+
+class File;
+
+/*! \cond libapi */
+//! \libinternal Output format for help writing.
+enum HelpOutputFormat
+{
+ eHelpOutputFormat_Console, //!< Plain text directly on the console.
+ eHelpOutputFormat_NR //!< Used for the number of output formats.
+};
+//! \endcond
+
+/*! \libinternal \brief
+ * Context information for writing out help.
+ *
+ * The purpose of this class is to pass information about the output format to
+ * methods that write help, and to abstract away most of the details of
+ * different output formats.
+ * Additionally, it can keep other context information, although it currently
+ * does not. Such additional context information would be useful for
+ * formatting links/references to other help topics.
+ *
+ * TODO: This class will need additional work as part of Redmine issue #969.
+ *
+ * \inlibraryapi
+ * \ingroup module_onlinehelp
+ */
+class HelpWriterContext
+{
+ public:
+ /*! \brief
+ * Initializes a context with the given output file and format.
+ *
+ * \throws std::bad_alloc if out of memory.
+ */
+ HelpWriterContext(File *file, HelpOutputFormat format);
+ ~HelpWriterContext();
+
+ /*! \brief
+ * Returns the active output format.
+ *
+ * Does not throw.
+ */
+ HelpOutputFormat outputFormat() const;
+ /*! \brief
+ * Returns the raw output file for writing the help.
+ *
+ * Using this file directly should be avoided, as it requires one to
+ * have different code for each output format.
+ * Using other methods in this class should be preferred.
+ *
+ * Does not throw.
+ */
+ File &outputFile() const;
+
+ /*! \brief
+ * Substitutes markup used in help text.
+ *
+ * \param[in] text Text to substitute.
+ * \returns \p text with markup substituted.
+ * \throws std::bad_alloc if out of memory.
+ */
+ std::string substituteMarkup(const std::string &text) const;
+ /*! \brief
+ * Writes a title for the current help topic.
+ *
+ * \param[in] title Title to write.
+ * \throws std::bad_alloc if out of memory.
+ * \throws FileIOError on any I/O error.
+ */
+ void writeTitle(const std::string &title) const;
+ /*! \brief
+ * Writes a formatted text block into the output.
+ *
+ * \param[in] text Text to format.
+ * \throws std::bad_alloc if out of memory.
+ * \throws FileIOError on any I/O error.
+ *
+ * In addition to substituteMarkup(), also does line wrapping for
+ * console output.
+ *
+ * TODO: This function and substituteMarkup() should work more
+ * similarly.
+ */
+ void writeTextBlock(const std::string &text) const;
+
+ private:
+ class Impl;
+
+ PrivateImplPointer<Impl> impl_;
+};
+
+} // namespace gmx
+
+#endif
#include <gtest/gtest.h>
#include "gromacs/onlinehelp/helptopic.h"
+#include "gromacs/onlinehelp/helpwritercontext.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/file.h"
gmx::test::TestFileManager tempFiles_;
MockHelpTopic rootTopic_;
+ std::string filename_;
+ gmx::File helpFile_;
+ gmx::HelpWriterContext context_;
gmx::HelpManager manager_;
};
HelpTestBase::HelpTestBase()
: rootTopic_("", NULL, "Root topic text"),
- manager_(rootTopic_)
+ filename_(tempFiles_.getTemporaryFilePath("helptext.txt")),
+ helpFile_(filename_, "w"),
+ context_(&helpFile_, gmx::eHelpOutputFormat_Console),
+ manager_(rootTopic_, context_)
{
}
* Tests for HelpManager
*/
-class HelpManagerTest : public HelpTestBase
-{
- public:
- HelpManagerTest();
-
- gmx::File helpFile_;
-};
-
-HelpManagerTest::HelpManagerTest()
- : helpFile_(tempFiles_.getTemporaryFilePath("helptext.txt"), "w")
-{
-}
+typedef HelpTestBase HelpManagerTest;
TEST_F(HelpManagerTest, HandlesRootTopic)
{
- EXPECT_CALL(rootTopic_, writeHelp(&helpFile_));
- manager_.writeCurrentTopic(&helpFile_);
+ using ::testing::_;
+ EXPECT_CALL(rootTopic_, writeHelp(_));
+ manager_.writeCurrentTopic();
}
TEST_F(HelpManagerTest, HandlesSubTopics)
first.addSubTopic("firstsub", "First subtopic", "First subtopic text");
rootTopic_.addSubTopic("second", "Second topic", "Second topic text");
- EXPECT_CALL(firstSub, writeHelp(&helpFile_));
+ using ::testing::_;
+ EXPECT_CALL(firstSub, writeHelp(_));
ASSERT_NO_THROW(manager_.enterTopic("first"));
ASSERT_NO_THROW(manager_.enterTopic("firstsub"));
- manager_.writeCurrentTopic(&helpFile_);
+ manager_.writeCurrentTopic();
}
TEST_F(HelpManagerTest, HandlesInvalidTopics)
void HelpTopicFormattingTest::checkHelpFormatting()
{
- std::string filename = tempFiles_.getTemporaryFilePath("helptext.txt");
ASSERT_NO_THROW(manager_.enterTopic("testtopic"));
- gmx::File file(filename, "w");
- ASSERT_NO_THROW(manager_.writeCurrentTopic(&file));
- file.close();
+ ASSERT_NO_THROW(manager_.writeCurrentTopic());
+ helpFile_.close();
- checkFileContents(filename, "HelpText");
+ checkFileContents(filename_, "HelpText");
}
TEST_F(HelpTopicFormattingTest, FormatsSimpleTopic)
#include "string2.h"
#include "gromacs/onlinehelp/helpmanager.h"
+#include "gromacs/onlinehelp/helpwritercontext.h"
#include "gromacs/selection/poscalc.h"
#include "gromacs/selection/selection.h"
#include "gromacs/selection/selmethod.h"
{
sc->rootHelp = gmx::createSelectionHelpTopic();
}
- gmx::HelpManager manager(*sc->rootHelp);
+ gmx::HelpWriterContext context(&gmx::File::standardError(),
+ gmx::eHelpOutputFormat_Console);
+ gmx::HelpManager manager(*sc->rootHelp, context);
try
{
t_selexpr_value *value = topic;
fprintf(stderr, "%s\n", ex.what());
return;
}
- manager.writeCurrentTopic(&gmx::File::standardError());
+ manager.writeCurrentTopic();
}
#include <boost/shared_ptr.hpp>
#include "gromacs/onlinehelp/helptopic.h"
+#include "gromacs/onlinehelp/helpwritercontext.h"
+#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/file.h"
#include "gromacs/utility/stringutil.h"
public:
KeywordsHelpTopic();
- virtual void writeHelp(File *file) const;
+ virtual void writeHelp(const HelpWriterContext &context) const;
private:
/*! \brief
/*! \brief
* Prints a brief list of keywords (selection methods) available.
*
- * \param[in] file Where to write the list.
- * \param[in] type Only methods that return this type are printed.
+ * \param[in] context Context for printing the help.
+ * \param[in] type Only methods that return this type are printed.
* \param[in] bModifiers If false, \ref SMETH_MODIFIER methods are
* excluded, otherwise only them are printed.
*/
- void printKeywordList(File *file, e_selvalue_t type, bool bModifiers) const;
+ void printKeywordList(const HelpWriterContext &context,
+ e_selvalue_t type, bool bModifiers) const;
MethodList methods_;
};
}
}
-void KeywordsHelpTopic::writeHelp(File *file) const
+void KeywordsHelpTopic::writeHelp(const HelpWriterContext &context) const
{
- writeBasicHelpTopic(file, *this, helpText());
-
- /* Print the list of keywords */
- file->writeLine();
- file->writeLine("Keywords that select atoms by an integer property:");
- file->writeLine("(use in expressions or like \"atomnr 1 to 5 7 9\")");
- printKeywordList(file, INT_VALUE, false);
-
- file->writeLine();
- file->writeLine("Keywords that select atoms by a numeric property:");
- file->writeLine("(use in expressions or like \"occupancy 0.5 to 1\")");
- printKeywordList(file, REAL_VALUE, false);
-
- file->writeLine();
- file->writeLine("Keywords that select atoms by a string property:");
- file->writeLine("(use like \"name PATTERN [PATTERN] ...\")");
- printKeywordList(file, STR_VALUE, false);
-
- file->writeLine();
- file->writeLine("Additional keywords that directly select atoms:");
- printKeywordList(file, GROUP_VALUE, false);
-
- file->writeLine();
- file->writeLine("Keywords that directly evaluate to positions:");
- file->writeLine("(see also \"positions\" subtopic)");
- printKeywordList(file, POS_VALUE, false);
-
- file->writeLine();
- file->writeLine("Additional keywords:");
- printKeywordList(file, POS_VALUE, true);
- printKeywordList(file, NO_VALUE, true);
+ 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.
+ writeBasicHelpTopic(context, *this, helpText());
+ context.writeTextBlock("[BR]");
+
+ // Print the list of keywords
+ context.writeTextBlock(
+ "Keywords that select atoms by an integer property:[BR]"
+ "(use in expressions or like \"atomnr 1 to 5 7 9\")[BR]");
+ printKeywordList(context, INT_VALUE, false);
+ context.writeTextBlock("[BR]");
+
+ context.writeTextBlock(
+ "Keywords that select atoms by a numeric property:[BR]"
+ "(use in expressions or like \"occupancy 0.5 to 1\")[BR]");
+ printKeywordList(context, REAL_VALUE, false);
+ context.writeTextBlock("[BR]");
+
+ context.writeTextBlock(
+ "Keywords that select atoms by a string property:[BR]"
+ "(use like \"name PATTERN [PATTERN] ...\")[BR]");
+ printKeywordList(context, STR_VALUE, false);
+ context.writeTextBlock("[BR]");
+
+ context.writeTextBlock(
+ "Additional keywords that directly select atoms:[BR]");
+ printKeywordList(context, GROUP_VALUE, false);
+ context.writeTextBlock("[BR]");
+
+ context.writeTextBlock(
+ "Keywords that directly evaluate to positions:[BR]"
+ "(see also \"positions\" subtopic)[BR]");
+ printKeywordList(context, POS_VALUE, false);
+ context.writeTextBlock("[BR]");
+
+ context.writeTextBlock("Additional keywords:[BR]");
+ printKeywordList(context, POS_VALUE, true);
+ printKeywordList(context, NO_VALUE, true);
}
-void KeywordsHelpTopic::printKeywordList(File *file, e_selvalue_t type,
+void KeywordsHelpTopic::printKeywordList(const HelpWriterContext &context,
+ e_selvalue_t type,
bool bModifiers) const
{
+ File &file = context.outputFile();
MethodList::const_iterator iter;
for (iter = methods_.begin(); iter != methods_.end(); ++iter)
{
if (method.type == type && bModifiers == bIsModifier)
{
bool bHasHelp = (method.help.nlhelp > 0 && method.help.help != NULL);
- file->writeString(formatString(" %c ", bHasHelp ? '*' : ' '));
+ file.writeString(formatString(" %c ", bHasHelp ? '*' : ' '));
if (method.help.syntax != NULL)
{
- file->writeLine(method.help.syntax);
+ file.writeLine(method.help.syntax);
}
else
{
- const std::string &symname = iter->first;
- file->writeString(symname);
+ std::string symname = iter->first;
if (symname != method.name)
{
- file->writeString(formatString(" (synonym for %s)", method.name));
+ symname.append(formatString(" (synonym for %s)", method.name));
}
- file->writeLine();
+ file.writeLine(symname);
}
}
}
#include "gromacs/analysisdata/paralleloptions.h"
#include "gromacs/commandline/cmdlinehelpwriter.h"
#include "gromacs/commandline/cmdlineparser.h"
+#include "gromacs/onlinehelp/helpwritercontext.h"
#include "gromacs/options/options.h"
#include "gromacs/selection/selectioncollection.h"
#include "gromacs/selection/selectionoptioninfo.h"
TrajectoryAnalysisRunnerCommon::HelpFlags flags = common.helpFlags();
if (flags != 0)
{
+ HelpWriterContext context(&File::standardError(),
+ eHelpOutputFormat_Console);
CommandLineHelpWriter(options)
.setShowDescriptions(flags & TrajectoryAnalysisRunnerCommon::efHelpShowDescriptions)
.setShowHidden(flags & TrajectoryAnalysisRunnerCommon::efHelpShowHidden)
.setTimeUnitString(settings.timeUnitManager().timeUnitAsString())
- .writeHelp(&File::standardError());
+ .writeHelp(context);
}
}
void
-TrajectoryAnalysisCommandLineRunner::writeHelp(File *file)
+TrajectoryAnalysisCommandLineRunner::writeHelp(const HelpWriterContext &context)
{
// TODO: This method duplicates some code from run() and Impl::printHelp().
// See how to best refactor it to share the common code.
CommandLineHelpWriter(options)
.setShowDescriptions(true)
.setTimeUnitString(settings.timeUnitManager().timeUnitAsString())
- .writeHelp(file);
+ .writeHelp(context);
}
} // namespace gmx
namespace gmx
{
-class File;
+class HelpWriterContext;
class TrajectoryAnalysisModule;
/*! \brief
/*! \brief
* Prints help for the module, including common options from the runner.
*
- * \param[in] file File to write the help to.
+ * \param[in] context Context object for writing the help.
* \throws std::bad_alloc if out of memory.
+ * \throws FileIOError on any I/O error.
*/
- void writeHelp(File *file);
+ void writeHelp(const HelpWriterContext &context);
private:
class Impl;
virtual const char *shortDescription() const = 0;
virtual int run(int argc, char *argv[]);
- virtual void writeHelp(File *file) const;
+ virtual void writeHelp(const HelpWriterContext &context) const;
protected:
//! Creates the analysis module for this wrapper.
return runner.run(argc, argv);
}
-void AbstractTrajAnalysisCmdLineWrapper::writeHelp(File *file) const
+void AbstractTrajAnalysisCmdLineWrapper::writeHelp(const HelpWriterContext &context) const
{
TrajectoryAnalysisModulePointer module(createModule());
TrajectoryAnalysisCommandLineRunner runner(module.get());
- runner.writeHelp(file);
+ runner.writeHelp(context);
}
/*! \internal \brief
#include <gmock/gmock.h>
#include "gromacs/onlinehelp/helptopic.h"
+#include "gromacs/onlinehelp/helpwritercontext.h"
namespace gmx
{
virtual const char *name() const;
virtual const char *title() const;
- MOCK_CONST_METHOD1(writeHelp, void(File *));
+ MOCK_CONST_METHOD1(writeHelp, void(const HelpWriterContext &context));
MockHelpTopic &addSubTopic(const char *name, const char *title,
const char *text);