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