51241de071d09c1b05b6ddc8c7625a3b99e797da
[alexxy/gromacs.git] / src / gromacs / commandline / cmdlinehelpmodule.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 /*! \internal \file
36  * \brief
37  * Implements gmx::CommandLineHelpModule.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_commandline
41  */
42 #include "gmxpre.h"
43
44 #include "cmdlinehelpmodule.h"
45
46 #include <string>
47 #include <vector>
48
49 #include <boost/scoped_ptr.hpp>
50
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/baseversion.h"
61 #include "gromacs/utility/exceptions.h"
62 #include "gromacs/utility/file.h"
63 #include "gromacs/utility/gmxassert.h"
64 #include "gromacs/utility/programcontext.h"
65 #include "gromacs/utility/stringutil.h"
66
67 #include "shellcompletions.h"
68
69 namespace gmx
70 {
71
72 namespace
73 {
74 class HelpExportInterface;
75 class RootHelpTopic;
76 }   // namespace
77
78 /********************************************************************
79  * CommandLineHelpModuleImpl declaration
80  */
81
82 class CommandLineHelpModuleImpl
83 {
84     public:
85         CommandLineHelpModuleImpl(const ProgramContextInterface    &programContext,
86                                   const std::string                &binaryName,
87                                   const CommandLineModuleMap       &modules,
88                                   const CommandLineModuleGroupList &groups);
89
90         void exportHelp(HelpExportInterface *exporter) const;
91
92         boost::scoped_ptr<RootHelpTopic>  rootTopic_;
93         const ProgramContextInterface    &programContext_;
94         std::string                       binaryName_;
95         const CommandLineModuleMap       &modules_;
96         const CommandLineModuleGroupList &groups_;
97
98         CommandLineHelpContext           *context_;
99         const CommandLineModuleInterface *moduleOverride_;
100         bool                              bHidden_;
101
102         File                             *outputOverride_;
103
104         GMX_DISALLOW_COPY_AND_ASSIGN(CommandLineHelpModuleImpl);
105 };
106
107 namespace
108 {
109
110 /********************************************************************
111  * RootHelpTopic
112  */
113
114 struct RootHelpText
115 {
116     static const char        name[];
117     static const char        title[];
118     static const char *const text[];
119 };
120
121 // The first two are not used.
122 const char        RootHelpText::name[]  = "";
123 const char        RootHelpText::title[] = "";
124 const char *const RootHelpText::text[]  = { "" };
125
126 /*! \brief
127  * Help topic that forms the root of the help tree for the help subcommand.
128  *
129  * \ingroup module_commandline
130  */
131 class RootHelpTopic : public CompositeHelpTopic<RootHelpText>
132 {
133     public:
134         /*! \brief
135          * Creates a root help topic.
136          *
137          * Does not throw.
138          */
139         explicit RootHelpTopic(const CommandLineHelpModuleImpl &helpModule)
140             : helpModule_(helpModule)
141         {
142         }
143
144         virtual void writeHelp(const HelpWriterContext &context) const;
145
146     private:
147         const CommandLineHelpModuleImpl  &helpModule_;
148
149         GMX_DISALLOW_COPY_AND_ASSIGN(RootHelpTopic);
150 };
151
152 void RootHelpTopic::writeHelp(const HelpWriterContext &context) const
153 {
154     if (context.outputFormat() != eHelpOutputFormat_Console)
155     {
156         // TODO: Implement once the situation with Redmine issue #969 is more
157         // clear.
158         GMX_THROW(NotImplementedError(
159                           "Root help is not implemented for this output format"));
160     }
161     {
162         CommandLineCommonOptionsHolder optionsHolder;
163         CommandLineHelpContext         cmdlineContext(*helpModule_.context_);
164         cmdlineContext.setModuleDisplayName(helpModule_.binaryName_);
165         optionsHolder.initOptions();
166         // TODO: Add <command> [<args>] into the synopsis.
167         CommandLineHelpWriter(*optionsHolder.options())
168             .writeHelp(cmdlineContext);
169     }
170     // TODO: Consider printing a list of "core" commands. Would require someone
171     // to determine such a set...
172     writeSubTopicList(context,
173                       "Additional help is available on the following topics:");
174     context.writeTextBlock("To access the help, use '[PROGRAM] help <topic>'.");
175     context.writeTextBlock("For help on a command, use '[PROGRAM] help <command>'.");
176 }
177
178 /********************************************************************
179  * CommandsHelpTopic
180  */
181
182 /*! \brief
183  * Help topic for listing the commands.
184  *
185  * \ingroup module_commandline
186  */
187 class CommandsHelpTopic : public HelpTopicInterface
188 {
189     public:
190         /*! \brief
191          * Creates a command list help topic.
192          *
193          * \param[in]     helpModule Help module to get module information from.
194          *
195          * Does not throw.
196          */
197         explicit CommandsHelpTopic(const CommandLineHelpModuleImpl &helpModule)
198             : helpModule_(helpModule)
199         {
200         }
201
202         virtual const char *name() const { return "commands"; }
203         virtual const char *title() const { return "List of available commands"; }
204         virtual bool hasSubTopics() const { return false; }
205         virtual const HelpTopicInterface *findSubTopic(const char * /*name*/) const
206         {
207             return NULL;
208         }
209
210         virtual void writeHelp(const HelpWriterContext &context) const;
211
212     private:
213         const CommandLineHelpModuleImpl &helpModule_;
214
215         GMX_DISALLOW_COPY_AND_ASSIGN(CommandsHelpTopic);
216 };
217
218 void CommandsHelpTopic::writeHelp(const HelpWriterContext &context) const
219 {
220     if (context.outputFormat() != eHelpOutputFormat_Console)
221     {
222         GMX_THROW(NotImplementedError(
223                           "Module list is not implemented for this output format"));
224     }
225     int maxNameLength = 0;
226     const CommandLineModuleMap           &modules = helpModule_.modules_;
227     CommandLineModuleMap::const_iterator  module;
228     for (module = modules.begin(); module != modules.end(); ++module)
229     {
230         int nameLength = static_cast<int>(module->first.length());
231         if (module->second->shortDescription() != NULL
232             && nameLength > maxNameLength)
233         {
234             maxNameLength = nameLength;
235         }
236     }
237     context.writeTextBlock(
238             "Usage: [PROGRAM] [<options>] <command> [<args>][PAR]"
239             "Available commands:");
240     File              &file = context.outputFile();
241     TextTableFormatter formatter;
242     formatter.addColumn(NULL, maxNameLength + 1, false);
243     formatter.addColumn(NULL, 72 - maxNameLength, true);
244     formatter.setFirstColumnIndent(4);
245     for (module = modules.begin(); module != modules.end(); ++module)
246     {
247         const char *name        = module->first.c_str();
248         const char *description = module->second->shortDescription();
249         if (description != NULL)
250         {
251             formatter.clear();
252             formatter.addColumnLine(0, name);
253             formatter.addColumnLine(1, description);
254             file.writeString(formatter.formatRow());
255         }
256     }
257     context.writeTextBlock(
258             "For help on a command, use '[PROGRAM] help <command>'.");
259 }
260
261 /********************************************************************
262  * ModuleHelpTopic
263  */
264
265 /*! \brief
266  * Help topic wrapper for a command-line module.
267  *
268  * This class implements HelpTopicInterface such that it wraps a
269  * CommandLineModuleInterface, allowing subcommand "help <command>"
270  * to produce the help for "<command>".
271  *
272  * \ingroup module_commandline
273  */
274 class ModuleHelpTopic : public HelpTopicInterface
275 {
276     public:
277         //! Constructs a help topic for a specific module.
278         ModuleHelpTopic(const CommandLineModuleInterface &module,
279                         const CommandLineHelpModuleImpl  &helpModule)
280             : module_(module), helpModule_(helpModule)
281         {
282         }
283
284         virtual const char *name() const { return module_.name(); }
285         virtual const char *title() const { return NULL; }
286         virtual bool hasSubTopics() const { return false; }
287         virtual const HelpTopicInterface *findSubTopic(const char * /*name*/) const
288         {
289             return NULL;
290         }
291         virtual void writeHelp(const HelpWriterContext &context) const;
292
293     private:
294         const CommandLineModuleInterface &module_;
295         const CommandLineHelpModuleImpl  &helpModule_;
296
297         GMX_DISALLOW_COPY_AND_ASSIGN(ModuleHelpTopic);
298 };
299
300 void ModuleHelpTopic::writeHelp(const HelpWriterContext & /*context*/) const
301 {
302     CommandLineHelpContext context(*helpModule_.context_);
303     const char *const      program = helpModule_.binaryName_.c_str();
304     context.setModuleDisplayName(formatString("%s %s", program, module_.name()));
305     module_.writeHelp(context);
306 }
307
308 /********************************************************************
309  * HelpExportInterface
310  */
311
312 /*! \brief
313  * Callbacks for exporting help information for command-line modules.
314  *
315  * \ingroup module_commandline
316  */
317 class HelpExportInterface
318 {
319     public:
320         //! Shorthand for a list of modules contained in a group.
321         typedef CommandLineModuleGroupData::ModuleList ModuleGroupContents;
322
323         virtual ~HelpExportInterface() {};
324
325         /*! \brief
326          * Called once before exporting individual modules.
327          *
328          * Can, e.g., open shared output files (e.g., if the output is written
329          * into a single file, or if a separate index is required) and write
330          * headers into them.
331          */
332         virtual void startModuleExport() = 0;
333         /*! \brief
334          * Called to export the help for each module.
335          *
336          * \param[in] module      Module for which the help should be exported.
337          * \param[in] tag         Unique tag for the module (gmx-something).
338          * \param[in] displayName Display name for the module (gmx something).
339          */
340         virtual void exportModuleHelp(
341             const CommandLineModuleInterface &module,
342             const std::string                &tag,
343             const std::string                &displayName) = 0;
344         /*! \brief
345          * Called after all modules have been exported.
346          *
347          * Can close files opened in startModuleExport(), write footers to them
348          * etc.
349          */
350         virtual void finishModuleExport() = 0;
351
352         /*! \brief
353          * Called once before exporting module groups.
354          *
355          * Can, e.g., open a single output file for listing all the groups.
356          */
357         virtual void startModuleGroupExport() = 0;
358         /*! \brief
359          * Called to export the help for each module group.
360          *
361          * \param[in] title    Title for the group.
362          * \param[in] modules  List of modules in the group.
363          */
364         virtual void exportModuleGroup(const char                *title,
365                                        const ModuleGroupContents &modules) = 0;
366         /*! \brief
367          * Called after all module groups have been exported.
368          *
369          * Can close files opened in startModuleGroupExport(), write footers to them
370          * etc.
371          */
372         virtual void finishModuleGroupExport() = 0;
373 };
374
375 /*! \internal \brief
376  * Adds hyperlinks to modules within this binary.
377  *
378  * \param[in,out] links      Links are added here.
379  * \param[in]     helpModule Help module to get module information from.
380  * \throws        std::bad_alloc if out of memory.
381  *
382  * Initializes a HelpLinks object with links to modules defined in
383  * \p helpModule.
384  *
385  * \ingroup module_commandline
386  */
387 void initProgramLinks(HelpLinks *links, const CommandLineHelpModuleImpl &helpModule)
388 {
389     const char *const                    program = helpModule.binaryName_.c_str();
390     CommandLineModuleMap::const_iterator module;
391     for (module = helpModule.modules_.begin();
392          module != helpModule.modules_.end();
393          ++module)
394     {
395         if (module->second->shortDescription() != NULL)
396         {
397             std::string linkName("[gmx-" + module->first + "]");
398             const char *name = module->first.c_str();
399             std::string reference(
400                     formatString(":doc:`%s %s <%s-%s>`", program, name, program, name));
401             std::string displayName(
402                     formatString("[TT]%s %s[tt]", program, name));
403             links->addLink(linkName, reference, displayName);
404         }
405     }
406 }
407
408 /********************************************************************
409  * HelpExportReStructuredText
410  */
411
412 /*! \internal \brief
413  * Implements export for web pages as reStructuredText.
414  *
415  * \ingroup module_commandline
416  */
417 class HelpExportReStructuredText : public HelpExportInterface
418 {
419     public:
420         //! Initializes reST exporter.
421         explicit HelpExportReStructuredText(
422             const CommandLineHelpModuleImpl &helpModule);
423
424         virtual void startModuleExport();
425         virtual void exportModuleHelp(
426             const CommandLineModuleInterface &module,
427             const std::string                &tag,
428             const std::string                &displayName);
429         virtual void finishModuleExport();
430
431         virtual void startModuleGroupExport();
432         virtual void exportModuleGroup(const char                *title,
433                                        const ModuleGroupContents &modules);
434         virtual void finishModuleGroupExport();
435
436     private:
437         HelpLinks                links_;
438         boost::scoped_ptr<File>  indexFile_;
439         boost::scoped_ptr<File>  manPagesFile_;
440 };
441
442 HelpExportReStructuredText::HelpExportReStructuredText(
443         const CommandLineHelpModuleImpl &helpModule)
444     : links_(eHelpOutputFormat_Rst)
445 {
446     File             linksFile("links.dat", "r");
447     std::string      line;
448     while (linksFile.readLine(&line))
449     {
450         links_.addLink("[REF]." + line + "[ref]",
451                        formatString(":ref:`.%s <%s>`", line.c_str(), line.c_str()),
452                        line);
453         links_.addLink("[REF]" + line + "[ref]", formatString(":ref:`%s`", line.c_str()), line);
454     }
455     linksFile.close();
456     initProgramLinks(&links_, helpModule);
457 }
458
459 void HelpExportReStructuredText::startModuleExport()
460 {
461     indexFile_.reset(new File("programs/byname.rst", "w"));
462     indexFile_->writeLine("Tools by Name");
463     indexFile_->writeLine("=============");
464     manPagesFile_.reset(new File("conf-man.py", "w"));
465     manPagesFile_->writeLine("man_pages = [");
466 }
467
468 void HelpExportReStructuredText::exportModuleHelp(
469         const CommandLineModuleInterface &module,
470         const std::string                &tag,
471         const std::string                &displayName)
472 {
473     // TODO: Ideally, the file would only be touched if it really changes.
474     // This would make Sphinx reruns much faster.
475     File file("programs/" + tag + ".rst", "w");
476     file.writeLine(formatString(".. _%s:", displayName.c_str()));
477     if (0 == displayName.compare("gmx mdrun"))
478     {
479         // Make an extra link target for the convenience of
480         // MPI-specific documentation
481         file.writeLine(".. _mdrun_mpi:");
482     }
483     file.writeLine();
484     file.writeLine(displayName);
485     file.writeLine(std::string(displayName.length(), '='));
486     CommandLineHelpContext context(&file, eHelpOutputFormat_Rst, &links_);
487     context.setModuleDisplayName(displayName);
488     module.writeHelp(context);
489
490     file.writeLine();
491     file.writeLine(".. only:: man");
492     file.writeLine();
493     file.writeLine("   See also");
494     file.writeLine("   --------");
495     file.writeLine();
496     file.writeLine("   :manpage:`gromacs(7)`");
497     file.writeLine();
498     file.writeLine("   More information about |Gromacs| is available at <http://www.gromacs.org/>.");
499     file.close();
500
501     indexFile_->writeLine(formatString("* :doc:`%s <%s>` - %s",
502                                        displayName.c_str(), tag.c_str(),
503                                        module.shortDescription()));
504     manPagesFile_->writeLine(
505             formatString("    ('programs/%s', '%s', \"%s\", '', 1),",
506                          tag.c_str(), tag.c_str(), module.shortDescription()));
507 }
508
509 void HelpExportReStructuredText::finishModuleExport()
510 {
511     indexFile_->close();
512     indexFile_.reset();
513     manPagesFile_->writeLine("    ('man/gromacs.7', 'gromacs', 'molecular dynamics simulation suite', '', 7)");
514     manPagesFile_->writeLine("]");
515     manPagesFile_->close();
516     manPagesFile_.reset();
517 }
518
519 void HelpExportReStructuredText::startModuleGroupExport()
520 {
521     indexFile_.reset(new File("programs/bytopic.rst", "w"));
522     indexFile_->writeLine("Tools by Topic");
523     indexFile_->writeLine("==============");
524     manPagesFile_.reset(new File("man/bytopic.rst", "w"));
525 }
526
527 void HelpExportReStructuredText::exportModuleGroup(
528         const char                *title,
529         const ModuleGroupContents &modules)
530 {
531     indexFile_->writeLine(title);
532     indexFile_->writeLine(std::string(std::strlen(title), '-'));
533     manPagesFile_->writeLine(title);
534     manPagesFile_->writeLine(std::string(std::strlen(title), '+'));
535
536     ModuleGroupContents::const_iterator module;
537     for (module = modules.begin(); module != modules.end(); ++module)
538     {
539         const std::string     &tag(module->first);
540         std::string            displayName(tag);
541         // TODO: This does not work if the binary name would contain a dash,
542         // but that is not currently the case.
543         const size_t           dashPos = displayName.find('-');
544         GMX_RELEASE_ASSERT(dashPos != std::string::npos,
545                            "There should always be at least one dash in the tag");
546         displayName[dashPos] = ' ';
547         indexFile_->writeLine(formatString("| :doc:`%s <%s>` - %s",
548                                            displayName.c_str(), tag.c_str(),
549                                            module->second));
550         manPagesFile_->writeLine(formatString("| ``%s`` - %s",
551                                               displayName.c_str(),
552                                               module->second));
553     }
554     indexFile_->writeLine();
555     manPagesFile_->writeLine();
556 }
557
558 void HelpExportReStructuredText::finishModuleGroupExport()
559 {
560     indexFile_->close();
561     indexFile_.reset();
562     manPagesFile_->close();
563     manPagesFile_.reset();
564 }
565
566 /********************************************************************
567  * HelpExportCompletion
568  */
569
570 /*! \internal \brief
571  * Implements export for command-line completion.
572  *
573  * \ingroup module_commandline
574  */
575 class HelpExportCompletion : public HelpExportInterface
576 {
577     public:
578         //! Initializes completion exporter.
579         explicit HelpExportCompletion(const CommandLineHelpModuleImpl &helpModule);
580
581         virtual void startModuleExport();
582         virtual void exportModuleHelp(
583             const CommandLineModuleInterface &module,
584             const std::string                &tag,
585             const std::string                &displayName);
586         virtual void finishModuleExport();
587
588         virtual void startModuleGroupExport() {}
589         virtual void exportModuleGroup(const char                * /*title*/,
590                                        const ModuleGroupContents & /*modules*/) {}
591         virtual void finishModuleGroupExport() {}
592
593     private:
594         ShellCompletionWriter    bashWriter_;
595         std::vector<std::string> modules_;
596 };
597
598 HelpExportCompletion::HelpExportCompletion(
599         const CommandLineHelpModuleImpl &helpModule)
600     : bashWriter_(helpModule.binaryName_, eShellCompletionFormat_Bash)
601 {
602 }
603
604 void HelpExportCompletion::startModuleExport()
605 {
606     bashWriter_.startCompletions();
607 }
608
609 void HelpExportCompletion::exportModuleHelp(
610         const CommandLineModuleInterface &module,
611         const std::string                 & /*tag*/,
612         const std::string                 & /*displayName*/)
613 {
614     modules_.push_back(module.name());
615     {
616         CommandLineHelpContext context(&bashWriter_);
617         // We use the display name to pass the name of the module to the
618         // completion writer.
619         context.setModuleDisplayName(module.name());
620         module.writeHelp(context);
621     }
622 }
623
624 void HelpExportCompletion::finishModuleExport()
625 {
626     CommandLineCommonOptionsHolder optionsHolder;
627     optionsHolder.initOptions();
628     bashWriter_.writeWrapperCompletions(modules_, *optionsHolder.options());
629     bashWriter_.finishCompletions();
630 }
631
632 }   // namespace
633
634 /********************************************************************
635  * CommandLineHelpModuleImpl implementation
636  */
637 CommandLineHelpModuleImpl::CommandLineHelpModuleImpl(
638         const ProgramContextInterface    &programContext,
639         const std::string                &binaryName,
640         const CommandLineModuleMap       &modules,
641         const CommandLineModuleGroupList &groups)
642     : rootTopic_(new RootHelpTopic(*this)), programContext_(programContext),
643       binaryName_(binaryName), modules_(modules), groups_(groups),
644       context_(NULL), moduleOverride_(NULL), bHidden_(false),
645       outputOverride_(NULL)
646 {
647 }
648
649 void CommandLineHelpModuleImpl::exportHelp(HelpExportInterface *exporter) const
650 {
651     // TODO: Would be nicer to have the file names supplied by the build system
652     // and/or export a list of files from here.
653     const char *const program = binaryName_.c_str();
654
655     exporter->startModuleExport();
656     CommandLineModuleMap::const_iterator module;
657     for (module = modules_.begin(); module != modules_.end(); ++module)
658     {
659         if (module->second->shortDescription() != NULL)
660         {
661             const char *const moduleName = module->first.c_str();
662             std::string       tag(formatString("%s-%s", program, moduleName));
663             std::string       displayName(formatString("%s %s", program, moduleName));
664             exporter->exportModuleHelp(*module->second, tag, displayName);
665         }
666     }
667     exporter->finishModuleExport();
668
669     exporter->startModuleGroupExport();
670     CommandLineModuleGroupList::const_iterator group;
671     for (group = groups_.begin(); group != groups_.end(); ++group)
672     {
673         exporter->exportModuleGroup((*group)->title(), (*group)->modules());
674     }
675     exporter->finishModuleGroupExport();
676 }
677
678 /********************************************************************
679  * CommandLineHelpModule
680  */
681
682 CommandLineHelpModule::CommandLineHelpModule(
683         const ProgramContextInterface    &programContext,
684         const std::string                &binaryName,
685         const CommandLineModuleMap       &modules,
686         const CommandLineModuleGroupList &groups)
687     : impl_(new Impl(programContext, binaryName, modules, groups))
688 {
689 }
690
691 CommandLineHelpModule::~CommandLineHelpModule()
692 {
693 }
694
695 HelpTopicPointer CommandLineHelpModule::createModuleHelpTopic(
696         const CommandLineModuleInterface &module) const
697 {
698     return HelpTopicPointer(new ModuleHelpTopic(module, *impl_));
699 }
700
701 void CommandLineHelpModule::addTopic(HelpTopicPointer topic)
702 {
703     impl_->rootTopic_->addSubTopic(move(topic));
704 }
705
706 void CommandLineHelpModule::setShowHidden(bool bHidden)
707 {
708     impl_->bHidden_ = bHidden;
709 }
710
711 void CommandLineHelpModule::setModuleOverride(
712         const CommandLineModuleInterface &module)
713 {
714     impl_->moduleOverride_ = &module;
715 }
716
717 void CommandLineHelpModule::setOutputRedirect(File *output)
718 {
719     impl_->outputOverride_ = output;
720 }
721
722 int CommandLineHelpModule::run(int argc, char *argv[])
723 {
724     // Add internal topics lazily here.
725     addTopic(HelpTopicPointer(new CommandsHelpTopic(*impl_)));
726
727     const char *const exportFormats[] = { "rst", "completion" };
728     std::string       exportFormat;
729     Options           options(NULL, NULL);
730     options.addOption(StringOption("export").store(&exportFormat)
731                           .enumValue(exportFormats));
732     CommandLineParser(&options).parse(&argc, argv);
733     if (!exportFormat.empty())
734     {
735         boost::scoped_ptr<HelpExportInterface> exporter;
736         if (exportFormat == "rst")
737         {
738             exporter.reset(new HelpExportReStructuredText(*impl_));
739         }
740         else if (exportFormat == "completion")
741         {
742             exporter.reset(new HelpExportCompletion(*impl_));
743         }
744         else
745         {
746             GMX_THROW(NotImplementedError("This help format is not implemented"));
747         }
748         impl_->exportHelp(exporter.get());
749         return 0;
750     }
751
752     File *outputFile = &File::standardOutput();
753     if (impl_->outputOverride_ != NULL)
754     {
755         outputFile = impl_->outputOverride_;
756     }
757     HelpLinks                                 links(eHelpOutputFormat_Console);
758     initProgramLinks(&links, *impl_);
759     boost::scoped_ptr<CommandLineHelpContext> context(
760             new CommandLineHelpContext(outputFile,
761                                        eHelpOutputFormat_Console, &links));
762     context->setShowHidden(impl_->bHidden_);
763     if (impl_->moduleOverride_ != NULL)
764     {
765         context->setModuleDisplayName(impl_->programContext_.displayName());
766         impl_->moduleOverride_->writeHelp(*context);
767         return 0;
768     }
769     impl_->context_ = context.get();
770
771     HelpManager helpManager(*impl_->rootTopic_, context->writerContext());
772     try
773     {
774         for (int i = 1; i < argc; ++i)
775         {
776             helpManager.enterTopic(argv[i]);
777         }
778     }
779     catch (const InvalidInputError &ex)
780     {
781         fprintf(stderr, "%s\n", ex.what());
782         return 2;
783     }
784     helpManager.writeCurrentTopic();
785     return 0;
786 }
787
788 void CommandLineHelpModule::writeHelp(const CommandLineHelpContext &context) const
789 {
790     const HelpWriterContext &writerContext = context.writerContext();
791     // TODO: Implement.
792     if (writerContext.outputFormat() != eHelpOutputFormat_Console)
793     {
794         return;
795     }
796     writerContext.writeTextBlock(
797             "Usage: [PROGRAM] help [<command>|<topic> [<subtopic> [...]]]");
798     // TODO: More information.
799 }
800
801 } // namespace gmx