Separated string formatting used only for help.
[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 #include "cmdlinehelpwriter-impl.h"
54
55 namespace gmx
56 {
57
58 namespace
59 {
60
61 /********************************************************************
62  * DescriptionWriter
63  */
64
65 /*! \internal \brief
66  * Helper object for writing section descriptions to help.
67  *
68  * \ingroup module_commandline
69  */
70 class DescriptionWriter : public OptionsVisitor
71 {
72     public:
73         //! Creates a helper object for writing section descriptions.
74         explicit DescriptionWriter(File *file) : file_(*file) {}
75
76         virtual void visitSubSection(const Options &section);
77         virtual void visitOption(const OptionInfo & /*option*/) { }
78
79     private:
80         File                   &file_;
81 };
82
83 void DescriptionWriter::visitSubSection(const Options &section)
84 {
85     if (!section.description().empty())
86     {
87         const std::string &title = section.title();
88         if (!title.empty())
89         {
90             file_.writeLine(title);
91             file_.writeLine();
92         }
93         writeHelpTextForConsole(&file_, section.description());
94         file_.writeLine();
95     }
96     OptionsIterator(section).acceptSubSections(this);
97 }
98
99
100 /********************************************************************
101  * FileParameterWriter
102  */
103
104 /*! \internal \brief
105  * Helper object for writing help for file parameters.
106  *
107  * \ingroup module_commandline
108  */
109 class FileParameterWriter : public OptionsTypeVisitor<FileNameOptionInfo>
110 {
111     public:
112         //! Creates a helper object for writing file parameters.
113         explicit FileParameterWriter(File *file);
114
115         //! Returns true if anything was written out.
116         bool didOutput() const { return formatter_.didOutput(); }
117
118         virtual void visitSubSection(const Options &section);
119         virtual void visitOptionType(const FileNameOptionInfo &option);
120
121     private:
122         File                   &file_;
123         TextTableFormatter      formatter_;
124 };
125
126 FileParameterWriter::FileParameterWriter(File *file)
127     : file_(*file)
128 {
129     formatter_.addColumn("Option",      6, false);
130     formatter_.addColumn("Filename",    12, false);
131     formatter_.addColumn("Type",        12, false);
132     formatter_.addColumn("Description", 45, true);
133 }
134
135 void FileParameterWriter::visitSubSection(const Options &section)
136 {
137     OptionsIterator iterator(section);
138     iterator.acceptSubSections(this);
139     iterator.acceptOptions(this);
140 }
141
142 void FileParameterWriter::visitOptionType(const FileNameOptionInfo &option)
143 {
144     int firstShortValue = 0; // The first value after which the type fits.
145     int firstLongValue = -1; // First value that overlaps description column.
146     int lastLongValue = -1;  // Last value like the above.
147
148     // Get the values to write and check where text overflows the columns.
149     formatter_.clear();
150     std::string name(formatString("-%s", option.name().c_str()));
151     formatter_.addColumnLine(0, name);
152     for (int i = 0; i < option.valueCount() || i == 0; ++i)
153     {
154         std::string value;
155         if (option.valueCount() == 0)
156         {
157             value = option.formatDefaultValueIfSet();
158         }
159         else
160         {
161             value = option.formatValue(i);
162         }
163         formatter_.addColumnLine(1, value);
164         if (value.length() > 12U && i == firstShortValue)
165         {
166             firstShortValue = i + 1;
167         }
168         if (value.length() > 25U)
169         {
170             if (firstLongValue == -1)
171             {
172                 firstLongValue = i;
173             }
174             lastLongValue = i;
175         }
176     }
177     std::string type;
178     if (option.isInputOutputFile())
179     {
180         type = "In/Out";
181     }
182     else if (option.isInputFile())
183     {
184         type = "Input";
185     }
186     else if (option.isOutputFile())
187     {
188         type = "Output";
189     }
190     if (!option.isRequired())
191     {
192         type += ", Opt.";
193     }
194     if (option.isLibraryFile())
195     {
196         type += ", Lib.";
197     }
198     bool bLongType = (type.length() > 12U);
199     formatter_.addColumnLine(2, type);
200     formatter_.addColumnLine(3, substituteMarkupForConsole(option.description()));
201
202     // Compute layout.
203     if (name.length() > 6U || firstShortValue > 0)
204     {
205         formatter_.setColumnFirstLineOffset(1, 1);
206         // Assume that the name is <20 chars, so that the type fits
207         if (firstLongValue >= 0)
208         {
209             ++firstLongValue;
210             ++lastLongValue;
211         }
212     }
213     int firstDescriptionLine = 0;
214     if (bLongType)
215     {
216         firstDescriptionLine = 1;
217     }
218     formatter_.setColumnFirstLineOffset(3, firstDescriptionLine);
219     if (firstLongValue >= 0 && formatter_.lastColumnLine(3) >= firstLongValue)
220     {
221         firstDescriptionLine = lastLongValue + 1;
222         formatter_.setColumnFirstLineOffset(3, firstDescriptionLine);
223     }
224
225     // Do the formatting.
226     file_.writeString(formatter_.formatRow());
227 }
228
229
230 /********************************************************************
231  * ParameterWriter
232  */
233
234 /*! \internal \brief
235  * Helper object for writing help for non-file parameters.
236  *
237  * \ingroup module_commandline
238  */
239 class ParameterWriter : public OptionsVisitor
240 {
241     public:
242         //! Creates a helper object for writing non-file parameters.
243         ParameterWriter(File *file, const char *timeUnit);
244
245         //! Sets the writer to show hidden options.
246         void setShowHidden(bool bSet) { bShowHidden_ = bSet; }
247         //! Returns true if anything was written out.
248         bool didOutput() const { return formatter_.didOutput(); }
249
250         virtual void visitSubSection(const Options &section);
251         virtual void visitOption(const OptionInfo &option);
252
253     private:
254         File                   &file_;
255         TextTableFormatter      formatter_;
256         const char             *timeUnit_;
257         bool                    bShowHidden_;
258 };
259
260 ParameterWriter::ParameterWriter(File *file, const char *timeUnit)
261     : file_(*file), timeUnit_(timeUnit), bShowHidden_(false)
262 {
263     formatter_.addColumn("Option",      12, false);
264     formatter_.addColumn("Type",         6, false);
265     formatter_.addColumn("Value",        6, false);
266     formatter_.addColumn("Description", 51, true);
267 }
268
269 void ParameterWriter::visitSubSection(const Options &section)
270 {
271     OptionsIterator iterator(section);
272     iterator.acceptSubSections(this);
273     iterator.acceptOptions(this);
274 }
275
276 void ParameterWriter::visitOption(const OptionInfo &option)
277 {
278     if (option.isType<FileNameOptionInfo>()
279         || option.isType<SelectionFileOptionInfo>()
280         || option.isType<SelectionOptionInfo>()
281         || (!bShowHidden_ && option.isHidden()))
282     {
283         return;
284     }
285
286     formatter_.clear();
287     bool bIsBool = option.isType<BooleanOptionInfo>();
288     std::string name(formatString("-%s%s", bIsBool ? "[no]" : "",
289                                            option.name().c_str()));
290     formatter_.addColumnLine(0, name);
291     formatter_.addColumnLine(1, option.type());
292     if (name.length() > 12U)
293     {
294         formatter_.setColumnFirstLineOffset(1, 1);
295     }
296     // TODO: Better handling of multiple long values
297     std::string values;
298     for (int i = 0; i < option.valueCount(); ++i)
299     {
300         if (i != 0)
301         {
302             values.append(" ");
303         }
304         values.append(option.formatValue(i));
305     }
306     formatter_.addColumnLine(2, values);
307     std::string description(substituteMarkupForConsole(option.description()));
308     const DoubleOptionInfo *doubleOption = option.toType<DoubleOptionInfo>();
309     if (doubleOption != NULL && doubleOption->isTime())
310     {
311         description = replaceAll(description, "%t", timeUnit_);
312     }
313     formatter_.addColumnLine(3, description);
314     if (values.length() > 6U)
315     {
316         formatter_.setColumnFirstLineOffset(3, 1);
317     }
318
319     file_.writeString(formatter_.formatRow());
320 }
321
322
323 /********************************************************************
324  * SelectionParameterWriter
325  */
326
327 /*! \internal \brief
328  * Helper object for writing help for selection parameters.
329  *
330  * \ingroup module_commandline
331  */
332 class SelectionParameterWriter : public OptionsVisitor
333 {
334     public:
335         //! Creates a helper object for writing selection parameters.
336         explicit SelectionParameterWriter(File *file);
337
338         //! Returns true if anything was written out.
339         bool didOutput() const { return formatter_.didOutput(); }
340
341         virtual void visitSubSection(const Options &section);
342         virtual void visitOption(const OptionInfo &option);
343
344     private:
345         File                   &file_;
346         TextTableFormatter      formatter_;
347 };
348
349 SelectionParameterWriter::SelectionParameterWriter(File *file)
350     : file_(*file)
351 {
352     formatter_.addColumn("Selection",   10, false);
353     formatter_.addColumn("Description", 67, true);
354 }
355
356 void SelectionParameterWriter::visitSubSection(const Options &section)
357 {
358     OptionsIterator iterator(section);
359     iterator.acceptSubSections(this);
360     iterator.acceptOptions(this);
361 }
362
363 void SelectionParameterWriter::visitOption(const OptionInfo &option)
364 {
365     if (!option.isType<SelectionFileOptionInfo>()
366         && !option.isType<SelectionOptionInfo>())
367     {
368         return;
369     }
370
371     formatter_.clear();
372     std::string name(formatString("-%s", option.name().c_str()));
373     formatter_.addColumnLine(0, name);
374     formatter_.addColumnLine(1, substituteMarkupForConsole(option.description()));
375     file_.writeString(formatter_.formatRow());
376
377     // TODO: What to do with selection variables?
378     // They are not printed as values for any option.
379     for (int i = 0; i < option.valueCount(); ++i)
380     {
381         std::string value(option.formatValue(i));
382         // TODO: Wrapping
383         file_.writeLine(formatString("    %s", value.c_str()));
384     }
385 }
386
387 } // namespace
388
389 /********************************************************************
390  * CommandLineHelpWriter::Impl
391  */
392
393 CommandLineHelpWriter::Impl::Impl(const Options &options)
394     : options_(options), timeUnit_(TimeUnitManager().timeUnitAsString()),
395       bShowDescriptions_(false), bShowHidden_(false)
396 {
397 }
398
399 /********************************************************************
400  * CommandLineHelpWriter
401  */
402
403 CommandLineHelpWriter::CommandLineHelpWriter(const Options &options)
404     : impl_(new Impl(options))
405 {
406 }
407
408 CommandLineHelpWriter::~CommandLineHelpWriter()
409 {
410 }
411
412 CommandLineHelpWriter &CommandLineHelpWriter::setShowHidden(bool bSet)
413 {
414     impl_->bShowHidden_ = bSet;
415     return *this;
416 }
417
418 CommandLineHelpWriter &CommandLineHelpWriter::setShowDescriptions(bool bSet)
419 {
420     impl_->bShowDescriptions_ = bSet;
421     return *this;
422 }
423
424 CommandLineHelpWriter &CommandLineHelpWriter::setTimeUnitString(const char *timeUnit)
425 {
426     impl_->timeUnit_ = timeUnit;
427     return *this;
428 }
429
430 void CommandLineHelpWriter::writeHelp(File *file)
431 {
432     if (impl_->bShowDescriptions_)
433     {
434         file->writeLine("DESCRIPTION");
435         file->writeLine("-----------");
436         file->writeLine();
437         DescriptionWriter(file).visitSubSection(impl_->options_);
438     }
439     {
440         FileParameterWriter writer(file);
441         writer.visitSubSection(impl_->options_);
442         if (writer.didOutput())
443         {
444             file->writeLine();
445         }
446     }
447     {
448         ParameterWriter writer(file, impl_->timeUnit_.c_str());
449         writer.setShowHidden(impl_->bShowHidden_);
450         writer.visitSubSection(impl_->options_);
451         if (writer.didOutput())
452         {
453             file->writeLine();
454         }
455     }
456     {
457         SelectionParameterWriter writer(file);
458         writer.visitSubSection(impl_->options_);
459         if (writer.didOutput())
460         {
461             file->writeLine();
462         }
463     }
464 }
465
466 } // namespace gmx