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"
80 class HelpExportInterface;
84 /********************************************************************
85 * CommandLineHelpModuleImpl declaration
88 class CommandLineHelpModuleImpl
91 CommandLineHelpModuleImpl(const ProgramContextInterface &programContext,
92 const std::string &binaryName,
93 const CommandLineModuleMap &modules,
94 const CommandLineModuleGroupList &groups);
96 void exportHelp(HelpExportInterface *exporter);
98 boost::scoped_ptr<RootHelpTopic> rootTopic_;
99 const ProgramContextInterface &programContext_;
100 std::string binaryName_;
101 const CommandLineModuleMap &modules_;
102 const CommandLineModuleGroupList &groups_;
104 CommandLineHelpContext *context_;
105 const CommandLineModuleInterface *moduleOverride_;
108 FileOutputRedirectorInterface *outputRedirector_;
110 GMX_DISALLOW_COPY_AND_ASSIGN(CommandLineHelpModuleImpl);
116 /********************************************************************
117 * HelpExportInterface
121 * Callbacks for exporting help information for command-line modules.
123 * \ingroup module_commandline
125 class HelpExportInterface
128 //! Shorthand for a list of modules contained in a group.
129 typedef CommandLineModuleGroupData::ModuleList ModuleGroupContents;
131 virtual ~HelpExportInterface() {};
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 CommandLineModuleInterface &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 HelpTopicInterface &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(HelpExportInterface *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(HelpExportInterface *exporter)
261 std::vector<std::string>::const_iterator topicName;
262 for (topicName = exportedTopics_.begin();
263 topicName != exportedTopics_.end();
266 const HelpTopicInterface *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 options.setDescription(RootHelpText::text);
294 // TODO: Add <command> [<args>] into the synopsis.
295 CommandLineHelpWriter(options)
296 .setShowDescriptions(context.outputFormat() != eHelpOutputFormat_Console)
297 .writeHelp(*cmdlineContext);
299 if (context.outputFormat() == eHelpOutputFormat_Console)
301 // TODO: Consider printing a list of "core" commands. Would require someone
302 // to determine such a set...
303 writeSubTopicList(context,
304 "Additional help is available on the following topics:");
305 context.writeTextBlock("To access the help, use '[PROGRAM] help <topic>'.");
306 context.writeTextBlock("For help on a command, use '[PROGRAM] help <command>'.");
310 // TODO: This should not really end up on the HTML page.
311 context.writeTitle(formatString("%s commands", helpModule_.binaryName_.c_str()));
312 context.writeTextBlock(
313 "The following commands are available. Please refer to their "
314 "individual man pages or [TT][PROGRAM] help <command>[tt] "
315 "for further details.");
316 context.writeTextBlock("");
317 context.writeTextBlock(".. include:: /fragments/bytopic-man.rst");
321 /********************************************************************
326 * Help topic for listing the commands.
328 * \ingroup module_commandline
330 class CommandsHelpTopic : public HelpTopicInterface
334 * Creates a command list help topic.
336 * \param[in] helpModule Help module to get module information from.
340 explicit CommandsHelpTopic(const CommandLineHelpModuleImpl &helpModule)
341 : helpModule_(helpModule)
345 virtual const char *name() const { return "commands"; }
346 virtual const char *title() const { return "List of available commands"; }
347 virtual bool hasSubTopics() const { return false; }
348 virtual const HelpTopicInterface *findSubTopic(const char * /*name*/) const
353 virtual void writeHelp(const HelpWriterContext &context) const;
356 const CommandLineHelpModuleImpl &helpModule_;
358 GMX_DISALLOW_COPY_AND_ASSIGN(CommandsHelpTopic);
361 void CommandsHelpTopic::writeHelp(const HelpWriterContext &context) const
363 if (context.outputFormat() != eHelpOutputFormat_Console)
365 GMX_THROW(NotImplementedError(
366 "Module list is not implemented for this output format"));
368 int maxNameLength = 0;
369 const CommandLineModuleMap &modules = helpModule_.modules_;
370 CommandLineModuleMap::const_iterator module;
371 for (module = modules.begin(); module != modules.end(); ++module)
373 int nameLength = static_cast<int>(module->first.length());
374 if (module->second->shortDescription() != NULL
375 && nameLength > maxNameLength)
377 maxNameLength = nameLength;
380 context.writeTextBlock(
381 "Usage: [PROGRAM] [<options>] <command> [<args>][PAR]"
382 "Available commands:");
383 TextWriter &file = context.outputFile();
384 TextTableFormatter formatter;
385 formatter.addColumn(NULL, maxNameLength + 1, false);
386 formatter.addColumn(NULL, 72 - maxNameLength, true);
387 formatter.setFirstColumnIndent(4);
388 for (module = modules.begin(); module != modules.end(); ++module)
390 const char *name = module->first.c_str();
391 const char *description = module->second->shortDescription();
392 if (description != NULL)
395 formatter.addColumnLine(0, name);
396 formatter.addColumnLine(1, description);
397 file.writeString(formatter.formatRow());
400 context.writeTextBlock(
401 "For help on a command, use '[PROGRAM] help <command>'.");
404 /********************************************************************
409 * Help topic wrapper for a command-line module.
411 * This class implements HelpTopicInterface such that it wraps a
412 * CommandLineModuleInterface, allowing subcommand "help <command>"
413 * to produce the help for "<command>".
415 * \ingroup module_commandline
417 class ModuleHelpTopic : public HelpTopicInterface
420 //! Constructs a help topic for a specific module.
421 ModuleHelpTopic(const CommandLineModuleInterface &module,
422 const CommandLineHelpModuleImpl &helpModule)
423 : module_(module), helpModule_(helpModule)
427 virtual const char *name() const { return module_.name(); }
428 virtual const char *title() const { return NULL; }
429 virtual bool hasSubTopics() const { return false; }
430 virtual const HelpTopicInterface *findSubTopic(const char * /*name*/) const
434 virtual void writeHelp(const HelpWriterContext &context) const;
437 const CommandLineModuleInterface &module_;
438 const CommandLineHelpModuleImpl &helpModule_;
440 GMX_DISALLOW_COPY_AND_ASSIGN(ModuleHelpTopic);
443 void ModuleHelpTopic::writeHelp(const HelpWriterContext & /*context*/) const
445 CommandLineHelpContext context(*helpModule_.context_);
446 const char *const program = helpModule_.binaryName_.c_str();
447 context.setModuleDisplayName(formatString("%s %s", program, module_.name()));
448 module_.writeHelp(context);
451 /********************************************************************
452 * HelpExportReStructuredText
456 * Adds hyperlinks to modules within this binary.
458 * \param[in,out] links Links are added here.
459 * \param[in] helpModule Help module to get module information from.
460 * \throws std::bad_alloc if out of memory.
462 * Initializes a HelpLinks object with links to modules defined in
465 * \ingroup module_commandline
467 void initProgramLinks(HelpLinks *links, const CommandLineHelpModuleImpl &helpModule)
469 const char *const program = helpModule.binaryName_.c_str();
470 CommandLineModuleMap::const_iterator module;
471 for (module = helpModule.modules_.begin();
472 module != helpModule.modules_.end();
475 if (module->second->shortDescription() != NULL)
477 std::string linkName("[gmx-" + module->first + "]");
478 const char *name = module->first.c_str();
479 std::string reference(
480 formatString(":doc:`%s %s <%s-%s>`", program, name, program, name));
481 std::string displayName(
482 formatString("[TT]%s %s[tt]", program, name));
483 links->addLink(linkName, reference, displayName);
489 * Implements export for web pages as reStructuredText.
491 * \ingroup module_commandline
493 class HelpExportReStructuredText : public HelpExportInterface
496 //! Initializes reST exporter.
497 HelpExportReStructuredText(
498 const CommandLineHelpModuleImpl &helpModule,
499 FileOutputRedirectorInterface *outputRedirector);
501 virtual void startModuleExport();
502 virtual void exportModuleHelp(
503 const CommandLineModuleInterface &module,
504 const std::string &tag,
505 const std::string &displayName);
506 virtual void finishModuleExport();
508 virtual void startModuleGroupExport();
509 virtual void exportModuleGroup(const char *title,
510 const ModuleGroupContents &modules);
511 virtual void finishModuleGroupExport();
513 virtual void exportTopic(const HelpTopicInterface &topic);
516 FileOutputRedirectorInterface *outputRedirector_;
517 const std::string &binaryName_;
519 boost::scoped_ptr<TextWriter> indexFile_;
520 boost::scoped_ptr<TextWriter> manPagesFile_;
523 HelpExportReStructuredText::HelpExportReStructuredText(
524 const CommandLineHelpModuleImpl &helpModule,
525 FileOutputRedirectorInterface *outputRedirector)
526 : outputRedirector_(outputRedirector),
527 binaryName_(helpModule.binaryName_),
528 links_(eHelpOutputFormat_Rst)
530 TextReader linksFile("links.dat");
532 while (linksFile.readLineTrimmed(&line))
534 links_.addLink("[REF]." + line + "[ref]",
535 formatString(":ref:`.%s <%s>`", line.c_str(), line.c_str()),
537 links_.addLink("[REF]" + line + "[ref]", formatString(":ref:`%s`", line.c_str()), line);
540 initProgramLinks(&links_, helpModule);
543 void HelpExportReStructuredText::startModuleExport()
547 outputRedirector_->openTextOutputFile("fragments/byname.rst")));
548 indexFile_->writeLine(formatString("* :doc:`%s </onlinehelp/%s>` - %s",
549 binaryName_.c_str(), binaryName_.c_str(),
550 RootHelpText::title));
553 outputRedirector_->openTextOutputFile("conf-man.py")));
554 manPagesFile_->writeLine("man_pages = [");
557 void HelpExportReStructuredText::exportModuleHelp(
558 const CommandLineModuleInterface &module,
559 const std::string &tag,
560 const std::string &displayName)
562 TextOutputStreamPointer file
563 = outputRedirector_->openTextOutputFile("onlinehelp/" + tag + ".rst");
564 TextWriter writer(file);
565 writer.writeLine(formatString(".. _%s:", displayName.c_str()));
566 if (0 == displayName.compare(binaryName_ + " mdrun"))
568 // Make an extra link target for the convenience of
569 // MPI-specific documentation
570 writer.writeLine(".. _mdrun_mpi:");
574 CommandLineHelpContext context(file.get(), eHelpOutputFormat_Rst, &links_, binaryName_);
575 context.enterSubSection(displayName);
576 context.setModuleDisplayName(displayName);
577 module.writeHelp(context);
580 writer.writeLine(".. only:: man");
582 writer.writeLine(" See also");
583 writer.writeLine(" --------");
585 writer.writeLine(formatString(" :manpage:`%s(1)`", binaryName_.c_str()));
587 writer.writeLine(" More information about |Gromacs| is available at <http://www.gromacs.org/>.");
590 indexFile_->writeLine(formatString("* :doc:`%s </onlinehelp/%s>` - %s",
591 displayName.c_str(), tag.c_str(),
592 module.shortDescription()));
593 manPagesFile_->writeLine(
594 formatString(" ('onlinehelp/%s', '%s', \"%s\", '', 1),",
595 tag.c_str(), tag.c_str(), module.shortDescription()));
598 void HelpExportReStructuredText::finishModuleExport()
603 manPagesFile_->writeLine(
604 formatString(" ('onlinehelp/%s', '%s', '%s', '', 1)",
605 binaryName_.c_str(), binaryName_.c_str(),
606 RootHelpText::title));
607 manPagesFile_->writeLine("]");
608 manPagesFile_->close();
609 manPagesFile_.reset();
612 void HelpExportReStructuredText::startModuleGroupExport()
616 outputRedirector_->openTextOutputFile("fragments/bytopic.rst")));
619 outputRedirector_->openTextOutputFile("fragments/bytopic-man.rst")));
622 void HelpExportReStructuredText::exportModuleGroup(
624 const ModuleGroupContents &modules)
626 indexFile_->writeLine(title);
627 indexFile_->writeLine(std::string(std::strlen(title), '^'));
628 manPagesFile_->writeLine(title);
629 manPagesFile_->writeLine(std::string(std::strlen(title), '^'));
631 ModuleGroupContents::const_iterator module;
632 for (module = modules.begin(); module != modules.end(); ++module)
634 const std::string &tag(module->first);
635 std::string displayName(tag);
636 // TODO: This does not work if the binary name would contain a dash,
637 // but that is not currently the case.
638 const size_t dashPos = displayName.find('-');
639 GMX_RELEASE_ASSERT(dashPos != std::string::npos,
640 "There should always be at least one dash in the tag");
641 displayName[dashPos] = ' ';
642 indexFile_->writeLine(formatString(":doc:`%s </onlinehelp/%s>`\n %s",
643 displayName.c_str(), tag.c_str(),
645 manPagesFile_->writeLine(formatString(":manpage:`%s(1)`\n %s",
649 indexFile_->writeLine();
650 manPagesFile_->writeLine();
653 void HelpExportReStructuredText::finishModuleGroupExport()
657 manPagesFile_->close();
658 manPagesFile_.reset();
661 void HelpExportReStructuredText::exportTopic(const HelpTopicInterface &topic)
663 const std::string path("onlinehelp/" + std::string(topic.name()) + ".rst");
664 TextOutputStreamPointer file(outputRedirector_->openTextOutputFile(path));
665 CommandLineHelpContext context(file.get(), eHelpOutputFormat_Rst, &links_,
667 HelpManager manager(topic, context.writerContext());
668 manager.writeCurrentTopic();
672 /********************************************************************
673 * HelpExportCompletion
677 * Implements export for command-line completion.
679 * \ingroup module_commandline
681 class HelpExportCompletion : public HelpExportInterface
684 //! Initializes completion exporter.
685 explicit HelpExportCompletion(const CommandLineHelpModuleImpl &helpModule);
687 virtual void startModuleExport();
688 virtual void exportModuleHelp(
689 const CommandLineModuleInterface &module,
690 const std::string &tag,
691 const std::string &displayName);
692 virtual void finishModuleExport();
694 virtual void startModuleGroupExport() {}
695 virtual void exportModuleGroup(const char * /*title*/,
696 const ModuleGroupContents & /*modules*/) {}
697 virtual void finishModuleGroupExport() {}
699 virtual void exportTopic(const HelpTopicInterface & /*topic*/) {}
702 ShellCompletionWriter bashWriter_;
703 std::vector<std::string> modules_;
706 HelpExportCompletion::HelpExportCompletion(
707 const CommandLineHelpModuleImpl &helpModule)
708 : bashWriter_(helpModule.binaryName_, eShellCompletionFormat_Bash)
712 void HelpExportCompletion::startModuleExport()
714 bashWriter_.startCompletions();
717 void HelpExportCompletion::exportModuleHelp(
718 const CommandLineModuleInterface &module,
719 const std::string & /*tag*/,
720 const std::string & /*displayName*/)
722 modules_.push_back(module.name());
724 CommandLineHelpContext context(&bashWriter_);
725 // We use the display name to pass the name of the module to the
726 // completion writer.
727 context.setModuleDisplayName(module.name());
728 module.writeHelp(context);
732 void HelpExportCompletion::finishModuleExport()
734 CommandLineCommonOptionsHolder optionsHolder;
735 optionsHolder.initOptions();
736 bashWriter_.writeWrapperCompletions(modules_, *optionsHolder.options());
737 bashWriter_.finishCompletions();
742 /********************************************************************
743 * CommandLineHelpModuleImpl implementation
746 CommandLineHelpModuleImpl::CommandLineHelpModuleImpl(
747 const ProgramContextInterface &programContext,
748 const std::string &binaryName,
749 const CommandLineModuleMap &modules,
750 const CommandLineModuleGroupList &groups)
751 : rootTopic_(new RootHelpTopic(*this)), programContext_(programContext),
752 binaryName_(binaryName), modules_(modules), groups_(groups),
753 context_(NULL), moduleOverride_(NULL), bHidden_(false),
754 outputRedirector_(&defaultFileOutputRedirector())
758 void CommandLineHelpModuleImpl::exportHelp(HelpExportInterface *exporter)
760 // TODO: Would be nicer to have the file names supplied by the build system
761 // and/or export a list of files from here.
762 const char *const program = binaryName_.c_str();
764 exporter->startModuleExport();
765 CommandLineModuleMap::const_iterator module;
766 for (module = modules_.begin(); module != modules_.end(); ++module)
768 if (module->second->shortDescription() != NULL)
770 const char *const moduleName = module->first.c_str();
771 std::string tag(formatString("%s-%s", program, moduleName));
772 std::string displayName(formatString("%s %s", program, moduleName));
773 exporter->exportModuleHelp(*module->second, tag, displayName);
776 exporter->finishModuleExport();
778 exporter->startModuleGroupExport();
779 CommandLineModuleGroupList::const_iterator group;
780 for (group = groups_.begin(); group != groups_.end(); ++group)
782 exporter->exportModuleGroup((*group)->title(), (*group)->modules());
784 exporter->finishModuleGroupExport();
786 rootTopic_->exportHelp(exporter);
792 /********************************************************************
793 * ModificationCheckingFileOutputStream
796 class ModificationCheckingFileOutputStream : public TextOutputStream
799 ModificationCheckingFileOutputStream(
801 FileOutputRedirectorInterface *redirector)
802 : path_(path), redirector_(redirector)
806 virtual void write(const char *str) { contents_.write(str); }
809 const std::string &newContents = contents_.toString();
810 // TODO: Redirect these for unit tests.
811 if (File::exists(path_))
813 const std::string originalContents_
814 = TextReader::readFileToString(path_);
815 if (originalContents_ == newContents)
820 TextWriter writer(redirector_->openTextOutputFile(path_));
821 writer.writeString(newContents);
826 StringOutputStream contents_;
827 FileOutputRedirectorInterface *redirector_;
830 /********************************************************************
831 * ModificationCheckingFileOutputRedirector
834 class ModificationCheckingFileOutputRedirector : public FileOutputRedirectorInterface
837 explicit ModificationCheckingFileOutputRedirector(
838 FileOutputRedirectorInterface *redirector)
839 : redirector_(redirector)
843 virtual TextOutputStream &standardOutput()
845 return redirector_->standardOutput();
847 virtual TextOutputStreamPointer openTextOutputFile(const char *filename)
849 return TextOutputStreamPointer(
850 new ModificationCheckingFileOutputStream(filename, redirector_));
854 FileOutputRedirectorInterface *redirector_;
859 /********************************************************************
860 * CommandLineHelpModule
863 CommandLineHelpModule::CommandLineHelpModule(
864 const ProgramContextInterface &programContext,
865 const std::string &binaryName,
866 const CommandLineModuleMap &modules,
867 const CommandLineModuleGroupList &groups)
868 : impl_(new Impl(programContext, binaryName, modules, groups))
872 CommandLineHelpModule::~CommandLineHelpModule()
876 HelpTopicPointer CommandLineHelpModule::createModuleHelpTopic(
877 const CommandLineModuleInterface &module) const
879 return HelpTopicPointer(new ModuleHelpTopic(module, *impl_));
882 void CommandLineHelpModule::addTopic(HelpTopicPointer topic, bool bExported)
884 impl_->rootTopic_->addTopic(move(topic), bExported);
887 void CommandLineHelpModule::setShowHidden(bool bHidden)
889 impl_->bHidden_ = bHidden;
892 void CommandLineHelpModule::setModuleOverride(
893 const CommandLineModuleInterface &module)
895 impl_->moduleOverride_ = &module;
898 void CommandLineHelpModule::setOutputRedirector(
899 FileOutputRedirectorInterface *output)
901 impl_->outputRedirector_ = output;
904 int CommandLineHelpModule::run(int argc, char *argv[])
906 // Add internal topics lazily here.
907 addTopic(HelpTopicPointer(new CommandsHelpTopic(*impl_)), false);
909 const char *const exportFormats[] = { "rst", "completion" };
910 std::string exportFormat;
911 Options options(NULL, NULL);
912 options.addOption(StringOption("export").store(&exportFormat)
913 .enumValue(exportFormats));
914 CommandLineParser(&options).parse(&argc, argv);
915 if (!exportFormat.empty())
917 ModificationCheckingFileOutputRedirector redirector(impl_->outputRedirector_);
918 boost::scoped_ptr<HelpExportInterface> exporter;
919 if (exportFormat == "rst")
921 exporter.reset(new HelpExportReStructuredText(*impl_, &redirector));
923 else if (exportFormat == "completion")
925 exporter.reset(new HelpExportCompletion(*impl_));
929 GMX_THROW(NotImplementedError("This help format is not implemented"));
931 impl_->exportHelp(exporter.get());
935 TextOutputStream &outputFile = impl_->outputRedirector_->standardOutput();
936 HelpLinks links(eHelpOutputFormat_Console);
937 initProgramLinks(&links, *impl_);
938 CommandLineHelpContext context(&outputFile, eHelpOutputFormat_Console, &links,
940 context.setShowHidden(impl_->bHidden_);
941 if (impl_->moduleOverride_ != NULL)
943 context.setModuleDisplayName(impl_->programContext_.displayName());
944 impl_->moduleOverride_->writeHelp(context);
947 impl_->context_ = &context;
949 HelpManager helpManager(*impl_->rootTopic_, context.writerContext());
952 for (int i = 1; i < argc; ++i)
954 helpManager.enterTopic(argv[i]);
957 catch (const InvalidInputError &ex)
959 fprintf(stderr, "%s\n", ex.what());
962 helpManager.writeCurrentTopic();
966 void CommandLineHelpModule::writeHelp(const CommandLineHelpContext &context) const
968 const HelpWriterContext &writerContext = context.writerContext();
970 if (writerContext.outputFormat() != eHelpOutputFormat_Console)
974 writerContext.writeTextBlock(
975 "Usage: [PROGRAM] help [<command>|<topic> [<subtopic> [...]]]");
976 // TODO: More information.