b4fce4cb31f06e1ea8bb1510534cdc83da5a3014
[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(
175             "To access the help, use '[PROGRAM] help <topic>'.[BR]"
176             "For help on a command, use '[PROGRAM] help <command>'.");
177 }
178
179 /********************************************************************
180  * CommandsHelpTopic
181  */
182
183 /*! \brief
184  * Help topic for listing the commands.
185  *
186  * \ingroup module_commandline
187  */
188 class CommandsHelpTopic : public HelpTopicInterface
189 {
190     public:
191         /*! \brief
192          * Creates a command list help topic.
193          *
194          * \param[in]     helpModule Help module to get module information from.
195          *
196          * Does not throw.
197          */
198         explicit CommandsHelpTopic(const CommandLineHelpModuleImpl &helpModule)
199             : helpModule_(helpModule)
200         {
201         }
202
203         virtual const char *name() const { return "commands"; }
204         virtual const char *title() const { return "List of available commands"; }
205         virtual bool hasSubTopics() const { return false; }
206         virtual const HelpTopicInterface *findSubTopic(const char * /*name*/) const
207         {
208             return NULL;
209         }
210
211         virtual void writeHelp(const HelpWriterContext &context) const;
212
213     private:
214         const CommandLineHelpModuleImpl &helpModule_;
215
216         GMX_DISALLOW_COPY_AND_ASSIGN(CommandsHelpTopic);
217 };
218
219 void CommandsHelpTopic::writeHelp(const HelpWriterContext &context) const
220 {
221     if (context.outputFormat() != eHelpOutputFormat_Console)
222     {
223         GMX_THROW(NotImplementedError(
224                           "Module list is not implemented for this output format"));
225     }
226     int maxNameLength = 0;
227     const CommandLineModuleMap           &modules = helpModule_.modules_;
228     CommandLineModuleMap::const_iterator  module;
229     for (module = modules.begin(); module != modules.end(); ++module)
230     {
231         int nameLength = static_cast<int>(module->first.length());
232         if (module->second->shortDescription() != NULL
233             && nameLength > maxNameLength)
234         {
235             maxNameLength = nameLength;
236         }
237     }
238     context.writeTextBlock(
239             "Usage: [PROGRAM] [<options>] <command> [<args>][PAR]"
240             "Available commands:");
241     File              &file = context.outputFile();
242     TextTableFormatter formatter;
243     formatter.addColumn(NULL, maxNameLength + 1, false);
244     formatter.addColumn(NULL, 72 - maxNameLength, true);
245     formatter.setFirstColumnIndent(4);
246     for (module = modules.begin(); module != modules.end(); ++module)
247     {
248         const char *name        = module->first.c_str();
249         const char *description = module->second->shortDescription();
250         if (description != NULL)
251         {
252             formatter.clear();
253             formatter.addColumnLine(0, name);
254             formatter.addColumnLine(1, description);
255             file.writeString(formatter.formatRow());
256         }
257     }
258     context.writeTextBlock(
259             "For help on a command, use '[PROGRAM] help <command>'.");
260 }
261
262 /********************************************************************
263  * ModuleHelpTopic
264  */
265
266 /*! \brief
267  * Help topic wrapper for a command-line module.
268  *
269  * This class implements HelpTopicInterface such that it wraps a
270  * CommandLineModuleInterface, allowing subcommand "help <command>"
271  * to produce the help for "<command>".
272  *
273  * \ingroup module_commandline
274  */
275 class ModuleHelpTopic : public HelpTopicInterface
276 {
277     public:
278         //! Constructs a help topic for a specific module.
279         ModuleHelpTopic(const CommandLineModuleInterface &module,
280                         const CommandLineHelpModuleImpl  &helpModule)
281             : module_(module), helpModule_(helpModule)
282         {
283         }
284
285         virtual const char *name() const { return module_.name(); }
286         virtual const char *title() const { return NULL; }
287         virtual bool hasSubTopics() const { return false; }
288         virtual const HelpTopicInterface *findSubTopic(const char * /*name*/) const
289         {
290             return NULL;
291         }
292         virtual void writeHelp(const HelpWriterContext &context) const;
293
294     private:
295         const CommandLineModuleInterface &module_;
296         const CommandLineHelpModuleImpl  &helpModule_;
297
298         GMX_DISALLOW_COPY_AND_ASSIGN(ModuleHelpTopic);
299 };
300
301 void ModuleHelpTopic::writeHelp(const HelpWriterContext & /*context*/) const
302 {
303     CommandLineHelpContext context(*helpModule_.context_);
304     const char *const      program = helpModule_.binaryName_.c_str();
305     context.setModuleDisplayName(formatString("%s %s", program, module_.name()));
306     module_.writeHelp(context);
307 }
308
309 /********************************************************************
310  * HelpExportInterface
311  */
312
313 /*! \brief
314  * Callbacks for exporting help information for command-line modules.
315  *
316  * \ingroup module_commandline
317  */
318 class HelpExportInterface
319 {
320     public:
321         //! Shorthand for a list of modules contained in a group.
322         typedef CommandLineModuleGroupData::ModuleList ModuleGroupContents;
323
324         virtual ~HelpExportInterface() {};
325
326         /*! \brief
327          * Called once before exporting individual modules.
328          *
329          * Can, e.g., open shared output files (e.g., if the output is written
330          * into a single file, or if a separate index is required) and write
331          * headers into them.
332          */
333         virtual void startModuleExport() = 0;
334         /*! \brief
335          * Called to export the help for each module.
336          *
337          * \param[in] module      Module for which the help should be exported.
338          * \param[in] tag         Unique tag for the module (gmx-something).
339          * \param[in] displayName Display name for the module (gmx something).
340          */
341         virtual void exportModuleHelp(
342             const CommandLineModuleInterface &module,
343             const std::string                &tag,
344             const std::string                &displayName) = 0;
345         /*! \brief
346          * Called after all modules have been exported.
347          *
348          * Can close files opened in startModuleExport(), write footers to them
349          * etc.
350          */
351         virtual void finishModuleExport() = 0;
352
353         /*! \brief
354          * Called once before exporting module groups.
355          *
356          * Can, e.g., open a single output file for listing all the groups.
357          */
358         virtual void startModuleGroupExport() = 0;
359         /*! \brief
360          * Called to export the help for each module group.
361          *
362          * \param[in] title    Title for the group.
363          * \param[in] modules  List of modules in the group.
364          */
365         virtual void exportModuleGroup(const char                *title,
366                                        const ModuleGroupContents &modules) = 0;
367         /*! \brief
368          * Called after all module groups have been exported.
369          *
370          * Can close files opened in startModuleGroupExport(), write footers to them
371          * etc.
372          */
373         virtual void finishModuleGroupExport() = 0;
374 };
375
376 /*! \internal \brief
377  * Adds hyperlinks to modules within this binary.
378  *
379  * \param[in,out] links      Links are added here.
380  * \param[in]     helpModule Help module to get module information from.
381  * \throws        std::bad_alloc if out of memory.
382  *
383  * Initializes a HelpLinks object with links to modules defined in
384  * \p helpModule.
385  *
386  * \ingroup module_commandline
387  */
388 void initProgramLinks(HelpLinks *links, const CommandLineHelpModuleImpl &helpModule)
389 {
390     const char *const                    program = helpModule.binaryName_.c_str();
391     CommandLineModuleMap::const_iterator module;
392     for (module = helpModule.modules_.begin();
393          module != helpModule.modules_.end();
394          ++module)
395     {
396         if (module->second->shortDescription() != NULL)
397         {
398             std::string linkName("[gmx-" + module->first + "]");
399             const char *name = module->first.c_str();
400             std::string reference(
401                     formatString(":doc:`%s %s <%s-%s>`", program, name, program, name));
402             std::string displayName(
403                     formatString("[TT]%s %s[tt]", program, name));
404             links->addLink(linkName, reference, displayName);
405         }
406     }
407 }
408
409 /********************************************************************
410  * HelpExportHtml
411  */
412
413 /*! \internal
414  * \brief
415  * Implements export for HTML help.
416  *
417  * This whole class can go once docs/old-html/ no longer requires header.html
418  * that it generates.
419  *
420  * \ingroup module_commandline
421  */
422 class HelpExportHtml : public HelpExportInterface
423 {
424     public:
425         //! Initializes HTML exporter.
426         HelpExportHtml();
427
428         virtual void startModuleExport() {}
429         virtual void exportModuleHelp(
430             const CommandLineModuleInterface & /*module*/,
431             const std::string                & /*tag*/,
432             const std::string                & /*displayName*/) {}
433         virtual void finishModuleExport() {}
434
435         virtual void startModuleGroupExport() {}
436         virtual void exportModuleGroup(const char                * /*title*/,
437                                        const ModuleGroupContents & /*modules*/) {}
438         virtual void finishModuleGroupExport() {}
439 };
440
441 HelpExportHtml::HelpExportHtml()
442 {
443     std::string header = gmx::File::readToString("header.html.in");
444     header = replaceAll(header, "@VERSION@", gmx_version());
445     gmx::File::writeFileFromString("header.html", header);
446 }
447
448 /********************************************************************
449  * HelpExportReStructuredText
450  */
451
452 /*! \internal \brief
453  * Implements export for web pages as reStructuredText.
454  *
455  * \ingroup module_commandline
456  */
457 class HelpExportReStructuredText : public HelpExportInterface
458 {
459     public:
460         //! Initializes reST exporter.
461         explicit HelpExportReStructuredText(
462             const CommandLineHelpModuleImpl &helpModule);
463
464         virtual void startModuleExport();
465         virtual void exportModuleHelp(
466             const CommandLineModuleInterface &module,
467             const std::string                &tag,
468             const std::string                &displayName);
469         virtual void finishModuleExport();
470
471         virtual void startModuleGroupExport();
472         virtual void exportModuleGroup(const char                *title,
473                                        const ModuleGroupContents &modules);
474         virtual void finishModuleGroupExport();
475
476     private:
477         HelpLinks                links_;
478         boost::scoped_ptr<File>  indexFile_;
479         boost::scoped_ptr<File>  manPagesFile_;
480 };
481
482 HelpExportReStructuredText::HelpExportReStructuredText(
483         const CommandLineHelpModuleImpl &helpModule)
484     : links_(eHelpOutputFormat_Rst)
485 {
486     File             linksFile("links.dat", "r");
487     std::string      line;
488     while (linksFile.readLine(&line))
489     {
490         links_.addLink("[REF]." + line + "[ref]",
491                        formatString(":ref:`.%s <%s>`", line.c_str(), line.c_str()),
492                        line);
493         links_.addLink("[REF]" + line + "[ref]", formatString(":ref:`%s`", line.c_str()), line);
494     }
495     linksFile.close();
496     initProgramLinks(&links_, helpModule);
497 }
498
499 void HelpExportReStructuredText::startModuleExport()
500 {
501     indexFile_.reset(new File("programs/byname.rst", "w"));
502     indexFile_->writeLine("Tools by Name");
503     indexFile_->writeLine("=============");
504     manPagesFile_.reset(new File("conf-man.py", "w"));
505     manPagesFile_->writeLine("man_pages = [");
506 }
507
508 void HelpExportReStructuredText::exportModuleHelp(
509         const CommandLineModuleInterface &module,
510         const std::string                &tag,
511         const std::string                &displayName)
512 {
513     // TODO: Ideally, the file would only be touched if it really changes.
514     // This would make Sphinx reruns much faster.
515     File file("programs/" + tag + ".rst", "w");
516     file.writeLine(formatString(".. _%s:", displayName.c_str()));
517     file.writeLine();
518     file.writeLine(displayName);
519     file.writeLine(std::string(displayName.length(), '='));
520     CommandLineHelpContext context(&file, eHelpOutputFormat_Rst, &links_);
521     context.setModuleDisplayName(displayName);
522     module.writeHelp(context);
523
524     file.writeLine();
525     file.writeLine(".. only:: man");
526     file.writeLine();
527     file.writeLine("   See also");
528     file.writeLine("   --------");
529     file.writeLine();
530     file.writeLine("   :manpage:`gromacs(7)`");
531     file.writeLine();
532     file.writeLine("   More information about |Gromacs| is available at <http://www.gromacs.org/>.");
533     file.close();
534
535     indexFile_->writeLine(formatString("* :doc:`%s <%s>` - %s",
536                                        displayName.c_str(), tag.c_str(),
537                                        module.shortDescription()));
538     manPagesFile_->writeLine(
539             formatString("    ('programs/%s', '%s', \"%s\", '', 1),",
540                          tag.c_str(), tag.c_str(), module.shortDescription()));
541 }
542
543 void HelpExportReStructuredText::finishModuleExport()
544 {
545     indexFile_->close();
546     indexFile_.reset();
547     manPagesFile_->writeLine("    ('man/gromacs.7', 'gromacs', 'molecular dynamics simulation suite', '', 7)");
548     manPagesFile_->writeLine("]");
549     manPagesFile_->close();
550     manPagesFile_.reset();
551 }
552
553 void HelpExportReStructuredText::startModuleGroupExport()
554 {
555     indexFile_.reset(new File("programs/bytopic.rst", "w"));
556     indexFile_->writeLine("Tools by Topic");
557     indexFile_->writeLine("==============");
558     manPagesFile_.reset(new File("man/bytopic.rst", "w"));
559 }
560
561 void HelpExportReStructuredText::exportModuleGroup(
562         const char                *title,
563         const ModuleGroupContents &modules)
564 {
565     indexFile_->writeLine(title);
566     indexFile_->writeLine(std::string(std::strlen(title), '-'));
567     manPagesFile_->writeLine(title);
568     manPagesFile_->writeLine(std::string(std::strlen(title), '+'));
569
570     ModuleGroupContents::const_iterator module;
571     for (module = modules.begin(); module != modules.end(); ++module)
572     {
573         const std::string     &tag(module->first);
574         std::string            displayName(tag);
575         // TODO: This does not work if the binary name would contain a dash,
576         // but that is not currently the case.
577         const size_t           dashPos = displayName.find('-');
578         GMX_RELEASE_ASSERT(dashPos != std::string::npos,
579                            "There should always be at least one dash in the tag");
580         displayName[dashPos] = ' ';
581         indexFile_->writeLine(formatString("| :doc:`%s <%s>` - %s",
582                                            displayName.c_str(), tag.c_str(),
583                                            module->second));
584         manPagesFile_->writeLine(formatString("| ``%s`` - %s",
585                                               displayName.c_str(),
586                                               module->second));
587     }
588     indexFile_->writeLine();
589     manPagesFile_->writeLine();
590 }
591
592 void HelpExportReStructuredText::finishModuleGroupExport()
593 {
594     indexFile_->close();
595     indexFile_.reset();
596     manPagesFile_->close();
597     manPagesFile_.reset();
598 }
599
600 /********************************************************************
601  * HelpExportCompletion
602  */
603
604 /*! \internal \brief
605  * Implements export for command-line completion.
606  *
607  * \ingroup module_commandline
608  */
609 class HelpExportCompletion : public HelpExportInterface
610 {
611     public:
612         //! Initializes completion exporter.
613         explicit HelpExportCompletion(const CommandLineHelpModuleImpl &helpModule);
614
615         virtual void startModuleExport();
616         virtual void exportModuleHelp(
617             const CommandLineModuleInterface &module,
618             const std::string                &tag,
619             const std::string                &displayName);
620         virtual void finishModuleExport();
621
622         virtual void startModuleGroupExport() {}
623         virtual void exportModuleGroup(const char                * /*title*/,
624                                        const ModuleGroupContents & /*modules*/) {}
625         virtual void finishModuleGroupExport() {}
626
627     private:
628         ShellCompletionWriter    bashWriter_;
629         std::vector<std::string> modules_;
630 };
631
632 HelpExportCompletion::HelpExportCompletion(
633         const CommandLineHelpModuleImpl &helpModule)
634     : bashWriter_(helpModule.binaryName_, eShellCompletionFormat_Bash)
635 {
636 }
637
638 void HelpExportCompletion::startModuleExport()
639 {
640     bashWriter_.startCompletions();
641 }
642
643 void HelpExportCompletion::exportModuleHelp(
644         const CommandLineModuleInterface &module,
645         const std::string                 & /*tag*/,
646         const std::string                 & /*displayName*/)
647 {
648     modules_.push_back(module.name());
649     {
650         CommandLineHelpContext context(&bashWriter_);
651         // We use the display name to pass the name of the module to the
652         // completion writer.
653         context.setModuleDisplayName(module.name());
654         module.writeHelp(context);
655     }
656 }
657
658 void HelpExportCompletion::finishModuleExport()
659 {
660     CommandLineCommonOptionsHolder optionsHolder;
661     optionsHolder.initOptions();
662     bashWriter_.writeWrapperCompletions(modules_, *optionsHolder.options());
663     bashWriter_.finishCompletions();
664 }
665
666 }   // namespace
667
668 /********************************************************************
669  * CommandLineHelpModuleImpl implementation
670  */
671 CommandLineHelpModuleImpl::CommandLineHelpModuleImpl(
672         const ProgramContextInterface    &programContext,
673         const std::string                &binaryName,
674         const CommandLineModuleMap       &modules,
675         const CommandLineModuleGroupList &groups)
676     : rootTopic_(new RootHelpTopic(*this)), programContext_(programContext),
677       binaryName_(binaryName), modules_(modules), groups_(groups),
678       context_(NULL), moduleOverride_(NULL), bHidden_(false),
679       outputOverride_(NULL)
680 {
681 }
682
683 void CommandLineHelpModuleImpl::exportHelp(HelpExportInterface *exporter) const
684 {
685     // TODO: Would be nicer to have the file names supplied by the build system
686     // and/or export a list of files from here.
687     const char *const program = binaryName_.c_str();
688
689     exporter->startModuleExport();
690     CommandLineModuleMap::const_iterator module;
691     for (module = modules_.begin(); module != modules_.end(); ++module)
692     {
693         if (module->second->shortDescription() != NULL)
694         {
695             const char *const moduleName = module->first.c_str();
696             std::string       tag(formatString("%s-%s", program, moduleName));
697             std::string       displayName(formatString("%s %s", program, moduleName));
698             exporter->exportModuleHelp(*module->second, tag, displayName);
699         }
700     }
701     exporter->finishModuleExport();
702
703     exporter->startModuleGroupExport();
704     CommandLineModuleGroupList::const_iterator group;
705     for (group = groups_.begin(); group != groups_.end(); ++group)
706     {
707         exporter->exportModuleGroup((*group)->title(), (*group)->modules());
708     }
709     exporter->finishModuleGroupExport();
710 }
711
712 /********************************************************************
713  * CommandLineHelpModule
714  */
715
716 CommandLineHelpModule::CommandLineHelpModule(
717         const ProgramContextInterface    &programContext,
718         const std::string                &binaryName,
719         const CommandLineModuleMap       &modules,
720         const CommandLineModuleGroupList &groups)
721     : impl_(new Impl(programContext, binaryName, modules, groups))
722 {
723 }
724
725 CommandLineHelpModule::~CommandLineHelpModule()
726 {
727 }
728
729 HelpTopicPointer CommandLineHelpModule::createModuleHelpTopic(
730         const CommandLineModuleInterface &module) const
731 {
732     return HelpTopicPointer(new ModuleHelpTopic(module, *impl_));
733 }
734
735 void CommandLineHelpModule::addTopic(HelpTopicPointer topic)
736 {
737     impl_->rootTopic_->addSubTopic(move(topic));
738 }
739
740 void CommandLineHelpModule::setShowHidden(bool bHidden)
741 {
742     impl_->bHidden_ = bHidden;
743 }
744
745 void CommandLineHelpModule::setModuleOverride(
746         const CommandLineModuleInterface &module)
747 {
748     impl_->moduleOverride_ = &module;
749 }
750
751 void CommandLineHelpModule::setOutputRedirect(File *output)
752 {
753     impl_->outputOverride_ = output;
754 }
755
756 int CommandLineHelpModule::run(int argc, char *argv[])
757 {
758     // Add internal topics lazily here.
759     addTopic(HelpTopicPointer(new CommandsHelpTopic(*impl_)));
760
761     const char *const exportFormats[] = { "html", "rst", "completion" };
762     std::string       exportFormat;
763     Options           options(NULL, NULL);
764     options.addOption(StringOption("export").store(&exportFormat)
765                           .enumValue(exportFormats));
766     CommandLineParser(&options).parse(&argc, argv);
767     if (!exportFormat.empty())
768     {
769         boost::scoped_ptr<HelpExportInterface> exporter;
770         if (exportFormat == "html")
771         {
772             exporter.reset(new HelpExportHtml());
773         }
774         else if (exportFormat == "rst")
775         {
776             exporter.reset(new HelpExportReStructuredText(*impl_));
777         }
778         else if (exportFormat == "completion")
779         {
780             exporter.reset(new HelpExportCompletion(*impl_));
781         }
782         else
783         {
784             GMX_THROW(NotImplementedError("This help format is not implemented"));
785         }
786         impl_->exportHelp(exporter.get());
787         return 0;
788     }
789
790     File *outputFile = &File::standardOutput();
791     if (impl_->outputOverride_ != NULL)
792     {
793         outputFile = impl_->outputOverride_;
794     }
795     HelpLinks                                 links(eHelpOutputFormat_Console);
796     initProgramLinks(&links, *impl_);
797     boost::scoped_ptr<CommandLineHelpContext> context(
798             new CommandLineHelpContext(outputFile,
799                                        eHelpOutputFormat_Console, &links));
800     context->setShowHidden(impl_->bHidden_);
801     if (impl_->moduleOverride_ != NULL)
802     {
803         context->setModuleDisplayName(impl_->programContext_.displayName());
804         impl_->moduleOverride_->writeHelp(*context);
805         return 0;
806     }
807     impl_->context_ = context.get();
808
809     HelpManager helpManager(*impl_->rootTopic_, context->writerContext());
810     try
811     {
812         for (int i = 1; i < argc; ++i)
813         {
814             helpManager.enterTopic(argv[i]);
815         }
816     }
817     catch (const InvalidInputError &ex)
818     {
819         fprintf(stderr, "%s\n", ex.what());
820         return 2;
821     }
822     helpManager.writeCurrentTopic();
823     return 0;
824 }
825
826 void CommandLineHelpModule::writeHelp(const CommandLineHelpContext &context) const
827 {
828     const HelpWriterContext &writerContext = context.writerContext();
829     // TODO: Implement.
830     if (writerContext.outputFormat() != eHelpOutputFormat_Console)
831     {
832         return;
833     }
834     writerContext.writeTextBlock(
835             "Usage: [PROGRAM] help [<command>|<topic> [<subtopic> [...]]]");
836     // TODO: More information.
837 }
838
839 } // namespace gmx