2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2012,2013,2014,2015, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
37 * Implements gmx::HelpWriterContext.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_onlinehelp
44 #include "helpwritercontext.h"
52 #include <boost/shared_ptr.hpp>
54 #include "gromacs/utility/exceptions.h"
55 #include "gromacs/utility/file.h"
56 #include "gromacs/utility/gmxassert.h"
57 #include "gromacs/utility/programcontext.h"
58 #include "gromacs/utility/stringutil.h"
66 //! \internal \addtogroup module_onlinehelp
75 /* The order of these arrays is significant. Text search and replace
76 * for each element occurs in order, so earlier changes can induce
77 * subsequent changes even though the original text might not appear
78 * to invoke the latter changes.
79 * TODO: Get rid of this behavior. It makes it very difficult to manage
80 * replacements coming from multiple sources (e.g., hyperlinks).*/
82 //! List of replacements for console output.
83 const t_sandr sandrTty[] = {
98 { "[INT]", "integral" },
99 { "[FROM]", " from " },
108 { "[SQRT]", "sqrt(" },
122 { "[COSH]", "cosh(" },
124 { "[SINH]", "sinh(" },
126 { "[TANH]", "tanh(" },
134 //! List of replacements for reStructuredText output.
135 const t_sandr sandrRst[] = {
144 { "[CHEVRON]", "<" },
145 { "[chevron]", ">" },
148 { "[INT]", "integral" },
149 { "[FROM]", " from " },
158 { "[SQRT]", "sqrt(" },
172 { "[COSH]", "cosh(" },
174 { "[SINH]", "sinh(" },
176 { "[TANH]", "tanh(" },
179 // [BR] is fundamentally incompatible with rst
186 * Replaces all entries from a list of replacements.
188 std::string repall(const std::string &s, int nsr, const t_sandr sa[])
190 std::string result(s);
191 for (int i = 0; i < nsr; ++i)
193 result = replaceAll(result, sa[i].search, sa[i].replace);
199 * Replaces all entries from a list of replacements.
201 template <size_t nsr>
202 std::string repall(const std::string &s, const t_sandr (&sa)[nsr])
204 return repall(s, nsr, sa);
208 * Custom output interface for HelpWriterContext::Impl::processMarkup().
210 * Provides an interface that is used to implement different types of output
211 * from HelpWriterContext::Impl::processMarkup().
213 class WrapperInterface
216 virtual ~WrapperInterface() {}
219 * Provides the wrapping settings.
221 * HelpWriterContext::Impl::processMarkup() may provide some default
222 * values for the settings if they are not set; this is the reason the
223 * return value is not const.
225 virtual TextLineWrapperSettings &settings() = 0;
226 //! Appends the given string to output.
227 virtual void wrap(const std::string &text) = 0;
231 * Wraps markup output into a single string.
233 class WrapperToString : public WrapperInterface
236 //! Creates a wrapper with the given settings.
237 explicit WrapperToString(const TextLineWrapperSettings &settings)
242 virtual TextLineWrapperSettings &settings()
244 return wrapper_.settings();
246 virtual void wrap(const std::string &text)
248 result_.append(wrapper_.wrapToString(text));
250 //! Returns the result string.
251 const std::string &result() const { return result_; }
254 TextLineWrapper wrapper_;
259 * Wraps markup output into a vector of string (one line per element).
261 class WrapperToVector : public WrapperInterface
264 //! Creates a wrapper with the given settings.
265 explicit WrapperToVector(const TextLineWrapperSettings &settings)
270 virtual TextLineWrapperSettings &settings()
272 return wrapper_.settings();
274 virtual void wrap(const std::string &text)
276 const std::vector<std::string> &lines = wrapper_.wrapToVector(text);
277 result_.insert(result_.end(), lines.begin(), lines.end());
279 //! Returns a vector with the output lines.
280 const std::vector<std::string> &result() const { return result_; }
283 TextLineWrapper wrapper_;
284 std::vector<std::string> result_;
288 * Makes the string uppercase.
290 * \param[in] text Input text.
291 * \returns \p text with all characters transformed to uppercase.
292 * \throws std::bad_alloc if out of memory.
294 std::string toUpperCase(const std::string &text)
296 std::string result(text);
297 std::transform(result.begin(), result.end(), result.begin(), toupper);
305 /********************************************************************
310 * Private implementation class for HelpLinks.
312 * \ingroup module_onlinehelp
314 class HelpLinks::Impl
319 LinkItem(const std::string &linkName,
320 const std::string &replacement)
321 : linkName(linkName), replacement(replacement)
324 std::string linkName;
325 std::string replacement;
328 //! Shorthand for a list of links.
329 typedef std::vector<LinkItem> LinkList;
331 //! Initializes empty links with the given format.
332 explicit Impl(HelpOutputFormat format) : format_(format)
338 //! Output format for which the links are formatted.
339 HelpOutputFormat format_;
342 /********************************************************************
346 HelpLinks::HelpLinks(HelpOutputFormat format) : impl_(new Impl(format))
350 HelpLinks::~HelpLinks()
354 void HelpLinks::addLink(const std::string &linkName,
355 const std::string &targetName,
356 const std::string &displayName)
358 std::string replacement;
359 switch (impl_->format_)
361 case eHelpOutputFormat_Console:
362 replacement = repall(displayName, sandrTty);
364 case eHelpOutputFormat_Rst:
365 replacement = formatString(
366 ":doc:`%s <%s>`", repall(displayName, sandrTty).c_str(),
370 GMX_RELEASE_ASSERT(false, "Output format not implemented for links");
372 impl_->links_.push_back(Impl::LinkItem(linkName, replacement));
375 /********************************************************************
376 * HelpWriterContext::Impl
380 * Private implementation class for HelpWriterContext.
382 * \ingroup module_onlinehelp
384 class HelpWriterContext::Impl
388 * Shared, non-modifiable state for context objects.
390 * Contents of this structure are shared between all context objects
391 * that are created from a common parent.
392 * This state should not be modified after construction.
394 * \ingroup module_onlinehelp
398 //! Initializes the state with the given parameters.
399 SharedState(File *file, HelpOutputFormat format,
400 const HelpLinks *links)
401 : file_(*file), format_(format), links_(links)
405 //! Output file to which the help is written.
407 //! Output format for the help output.
408 HelpOutputFormat format_;
410 const HelpLinks *links_;
415 ReplaceItem(const std::string &search,
416 const std::string &replace)
417 : search(search), replace(replace)
424 //! Smart pointer type for managing the shared state.
425 typedef boost::shared_ptr<const SharedState> StatePointer;
426 //! Shorthand for a list of markup/other replacements.
427 typedef std::vector<ReplaceItem> ReplaceList;
429 //! Initializes the context with the given state.
430 explicit Impl(const StatePointer &state)
433 initDefaultReplacements();
436 //! Initializes default replacements for the chosen output format.
437 void initDefaultReplacements();
438 //! Adds a new replacement.
439 void addReplacement(const std::string &search,
440 const std::string &replace)
442 replacements_.push_back(ReplaceItem(search, replace));
445 //! Replaces links in a given string.
446 std::string replaceLinks(const std::string &input) const;
449 * Process markup and wrap lines within a block of text.
451 * \param[in] text Text to process.
452 * \param wrapper Object used to wrap the text.
454 * The \p wrapper should take care of either writing the text to output
455 * or providing an interface for the caller to retrieve the output.
457 void processMarkup(const std::string &text,
458 WrapperInterface *wrapper) const;
460 //! Constant state shared by all child context objects.
462 //! List of markup/other replacements.
463 ReplaceList replacements_;
466 GMX_DISALLOW_ASSIGN(Impl);
469 void HelpWriterContext::Impl::initDefaultReplacements()
471 const char *program = getProgramContext().programName();
472 addReplacement("[PROGRAM]", program);
475 std::string HelpWriterContext::Impl::replaceLinks(const std::string &input) const
477 std::string result(input);
478 if (state_->links_ != NULL)
480 HelpLinks::Impl::LinkList::const_iterator link;
481 for (link = state_->links_->impl_->links_.begin();
482 link != state_->links_->impl_->links_.end(); ++link)
484 result = replaceAllWords(result, link->linkName, link->replacement);
490 void HelpWriterContext::Impl::processMarkup(const std::string &text,
491 WrapperInterface *wrapper) const
493 std::string result(text);
494 for (ReplaceList::const_iterator i = replacements_.begin();
495 i != replacements_.end(); ++i)
497 result = replaceAll(result, i->search, i->replace);
499 switch (state_->format_)
501 case eHelpOutputFormat_Console:
503 result = repall(result, sandrTty);
504 result = replaceLinks(result);
505 return wrapper->wrap(result);
507 case eHelpOutputFormat_Rst:
509 result = repall(result, sandrRst);
510 result = replaceLinks(result);
511 return wrapper->wrap(result);
514 GMX_THROW(InternalError("Invalid help output format"));
518 /********************************************************************
522 HelpWriterContext::HelpWriterContext(File *file, HelpOutputFormat format)
523 : impl_(new Impl(Impl::StatePointer(new Impl::SharedState(file, format, NULL))))
527 HelpWriterContext::HelpWriterContext(File *file, HelpOutputFormat format,
528 const HelpLinks *links)
529 : impl_(new Impl(Impl::StatePointer(new Impl::SharedState(file, format, links))))
533 GMX_RELEASE_ASSERT(links->impl_->format_ == format,
534 "Links must have the same output format as the context");
538 HelpWriterContext::HelpWriterContext(Impl *impl)
543 HelpWriterContext::HelpWriterContext(const HelpWriterContext &other)
544 : impl_(new Impl(*other.impl_))
548 HelpWriterContext::~HelpWriterContext()
552 void HelpWriterContext::setReplacement(const std::string &search,
553 const std::string &replace)
555 impl_->addReplacement(search, replace);
558 HelpOutputFormat HelpWriterContext::outputFormat() const
560 return impl_->state_->format_;
563 File &HelpWriterContext::outputFile() const
565 return impl_->state_->file_;
569 HelpWriterContext::substituteMarkupAndWrapToString(
570 const TextLineWrapperSettings &settings, const std::string &text) const
572 WrapperToString wrapper(settings);
573 impl_->processMarkup(text, &wrapper);
574 return wrapper.result();
577 std::vector<std::string>
578 HelpWriterContext::substituteMarkupAndWrapToVector(
579 const TextLineWrapperSettings &settings, const std::string &text) const
581 WrapperToVector wrapper(settings);
582 impl_->processMarkup(text, &wrapper);
583 return wrapper.result();
586 void HelpWriterContext::writeTitle(const std::string &title) const
588 File &file = outputFile();
589 switch (outputFormat())
591 case eHelpOutputFormat_Console:
592 file.writeLine(toUpperCase(title));
595 case eHelpOutputFormat_Rst:
596 file.writeLine(title);
597 file.writeLine(std::string(title.length(), '-'));
600 GMX_THROW(NotImplementedError(
601 "This output format is not implemented"));
605 void HelpWriterContext::writeTextBlock(const std::string &text) const
607 TextLineWrapperSettings settings;
608 if (outputFormat() == eHelpOutputFormat_Console)
610 settings.setLineLength(78);
612 outputFile().writeLine(substituteMarkupAndWrapToString(settings, text));
615 void HelpWriterContext::writeOptionListStart() const
619 void HelpWriterContext::writeOptionItem(const std::string &name,
620 const std::string &args,
621 const std::string &description) const
623 File &file = outputFile();
624 switch (outputFormat())
626 case eHelpOutputFormat_Console:
627 // TODO: Generalize this when there is need for it; the current,
628 // special implementation is in CommandLineHelpWriter.
629 GMX_THROW(NotImplementedError("Option item formatting for console output not implemented"));
631 case eHelpOutputFormat_Rst:
633 file.writeLine(formatString("``%s`` %s", name.c_str(), args.c_str()));
634 TextLineWrapperSettings settings;
635 settings.setIndent(4);
636 file.writeLine(substituteMarkupAndWrapToString(settings, description));
640 GMX_THROW(NotImplementedError(
641 "This output format is not implemented"));
645 void HelpWriterContext::writeOptionListEnd() const