2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2012,2013,2014, 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
42 #include "helpwritercontext.h"
50 #include <boost/shared_ptr.hpp>
52 #include "gromacs/utility/exceptions.h"
53 #include "gromacs/utility/file.h"
54 #include "gromacs/utility/gmxassert.h"
55 #include "gromacs/utility/programcontext.h"
56 #include "gromacs/utility/stringutil.h"
64 //! \addtogroup module_onlinehelp
73 /* The order of these arrays is significant. Text search and replace
74 * for each element occurs in order, so earlier changes can induce
75 * subsequent changes even though the original text might not appear
76 * to invoke the latter changes.
77 * TODO: Get rid of this behavior. It makes it very difficult to manage
78 * replacements coming from multiple sources (e.g., hyperlinks).*/
80 //! List of replacements for console output.
81 const t_sandr sandrTty
[] = {
94 { "[INT]", "integral" },
95 { "[FROM]", " from " },
104 { "[SQRT]", "sqrt(" },
118 { "[COSH]", "cosh(" },
120 { "[SINH]", "sinh(" },
122 { "[TANH]", "tanh(" },
130 //! List of replacements for man page output.
131 const t_sandr sandrMan
[] = {
140 { "[CHEVRON]", "<" },
141 { "[chevron]", ">" },
144 { "[INT]", "integral" },
145 { "[FROM]", " from " },
154 { "[SQRT]", "sqrt(" },
168 { "[COSH]", "cosh(" },
170 { "[SINH]", "sinh(" },
172 { "[TANH]", "tanh(" },
186 //! List of replacements for HTML output.
187 const t_sandr sandrHtml
[] = {
198 { "[CHEVRON]", "<" },
199 { "[chevron]", ">" },
202 { "[INT]", "integral" },
203 { "[FROM]", " from " },
212 { "[SQRT]", "sqrt(" },
226 { "[COSH]", "cosh(" },
228 { "[SINH]", "sinh(" },
230 { "[TANH]", "tanh(" },
239 * Replaces all entries from a list of replacements.
241 std::string
repall(const std::string
&s
, int nsr
, const t_sandr sa
[])
243 std::string
result(s
);
244 for (int i
= 0; i
< nsr
; ++i
)
246 result
= replaceAll(result
, sa
[i
].search
, sa
[i
].replace
);
252 * Replaces all entries from a list of replacements.
254 template <size_t nsr
>
255 std::string
repall(const std::string
&s
, const t_sandr (&sa
)[nsr
])
257 return repall(s
, nsr
, sa
);
261 * Custom output interface for HelpWriterContext::Impl::processMarkup().
263 * Provides an interface that is used to implement different types of output
264 * from HelpWriterContext::Impl::processMarkup().
266 class WrapperInterface
269 virtual ~WrapperInterface() {}
272 * Provides the wrapping settings.
274 * HelpWriterContext::Impl::processMarkup() may provide some default
275 * values for the settings if they are not set; this is the reason the
276 * return value is not const.
278 virtual TextLineWrapperSettings
&settings() = 0;
279 //! Appends the given string to output.
280 virtual void wrap(const std::string
&text
) = 0;
284 * Wraps markup output into a single string.
286 class WrapperToString
: public WrapperInterface
289 //! Creates a wrapper with the given settings.
290 explicit WrapperToString(const TextLineWrapperSettings
&settings
)
295 virtual TextLineWrapperSettings
&settings()
297 return wrapper_
.settings();
299 virtual void wrap(const std::string
&text
)
301 result_
.append(wrapper_
.wrapToString(text
));
303 //! Returns the result string.
304 const std::string
&result() const { return result_
; }
307 TextLineWrapper wrapper_
;
312 * Wraps markup output into a vector of string (one line per element).
314 class WrapperToVector
: public WrapperInterface
317 //! Creates a wrapper with the given settings.
318 explicit WrapperToVector(const TextLineWrapperSettings
&settings
)
323 virtual TextLineWrapperSettings
&settings()
325 return wrapper_
.settings();
327 virtual void wrap(const std::string
&text
)
329 const std::vector
<std::string
> &lines
= wrapper_
.wrapToVector(text
);
330 result_
.insert(result_
.end(), lines
.begin(), lines
.end());
332 //! Returns a vector with the output lines.
333 const std::vector
<std::string
> &result() const { return result_
; }
336 TextLineWrapper wrapper_
;
337 std::vector
<std::string
> result_
;
341 * Makes the string uppercase.
343 * \param[in] text Input text.
344 * \returns \p text with all characters transformed to uppercase.
345 * \throws std::bad_alloc if out of memory.
347 std::string
toUpperCase(const std::string
&text
)
349 std::string
result(text
);
350 transform(result
.begin(), result
.end(), result
.begin(), toupper
);
358 /********************************************************************
363 * Private implementation class for HelpLinks.
365 * \ingroup module_onlinehelp
367 class HelpLinks::Impl
372 LinkItem(const std::string
&linkName
,
373 const std::string
&replacement
)
374 : linkName(linkName
), replacement(replacement
)
377 std::string linkName
;
378 std::string replacement
;
381 //! Shorthand for a list of links.
382 typedef std::vector
<LinkItem
> LinkList
;
384 //! Initializes empty links with the given format.
385 explicit Impl(HelpOutputFormat format
) : format_(format
)
391 //! Output format for which the links are formatted.
392 HelpOutputFormat format_
;
395 /********************************************************************
399 HelpLinks::HelpLinks(HelpOutputFormat format
) : impl_(new Impl(format
))
403 HelpLinks::~HelpLinks()
407 void HelpLinks::addLink(const std::string
&linkName
,
408 const std::string
&targetName
,
409 const std::string
&displayName
)
411 std::string replacement
;
412 switch (impl_
->format_
)
414 case eHelpOutputFormat_Console
:
415 replacement
= repall(displayName
, sandrTty
);
417 case eHelpOutputFormat_Man
:
418 replacement
= repall(displayName
, sandrMan
);
420 case eHelpOutputFormat_Html
:
421 replacement
= formatString(
422 "<a href=\"%s.html\">%s</a>", targetName
.c_str(),
423 repall(displayName
, sandrHtml
).c_str());
426 GMX_RELEASE_ASSERT(false, "Output format not implemented for links");
428 impl_
->links_
.push_back(Impl::LinkItem(linkName
, replacement
));
431 /********************************************************************
432 * HelpWriterContext::Impl
436 * Private implementation class for HelpWriterContext.
438 * \ingroup module_onlinehelp
440 class HelpWriterContext::Impl
444 * Shared, non-modifiable state for context objects.
446 * Contents of this structure are shared between all context objects
447 * that are created from a common parent.
448 * This state should not be modified after construction.
450 * \ingroup module_onlinehelp
454 //! Initializes the state with the given parameters.
455 SharedState(File
*file
, HelpOutputFormat format
,
456 const HelpLinks
*links
)
457 : file_(*file
), format_(format
), links_(links
)
461 //! Output file to which the help is written.
463 //! Output format for the help output.
464 HelpOutputFormat format_
;
466 const HelpLinks
*links_
;
471 ReplaceItem(const std::string
&search
,
472 const std::string
&replace
)
473 : search(search
), replace(replace
)
480 //! Smart pointer type for managing the shared state.
481 typedef boost::shared_ptr
<const SharedState
> StatePointer
;
482 //! Shorthand for a list of markup/other replacements.
483 typedef std::vector
<ReplaceItem
> ReplaceList
;
485 //! Initializes the context with the given state.
486 explicit Impl(const StatePointer
&state
)
489 initDefaultReplacements();
492 //! Initializes default replacements for the chosen output format.
493 void initDefaultReplacements();
494 //! Adds a new replacement.
495 void addReplacement(const std::string
&search
,
496 const std::string
&replace
)
498 replacements_
.push_back(ReplaceItem(search
, replace
));
501 //! Replaces links in a given string.
502 std::string
replaceLinks(const std::string
&input
) const;
505 * Process markup and wrap lines within a block of text.
507 * \param[in] text Text to process.
508 * \param wrapper Object used to wrap the text.
510 * The \p wrapper should take care of either writing the text to output
511 * or providing an interface for the caller to retrieve the output.
513 void processMarkup(const std::string
&text
,
514 WrapperInterface
*wrapper
) const;
516 //! Constant state shared by all child context objects.
518 //! List of markup/other replacements.
519 ReplaceList replacements_
;
522 GMX_DISALLOW_ASSIGN(Impl
);
525 void HelpWriterContext::Impl::initDefaultReplacements()
527 const char *program
= getProgramContext().programName();
528 addReplacement("[PROGRAM]", program
);
531 std::string
HelpWriterContext::Impl::replaceLinks(const std::string
&input
) const
533 std::string
result(input
);
534 if (state_
->links_
!= NULL
)
536 HelpLinks::Impl::LinkList::const_iterator link
;
537 for (link
= state_
->links_
->impl_
->links_
.begin();
538 link
!= state_
->links_
->impl_
->links_
.end(); ++link
)
540 result
= replaceAllWords(result
, link
->linkName
, link
->replacement
);
546 void HelpWriterContext::Impl::processMarkup(const std::string
&text
,
547 WrapperInterface
*wrapper
) const
549 std::string
result(text
);
550 for (ReplaceList::const_iterator i
= replacements_
.begin();
551 i
!= replacements_
.end(); ++i
)
553 result
= replaceAll(result
, i
->search
, i
->replace
);
555 switch (state_
->format_
)
557 case eHelpOutputFormat_Console
:
559 result
= repall(result
, sandrTty
);
560 result
= replaceLinks(result
);
561 return wrapper
->wrap(result
);
563 case eHelpOutputFormat_Man
:
565 // Needs to be done first to avoid '-' -> '\-' messing up the links.
566 result
= replaceLinks(result
);
567 result
= repall(result
, sandrMan
);
568 return wrapper
->wrap(result
);
570 case eHelpOutputFormat_Html
:
572 result
= repall(result
, sandrHtml
);
573 result
= replaceLinks(result
);
574 return wrapper
->wrap(result
);
577 GMX_THROW(InternalError("Invalid help output format"));
581 /********************************************************************
585 HelpWriterContext::HelpWriterContext(File
*file
, HelpOutputFormat format
)
586 : impl_(new Impl(Impl::StatePointer(new Impl::SharedState(file
, format
, NULL
))))
590 HelpWriterContext::HelpWriterContext(File
*file
, HelpOutputFormat format
,
591 const HelpLinks
*links
)
592 : impl_(new Impl(Impl::StatePointer(new Impl::SharedState(file
, format
, links
))))
596 GMX_RELEASE_ASSERT(links
->impl_
->format_
== format
,
597 "Links must have the same output format as the context");
601 HelpWriterContext::HelpWriterContext(Impl
*impl
)
606 HelpWriterContext::HelpWriterContext(const HelpWriterContext
&other
)
607 : impl_(new Impl(*other
.impl_
))
611 HelpWriterContext::~HelpWriterContext()
615 void HelpWriterContext::setReplacement(const std::string
&search
,
616 const std::string
&replace
)
618 impl_
->addReplacement(search
, replace
);
621 HelpOutputFormat
HelpWriterContext::outputFormat() const
623 return impl_
->state_
->format_
;
626 File
&HelpWriterContext::outputFile() const
628 return impl_
->state_
->file_
;
632 HelpWriterContext::substituteMarkupAndWrapToString(
633 const TextLineWrapperSettings
&settings
, const std::string
&text
) const
635 WrapperToString
wrapper(settings
);
636 impl_
->processMarkup(text
, &wrapper
);
637 return wrapper
.result();
640 std::vector
<std::string
>
641 HelpWriterContext::substituteMarkupAndWrapToVector(
642 const TextLineWrapperSettings
&settings
, const std::string
&text
) const
644 WrapperToVector
wrapper(settings
);
645 impl_
->processMarkup(text
, &wrapper
);
646 return wrapper
.result();
649 void HelpWriterContext::writeTitle(const std::string
&title
) const
651 File
&file
= outputFile();
652 switch (outputFormat())
654 case eHelpOutputFormat_Console
:
655 file
.writeLine(toUpperCase(title
));
658 case eHelpOutputFormat_Man
:
659 file
.writeLine(formatString(".SH %s", toUpperCase(title
).c_str()));
661 case eHelpOutputFormat_Html
:
662 file
.writeLine(formatString("<H3>%s</H3>", title
.c_str()));
665 GMX_THROW(NotImplementedError(
666 "This output format is not implemented"));
670 void HelpWriterContext::writeTextBlock(const std::string
&text
) const
672 TextLineWrapperSettings settings
;
673 if (outputFormat() == eHelpOutputFormat_Console
)
675 settings
.setLineLength(78);
677 outputFile().writeLine(substituteMarkupAndWrapToString(settings
, text
));
680 void HelpWriterContext::writeOptionListStart() const
682 if (outputFormat() == eHelpOutputFormat_Html
)
684 outputFile().writeLine("<dl>");
688 void HelpWriterContext::writeOptionItem(const std::string
&name
,
689 const std::string
&args
,
690 const std::string
&description
) const
692 File
&file
= outputFile();
693 switch (outputFormat())
695 case eHelpOutputFormat_Console
:
696 // TODO: Generalize this when there is need for it; the current,
697 // special implementation is in CommandLineHelpWriter.
698 GMX_THROW(NotImplementedError("Option item formatting for console output not implemented"));
700 case eHelpOutputFormat_Man
:
701 file
.writeLine(formatString(".BI \"\\%s\" \" %s\"", name
.c_str(), args
.c_str()));
702 file
.writeString(" ");
703 writeTextBlock(description
);
706 case eHelpOutputFormat_Html
:
708 std::string substArgs
=
709 substituteMarkupAndWrapToString(TextLineWrapperSettings(), args
);
710 file
.writeLine(formatString("<dt><b><tt>%s</tt></b> %s</dt>", name
.c_str(),
712 file
.writeLine("<dd>");
713 writeTextBlock(description
);
714 file
.writeLine("</dd>");
718 GMX_THROW(NotImplementedError(
719 "This output format is not implemented"));
723 void HelpWriterContext::writeOptionListEnd() const
725 if (outputFormat() == eHelpOutputFormat_Html
)
727 outputFile().writeLine("</dl>");