Split CommandLineHelpModule into a separate file
[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, 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 "gromacs/commandline/cmdlinehelpmodule.h"
43
44 #include <algorithm>
45 #include <string>
46
47 #include <boost/scoped_ptr.hpp>
48
49 #include "gromacs/legacyheaders/copyrite.h"
50 #include "gromacs/legacyheaders/smalloc.h"
51
52 #include "gromacs/commandline/cmdlinehelpcontext.h"
53 #include "gromacs/commandline/cmdlineparser.h"
54 #include "gromacs/fileio/futil.h"
55 #include "gromacs/onlinehelp/helpformat.h"
56 #include "gromacs/onlinehelp/helpmanager.h"
57 #include "gromacs/onlinehelp/helptopic.h"
58 #include "gromacs/onlinehelp/helpwritercontext.h"
59 #include "gromacs/options/basicoptions.h"
60 #include "gromacs/options/options.h"
61 #include "gromacs/utility/exceptions.h"
62 #include "gromacs/utility/file.h"
63 #include "gromacs/utility/gmxassert.h"
64 #include "gromacs/utility/programinfo.h"
65 #include "gromacs/utility/stringutil.h"
66
67 namespace gmx
68 {
69
70 namespace
71 {
72 class HelpExportInterface;
73 class RootHelpTopic;
74 }   // namespace
75
76 /********************************************************************
77  * CommandLineHelpModuleImpl declaration
78  */
79
80 class CommandLineHelpModuleImpl
81 {
82     public:
83         CommandLineHelpModuleImpl(const ProgramInfo                &programInfo,
84                                   const CommandLineModuleMap       &modules,
85                                   const CommandLineModuleGroupList &groups);
86
87         void exportHelp(HelpExportInterface *exporter) const;
88
89         boost::scoped_ptr<RootHelpTopic>  rootTopic_;
90         const ProgramInfo                &programInfo_;
91         const CommandLineModuleMap       &modules_;
92         const CommandLineModuleGroupList &groups_;
93
94         CommandLineHelpContext           *context_;
95         const CommandLineModuleInterface *moduleOverride_;
96         bool                              bHidden_;
97
98         GMX_DISALLOW_COPY_AND_ASSIGN(CommandLineHelpModuleImpl);
99 };
100
101 namespace
102 {
103
104 /********************************************************************
105  * RootHelpTopic
106  */
107
108 struct RootHelpText
109 {
110     static const char        name[];
111     static const char        title[];
112     static const char *const text[];
113 };
114
115 // The first two are not used.
116 const char        RootHelpText::name[]  = "";
117 const char        RootHelpText::title[] = "";
118 const char *const RootHelpText::text[]  = {
119     "Usage: [PROGRAM] <command> [<args>]",
120 };
121
122 /*! \brief
123  * Help topic that forms the root of the help tree for the help subcommand.
124  *
125  * \ingroup module_commandline
126  */
127 class RootHelpTopic : public CompositeHelpTopic<RootHelpText>
128 {
129     public:
130         /*! \brief
131          * Creates a root help topic.
132          *
133          * \param[in] modules  List of modules for to use for module listings.
134          *
135          * Does not throw.
136          */
137         explicit RootHelpTopic(const CommandLineModuleMap &modules)
138             : modules_(modules)
139         {
140         }
141
142         virtual void writeHelp(const HelpWriterContext &context) const;
143
144     private:
145         void printModuleList(const HelpWriterContext &context) const;
146
147         const CommandLineModuleMap &modules_;
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     writeBasicHelpTopic(context, *this, helpText());
162     // TODO: If/when this list becomes long, it may be better to only print
163     // "common" commands here, and have a separate topic (e.g.,
164     // "help commands") that prints the full list.
165     printModuleList(context);
166     context.writeTextBlock(
167             "For additional help on a command, use '[PROGRAM] help <command>'");
168     writeSubTopicList(context,
169                       "\nAdditional help is available on the following topics:");
170     context.writeTextBlock(
171             "To access the help, use '[PROGRAM] help <topic>'.");
172 }
173
174 void RootHelpTopic::printModuleList(const HelpWriterContext &context) const
175 {
176     if (context.outputFormat() != eHelpOutputFormat_Console)
177     {
178         // TODO: Implement once the situation with Redmine issue #969 is more
179         // clear.
180         GMX_THROW(NotImplementedError(
181                           "Module list is not implemented for this output format"));
182     }
183     int maxNameLength = 0;
184     CommandLineModuleMap::const_iterator module;
185     for (module = modules_.begin(); module != modules_.end(); ++module)
186     {
187         int nameLength = static_cast<int>(module->first.length());
188         if (module->second->shortDescription() != NULL
189             && nameLength > maxNameLength)
190         {
191             maxNameLength = nameLength;
192         }
193     }
194     File              &file = context.outputFile();
195     TextTableFormatter formatter;
196     formatter.addColumn(NULL, maxNameLength + 1, false);
197     formatter.addColumn(NULL, 72 - maxNameLength, true);
198     formatter.setFirstColumnIndent(4);
199     file.writeLine();
200     file.writeLine("Available commands:");
201     for (module = modules_.begin(); module != modules_.end(); ++module)
202     {
203         const char *name        = module->first.c_str();
204         const char *description = module->second->shortDescription();
205         if (description != NULL)
206         {
207             formatter.clear();
208             formatter.addColumnLine(0, name);
209             formatter.addColumnLine(1, description);
210             file.writeString(formatter.formatRow());
211         }
212     }
213 }
214
215 /********************************************************************
216  * ModuleHelpTopic
217  */
218
219 /*! \brief
220  * Help topic wrapper for a command-line module.
221  *
222  * This class implements HelpTopicInterface such that it wraps a
223  * CommandLineModuleInterface, allowing subcommand "help <command>"
224  * to produce the help for "<command>".
225  *
226  * \ingroup module_commandline
227  */
228 class ModuleHelpTopic : public HelpTopicInterface
229 {
230     public:
231         //! Constructs a help topic for a specific module.
232         ModuleHelpTopic(const CommandLineModuleInterface &module,
233                         const CommandLineHelpModule      &helpModule)
234             : module_(module), helpModule_(helpModule)
235         {
236         }
237
238         virtual const char *name() const { return module_.name(); }
239         virtual const char *title() const { return NULL; }
240         virtual bool hasSubTopics() const { return false; }
241         virtual const HelpTopicInterface *findSubTopic(const char * /*name*/) const
242         {
243             return NULL;
244         }
245         virtual void writeHelp(const HelpWriterContext &context) const;
246
247     private:
248         const CommandLineModuleInterface &module_;
249         const CommandLineHelpModule      &helpModule_;
250
251         GMX_DISALLOW_COPY_AND_ASSIGN(ModuleHelpTopic);
252 };
253
254 void ModuleHelpTopic::writeHelp(const HelpWriterContext & /*context*/) const
255 {
256     CommandLineHelpContext context(helpModule_.context());
257     const char *const      program =
258         helpModule_.programInfo().realBinaryName().c_str();
259     context.setModuleDisplayName(formatString("%s %s", program, module_.name()));
260     module_.writeHelp(context);
261 }
262
263 /********************************************************************
264  * HelpExportInterface
265  */
266
267 /*! \brief
268  * Callbacks for exporting help information for command-line modules.
269  *
270  * \ingroup module_commandline
271  */
272 class HelpExportInterface
273 {
274     public:
275         //! Shorthand for a list of modules contained in a group.
276         typedef CommandLineModuleGroupData::ModuleList ModuleGroupContents;
277
278         virtual ~HelpExportInterface() {};
279
280         /*! \brief
281          * Called once before exporting individual modules.
282          *
283          * Can, e.g., open shared output files (e.g., if the output is written
284          * into a single file, or if a separate index is required) and write
285          * headers into them.
286          */
287         virtual void startModuleExport() = 0;
288         /*! \brief
289          * Called to export the help for each module.
290          *
291          * \param[in] module      Module for which the help should be exported.
292          * \param[in] tag         Unique tag for the module (gmx-something).
293          * \param[in] displayName Display name for the module (gmx something).
294          */
295         virtual void exportModuleHelp(
296             const CommandLineModuleInterface &module,
297             const std::string                &tag,
298             const std::string                &displayName) = 0;
299         /*! \brief
300          * Called after all modules have been exported.
301          *
302          * Can close files opened in startModuleExport(), write footers to them
303          * etc.
304          */
305         virtual void finishModuleExport() = 0;
306
307         /*! \brief
308          * Called once before exporting module groups.
309          *
310          * Can, e.g., open a single output file for listing all the groups.
311          */
312         virtual void startModuleGroupExport() = 0;
313         /*! \brief
314          * Called to export the help for each module group.
315          *
316          * \param[in] title    Title for the group.
317          * \param[in] modules  List of modules in the group.
318          */
319         virtual void exportModuleGroup(const char                *title,
320                                        const ModuleGroupContents &modules) = 0;
321         /*! \brief
322          * Called after all module groups have been exported.
323          *
324          * Can close files opened in startModuleGroupExport(), write footers to them
325          * etc.
326          */
327         virtual void finishModuleGroupExport() = 0;
328 };
329
330 /*! \internal \brief
331  * Adds hyperlinks to modules within this binary.
332  *
333  * \param[in,out] links   Links are added here.
334  * \param[in]     modules Modules in the current binary.
335  * \throws        std::bad_alloc if out of memory.
336  *
337  * Initializes a HelpLinks object with links to modules defined in \p modules.
338  *
339  * \ingroup module_commandline
340  */
341 void initProgramLinks(HelpLinks *links, const CommandLineModuleMap &modules)
342 {
343     const char *const                    program =
344         ProgramInfo::getInstance().realBinaryName().c_str();
345     CommandLineModuleMap::const_iterator module;
346     for (module = modules.begin(); module != modules.end(); ++module)
347     {
348         if (module->second->shortDescription() != NULL)
349         {
350             std::string linkName("[gmx-" + module->first + "]");
351             std::string targetName(
352                     formatString("%s-%s", program, module->first.c_str()));
353             std::string displayName(
354                     formatString("[TT]%s %s[tt]", program, module->first.c_str()));
355             links->addLink(linkName, targetName, displayName);
356         }
357     }
358 }
359
360 /********************************************************************
361  * HelpExportMan
362  */
363
364 /*! \internal \brief
365  * Implements export for man pages.
366  *
367  * \ingroup module_commandline
368  */
369 class HelpExportMan : public HelpExportInterface
370 {
371     public:
372         //! Initializes man page exporter.
373         explicit HelpExportMan(const CommandLineModuleMap &modules)
374             : links_(eHelpOutputFormat_Man)
375         {
376             initProgramLinks(&links_, modules);
377         }
378
379         virtual void startModuleExport() {}
380         virtual void exportModuleHelp(
381             const CommandLineModuleInterface &module,
382             const std::string                &tag,
383             const std::string                &displayName);
384         virtual void finishModuleExport() {}
385
386         virtual void startModuleGroupExport();
387         virtual void exportModuleGroup(const char                *title,
388                                        const ModuleGroupContents &modules);
389         virtual void finishModuleGroupExport();
390
391     private:
392         HelpLinks                links_;
393         boost::scoped_ptr<File>  man7File_;
394         std::string              man7Footer_;
395 };
396
397 void HelpExportMan::exportModuleHelp(
398         const CommandLineModuleInterface &module,
399         const std::string                &tag,
400         const std::string                &displayName)
401 {
402     File file("man1/" + tag + ".1", "w");
403
404     // TODO: It would be nice to remove the VERSION prefix from the version
405     // string to make it shorter.
406     file.writeLine(formatString(".TH %s 1 \"\" \"%s\" \"GROMACS Manual\"\n",
407                                 tag.c_str(),
408                                 GromacsVersion()));
409     file.writeLine(".SH NAME");
410     file.writeLine(formatString("%s - %s", tag.c_str(),
411                                 module.shortDescription()));
412     file.writeLine();
413
414     CommandLineHelpContext context(&file, eHelpOutputFormat_Man, &links_);
415     context.setModuleDisplayName(displayName);
416     module.writeHelp(context);
417
418     file.writeLine(".SH SEE ALSO");
419     file.writeLine(".BR gromacs(7)");
420     file.writeLine();
421     file.writeLine("More information about \\fBGROMACS\\fR is available at <\\fIhttp://www.gromacs.org/\\fR>.");
422 }
423
424 void HelpExportMan::startModuleGroupExport()
425 {
426     const char *const programListPlaceholder = "@PROGMANPAGES@";
427
428     const std::string man7Template = gmx::File::readToString("man7/gromacs.7.in");
429     const size_t      index        = man7Template.find(programListPlaceholder);
430     GMX_RELEASE_ASSERT(index != std::string::npos,
431                        "gromacs.7.in must contain a @PROGMANPAGES@ line");
432     std::string header = man7Template.substr(0, index);
433     man7Footer_ = man7Template.substr(index + std::strlen(programListPlaceholder));
434     header      = replaceAll(header, "@VERSION@", GromacsVersion());
435     man7File_.reset(new File("man7/gromacs.7", "w"));
436     man7File_->writeLine(header);
437 }
438
439 void HelpExportMan::exportModuleGroup(const char                *title,
440                                       const ModuleGroupContents &modules)
441 {
442     man7File_->writeLine(formatString(".Sh \"%s\"", title));
443     man7File_->writeLine(formatString(".IX Subsection \"%s\"", title));
444     man7File_->writeLine(".Vb");
445     man7File_->writeLine(".ta 16n");
446
447     ModuleGroupContents::const_iterator module;
448     for (module = modules.begin(); module != modules.end(); ++module)
449     {
450         const std::string &tag(module->first);
451         man7File_->writeLine(formatString("\\&  %s\t%s",
452                                           tag.c_str(), module->second));
453     }
454
455     man7File_->writeLine(".Ve");
456 }
457
458 void HelpExportMan::finishModuleGroupExport()
459 {
460     man7File_->writeLine(man7Footer_);
461     man7File_->close();
462 }
463
464 /********************************************************************
465  * HelpExportHtml
466  */
467
468 /*! \internal \brief
469  * Implements export for HTML help.
470  *
471  * \ingroup module_commandline
472  */
473 class HelpExportHtml : public HelpExportInterface
474 {
475     public:
476         //! Initializes HTML exporter.
477         explicit HelpExportHtml(const CommandLineModuleMap &modules);
478
479         virtual void startModuleExport();
480         virtual void exportModuleHelp(
481             const CommandLineModuleInterface &module,
482             const std::string                &tag,
483             const std::string                &displayName);
484         virtual void finishModuleExport();
485
486         virtual void startModuleGroupExport();
487         virtual void exportModuleGroup(const char                *title,
488                                        const ModuleGroupContents &modules);
489         virtual void finishModuleGroupExport();
490
491     private:
492         void setupHeaderAndFooter();
493
494         void writeHtmlHeader(File *file, const std::string &title) const;
495         void writeHtmlFooter(File *file) const;
496
497         HelpLinks                links_;
498         boost::scoped_ptr<File>  indexFile_;
499         std::string              header_;
500         std::string              footer_;
501 };
502
503 HelpExportHtml::HelpExportHtml(const CommandLineModuleMap &modules)
504     : links_(eHelpOutputFormat_Html)
505 {
506     initProgramLinks(&links_, modules);
507     char *linksFilename = low_gmxlibfn("links.dat", FALSE, FALSE);
508     if (linksFilename != NULL)
509     {
510         scoped_ptr_sfree guard(linksFilename);
511         File             linksFile(linksFilename, "r");
512         std::string      line;
513         while (linksFile.readLine(&line))
514         {
515             links_.addLink(line, "../online/" + line, line);
516         }
517     }
518     setupHeaderAndFooter();
519 }
520
521 void HelpExportHtml::setupHeaderAndFooter()
522 {
523     header_ = gmx::File::readToString("header.html.in");
524     header_ = replaceAll(header_, "@VERSION@", GromacsVersion());
525     gmx::File::writeFileFromString("header.html", header_);
526     header_ = replaceAll(header_, "@ROOTPATH@", "../");
527     footer_ = gmx::File::readToString("footer.html");
528 }
529
530 void HelpExportHtml::startModuleExport()
531 {
532     indexFile_.reset(new File("final/programs/byname.html", "w"));
533     writeHtmlHeader(indexFile_.get(), "GROMACS Programs by Name");
534     indexFile_->writeLine("<H3>GROMACS Programs Alphabetically</H3>");
535 }
536
537 void HelpExportHtml::exportModuleHelp(
538         const CommandLineModuleInterface &module,
539         const std::string                &tag,
540         const std::string                &displayName)
541 {
542     File file("final/programs/" + tag + ".html", "w");
543     writeHtmlHeader(&file, displayName);
544
545     CommandLineHelpContext context(&file, eHelpOutputFormat_Html, &links_);
546     context.setModuleDisplayName(displayName);
547     module.writeHelp(context);
548
549     writeHtmlFooter(&file);
550     file.close();
551
552     indexFile_->writeLine(formatString("<a href=\"%s.html\">%s</a> - %s<br>",
553                                        tag.c_str(), displayName.c_str(),
554                                        module.shortDescription()));
555 }
556
557 void HelpExportHtml::finishModuleExport()
558 {
559     writeHtmlFooter(indexFile_.get());
560     indexFile_->close();
561 }
562
563 void HelpExportHtml::startModuleGroupExport()
564 {
565     indexFile_.reset(new File("final/programs/bytopic.html", "w"));
566     writeHtmlHeader(indexFile_.get(), "GROMACS Programs by Topic");
567     indexFile_->writeLine("<H3>GROMACS Programs by Topic</H3>");
568 }
569
570 void HelpExportHtml::exportModuleGroup(const char                *title,
571                                        const ModuleGroupContents &modules)
572 {
573     indexFile_->writeLine(formatString("<H4>%s</H4>", title));
574
575     ModuleGroupContents::const_iterator module;
576     for (module = modules.begin(); module != modules.end(); ++module)
577     {
578         const std::string     &tag(module->first);
579         std::string            displayName(tag);
580         std::replace(displayName.begin(), displayName.end(), '-', ' ');
581         indexFile_->writeLine(formatString("<a href=\"%s.html\">%s</a> - %s<br>",
582                                            tag.c_str(), displayName.c_str(),
583                                            module->second));
584     }
585 }
586
587 void HelpExportHtml::finishModuleGroupExport()
588 {
589     writeHtmlFooter(indexFile_.get());
590     indexFile_->close();
591 }
592
593 void HelpExportHtml::writeHtmlHeader(File *file, const std::string &title) const
594 {
595     file->writeLine(replaceAll(header_, "@TITLE@", title));
596 }
597
598 void HelpExportHtml::writeHtmlFooter(File *file) const
599 {
600     file->writeLine(footer_);
601 }
602
603 }   // namespace
604
605 /********************************************************************
606  * CommandLineHelpModuleImpl implementation
607  */
608 CommandLineHelpModuleImpl::CommandLineHelpModuleImpl(
609         const ProgramInfo                &programInfo,
610         const CommandLineModuleMap       &modules,
611         const CommandLineModuleGroupList &groups)
612     : rootTopic_(new RootHelpTopic(modules)), programInfo_(programInfo),
613       modules_(modules), groups_(groups),
614       context_(NULL), moduleOverride_(NULL), bHidden_(false)
615 {
616 }
617
618 void CommandLineHelpModuleImpl::exportHelp(HelpExportInterface *exporter) const
619 {
620     // TODO: Would be nicer to have the file names supplied by the build system
621     // and/or export a list of files from here.
622     const char *const program = programInfo_.realBinaryName().c_str();
623
624     exporter->startModuleExport();
625     CommandLineModuleMap::const_iterator module;
626     for (module = modules_.begin(); module != modules_.end(); ++module)
627     {
628         if (module->second->shortDescription() != NULL)
629         {
630             const char *const moduleName = module->first.c_str();
631             std::string       tag(formatString("%s-%s", program, moduleName));
632             std::string       displayName(tag);
633             std::replace(displayName.begin(), displayName.end(), '-', ' ');
634             exporter->exportModuleHelp(*module->second, tag, displayName);
635         }
636     }
637     exporter->finishModuleExport();
638
639     exporter->startModuleGroupExport();
640     CommandLineModuleGroupList::const_iterator group;
641     for (group = groups_.begin(); group != groups_.end(); ++group)
642     {
643         exporter->exportModuleGroup((*group)->title(), (*group)->modules());
644     }
645     exporter->finishModuleGroupExport();
646 }
647
648 /********************************************************************
649  * CommandLineHelpModule
650  */
651
652 CommandLineHelpModule::CommandLineHelpModule(
653         const ProgramInfo                &programInfo,
654         const CommandLineModuleMap       &modules,
655         const CommandLineModuleGroupList &groups)
656     : impl_(new Impl(programInfo, modules, groups))
657 {
658 }
659
660 CommandLineHelpModule::~CommandLineHelpModule()
661 {
662 }
663
664 HelpTopicPointer CommandLineHelpModule::createModuleHelpTopic(
665         const CommandLineModuleInterface &module) const
666 {
667     return HelpTopicPointer(new ModuleHelpTopic(module, *this));
668 }
669
670 void CommandLineHelpModule::addTopic(HelpTopicPointer topic)
671 {
672     impl_->rootTopic_->addSubTopic(move(topic));
673 }
674
675 void CommandLineHelpModule::setShowHidden(bool bHidden)
676 {
677     impl_->bHidden_ = bHidden;
678 }
679
680 void CommandLineHelpModule::setModuleOverride(
681         const CommandLineModuleInterface &module)
682 {
683     impl_->moduleOverride_ = &module;
684 }
685
686 const CommandLineHelpContext &CommandLineHelpModule::context() const
687 {
688     return *impl_->context_;
689 }
690
691 const ProgramInfo &CommandLineHelpModule::programInfo() const
692 {
693     return impl_->programInfo_;
694 }
695
696 int CommandLineHelpModule::run(int argc, char *argv[])
697 {
698     const char *const exportFormats[] = { "man", "html", "completion" };
699     std::string       exportFormat;
700     Options           options(NULL, NULL);
701     options.addOption(StringOption("export").store(&exportFormat)
702                           .enumValue(exportFormats));
703     CommandLineParser(&options).parse(&argc, argv);
704     if (!exportFormat.empty())
705     {
706         boost::scoped_ptr<HelpExportInterface> exporter;
707         if (exportFormat == "man")
708         {
709             exporter.reset(new HelpExportMan(impl_->modules_));
710         }
711         else if (exportFormat == "html")
712         {
713             exporter.reset(new HelpExportHtml(impl_->modules_));
714         }
715         else
716         {
717             GMX_THROW(NotImplementedError("This help format is not implemented"));
718         }
719         impl_->exportHelp(exporter.get());
720         return 0;
721     }
722
723     HelpLinks                                 links(eHelpOutputFormat_Console);
724     initProgramLinks(&links, impl_->modules_);
725     boost::scoped_ptr<CommandLineHelpContext> context(
726             new CommandLineHelpContext(&File::standardOutput(),
727                                        eHelpOutputFormat_Console, &links));
728     context->setShowHidden(impl_->bHidden_);
729     if (impl_->moduleOverride_ != NULL)
730     {
731         context->setModuleDisplayName(impl_->programInfo_.displayName());
732         impl_->moduleOverride_->writeHelp(*context);
733         return 0;
734     }
735     impl_->context_ = context.get();
736
737     HelpManager helpManager(*impl_->rootTopic_, context->writerContext());
738     try
739     {
740         for (int i = 1; i < argc; ++i)
741         {
742             helpManager.enterTopic(argv[i]);
743         }
744     }
745     catch (const InvalidInputError &ex)
746     {
747         fprintf(stderr, "%s\n", ex.what());
748         return 2;
749     }
750     helpManager.writeCurrentTopic();
751     return 0;
752 }
753
754 void CommandLineHelpModule::writeHelp(const CommandLineHelpContext &context) const
755 {
756     const HelpWriterContext &writerContext = context.writerContext();
757     // TODO: Implement.
758     if (writerContext.outputFormat() != eHelpOutputFormat_Console)
759     {
760         return;
761     }
762     writerContext.writeTextBlock(
763             "Usage: [PROGRAM] help [<command>|<topic> [<subtopic> [...]]]");
764     // TODO: More information.
765 }
766
767 } // namespace gmx