Merge remote-tracking branch 'origin/release-4-6'
[alexxy/gromacs.git] / src / gromacs / commandline / cmdlinehelpwriter.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief
33  * Implements gmx::CommandLineHelpWriter.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_commandline
37  */
38 #include "cmdlinehelpwriter.h"
39
40 #include <string>
41
42 #include "gromacs/onlinehelp/helpformat.h"
43 #include "gromacs/options/basicoptioninfo.h"
44 #include "gromacs/options/filenameoptioninfo.h"
45 #include "gromacs/options/options.h"
46 #include "gromacs/options/optionsvisitor.h"
47 #include "gromacs/options/timeunitmanager.h"
48 #include "gromacs/selection/selectionfileoptioninfo.h"
49 #include "gromacs/selection/selectionoptioninfo.h"
50 #include "gromacs/utility/file.h"
51 #include "gromacs/utility/format.h"
52
53 namespace gmx
54 {
55
56 namespace
57 {
58
59 /********************************************************************
60  * DescriptionWriter
61  */
62
63 /*! \internal \brief
64  * Helper object for writing section descriptions to help.
65  *
66  * \ingroup module_commandline
67  */
68 class DescriptionWriter : public OptionsVisitor
69 {
70     public:
71         //! Creates a helper object for writing section descriptions.
72         explicit DescriptionWriter(File *file) : file_(*file) {}
73
74         virtual void visitSubSection(const Options &section);
75         virtual void visitOption(const OptionInfo & /*option*/) { }
76
77     private:
78         File                   &file_;
79 };
80
81 void DescriptionWriter::visitSubSection(const Options &section)
82 {
83     if (!section.description().empty())
84     {
85         const std::string &title = section.title();
86         if (!title.empty())
87         {
88             file_.writeLine(title);
89             file_.writeLine();
90         }
91         writeHelpTextForConsole(&file_, section.description());
92         file_.writeLine();
93     }
94     OptionsIterator(section).acceptSubSections(this);
95 }
96
97
98 /********************************************************************
99  * FileParameterWriter
100  */
101
102 /*! \internal \brief
103  * Helper object for writing help for file parameters.
104  *
105  * \ingroup module_commandline
106  */
107 class FileParameterWriter : public OptionsTypeVisitor<FileNameOptionInfo>
108 {
109     public:
110         //! Creates a helper object for writing file parameters.
111         explicit FileParameterWriter(File *file);
112
113         //! Returns true if anything was written out.
114         bool didOutput() const { return formatter_.didOutput(); }
115
116         virtual void visitSubSection(const Options &section);
117         virtual void visitOptionType(const FileNameOptionInfo &option);
118
119     private:
120         File                   &file_;
121         TextTableFormatter      formatter_;
122 };
123
124 FileParameterWriter::FileParameterWriter(File *file)
125     : file_(*file)
126 {
127     formatter_.addColumn("Option",      6, false);
128     formatter_.addColumn("Filename",    12, false);
129     formatter_.addColumn("Type",        12, false);
130     formatter_.addColumn("Description", 45, true);
131 }
132
133 void FileParameterWriter::visitSubSection(const Options &section)
134 {
135     OptionsIterator iterator(section);
136     iterator.acceptSubSections(this);
137     iterator.acceptOptions(this);
138 }
139
140 void FileParameterWriter::visitOptionType(const FileNameOptionInfo &option)
141 {
142     int firstShortValue = 0; // The first value after which the type fits.
143     int firstLongValue = -1; // First value that overlaps description column.
144     int lastLongValue = -1;  // Last value like the above.
145
146     // Get the values to write and check where text overflows the columns.
147     formatter_.clear();
148     std::string name(formatString("-%s", option.name().c_str()));
149     formatter_.addColumnLine(0, name);
150     for (int i = 0; i < option.valueCount() || i == 0; ++i)
151     {
152         std::string value;
153         if (option.valueCount() == 0)
154         {
155             value = option.formatDefaultValueIfSet();
156         }
157         else
158         {
159             value = option.formatValue(i);
160         }
161         formatter_.addColumnLine(1, value);
162         if (value.length() > 12U && i == firstShortValue)
163         {
164             firstShortValue = i + 1;
165         }
166         if (value.length() > 25U)
167         {
168             if (firstLongValue == -1)
169             {
170                 firstLongValue = i;
171             }
172             lastLongValue = i;
173         }
174     }
175     std::string type;
176     if (option.isInputOutputFile())
177     {
178         type = "In/Out";
179     }
180     else if (option.isInputFile())
181     {
182         type = "Input";
183     }
184     else if (option.isOutputFile())
185     {
186         type = "Output";
187     }
188     if (!option.isRequired())
189     {
190         type += ", Opt.";
191     }
192     if (option.isLibraryFile())
193     {
194         type += ", Lib.";
195     }
196     bool bLongType = (type.length() > 12U);
197     formatter_.addColumnLine(2, type);
198     formatter_.addColumnLine(3, substituteMarkupForConsole(option.description()));
199
200     // Compute layout.
201     if (name.length() > 6U || firstShortValue > 0)
202     {
203         formatter_.setColumnFirstLineOffset(1, 1);
204         // Assume that the name is <20 chars, so that the type fits
205         if (firstLongValue >= 0)
206         {
207             ++firstLongValue;
208             ++lastLongValue;
209         }
210     }
211     int firstDescriptionLine = 0;
212     if (bLongType)
213     {
214         firstDescriptionLine = 1;
215     }
216     formatter_.setColumnFirstLineOffset(3, firstDescriptionLine);
217     if (firstLongValue >= 0 && formatter_.lastColumnLine(3) >= firstLongValue)
218     {
219         firstDescriptionLine = lastLongValue + 1;
220         formatter_.setColumnFirstLineOffset(3, firstDescriptionLine);
221     }
222
223     // Do the formatting.
224     file_.writeString(formatter_.formatRow());
225 }
226
227
228 /********************************************************************
229  * ParameterWriter
230  */
231
232 /*! \internal \brief
233  * Helper object for writing help for non-file parameters.
234  *
235  * \ingroup module_commandline
236  */
237 class ParameterWriter : public OptionsVisitor
238 {
239     public:
240         //! Creates a helper object for writing non-file parameters.
241         ParameterWriter(File *file, const char *timeUnit);
242
243         //! Sets the writer to show hidden options.
244         void setShowHidden(bool bSet) { bShowHidden_ = bSet; }
245         //! Returns true if anything was written out.
246         bool didOutput() const { return formatter_.didOutput(); }
247
248         virtual void visitSubSection(const Options &section);
249         virtual void visitOption(const OptionInfo &option);
250
251     private:
252         File                   &file_;
253         TextTableFormatter      formatter_;
254         const char             *timeUnit_;
255         bool                    bShowHidden_;
256 };
257
258 ParameterWriter::ParameterWriter(File *file, const char *timeUnit)
259     : file_(*file), timeUnit_(timeUnit), bShowHidden_(false)
260 {
261     formatter_.addColumn("Option",      12, false);
262     formatter_.addColumn("Type",         6, false);
263     formatter_.addColumn("Value",        6, false);
264     formatter_.addColumn("Description", 51, true);
265 }
266
267 void ParameterWriter::visitSubSection(const Options &section)
268 {
269     OptionsIterator iterator(section);
270     iterator.acceptSubSections(this);
271     iterator.acceptOptions(this);
272 }
273
274 void ParameterWriter::visitOption(const OptionInfo &option)
275 {
276     if (option.isType<FileNameOptionInfo>()
277         || option.isType<SelectionFileOptionInfo>()
278         || option.isType<SelectionOptionInfo>()
279         || (!bShowHidden_ && option.isHidden()))
280     {
281         return;
282     }
283
284     formatter_.clear();
285     bool bIsBool = option.isType<BooleanOptionInfo>();
286     std::string name(formatString("-%s%s", bIsBool ? "[no]" : "",
287                                            option.name().c_str()));
288     formatter_.addColumnLine(0, name);
289     formatter_.addColumnLine(1, option.type());
290     if (name.length() > 12U)
291     {
292         formatter_.setColumnFirstLineOffset(1, 1);
293     }
294     // TODO: Better handling of multiple long values
295     std::string values;
296     for (int i = 0; i < option.valueCount(); ++i)
297     {
298         if (i != 0)
299         {
300             values.append(" ");
301         }
302         values.append(option.formatValue(i));
303     }
304     formatter_.addColumnLine(2, values);
305     std::string description(substituteMarkupForConsole(option.description()));
306     const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
307     if (doubleOption != NULL && doubleOption->isTime())
308     {
309         description = replaceAll(description, "%t", timeUnit_);
310     }
311     formatter_.addColumnLine(3, description);
312     if (values.length() > 6U)
313     {
314         formatter_.setColumnFirstLineOffset(3, 1);
315     }
316
317     file_.writeString(formatter_.formatRow());
318 }
319
320
321 /********************************************************************
322  * SelectionParameterWriter
323  */
324
325 /*! \internal \brief
326  * Helper object for writing help for selection parameters.
327  *
328  * \ingroup module_commandline
329  */
330 class SelectionParameterWriter : public OptionsVisitor
331 {
332     public:
333         //! Creates a helper object for writing selection parameters.
334         explicit SelectionParameterWriter(File *file);
335
336         //! Returns true if anything was written out.
337         bool didOutput() const { return formatter_.didOutput(); }
338
339         virtual void visitSubSection(const Options &section);
340         virtual void visitOption(const OptionInfo &option);
341
342     private:
343         File                   &file_;
344         TextTableFormatter      formatter_;
345 };
346
347 SelectionParameterWriter::SelectionParameterWriter(File *file)
348     : file_(*file)
349 {
350     formatter_.addColumn("Selection",   10, false);
351     formatter_.addColumn("Description", 67, true);
352 }
353
354 void SelectionParameterWriter::visitSubSection(const Options &section)
355 {
356     OptionsIterator iterator(section);
357     iterator.acceptSubSections(this);
358     iterator.acceptOptions(this);
359 }
360
361 void SelectionParameterWriter::visitOption(const OptionInfo &option)
362 {
363     if (!option.isType<SelectionFileOptionInfo>()
364         && !option.isType<SelectionOptionInfo>())
365     {
366         return;
367     }
368
369     formatter_.clear();
370     std::string name(formatString("-%s", option.name().c_str()));
371     formatter_.addColumnLine(0, name);
372     formatter_.addColumnLine(1, substituteMarkupForConsole(option.description()));
373     file_.writeString(formatter_.formatRow());
374
375     // TODO: What to do with selection variables?
376     // They are not printed as values for any option.
377     for (int i = 0; i < option.valueCount(); ++i)
378     {
379         std::string value(option.formatValue(i));
380         // TODO: Wrapping
381         file_.writeLine(formatString("    %s", value.c_str()));
382     }
383 }
384
385 } // namespace
386
387 /********************************************************************
388  * CommandLineHelpWriter::Impl
389  */
390
391 /*! \internal \brief
392  * Private implementation class for CommandLineHelpWriter.
393  *
394  * \ingroup module_commandline
395  */
396 class CommandLineHelpWriter::Impl
397 {
398     public:
399         //! Sets the Options object to use for generating help.
400         explicit Impl(const Options &options);
401
402         //! Options object to use for generating help.
403         const Options          &options_;
404         //! Time unit to show in descriptions.
405         std::string             timeUnit_;
406         //! Whether to write descriptions to output.
407         bool                    bShowDescriptions_;
408         //! Whether to write hidden options to output.
409         bool                    bShowHidden_;
410 };
411
412 CommandLineHelpWriter::Impl::Impl(const Options &options)
413     : options_(options), timeUnit_(TimeUnitManager().timeUnitAsString()),
414       bShowDescriptions_(false), bShowHidden_(false)
415 {
416 }
417
418 /********************************************************************
419  * CommandLineHelpWriter
420  */
421
422 CommandLineHelpWriter::CommandLineHelpWriter(const Options &options)
423     : impl_(new Impl(options))
424 {
425 }
426
427 CommandLineHelpWriter::~CommandLineHelpWriter()
428 {
429 }
430
431 CommandLineHelpWriter &CommandLineHelpWriter::setShowHidden(bool bSet)
432 {
433     impl_->bShowHidden_ = bSet;
434     return *this;
435 }
436
437 CommandLineHelpWriter &CommandLineHelpWriter::setShowDescriptions(bool bSet)
438 {
439     impl_->bShowDescriptions_ = bSet;
440     return *this;
441 }
442
443 CommandLineHelpWriter &CommandLineHelpWriter::setTimeUnitString(const char *timeUnit)
444 {
445     impl_->timeUnit_ = timeUnit;
446     return *this;
447 }
448
449 void CommandLineHelpWriter::writeHelp(File *file)
450 {
451     if (impl_->bShowDescriptions_)
452     {
453         file->writeLine("DESCRIPTION");
454         file->writeLine("-----------");
455         file->writeLine();
456         DescriptionWriter(file).visitSubSection(impl_->options_);
457     }
458     {
459         FileParameterWriter writer(file);
460         writer.visitSubSection(impl_->options_);
461         if (writer.didOutput())
462         {
463             file->writeLine();
464         }
465     }
466     {
467         ParameterWriter writer(file, impl_->timeUnit_.c_str());
468         writer.setShowHidden(impl_->bShowHidden_);
469         writer.visitSubSection(impl_->options_);
470         if (writer.didOutput())
471         {
472             file->writeLine();
473         }
474     }
475     {
476         SelectionParameterWriter writer(file);
477         writer.visitSubSection(impl_->options_);
478         if (writer.didOutput())
479         {
480             file->writeLine();
481         }
482     }
483 }
484
485 } // namespace gmx