Merge remote-tracking branch 'origin/release-4-6' into HEAD
[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/stringutil.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             || (option.valueCount() == 1 && option.formatValue(0).empty()))
155         {
156             value = option.formatDefaultValueIfSet();
157         }
158         else
159         {
160             value = option.formatValue(i);
161         }
162         formatter_.addColumnLine(1, value);
163         if (value.length() > 12U && i == firstShortValue)
164         {
165             firstShortValue = i + 1;
166         }
167         if (value.length() > 25U)
168         {
169             if (firstLongValue == -1)
170             {
171                 firstLongValue = i;
172             }
173             lastLongValue = i;
174         }
175     }
176     std::string type;
177     if (option.isInputOutputFile())
178     {
179         type = "In/Out";
180     }
181     else if (option.isInputFile())
182     {
183         type = "Input";
184     }
185     else if (option.isOutputFile())
186     {
187         type = "Output";
188     }
189     if (!option.isRequired())
190     {
191         type += ", Opt.";
192     }
193     if (option.isLibraryFile())
194     {
195         type += ", Lib.";
196     }
197     bool bLongType = (type.length() > 12U);
198     formatter_.addColumnLine(2, type);
199     formatter_.addColumnLine(3, substituteMarkupForConsole(option.description()));
200
201     // Compute layout.
202     if (name.length() > 6U || firstShortValue > 0)
203     {
204         formatter_.setColumnFirstLineOffset(1, 1);
205         // Assume that the name is <20 chars, so that the type fits
206         if (firstLongValue >= 0)
207         {
208             ++firstLongValue;
209             ++lastLongValue;
210         }
211     }
212     int firstDescriptionLine = 0;
213     if (bLongType)
214     {
215         firstDescriptionLine = 1;
216     }
217     formatter_.setColumnFirstLineOffset(3, firstDescriptionLine);
218     if (firstLongValue >= 0 && formatter_.lastColumnLine(3) >= firstLongValue)
219     {
220         firstDescriptionLine = lastLongValue + 1;
221         formatter_.setColumnFirstLineOffset(3, firstDescriptionLine);
222     }
223
224     // Do the formatting.
225     file_.writeString(formatter_.formatRow());
226 }
227
228
229 /********************************************************************
230  * ParameterWriter
231  */
232
233 /*! \internal \brief
234  * Helper object for writing help for non-file parameters.
235  *
236  * \ingroup module_commandline
237  */
238 class ParameterWriter : public OptionsVisitor
239 {
240     public:
241         //! Creates a helper object for writing non-file parameters.
242         ParameterWriter(File *file, const char *timeUnit);
243
244         //! Sets the writer to show hidden options.
245         void setShowHidden(bool bSet) { bShowHidden_ = bSet; }
246         //! Returns true if anything was written out.
247         bool didOutput() const { return formatter_.didOutput(); }
248
249         virtual void visitSubSection(const Options &section);
250         virtual void visitOption(const OptionInfo &option);
251
252     private:
253         File                   &file_;
254         TextTableFormatter      formatter_;
255         const char             *timeUnit_;
256         bool                    bShowHidden_;
257 };
258
259 ParameterWriter::ParameterWriter(File *file, const char *timeUnit)
260     : file_(*file), timeUnit_(timeUnit), bShowHidden_(false)
261 {
262     formatter_.addColumn("Option",      12, false);
263     formatter_.addColumn("Type",         6, false);
264     formatter_.addColumn("Value",        6, false);
265     formatter_.addColumn("Description", 51, true);
266 }
267
268 void ParameterWriter::visitSubSection(const Options &section)
269 {
270     OptionsIterator iterator(section);
271     iterator.acceptSubSections(this);
272     iterator.acceptOptions(this);
273 }
274
275 void ParameterWriter::visitOption(const OptionInfo &option)
276 {
277     if (option.isType<FileNameOptionInfo>()
278         || option.isType<SelectionFileOptionInfo>()
279         || option.isType<SelectionOptionInfo>()
280         || (!bShowHidden_ && option.isHidden()))
281     {
282         return;
283     }
284
285     formatter_.clear();
286     bool bIsBool = option.isType<BooleanOptionInfo>();
287     std::string name(formatString("-%s%s", bIsBool ? "[no]" : "",
288                                            option.name().c_str()));
289     formatter_.addColumnLine(0, name);
290     formatter_.addColumnLine(1, option.type());
291     if (name.length() > 12U)
292     {
293         formatter_.setColumnFirstLineOffset(1, 1);
294     }
295     // TODO: Better handling of multiple long values
296     std::string values;
297     for (int i = 0; i < option.valueCount(); ++i)
298     {
299         if (i != 0)
300         {
301             values.append(" ");
302         }
303         values.append(option.formatValue(i));
304     }
305     formatter_.addColumnLine(2, values);
306     std::string description(substituteMarkupForConsole(option.description()));
307     const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
308     if (doubleOption != NULL && doubleOption->isTime())
309     {
310         description = replaceAll(description, "%t", timeUnit_);
311     }
312     formatter_.addColumnLine(3, description);
313     if (values.length() > 6U)
314     {
315         formatter_.setColumnFirstLineOffset(3, 1);
316     }
317
318     file_.writeString(formatter_.formatRow());
319 }
320
321
322 /********************************************************************
323  * SelectionParameterWriter
324  */
325
326 /*! \internal \brief
327  * Helper object for writing help for selection parameters.
328  *
329  * \ingroup module_commandline
330  */
331 class SelectionParameterWriter : public OptionsVisitor
332 {
333     public:
334         //! Creates a helper object for writing selection parameters.
335         explicit SelectionParameterWriter(File *file);
336
337         //! Returns true if anything was written out.
338         bool didOutput() const { return formatter_.didOutput(); }
339
340         virtual void visitSubSection(const Options &section);
341         virtual void visitOption(const OptionInfo &option);
342
343     private:
344         File                   &file_;
345         TextTableFormatter      formatter_;
346 };
347
348 SelectionParameterWriter::SelectionParameterWriter(File *file)
349     : file_(*file)
350 {
351     formatter_.addColumn("Selection",   10, false);
352     formatter_.addColumn("Description", 67, true);
353 }
354
355 void SelectionParameterWriter::visitSubSection(const Options &section)
356 {
357     OptionsIterator iterator(section);
358     iterator.acceptSubSections(this);
359     iterator.acceptOptions(this);
360 }
361
362 void SelectionParameterWriter::visitOption(const OptionInfo &option)
363 {
364     if (!option.isType<SelectionFileOptionInfo>()
365         && !option.isType<SelectionOptionInfo>())
366     {
367         return;
368     }
369
370     formatter_.clear();
371     std::string name(formatString("-%s", option.name().c_str()));
372     formatter_.addColumnLine(0, name);
373     formatter_.addColumnLine(1, substituteMarkupForConsole(option.description()));
374     file_.writeString(formatter_.formatRow());
375
376     // TODO: What to do with selection variables?
377     // They are not printed as values for any option.
378     for (int i = 0; i < option.valueCount(); ++i)
379     {
380         std::string value(option.formatValue(i));
381         // TODO: Wrapping
382         file_.writeLine(formatString("    %s", value.c_str()));
383     }
384 }
385
386 } // namespace
387
388 /********************************************************************
389  * CommandLineHelpWriter::Impl
390  */
391
392 /*! \internal \brief
393  * Private implementation class for CommandLineHelpWriter.
394  *
395  * \ingroup module_commandline
396  */
397 class CommandLineHelpWriter::Impl
398 {
399     public:
400         //! Sets the Options object to use for generating help.
401         explicit Impl(const Options &options);
402
403         //! Options object to use for generating help.
404         const Options          &options_;
405         //! Time unit to show in descriptions.
406         std::string             timeUnit_;
407         //! Whether to write descriptions to output.
408         bool                    bShowDescriptions_;
409         //! Whether to write hidden options to output.
410         bool                    bShowHidden_;
411 };
412
413 CommandLineHelpWriter::Impl::Impl(const Options &options)
414     : options_(options), timeUnit_(TimeUnitManager().timeUnitAsString()),
415       bShowDescriptions_(false), bShowHidden_(false)
416 {
417 }
418
419 /********************************************************************
420  * CommandLineHelpWriter
421  */
422
423 CommandLineHelpWriter::CommandLineHelpWriter(const Options &options)
424     : impl_(new Impl(options))
425 {
426 }
427
428 CommandLineHelpWriter::~CommandLineHelpWriter()
429 {
430 }
431
432 CommandLineHelpWriter &CommandLineHelpWriter::setShowHidden(bool bSet)
433 {
434     impl_->bShowHidden_ = bSet;
435     return *this;
436 }
437
438 CommandLineHelpWriter &CommandLineHelpWriter::setShowDescriptions(bool bSet)
439 {
440     impl_->bShowDescriptions_ = bSet;
441     return *this;
442 }
443
444 CommandLineHelpWriter &CommandLineHelpWriter::setTimeUnitString(const char *timeUnit)
445 {
446     impl_->timeUnit_ = timeUnit;
447     return *this;
448 }
449
450 void CommandLineHelpWriter::writeHelp(File *file)
451 {
452     if (impl_->bShowDescriptions_)
453     {
454         file->writeLine("DESCRIPTION");
455         file->writeLine("-----------");
456         file->writeLine();
457         DescriptionWriter(file).visitSubSection(impl_->options_);
458     }
459     {
460         FileParameterWriter writer(file);
461         writer.visitSubSection(impl_->options_);
462         if (writer.didOutput())
463         {
464             file->writeLine();
465         }
466     }
467     {
468         ParameterWriter writer(file, impl_->timeUnit_.c_str());
469         writer.setShowHidden(impl_->bShowHidden_);
470         writer.visitSubSection(impl_->options_);
471         if (writer.didOutput())
472         {
473             file->writeLine();
474         }
475     }
476     {
477         SelectionParameterWriter writer(file);
478         writer.visitSubSection(impl_->options_);
479         if (writer.didOutput())
480         {
481             file->writeLine();
482         }
483     }
484 }
485
486 } // namespace gmx