1 module sily.getopt;
2 
3 import std.algorithm : max;
4 import std.getopt : Option;
5 import std.stdio : writefln;
6 /** 
7 Helper function to get std.getopt.Option
8 Params:
9     _long = Option name
10     _help = Option help
11 Returns: std.getopt.Option
12 */
13 Option customOption(string _long, string _help) { return Option("", _long, _help, false); }
14 
15 private enum bool isOptionArray(T) = is(T == Option[]);
16 private enum bool isOption(T) = is(T == Option);
17 private enum bool isString(T) = is(T == string);
18 
19 /** 
20  * Prints passed **Option**s and text in aligned manner on stdout, i.e:
21  * ```
22  * A simple cli tool
23  * 
24  * Usage: 
25  *   scli [options] [script] \
26  *   scli run [script]
27  * 
28  * Options: 
29  *   -h, --help   This help information. \
30  *   -c, --check  Check syntax without running. \
31  *   --quiet      Run silently (no output). 
32  * 
33  * Commands:
34  *   run          Runs script. \
35  *   compile      Compiles script.
36  * ```
37  * Can be used like:
38  * ---------
39  * printGetopt("Usage", "Options", help.options, "CustomOptions", customArray, customOption("opt", "-h"));
40  * ---------
41  * Params:
42  *   S = Can be either std.getopt.Option[], std.getopt.Option or string
43  */
44 void printGetopt(S...)(S args) { // string text, string usage, Option[] opt, 
45     size_t maxLen = 0;
46     bool[] isNextOpt = [];
47 
48     foreach (arg; args) {
49         alias A = typeof(arg);
50 
51         static if(isOptionArray!A) {
52             foreach (it; arg) {
53                 int sep = it.optShort == "" ? 0 : 2;
54                 maxLen = max(maxLen, it.optShort.length + it.optLong.length + sep);
55             }
56             isNextOpt ~= true;
57             continue;
58         } else
59         static if(isOption!A) {
60             int sep = arg.optShort == "" ? 0 : 2;
61             maxLen = max(maxLen, arg.optShort.length + arg.optLong.length + sep);
62             isNextOpt ~= true;
63             continue;
64         } else
65         static if(isString!A) {
66             isNextOpt ~= false;
67             continue;
68         }
69     }
70 
71     int i = 0;
72     foreach (arg; args) {
73         alias A = typeof(arg);
74         static if(isOptionArray!A) {
75             foreach (it; arg) {
76                 string opts = it.optShort ~ (it.optShort == "" ? "" : ", ") ~ it.optLong;
77                 writefln("  %-*s  %s", maxLen, opts, it.help);
78             }
79         } else 
80         static if(isOption!A) {
81             string opts = arg.optShort ~ (arg.optShort == "" ? "" : ", ") ~ arg.optLong;
82             writefln("  %-*s  %s", maxLen, opts, arg.help);
83         } else
84         static if(isString!A) {
85             bool nopt = i + 1 < isNextOpt.length ? (isNextOpt[ i + 1 ]) : (false);
86             bool popt = i - 1 > 0 ? (isNextOpt[ i - 1 ]) : (false);
87             writefln((popt ? "\n" : "") ~ arg ~ (nopt ? ":" : "\n"));
88         }
89 
90         ++i;
91     }
92 }