1 module examples.strutil;
2 
3 import std.stdio;
4 import std.string;
5 import std.regex;
6 import std.range;
7 import std.array : array;
8 import std.format;
9 import std.process;
10 import cmdline;
11 
12 mixin template ConfigCmd() {
13     mixin BEGIN;
14     mixin DESC!("CLI to some string utilities");
15     mixin VERSION!("0.0.1");
16 
17     mixin CONFIG;
18     mixin PASS_THROUGH;
19 
20     mixin SUB_CMD!(JoinResult, SplitResult, ReplaceResult);
21 
22     mixin DEF!(
23         "flag", bool,
24         Flag_d!"-f",
25         Desc_d!"the global flag"
26     );
27 
28     mixin DEF!(
29         "greet", string,
30         Flag_d!"-g [greeting]",
31         Desc_d!"set the greeting string",
32         Default_d!"hi!",
33         Preset_d!"hello!",
34         Negate_d!("-G", "opposite to `--greet`"),
35         Export_d!("-x", "-y", "-z", "--xyz"),
36         N_Export_d!("-X", "-Y", "-Z", "--XYZ")
37     );
38 
39     mixin END;
40 }
41 
42 mixin template ConfigSplitCmd() {
43     mixin BEGIN;
44     mixin ALIAS!("spl");
45     mixin DESC!("Split a string into substrings and display as an array.");
46 
47     mixin DEF!(
48         "str", string,
49         Desc_d!"string to split"
50     );
51 
52     mixin DEF!(
53         "separator", string,
54         Flag_d!"-s <char>",
55         Desc_d!"separator character",
56         Default_d!",",
57         ToArg_d,
58     );
59 
60     mixin END;
61 
62     void action() {
63         StrutilResult* parent = this.getParent!StrutilResult;
64         writeln(parent.flag ? true : false);
65         writeln(parent.greet ? parent.greet.get : "no greeting");
66         string s = str.get;
67         string sp = separator.get;
68         writeln(split(s, sp));
69     }
70 }
71 
72 mixin template ConfigJoinCmd() {
73     mixin BEGIN;
74     mixin ALIAS!("jr");
75     mixin DESC!("Join the command-arguments into a single string.");
76 
77     mixin DEF!(
78         "strs", string[],
79         Desc_d!"one or more string"
80     );
81 
82     mixin DEF!(
83         "separator", string,
84         Flag_d!"-s <char>",
85         Desc_d!"separator character",
86         Default_d!","
87     );
88 
89     mixin END;
90 
91     void action() {
92         StrutilResult* parent = this.getParent!StrutilResult;
93         writeln(parent.flag ? true : false);
94         writeln(parent.greet ? parent.greet.get : "no greeting");
95         auto ss = strs.get;
96         auto sp = separator.get;
97         writeln(ss.join(sp));
98     }
99 }
100 
101 mixin template ConfigReplaceCmd() {
102     mixin BEGIN;
103     mixin ALIAS!("rpl");
104     mixin DESC!("Replace the specified string with new string on a string");
105 
106     mixin DEF_ARG!(
107         "str", string,
108         Desc_d!"the string that would be mutated"
109     );
110 
111     mixin DEF_OPT!(
112         "ptr", string, "-p <ptr>",
113         Desc_d!"the pattern to search for",
114         ToArg_d
115     );
116 
117     mixin DEF_OPT!(
118         "rpl", string, "-r <replacent>",
119         Desc_d!"the replacent string",
120         ToArg_d
121     );
122 
123     OptVal!(bool, "-i") igc;
124     mixin DESC_OPT!(igc, "ignore the lower and upper cases");
125 
126     OptVal!(bool, "-g") glb;
127     mixin DESC_OPT!(glb, "global search all the satisfied string");
128 
129     OptVal!(bool, "-m") mlt;
130     mixin DESC_OPT!(mlt, "allow multipule line search");
131 
132     OptVal!(bool, "-c") cmp;
133     mixin DESC_OPT!(cmp, "show the comparision");
134 
135     mixin END;
136 
137     void action() {
138         StrutilResult* parent = this.getParent!StrutilResult;
139         writeln(parent.flag ? true : false);
140         writeln(parent.greet ? parent.greet.get : "no greeting");
141         string _str = this.str.get;
142         string _ptr = this.ptr.get;
143         string _rstr = this.rpl.get;
144         string _igc = this.igc ? "i" : "";
145         string _glb = this.glb ? "g" : "";
146         string _mlt = this.mlt ? "m" : "";
147         version (Windows) {
148             enum os_num = 0;
149         }
150         else version (Posix) {
151             enum os_num = 1;
152         }
153         bool is_cmp = this.cmp && os_num;
154         auto fmt = `\033[36m%s\033[0m`;
155         auto fn = (Captures!string m) {
156             string tmp = '_'.repeat.take(m.hit.length).array;
157             return _rstr.length
158                 ? (is_cmp ? format(fmt, _rstr) : _rstr) : (is_cmp ? format(fmt, tmp) : tmp);
159         };
160         auto pattern = regex(_ptr, join([_igc, _glb, _mlt], ""));
161         string new_str = replace!(fn)(_str, pattern);
162         auto ostr = is_cmp ? format("echo -e \"%s\"", new_str) : format("echo \"%s\"", new_str);
163         auto result = executeShell(ostr);
164         write(result.output);
165     }
166 }
167 
168 struct SplitResult {
169     mixin ConfigSplitCmd;
170 }
171 
172 struct JoinResult {
173     mixin ConfigJoinCmd;
174 }
175 
176 struct ReplaceResult {
177     mixin ConfigReplaceCmd;
178 }
179 
180 struct StrutilResult {
181     mixin ConfigCmd;
182 }
183 
184 void main(in string[] argv) {
185     argv.run!StrutilResult;
186 }