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::CommandLineHelpModule.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_commandline
44 #include "cmdlinehelpmodule.h"
49 #include <boost/scoped_ptr.hpp>
51 #include "gromacs/commandline/cmdlinehelpcontext.h"
52 #include "gromacs/commandline/cmdlinehelpwriter.h"
53 #include "gromacs/commandline/cmdlineparser.h"
54 #include "gromacs/onlinehelp/helpformat.h"
55 #include "gromacs/onlinehelp/helpmanager.h"
56 #include "gromacs/onlinehelp/helptopic.h"
57 #include "gromacs/onlinehelp/helpwritercontext.h"
58 #include "gromacs/options/basicoptions.h"
59 #include "gromacs/options/options.h"
60 #include "gromacs/utility/arrayref.h"
61 #include "gromacs/utility/baseversion.h"
62 #include "gromacs/utility/exceptions.h"
63 #include "gromacs/utility/fileredirector.h"
64 #include "gromacs/utility/gmxassert.h"
65 #include "gromacs/utility/path.h"
66 #include "gromacs/utility/programcontext.h"
67 #include "gromacs/utility/stringstream.h"
68 #include "gromacs/utility/stringutil.h"
69 #include "gromacs/utility/textreader.h"
70 #include "gromacs/utility/textstream.h"
71 #include "gromacs/utility/textwriter.h"
73 #include "shellcompletions.h"
84 /********************************************************************
85 * CommandLineHelpModuleImpl declaration
88 class CommandLineHelpModuleImpl
91 CommandLineHelpModuleImpl(const IProgramContext &programContext,
92 const std::string &binaryName,
93 const CommandLineModuleMap &modules,
94 const CommandLineModuleGroupList &groups);
96 void exportHelp(IHelpExport *exporter);
98 boost::scoped_ptr<RootHelpTopic> rootTopic_;
99 const IProgramContext &programContext_;
100 std::string binaryName_;
101 const CommandLineModuleMap &modules_;
102 const CommandLineModuleGroupList &groups_;
104 CommandLineHelpContext *context_;
105 const ICommandLineModule *moduleOverride_;
108 IFileOutputRedirector *outputRedirector_;
110 GMX_DISALLOW_COPY_AND_ASSIGN(CommandLineHelpModuleImpl);
116 /********************************************************************
121 * Callbacks for exporting help information for command-line modules.
123 * \ingroup module_commandline
128 //! Shorthand for a list of modules contained in a group.
129 typedef CommandLineModuleGroupData::ModuleList ModuleGroupContents;
131 virtual ~IHelpExport() {};
134 * Called once before exporting individual modules.
136 * Can, e.g., open shared output files (e.g., if the output is written
137 * into a single file, or if a separate index is required) and write
140 virtual void startModuleExport() = 0;
142 * Called to export the help for each module.
144 * \param[in] module Module for which the help should be exported.
145 * \param[in] tag Unique tag for the module (gmx-something).
146 * \param[in] displayName Display name for the module (gmx something).
148 virtual void exportModuleHelp(
149 const ICommandLineModule &module,
150 const std::string &tag,
151 const std::string &displayName) = 0;
153 * Called after all modules have been exported.
155 * Can close files opened in startModuleExport(), write footers to them
158 virtual void finishModuleExport() = 0;
161 * Called once before exporting module groups.
163 * Can, e.g., open a single output file for listing all the groups.
165 virtual void startModuleGroupExport() = 0;
167 * Called to export the help for each module group.
169 * \param[in] title Title for the group.
170 * \param[in] modules List of modules in the group.
172 virtual void exportModuleGroup(const char *title,
173 const ModuleGroupContents &modules) = 0;
175 * Called after all module groups have been exported.
177 * Can close files opened in startModuleGroupExport(), write footers to them
180 virtual void finishModuleGroupExport() = 0;
183 * Called to export the help for a top-level topic.
185 * \param[in] topic Topic to export.
187 virtual void exportTopic(const IHelpTopic &topic) = 0;
190 /********************************************************************
196 static const char title[];
197 static const char *const text[];
200 // These are used for the gmx.1 man page.
201 // TODO: Do not hardcode them here, but pass them from the outside to make this
202 // code more generic.
203 const char RootHelpText::title[] = "molecular dynamics simulation suite";
204 const char *const RootHelpText::text[] = {
205 "|Gromacs| is a full-featured suite of programs to perform molecular",
206 "dynamics simulations, i.e., to simulate the behavior of systems with",
207 "hundreds to millions of particles using Newtonian equations of motion.",
208 "It is primarily used for research on proteins, lipids, and polymers, but",
209 "can be applied to a wide variety of chemical and biological research",
214 * Help topic that forms the root of the help tree for the help subcommand.
216 * \ingroup module_commandline
218 class RootHelpTopic : public AbstractCompositeHelpTopic
222 * Creates a root help topic.
226 explicit RootHelpTopic(const CommandLineHelpModuleImpl &helpModule)
227 : helpModule_(helpModule)
231 virtual const char *name() const { return helpModule_.binaryName_.c_str(); }
232 virtual const char *title() const { return title_.c_str(); }
234 //! Adds a top-level topic and optionally marks it as exported.
235 void addTopic(HelpTopicPointer topic, bool bExported)
239 exportedTopics_.push_back(topic->name());
241 addSubTopic(move(topic));
243 //! Exports all the top-level topics with the given exporter.
244 void exportHelp(IHelpExport *exporter);
246 virtual void writeHelp(const HelpWriterContext &context) const;
249 // unused because of the writeHelp() override
250 virtual std::string helpText() const { return ""; }
252 const CommandLineHelpModuleImpl &helpModule_;
254 std::vector<std::string> exportedTopics_;
256 GMX_DISALLOW_COPY_AND_ASSIGN(RootHelpTopic);
259 void RootHelpTopic::exportHelp(IHelpExport *exporter)
261 std::vector<std::string>::const_iterator topicName;
262 for (topicName = exportedTopics_.begin();
263 topicName != exportedTopics_.end();
266 const IHelpTopic *topic = findSubTopic(topicName->c_str());
267 GMX_RELEASE_ASSERT(topic != NULL, "Exported help topic no longer found");
268 exporter->exportTopic(*topic);
270 // For now, the title is only set for the export to make it not appear in
271 // console output, which makes things consistent for 'gmx help' and
272 // 'gmx help <command>'.
273 title_ = RootHelpText::title;
274 exporter->exportTopic(*this);
277 void RootHelpTopic::writeHelp(const HelpWriterContext &context) const
280 CommandLineCommonOptionsHolder optionsHolder;
281 boost::scoped_ptr<CommandLineHelpContext> cmdlineContext;
282 if (helpModule_.context_ != NULL)
284 cmdlineContext.reset(new CommandLineHelpContext(*helpModule_.context_));
288 cmdlineContext.reset(new CommandLineHelpContext(context));
290 cmdlineContext->setModuleDisplayName(helpModule_.binaryName_);
291 optionsHolder.initOptions();
292 Options &options = *optionsHolder.options();
293 ConstArrayRef<const char *> helpText;
294 if (context.outputFormat() != eHelpOutputFormat_Console)
296 helpText = RootHelpText::text;
298 // TODO: Add <command> [<args>] into the synopsis.
299 CommandLineHelpWriter(options)
300 .setHelpText(helpText)
301 .writeHelp(*cmdlineContext);
303 if (context.outputFormat() == eHelpOutputFormat_Console)
305 // TODO: Consider printing a list of "core" commands. Would require someone
306 // to determine such a set...
307 writeSubTopicList(context,
308 "Additional help is available on the following topics:");
309 context.writeTextBlock("To access the help, use '[PROGRAM] help <topic>'.");
310 context.writeTextBlock("For help on a command, use '[PROGRAM] help <command>'.");
314 // TODO: This should not really end up on the HTML page.
315 context.writeTitle(formatString("%s commands", helpModule_.binaryName_.c_str()));
316 context.writeTextBlock(
317 "The following commands are available. Please refer to their "
318 "individual man pages or [TT][PROGRAM] help <command>[tt] "
319 "for further details.");
320 context.writeTextBlock("");
321 context.writeTextBlock(".. include:: /fragments/bytopic-man.rst");
325 /********************************************************************
330 * Help topic for listing the commands.
332 * \ingroup module_commandline
334 class CommandsHelpTopic : public IHelpTopic
338 * Creates a command list help topic.
340 * \param[in] helpModule Help module to get module information from.
344 explicit CommandsHelpTopic(const CommandLineHelpModuleImpl &helpModule)
345 : helpModule_(helpModule)
349 virtual const char *name() const { return "commands"; }
350 virtual const char *title() const { return "List of available commands"; }
351 virtual bool hasSubTopics() const { return false; }
352 virtual const IHelpTopic *findSubTopic(const char * /*name*/) const
357 virtual void writeHelp(const HelpWriterContext &context) const;
360 const CommandLineHelpModuleImpl &helpModule_;
362 GMX_DISALLOW_COPY_AND_ASSIGN(CommandsHelpTopic);
365 void CommandsHelpTopic::writeHelp(const HelpWriterContext &context) const
367 if (context.outputFormat() != eHelpOutputFormat_Console)
369 GMX_THROW(NotImplementedError(
370 "Module list is not implemented for this output format"));
372 int maxNameLength = 0;
373 const CommandLineModuleMap &modules = helpModule_.modules_;
374 CommandLineModuleMap::const_iterator module;
375 for (module = modules.begin(); module != modules.end(); ++module)
377 int nameLength = static_cast<int>(module->first.length());
378 if (module->second->shortDescription() != NULL
379 && nameLength > maxNameLength)
381 maxNameLength = nameLength;
384 context.writeTextBlock(
385 "Usage: [PROGRAM] [<options>] <command> [<args>][PAR]"
386 "Available commands:");
387 TextWriter &file = context.outputFile();
388 TextTableFormatter formatter;
389 formatter.addColumn(NULL, maxNameLength + 1, false);
390 formatter.addColumn(NULL, 72 - maxNameLength, true);
391 formatter.setFirstColumnIndent(4);
392 for (module = modules.begin(); module != modules.end(); ++module)
394 const char *name = module->first.c_str();
395 const char *description = module->second->shortDescription();
396 if (description != NULL)
399 formatter.addColumnLine(0, name);
400 formatter.addColumnLine(1, description);
401 file.writeString(formatter.formatRow());
404 context.writeTextBlock(
405 "For help on a command, use '[PROGRAM] help <command>'.");
408 /********************************************************************
413 * Help topic wrapper for a command-line module.
415 * This class implements IHelpTopic such that it wraps a
416 * ICommandLineModule, allowing subcommand "help <command>"
417 * to produce the help for "<command>".
419 * \ingroup module_commandline
421 class ModuleHelpTopic : public IHelpTopic
424 //! Constructs a help topic for a specific module.
425 ModuleHelpTopic(const ICommandLineModule &module,
426 const CommandLineHelpModuleImpl &helpModule)
427 : module_(module), helpModule_(helpModule)
431 virtual const char *name() const { return module_.name(); }
432 virtual const char *title() const { return NULL; }
433 virtual bool hasSubTopics() const { return false; }
434 virtual const IHelpTopic *findSubTopic(const char * /*name*/) const
438 virtual void writeHelp(const HelpWriterContext &context) const;
441 const ICommandLineModule &module_;
442 const CommandLineHelpModuleImpl &helpModule_;
444 GMX_DISALLOW_COPY_AND_ASSIGN(ModuleHelpTopic);
447 void ModuleHelpTopic::writeHelp(const HelpWriterContext & /*context*/) const
449 CommandLineHelpContext context(*helpModule_.context_);
450 const char *const program = helpModule_.binaryName_.c_str();
451 context.setModuleDisplayName(formatString("%s %s", program, module_.name()));
452 module_.writeHelp(context);
455 /********************************************************************
456 * HelpExportReStructuredText
460 * Adds hyperlinks to modules within this binary.
462 * \param[in,out] links Links are added here.
463 * \param[in] helpModule Help module to get module information from.
464 * \throws std::bad_alloc if out of memory.
466 * Initializes a HelpLinks object with links to modules defined in
469 * \ingroup module_commandline
471 void initProgramLinks(HelpLinks *links, const CommandLineHelpModuleImpl &helpModule)
473 const char *const program = helpModule.binaryName_.c_str();
474 CommandLineModuleMap::const_iterator module;
475 for (module = helpModule.modules_.begin();
476 module != helpModule.modules_.end();
479 if (module->second->shortDescription() != NULL)
481 std::string linkName("[gmx-" + module->first + "]");
482 const char *name = module->first.c_str();
483 std::string reference(
484 formatString(":doc:`%s %s <%s-%s>`", program, name, program, name));
485 std::string displayName(
486 formatString("[TT]%s %s[tt]", program, name));
487 links->addLink(linkName, reference, displayName);
493 * Implements export for web pages as reStructuredText.
495 * \ingroup module_commandline
497 class HelpExportReStructuredText : public IHelpExport
500 //! Initializes reST exporter.
501 HelpExportReStructuredText(
502 const CommandLineHelpModuleImpl &helpModule,
503 IFileOutputRedirector *outputRedirector);
505 virtual void startModuleExport();
506 virtual void exportModuleHelp(
507 const ICommandLineModule &module,
508 const std::string &tag,
509 const std::string &displayName);
510 virtual void finishModuleExport();
512 virtual void startModuleGroupExport();
513 virtual void exportModuleGroup(const char *title,
514 const ModuleGroupContents &modules);
515 virtual void finishModuleGroupExport();
517 virtual void exportTopic(const IHelpTopic &topic);
520 IFileOutputRedirector *outputRedirector_;
521 const std::string &binaryName_;
523 boost::scoped_ptr<TextWriter> indexFile_;
524 boost::scoped_ptr<TextWriter> manPagesFile_;
527 HelpExportReStructuredText::HelpExportReStructuredText(
528 const CommandLineHelpModuleImpl &helpModule,
529 IFileOutputRedirector *outputRedirector)
530 : outputRedirector_(outputRedirector),
531 binaryName_(helpModule.binaryName_),
532 links_(eHelpOutputFormat_Rst)
534 TextReader linksFile("links.dat");
536 while (linksFile.readLineTrimmed(&line))
538 links_.addLink("[REF]." + line + "[ref]",
539 formatString(":ref:`.%s <%s>`", line.c_str(), line.c_str()),
541 links_.addLink("[REF]" + line + "[ref]", formatString(":ref:`%s`", line.c_str()), line);
544 initProgramLinks(&links_, helpModule);
547 void HelpExportReStructuredText::startModuleExport()
551 outputRedirector_->openTextOutputFile("fragments/byname.rst")));
552 indexFile_->writeLine(formatString("* :doc:`%s </onlinehelp/%s>` - %s",
553 binaryName_.c_str(), binaryName_.c_str(),
554 RootHelpText::title));
557 outputRedirector_->openTextOutputFile("conf-man.py")));
558 manPagesFile_->writeLine("man_pages = [");
561 void HelpExportReStructuredText::exportModuleHelp(
562 const ICommandLineModule &module,
563 const std::string &tag,
564 const std::string &displayName)
566 TextOutputStreamPointer file
567 = outputRedirector_->openTextOutputFile("onlinehelp/" + tag + ".rst");
568 TextWriter writer(file);
569 writer.writeLine(formatString(".. _%s:", displayName.c_str()));
570 if (0 == displayName.compare(binaryName_ + " mdrun"))
572 // Make an extra link target for the convenience of
573 // MPI-specific documentation
574 writer.writeLine(".. _mdrun_mpi:");
578 CommandLineHelpContext context(file.get(), eHelpOutputFormat_Rst, &links_, binaryName_);
579 context.enterSubSection(displayName);
580 context.setModuleDisplayName(displayName);
581 module.writeHelp(context);
584 writer.writeLine(".. only:: man");
586 writer.writeLine(" See also");
587 writer.writeLine(" --------");
589 writer.writeLine(formatString(" :manpage:`%s(1)`", binaryName_.c_str()));
591 writer.writeLine(" More information about |Gromacs| is available at <http://www.gromacs.org/>.");
594 indexFile_->writeLine(formatString("* :doc:`%s </onlinehelp/%s>` - %s",
595 displayName.c_str(), tag.c_str(),
596 module.shortDescription()));
597 manPagesFile_->writeLine(
598 formatString(" ('onlinehelp/%s', '%s', \"%s\", '', 1),",
599 tag.c_str(), tag.c_str(), module.shortDescription()));
602 void HelpExportReStructuredText::finishModuleExport()
607 manPagesFile_->writeLine(
608 formatString(" ('onlinehelp/%s', '%s', '%s', '', 1)",
609 binaryName_.c_str(), binaryName_.c_str(),
610 RootHelpText::title));
611 manPagesFile_->writeLine("]");
612 manPagesFile_->close();
613 manPagesFile_.reset();
616 void HelpExportReStructuredText::startModuleGroupExport()
620 outputRedirector_->openTextOutputFile("fragments/bytopic.rst")));
623 outputRedirector_->openTextOutputFile("fragments/bytopic-man.rst")));
626 void HelpExportReStructuredText::exportModuleGroup(
628 const ModuleGroupContents &modules)
630 indexFile_->writeLine(title);
631 indexFile_->writeLine(std::string(std::strlen(title), '^'));
632 manPagesFile_->writeLine(title);
633 manPagesFile_->writeLine(std::string(std::strlen(title), '^'));
635 ModuleGroupContents::const_iterator module;
636 for (module = modules.begin(); module != modules.end(); ++module)
638 const std::string &tag(module->first);
639 std::string displayName(tag);
640 // TODO: This does not work if the binary name would contain a dash,
641 // but that is not currently the case.
642 const size_t dashPos = displayName.find('-');
643 GMX_RELEASE_ASSERT(dashPos != std::string::npos,
644 "There should always be at least one dash in the tag");
645 displayName[dashPos] = ' ';
646 indexFile_->writeLine(formatString(":doc:`%s </onlinehelp/%s>`\n %s",
647 displayName.c_str(), tag.c_str(),
649 manPagesFile_->writeLine(formatString(":manpage:`%s(1)`\n %s",
653 indexFile_->writeLine();
654 manPagesFile_->writeLine();
657 void HelpExportReStructuredText::finishModuleGroupExport()
661 manPagesFile_->close();
662 manPagesFile_.reset();
665 void HelpExportReStructuredText::exportTopic(const IHelpTopic &topic)
667 const std::string path("onlinehelp/" + std::string(topic.name()) + ".rst");
668 TextOutputStreamPointer file(outputRedirector_->openTextOutputFile(path));
669 CommandLineHelpContext context(file.get(), eHelpOutputFormat_Rst, &links_,
671 HelpManager manager(topic, context.writerContext());
672 manager.writeCurrentTopic();
676 /********************************************************************
677 * HelpExportCompletion
681 * Implements export for command-line completion.
683 * \ingroup module_commandline
685 class HelpExportCompletion : public IHelpExport
688 //! Initializes completion exporter.
689 explicit HelpExportCompletion(const CommandLineHelpModuleImpl &helpModule);
691 virtual void startModuleExport();
692 virtual void exportModuleHelp(
693 const ICommandLineModule &module,
694 const std::string &tag,
695 const std::string &displayName);
696 virtual void finishModuleExport();
698 virtual void startModuleGroupExport() {}
699 virtual void exportModuleGroup(const char * /*title*/,
700 const ModuleGroupContents & /*modules*/) {}
701 virtual void finishModuleGroupExport() {}
703 virtual void exportTopic(const IHelpTopic & /*topic*/) {}
706 ShellCompletionWriter bashWriter_;
707 std::vector<std::string> modules_;
710 HelpExportCompletion::HelpExportCompletion(
711 const CommandLineHelpModuleImpl &helpModule)
712 : bashWriter_(helpModule.binaryName_, eShellCompletionFormat_Bash)
716 void HelpExportCompletion::startModuleExport()
718 bashWriter_.startCompletions();
721 void HelpExportCompletion::exportModuleHelp(
722 const ICommandLineModule &module,
723 const std::string & /*tag*/,
724 const std::string & /*displayName*/)
726 modules_.push_back(module.name());
728 CommandLineHelpContext context(&bashWriter_);
729 // We use the display name to pass the name of the module to the
730 // completion writer.
731 context.setModuleDisplayName(module.name());
732 module.writeHelp(context);
736 void HelpExportCompletion::finishModuleExport()
738 CommandLineCommonOptionsHolder optionsHolder;
739 optionsHolder.initOptions();
740 bashWriter_.writeWrapperCompletions(modules_, *optionsHolder.options());
741 bashWriter_.finishCompletions();
746 /********************************************************************
747 * CommandLineHelpModuleImpl implementation
750 CommandLineHelpModuleImpl::CommandLineHelpModuleImpl(
751 const IProgramContext &programContext,
752 const std::string &binaryName,
753 const CommandLineModuleMap &modules,
754 const CommandLineModuleGroupList &groups)
755 : rootTopic_(new RootHelpTopic(*this)), programContext_(programContext),
756 binaryName_(binaryName), modules_(modules), groups_(groups),
757 context_(NULL), moduleOverride_(NULL), bHidden_(false),
758 outputRedirector_(&defaultFileOutputRedirector())
762 void CommandLineHelpModuleImpl::exportHelp(IHelpExport *exporter)
764 // TODO: Would be nicer to have the file names supplied by the build system
765 // and/or export a list of files from here.
766 const char *const program = binaryName_.c_str();
768 exporter->startModuleExport();
769 CommandLineModuleMap::const_iterator module;
770 for (module = modules_.begin(); module != modules_.end(); ++module)
772 if (module->second->shortDescription() != NULL)
774 const char *const moduleName = module->first.c_str();
775 std::string tag(formatString("%s-%s", program, moduleName));
776 std::string displayName(formatString("%s %s", program, moduleName));
777 exporter->exportModuleHelp(*module->second, tag, displayName);
780 exporter->finishModuleExport();
782 exporter->startModuleGroupExport();
783 CommandLineModuleGroupList::const_iterator group;
784 for (group = groups_.begin(); group != groups_.end(); ++group)
786 exporter->exportModuleGroup((*group)->title(), (*group)->modules());
788 exporter->finishModuleGroupExport();
790 rootTopic_->exportHelp(exporter);
796 /********************************************************************
797 * ModificationCheckingFileOutputStream
800 class ModificationCheckingFileOutputStream : public TextOutputStream
803 ModificationCheckingFileOutputStream(
805 IFileOutputRedirector *redirector)
806 : path_(path), redirector_(redirector)
810 virtual void write(const char *str) { contents_.write(str); }
813 const std::string &newContents = contents_.toString();
814 // TODO: Redirect these for unit tests.
815 if (File::exists(path_))
817 const std::string originalContents_
818 = TextReader::readFileToString(path_);
819 if (originalContents_ == newContents)
824 TextWriter writer(redirector_->openTextOutputFile(path_));
825 writer.writeString(newContents);
830 StringOutputStream contents_;
831 IFileOutputRedirector *redirector_;
834 /********************************************************************
835 * ModificationCheckingFileOutputRedirector
838 class ModificationCheckingFileOutputRedirector : public IFileOutputRedirector
841 explicit ModificationCheckingFileOutputRedirector(
842 IFileOutputRedirector *redirector)
843 : redirector_(redirector)
847 virtual TextOutputStream &standardOutput()
849 return redirector_->standardOutput();
851 virtual TextOutputStreamPointer openTextOutputFile(const char *filename)
853 return TextOutputStreamPointer(
854 new ModificationCheckingFileOutputStream(filename, redirector_));
858 IFileOutputRedirector *redirector_;
863 /********************************************************************
864 * CommandLineHelpModule
867 CommandLineHelpModule::CommandLineHelpModule(
868 const IProgramContext &programContext,
869 const std::string &binaryName,
870 const CommandLineModuleMap &modules,
871 const CommandLineModuleGroupList &groups)
872 : impl_(new Impl(programContext, binaryName, modules, groups))
876 CommandLineHelpModule::~CommandLineHelpModule()
880 HelpTopicPointer CommandLineHelpModule::createModuleHelpTopic(
881 const ICommandLineModule &module) const
883 return HelpTopicPointer(new ModuleHelpTopic(module, *impl_));
886 void CommandLineHelpModule::addTopic(HelpTopicPointer topic, bool bExported)
888 impl_->rootTopic_->addTopic(move(topic), bExported);
891 void CommandLineHelpModule::setShowHidden(bool bHidden)
893 impl_->bHidden_ = bHidden;
896 void CommandLineHelpModule::setModuleOverride(
897 const ICommandLineModule &module)
899 impl_->moduleOverride_ = &module;
902 void CommandLineHelpModule::setOutputRedirector(
903 IFileOutputRedirector *output)
905 impl_->outputRedirector_ = output;
908 int CommandLineHelpModule::run(int argc, char *argv[])
910 // Add internal topics lazily here.
911 addTopic(HelpTopicPointer(new CommandsHelpTopic(*impl_)), false);
913 const char *const exportFormats[] = { "rst", "completion" };
914 std::string exportFormat;
915 Options options(NULL, NULL);
916 options.addOption(StringOption("export").store(&exportFormat)
917 .enumValue(exportFormats));
918 CommandLineParser(&options).parse(&argc, argv);
919 if (!exportFormat.empty())
921 ModificationCheckingFileOutputRedirector redirector(impl_->outputRedirector_);
922 boost::scoped_ptr<IHelpExport> exporter;
923 if (exportFormat == "rst")
925 exporter.reset(new HelpExportReStructuredText(*impl_, &redirector));
927 else if (exportFormat == "completion")
929 exporter.reset(new HelpExportCompletion(*impl_));
933 GMX_THROW(NotImplementedError("This help format is not implemented"));
935 impl_->exportHelp(exporter.get());
939 TextOutputStream &outputFile = impl_->outputRedirector_->standardOutput();
940 HelpLinks links(eHelpOutputFormat_Console);
941 initProgramLinks(&links, *impl_);
942 CommandLineHelpContext context(&outputFile, eHelpOutputFormat_Console, &links,
944 context.setShowHidden(impl_->bHidden_);
945 if (impl_->moduleOverride_ != NULL)
947 context.setModuleDisplayName(impl_->programContext_.displayName());
948 impl_->moduleOverride_->writeHelp(context);
951 impl_->context_ = &context;
953 HelpManager helpManager(*impl_->rootTopic_, context.writerContext());
956 for (int i = 1; i < argc; ++i)
958 helpManager.enterTopic(argv[i]);
961 catch (const InvalidInputError &ex)
963 fprintf(stderr, "%s\n", ex.what());
966 helpManager.writeCurrentTopic();
970 void CommandLineHelpModule::writeHelp(const CommandLineHelpContext &context) const
972 const HelpWriterContext &writerContext = context.writerContext();
974 if (writerContext.outputFormat() != eHelpOutputFormat_Console)
978 writerContext.writeTextBlock(
979 "Usage: [PROGRAM] help [<command>|<topic> [<subtopic> [...]]]");
980 // TODO: More information.