summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jimmi Holst Christensen2019-08-17 18:48:06 +0200
committerGravatar Jimmi Holst Christensen2019-08-17 18:48:06 +0200
commit3990ea204ce06c470ff9401eb5af8752dce800f0 (patch)
tree57d8185833d12730666b350506149d00472ee092
parentadd missing word (diff)
downloadzig-clap-3990ea204ce06c470ff9401eb5af8752dce800f0.tar.gz
zig-clap-3990ea204ce06c470ff9401eb5af8752dce800f0.tar.xz
zig-clap-3990ea204ce06c470ff9401eb5af8752dce800f0.zip
make help message look more like other tools
Diffstat (limited to '')
-rw-r--r--README.md6
-rw-r--r--build.zig26
-rw-r--r--clap.zig144
-rw-r--r--example/comptime-clap.zig4
-rw-r--r--src/comptime.zig6
5 files changed, 101 insertions, 85 deletions
diff --git a/README.md b/README.md
index 1de7f05..01bc645 100644
--- a/README.md
+++ b/README.md
@@ -91,10 +91,10 @@ pub fn main() !void {
91 const allocator = std.heap.direct_allocator; 91 const allocator = std.heap.direct_allocator;
92 92
93 // First we specify what parameters our program can take. 93 // First we specify what parameters our program can take.
94 // We can use `parseParam` parse a string to a `Param(Help)` 94 // We can use `parseParam` to parse a string to a `Param(Help)`
95 const params = comptime [_]clap.Param(clap.Help){ 95 const params = comptime [_]clap.Param(clap.Help){
96 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, 96 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable,
97 clap.parseParam("-n, --number=NUM An option parameter, which takes a value.") catch unreachable, 97 clap.parseParam("-n, --number <NUM> An option parameter, which takes a value.") catch unreachable,
98 clap.Param(clap.Help){ 98 clap.Param(clap.Help){
99 .takes_value = true, 99 .takes_value = true,
100 }, 100 },
diff --git a/build.zig b/build.zig
index b9ec73a..104e7e3 100644
--- a/build.zig
+++ b/build.zig
@@ -7,6 +7,19 @@ const Builder = std.build.Builder;
7pub fn build(b: *Builder) void { 7pub fn build(b: *Builder) void {
8 const mode = b.standardReleaseOptions(); 8 const mode = b.standardReleaseOptions();
9 9
10 const test_all_step = b.step("test", "Run all tests in all modes.");
11 inline for ([_]Mode{ Mode.Debug, Mode.ReleaseFast, Mode.ReleaseSafe, Mode.ReleaseSmall }) |test_mode| {
12 const mode_str = comptime modeToString(test_mode);
13
14 const tests = b.addTest("clap.zig");
15 tests.setBuildMode(test_mode);
16 tests.setNamePrefix(mode_str ++ " ");
17
18 const test_step = b.step("test-" ++ mode_str, "Run all tests in " ++ mode_str ++ ".");
19 test_step.dependOn(&tests.step);
20 test_all_step.dependOn(test_step);
21 }
22
10 const example_step = b.step("examples", "Build examples"); 23 const example_step = b.step("examples", "Build examples");
11 inline for ([_][]const u8{ 24 inline for ([_][]const u8{
12 "comptime-clap", 25 "comptime-clap",
@@ -21,19 +34,6 @@ pub fn build(b: *Builder) void {
21 example_step.dependOn(&example.step); 34 example_step.dependOn(&example.step);
22 } 35 }
23 36
24 const test_all_step = b.step("test", "Run all tests in all modes.");
25 inline for ([_]Mode{ Mode.Debug, Mode.ReleaseFast, Mode.ReleaseSafe, Mode.ReleaseSmall }) |test_mode| {
26 const mode_str = comptime modeToString(test_mode);
27
28 const tests = b.addTest("clap.zig");
29 tests.setBuildMode(test_mode);
30 tests.setNamePrefix(mode_str ++ " ");
31
32 const test_step = b.step("test-" ++ mode_str, "Run all tests in " ++ mode_str ++ ".");
33 test_step.dependOn(&tests.step);
34 test_all_step.dependOn(test_step);
35 }
36
37 const readme_step = b.step("test", "Remake README."); 37 const readme_step = b.step("test", "Remake README.");
38 const readme = readMeStep(b); 38 const readme = readMeStep(b);
39 readme.dependOn(example_step); 39 readme.dependOn(example_step);
diff --git a/clap.zig b/clap.zig
index fe5a5b0..44c7d23 100644
--- a/clap.zig
+++ b/clap.zig
@@ -71,29 +71,24 @@ pub fn parseParam(line: []const u8) !Param(Help) {
71 if (found_comma) 71 if (found_comma)
72 param_str = param_str[0..param_str.len - 1]; 72 param_str = param_str[0..param_str.len - 1];
73 73
74 switch (param_str.len) { 74 if (param_str.len != 2)
75 1 => return error.InvalidShortParam, 75 return error.InvalidShortParam;
76 2 => { 76
77 res.names.short = param_str[1]; 77 res.names.short = param_str[1];
78 if (!found_comma) { 78 if (!found_comma) {
79 res.id.msg = mem.trim(u8, it.rest(), " \t"); 79 var help_msg = it.rest();
80 return res; 80 if (it.next()) |next| blk: {
81 if (mem.startsWith(u8, next, "<")) {
82 const start = mem.indexOfScalar(u8, help_msg, '<').? + 1;
83 const len = mem.indexOfScalar(u8, help_msg[start..], '>') orelse break :blk;
84 res.id.value = help_msg[start..][0..len];
85 res.takes_value = true;
86 help_msg = help_msg[start + len + 1..];
81 } 87 }
82 }, 88 }
83 else => {
84 res.names.short = param_str[1];
85 if (param_str[2] != '=')
86 return error.InvalidShortParam;
87
88 res.id.value = param_str[3..];
89 res.takes_value = true;
90 89
91 if (found_comma) 90 res.id.msg = mem.trim(u8, help_msg, " \t");
92 return error.TrailingComma; 91 return res;
93
94 res.id.msg = mem.trim(u8, it.rest(), " \t");
95 return res;
96 },
97 } 92 }
98 93
99 param_str = it.next() orelse return error.NoParamFound; 94 param_str = it.next() orelse return error.NoParamFound;
@@ -101,16 +96,22 @@ pub fn parseParam(line: []const u8) !Param(Help) {
101 96
102 if (mem.startsWith(u8, param_str, "--")) { 97 if (mem.startsWith(u8, param_str, "--")) {
103 res.names.long = param_str[2..]; 98 res.names.long = param_str[2..];
104 if (mem.indexOfScalar(u8, param_str, '=')) |eql_index| {
105 res.names.long = param_str[2..eql_index];
106 res.id.value = param_str[eql_index + 1 ..];
107 res.takes_value = true;
108 }
109 99
110 if (param_str[param_str.len - 1] == ',') 100 if (param_str[param_str.len - 1] == ',')
111 return error.TrailingComma; 101 return error.TrailingComma;
102
103 var help_msg = it.rest();
104 if (it.next()) |next| blk: {
105 if (mem.startsWith(u8, next, "<")) {
106 const start = mem.indexOfScalar(u8, help_msg, '<').? + 1;
107 const len = mem.indexOfScalar(u8, help_msg[start..], '>') orelse break :blk;
108 res.id.value = help_msg[start..][0..len];
109 res.takes_value = true;
110 help_msg = help_msg[start + len + 1..];
111 }
112 }
112 113
113 res.id.msg = mem.trim(u8, it.rest(), " \t"); 114 res.id.msg = mem.trim(u8, help_msg, " \t");
114 return res; 115 return res;
115 } 116 }
116 117
@@ -118,37 +119,37 @@ pub fn parseParam(line: []const u8) !Param(Help) {
118} 119}
119 120
120test "parseParam" { 121test "parseParam" {
121 var text: []const u8 = "-s, --long=value Help text"; 122 var text: []const u8 = "-s, --long <value> Help text";
122 testing.expectEqual(Param(Help){ 123 testing.expectEqual(Param(Help){
123 .id = Help{ 124 .id = Help{
124 .msg = text[17..], 125 .msg = find(text, "Help text"),
125 .value = text[11..16], 126 .value = find(text, "value"),
126 }, 127 },
127 .names = Names{ 128 .names = Names{
128 .short = 's', 129 .short = 's',
129 .long = text[6..10], 130 .long = find(text, "long"),
130 }, 131 },
131 .takes_value = true, 132 .takes_value = true,
132 }, try parseParam(text)); 133 }, try parseParam(text));
133 134
134 text = "--long=value Help text"; 135 text = "--long <value> Help text";
135 testing.expectEqual(Param(Help){ 136 testing.expectEqual(Param(Help){
136 .id = Help{ 137 .id = Help{
137 .msg = text[13..], 138 .msg = find(text, "Help text"),
138 .value = text[7..12], 139 .value = find(text, "value"),
139 }, 140 },
140 .names = Names{ 141 .names = Names{
141 .short = null, 142 .short = null,
142 .long = text[2..6], 143 .long = find(text, "long"),
143 }, 144 },
144 .takes_value = true, 145 .takes_value = true,
145 }, try parseParam(text)); 146 }, try parseParam(text));
146 147
147 text = "-s=value Help text"; 148 text = "-s <value> Help text";
148 testing.expectEqual(Param(Help){ 149 testing.expectEqual(Param(Help){
149 .id = Help{ 150 .id = Help{
150 .msg = text[9..], 151 .msg = find(text, "Help text"),
151 .value = text[3..8], 152 .value = find(text, "value"),
152 }, 153 },
153 .names = Names{ 154 .names = Names{
154 .short = 's', 155 .short = 's',
@@ -160,12 +161,12 @@ test "parseParam" {
160 text = "-s, --long Help text"; 161 text = "-s, --long Help text";
161 testing.expectEqual(Param(Help){ 162 testing.expectEqual(Param(Help){
162 .id = Help{ 163 .id = Help{
163 .msg = text[11..], 164 .msg = find(text, "Help text"),
164 .value = text[0..0], 165 .value = text[0..0],
165 }, 166 },
166 .names = Names{ 167 .names = Names{
167 .short = 's', 168 .short = 's',
168 .long = text[6..10], 169 .long = find(text, "long"),
169 }, 170 },
170 .takes_value = false, 171 .takes_value = false,
171 }, try parseParam(text)); 172 }, try parseParam(text));
@@ -173,7 +174,7 @@ test "parseParam" {
173 text = "-s Help text"; 174 text = "-s Help text";
174 testing.expectEqual(Param(Help){ 175 testing.expectEqual(Param(Help){
175 .id = Help{ 176 .id = Help{
176 .msg = text[3..], 177 .msg = find(text, "Help text"),
177 .value = text[0..0], 178 .value = text[0..0],
178 }, 179 },
179 .names = Names{ 180 .names = Names{
@@ -186,34 +187,49 @@ test "parseParam" {
186 text = "--long Help text"; 187 text = "--long Help text";
187 testing.expectEqual(Param(Help){ 188 testing.expectEqual(Param(Help){
188 .id = Help{ 189 .id = Help{
189 .msg = text[7..], 190 .msg = find(text, "Help text"),
190 .value = text[0..0], 191 .value = text[0..0],
191 }, 192 },
192 .names = Names{ 193 .names = Names{
193 .short = null, 194 .short = null,
194 .long = text[2..6], 195 .long = find(text, "long"),
195 }, 196 },
196 .takes_value = false, 197 .takes_value = false,
197 }, try parseParam(text)); 198 }, try parseParam(text));
198 199
200 text = "--long <A | B> Help text";
201 testing.expectEqual(Param(Help){
202 .id = Help{
203 .msg = find(text, "Help text"),
204 .value = find(text, "A | B"),
205 },
206 .names = Names{
207 .short = null,
208 .long = find(text, "long"),
209 },
210 .takes_value = true,
211 }, try parseParam(text));
212
199 testing.expectError(error.NoParamFound, parseParam("Help")); 213 testing.expectError(error.NoParamFound, parseParam("Help"));
200 testing.expectError(error.TrailingComma, parseParam("--long, Help")); 214 testing.expectError(error.TrailingComma, parseParam("--long, Help"));
201 testing.expectError(error.TrailingComma, parseParam("--long=value, Help"));
202 testing.expectError(error.NoParamFound, parseParam("-s, Help")); 215 testing.expectError(error.NoParamFound, parseParam("-s, Help"));
203 testing.expectError(error.TrailingComma, parseParam("-s=value, Help"));
204 testing.expectError(error.InvalidShortParam, parseParam("-ss Help")); 216 testing.expectError(error.InvalidShortParam, parseParam("-ss Help"));
205 testing.expectError(error.InvalidShortParam, parseParam("-ss=value Help")); 217 testing.expectError(error.InvalidShortParam, parseParam("-ss <value> Help"));
206 testing.expectError(error.InvalidShortParam, parseParam("- Help")); 218 testing.expectError(error.InvalidShortParam, parseParam("- Help"));
207} 219}
208 220
221fn find(str: []const u8, f: []const u8) []const u8 {
222 const i = mem.indexOf(u8, str, f).?;
223 return str[i..][0..f.len];
224}
209 225
210 226
211/// Will print a help message in the following format: 227/// Will print a help message in the following format:
212/// -s, --long=value_text help_text 228/// -s, --long <value_text> help_text
213/// -s, help_text 229/// -s, help_text
214/// -s=value_text help_text 230/// -s <value_text> help_text
215/// --long help_text 231/// --long help_text
216/// --long=value_text help_text 232/// --long <value_text> help_text
217pub fn helpFull( 233pub fn helpFull(
218 stream: var, 234 stream: var,
219 comptime Id: type, 235 comptime Id: type,
@@ -270,7 +286,7 @@ fn printParam(
270 try stream.print("--{}", l); 286 try stream.print("--{}", l);
271 } 287 }
272 if (param.takes_value) 288 if (param.takes_value)
273 try stream.print("={}", value_text(context, param)); 289 try stream.print(" <{}>", value_text(context, param));
274} 290}
275 291
276/// A wrapper around helpFull for simple help_text and value_text functions that 292/// A wrapper around helpFull for simple help_text and value_text functions that
@@ -333,12 +349,12 @@ test "clap.help" {
333 try help( 349 try help(
334 &slice_stream.stream, 350 &slice_stream.stream,
335 comptime [_]Param(Help){ 351 comptime [_]Param(Help){
336 parseParam("-a Short flag. ") catch unreachable, 352 parseParam("-a Short flag. ") catch unreachable,
337 parseParam("-b=V1 Short option.") catch unreachable, 353 parseParam("-b <V1> Short option.") catch unreachable,
338 parseParam("--aa Long flag. ") catch unreachable, 354 parseParam("--aa Long flag. ") catch unreachable,
339 parseParam("--bb=V2 Long option. ") catch unreachable, 355 parseParam("--bb <V2> Long option. ") catch unreachable,
340 parseParam("-c, --cc Both flag. ") catch unreachable, 356 parseParam("-c, --cc Both flag. ") catch unreachable,
341 parseParam("-d, --dd=V3 Both option. ") catch unreachable, 357 parseParam("-d, --dd <V3> Both option. ") catch unreachable,
342 Param(Help){ 358 Param(Help){
343 .id = Help{ 359 .id = Help{
344 .msg = "Positional. This should not appear in the help message.", 360 .msg = "Positional. This should not appear in the help message.",
@@ -349,12 +365,12 @@ test "clap.help" {
349 ); 365 );
350 366
351 const expected = "" ++ 367 const expected = "" ++
352 "\t-a \tShort flag.\n" ++ 368 "\t-a \tShort flag.\n" ++
353 "\t-b=V1 \tShort option.\n" ++ 369 "\t-b <V1> \tShort option.\n" ++
354 "\t --aa \tLong flag.\n" ++ 370 "\t --aa \tLong flag.\n" ++
355 "\t --bb=V2\tLong option.\n" ++ 371 "\t --bb <V2>\tLong option.\n" ++
356 "\t-c, --cc \tBoth flag.\n" ++ 372 "\t-c, --cc \tBoth flag.\n" ++
357 "\t-d, --dd=V3\tBoth option.\n"; 373 "\t-d, --dd <V3>\tBoth option.\n";
358 374
359 const actual = slice_stream.getWritten(); 375 const actual = slice_stream.getWritten();
360 if (!mem.eql(u8, actual, expected)) { 376 if (!mem.eql(u8, actual, expected)) {
diff --git a/example/comptime-clap.zig b/example/comptime-clap.zig
index 5df215b..8e0eb12 100644
--- a/example/comptime-clap.zig
+++ b/example/comptime-clap.zig
@@ -9,8 +9,8 @@ pub fn main() !void {
9 // First we specify what parameters our program can take. 9 // First we specify what parameters our program can take.
10 // We can use `parseParam` to parse a string to a `Param(Help)` 10 // We can use `parseParam` to parse a string to a `Param(Help)`
11 const params = comptime [_]clap.Param(clap.Help){ 11 const params = comptime [_]clap.Param(clap.Help){
12 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, 12 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable,
13 clap.parseParam("-n, --number=NUM An option parameter, which takes a value.") catch unreachable, 13 clap.parseParam("-n, --number <NUM> An option parameter, which takes a value.") catch unreachable,
14 clap.Param(clap.Help){ 14 clap.Param(clap.Help){
15 .takes_value = true, 15 .takes_value = true,
16 }, 16 },
diff --git a/src/comptime.zig b/src/comptime.zig
index 8fd3c1d..f5c2762 100644
--- a/src/comptime.zig
+++ b/src/comptime.zig
@@ -114,9 +114,9 @@ pub fn ComptimeClap(comptime Id: type, comptime params: []const clap.Param(Id))
114 114
115test "clap.comptime.ComptimeClap" { 115test "clap.comptime.ComptimeClap" {
116 const Clap = ComptimeClap(clap.Help, comptime [_]clap.Param(clap.Help){ 116 const Clap = ComptimeClap(clap.Help, comptime [_]clap.Param(clap.Help){
117 clap.parseParam("-a, --aa ") catch unreachable, 117 clap.parseParam("-a, --aa ") catch unreachable,
118 clap.parseParam("-b, --bb ") catch unreachable, 118 clap.parseParam("-b, --bb ") catch unreachable,
119 clap.parseParam("-c, --cc=V") catch unreachable, 119 clap.parseParam("-c, --cc <V>") catch unreachable,
120 clap.Param(clap.Help){ 120 clap.Param(clap.Help){
121 .takes_value = true, 121 .takes_value = true,
122 }, 122 },