1 /**
2  * @file bindings/cli/print_help.cpp
3  * @author Matthew Amidon
4  * @author Ryan Curtin
5  *
6  * Print help for a given function.
7  *
8  * mlpack is free software; you may redistribute it and/or modify it under the
9  * terms of the 3-clause BSD license.  You should have received a copy of the
10  * 3-clause BSD license along with mlpack.  If not, see
11  * http://www.opensource.org/licenses/BSD-3-Clause for more information.
12  */
13 #include "print_help.hpp"
14 
15 #include <mlpack/core.hpp>
16 #include <mlpack/core/util/hyphenate_string.hpp>
17 
18 namespace mlpack {
19 namespace bindings {
20 namespace cli {
21 
22 /* Prints the descriptions of the current hierarchy. */
PrintHelp(const std::string & param)23 void PrintHelp(const std::string& param)
24 {
25   std::string usedParam = param;
26   std::map<std::string, util::ParamData>& parameters = IO::Parameters();
27   const std::map<char, std::string>& aliases = IO::Aliases();
28   util::BindingDetails& bindingDetails = IO::GetSingleton().doc;
29   // If we pass a single param, alias it if necessary.
30   if (usedParam.length() == 1 && aliases.count(usedParam[0]))
31     usedParam = aliases.at(usedParam[0]);
32 
33   // Do we only want to print out one value?
34   if (usedParam != "" && parameters.count(usedParam))
35   {
36     util::ParamData& data = parameters.at(usedParam);
37     std::string alias = (data.alias != '\0') ? " (-"
38         + std::string(1, data.alias) + ")" : "";
39 
40     // Figure out the name of the type.
41     std::string printableType;
42     IO::GetSingleton().functionMap[data.tname]["StringTypeParam"](data, NULL,
43         (void*) &printableType);
44     std::string type = " [" + printableType + "]";
45 
46     // Now, print the descriptions.
47     std::string fullDesc = "  --" + usedParam + alias + type + "  ";
48 
49     if (fullDesc.length() <= 32) // It all fits on one line.
50       std::cout << fullDesc << std::string(32 - fullDesc.length(), ' ');
51     else // We need multiple lines.
52       std::cout << fullDesc << std::endl << std::string(32, ' ');
53 
54     std::cout << util::HyphenateString(data.desc, 32) << std::endl;
55     return;
56   }
57   else if (usedParam != "")
58   {
59     // User passed a single variable, but it doesn't exist.
60     std::cerr << "Parameter --" << usedParam << " does not exist."
61         << std::endl;
62     exit(1); // Nothing left to do.
63   }
64 
65   // Print out the descriptions.
66   if (bindingDetails.programName != "")
67   {
68     std::cout << bindingDetails.programName << std::endl << std::endl;
69     std::cout << "  " << util::HyphenateString(bindingDetails.longDescription(),
70         2) << std::endl << std::endl;
71     for (size_t j = 0; j < bindingDetails.example.size(); ++j)
72     {
73       std::cout << "  " << util::HyphenateString(bindingDetails.example[j](), 2)
74           << std::endl << std::endl;
75     }
76   }
77   else
78     std::cout << "[undocumented program]" << std::endl << std::endl;
79 
80   for (size_t pass = 0; pass < 3; ++pass)
81   {
82     bool printedHeader = false;
83     // Print out the descriptions of everything else.
84     for (auto& iter : parameters)
85     {
86       util::ParamData& data = iter.second;
87       const std::string key;
88       IO::GetSingleton().functionMap[data.tname]["MapParameterName"](data,
89           NULL, (void*) &key);
90 
91       std::string desc = data.desc;
92       std::string alias = (iter.second.alias != '\0') ?
93           std::string(1, iter.second.alias) : "";
94       alias = alias.length() ? " (-" + alias + ")" : alias;
95 
96       // Filter un-printed options.
97       if ((pass == 0) && !(data.required && data.input)) // Required input.
98         continue;
99       if ((pass == 1) && !(!data.required && data.input)) // Optional input.
100         continue;
101       if ((pass == 2) && data.input) // Output options only (always optional).
102         continue;
103 
104       // For reverse compatibility: this can be removed when these options are
105       // gone in mlpack 3.0.0.  We don't want to print the deprecated options.
106       if (data.name == "inputFile")
107         continue;
108 
109       if (!printedHeader)
110       {
111         printedHeader = true;
112         if (pass == 0)
113           std::cout << "Required input options:" << std::endl << std::endl;
114         else if (pass == 1)
115           std::cout << "Optional input options: " << std::endl << std::endl;
116         else if (pass == 2)
117           std::cout << "Optional output options: " << std::endl << std::endl;
118       }
119 
120       // Append default value to description.
121       if (pass >= 1 && (data.cppType == "int" || data.cppType == "double" ||
122                         data.cppType == "std::string" ||
123                         data.cppType == "std::vector<int>" ||
124                         data.cppType == "std::vector<double>" ||
125                         data.cppType == "std::vector<std::string>"))
126       {
127         std::string defaultValue;
128         IO::GetSingleton().functionMap[data.tname]["DefaultParam"](data,
129             NULL, (void*) &defaultValue);
130         desc += "  Default value " + defaultValue + ".";
131       }
132 
133       // Now, print the descriptions.
134       std::string printableType;
135       IO::GetSingleton().functionMap[data.tname]["StringTypeParam"](data,
136           NULL, (void*) &printableType);
137       std::string type = " [" + printableType + "]";
138       std::string fullDesc = "  --" + key + alias + type + "  ";
139 
140       if (fullDesc.length() <= 32) // It all fits on one line.
141         std::cout << fullDesc << std::string(32 - fullDesc.length(), ' ');
142       else // We need multiple lines.
143         std::cout << fullDesc << std::endl << std::string(32, ' ');
144 
145       std::cout << util::HyphenateString(desc, 32) << std::endl;
146     }
147 
148     if (printedHeader)
149       std::cout << std::endl;
150   }
151 
152   // Helpful information at the bottom of the help output, to point the user to
153   // citations and better documentation (if necessary).  See ticket #195.
154   std::cout << util::HyphenateString("For further information, including "
155       "relevant papers, citations, and theory, consult the documentation found "
156       "at http://www.mlpack.org or included with your distribution of mlpack.",
157       0) << std::endl;
158 }
159 
160 
161 } // namespace cli
162 } // namespace bindings
163 } // namespace mlpack
164