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