summaryrefslogtreecommitdiff
path: root/clap
diff options
context:
space:
mode:
Diffstat (limited to 'clap')
-rw-r--r--clap/streaming.zig275
1 files changed, 159 insertions, 116 deletions
diff --git a/clap/streaming.zig b/clap/streaming.zig
index 2ab9c8d..eba84bb 100644
--- a/clap/streaming.zig
+++ b/clap/streaming.zig
@@ -44,11 +44,14 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type {
44 }; 44 };
45 }; 45 };
46 46
47 state: State = .normal,
48
47 params: []const clap.Param(Id), 49 params: []const clap.Param(Id),
48 iter: *ArgIterator, 50 iter: *ArgIterator,
49 state: State = .normal, 51
50 positional: ?*const clap.Param(Id) = null, 52 positional: ?*const clap.Param(Id) = null,
51 diagnostic: ?*clap.Diagnostic = null, 53 diagnostic: ?*clap.Diagnostic = null,
54 assignment_separators: []const u8 = clap.default_assignment_separators,
52 55
53 /// Get the next Arg that matches a Param. 56 /// Get the next Arg that matches a Param.
54 pub fn next(parser: *@This()) !?Arg(Id) { 57 pub fn next(parser: *@This()) !?Arg(Id) {
@@ -68,7 +71,7 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type {
68 const arg = arg_info.arg; 71 const arg = arg_info.arg;
69 switch (arg_info.kind) { 72 switch (arg_info.kind) {
70 .long => { 73 .long => {
71 const eql_index = mem.indexOfScalar(u8, arg, '='); 74 const eql_index = mem.indexOfAny(u8, arg, parser.assignment_separators);
72 const name = if (eql_index) |i| arg[0..i] else arg; 75 const name = if (eql_index) |i| arg[0..i] else arg;
73 const maybe_value = if (eql_index) |i| arg[i + 1 ..] else null; 76 const maybe_value = if (eql_index) |i| arg[i + 1 ..] else null;
74 77
@@ -142,9 +145,13 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type {
142 } 145 }
143 } 146 }
144 147
145 const next_is_eql = if (next_index < arg.len) arg[next_index] == '=' else false; 148 const next_is_separator = if (next_index < arg.len)
149 std.mem.indexOfScalar(u8, parser.assignment_separators, arg[next_index]) != null
150 else
151 false;
152
146 if (param.takes_value == .none) { 153 if (param.takes_value == .none) {
147 if (next_is_eql) 154 if (next_is_separator)
148 return parser.err(arg, .{ .short = short }, Error.DoesntTakeValue); 155 return parser.err(arg, .{ .short = short }, Error.DoesntTakeValue);
149 return Arg(Id){ .param = param }; 156 return Arg(Id){ .param = param };
150 } 157 }
@@ -156,7 +163,7 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type {
156 return Arg(Id){ .param = param, .value = value }; 163 return Arg(Id){ .param = param, .value = value };
157 } 164 }
158 165
159 if (next_is_eql) 166 if (next_is_separator)
160 return Arg(Id){ .param = param, .value = arg[next_index + 1 ..] }; 167 return Arg(Id){ .param = param, .value = arg[next_index + 1 ..] };
161 168
162 return Arg(Id){ .param = param, .value = arg[next_index..] }; 169 return Arg(Id){ .param = param, .value = arg[next_index..] };
@@ -211,19 +218,12 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type {
211 }; 218 };
212} 219}
213 220
214fn testNoErr( 221fn expectArgs(
215 params: []const clap.Param(u8), 222 parser: *Clap(u8, args.SliceIterator),
216 args_strings: []const []const u8,
217 results: []const Arg(u8), 223 results: []const Arg(u8),
218) !void { 224) !void {
219 var iter = args.SliceIterator{ .args = args_strings };
220 var c = Clap(u8, args.SliceIterator){
221 .params = params,
222 .iter = &iter,
223 };
224
225 for (results) |res| { 225 for (results) |res| {
226 const arg = (try c.next()) orelse return error.TestFailed; 226 const arg = (try parser.next()) orelse return error.TestFailed;
227 try testing.expectEqual(res.param, arg.param); 227 try testing.expectEqual(res.param, arg.param);
228 const expected_value = res.value orelse { 228 const expected_value = res.value orelse {
229 try testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value); 229 try testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value);
@@ -233,23 +233,18 @@ fn testNoErr(
233 try testing.expectEqualSlices(u8, expected_value, actual_value); 233 try testing.expectEqualSlices(u8, expected_value, actual_value);
234 } 234 }
235 235
236 if (try c.next()) |_| 236 if (try parser.next()) |_|
237 return error.TestFailed; 237 return error.TestFailed;
238} 238}
239 239
240fn testErr( 240fn expectError(
241 params: []const clap.Param(u8), 241 parser: *Clap(u8, args.SliceIterator),
242 args_strings: []const []const u8,
243 expected: []const u8, 242 expected: []const u8,
244) !void { 243) !void {
245 var diag: clap.Diagnostic = undefined; 244 var diag: clap.Diagnostic = .{};
246 var iter = args.SliceIterator{ .args = args_strings }; 245 parser.diagnostic = &diag;
247 var c = Clap(u8, args.SliceIterator){ 246
248 .params = params, 247 while (parser.next() catch |err| {
249 .iter = &iter,
250 .diagnostic = &diag,
251 };
252 while (c.next() catch |err| {
253 var buf: [1024]u8 = undefined; 248 var buf: [1024]u8 = undefined;
254 var fbs = io.fixedBufferStream(&buf); 249 var fbs = io.fixedBufferStream(&buf);
255 diag.report(fbs.writer(), err) catch return error.TestFailed; 250 diag.report(fbs.writer(), err) catch return error.TestFailed;
@@ -281,29 +276,28 @@ test "short params" {
281 const c = &params[2]; 276 const c = &params[2];
282 const d = &params[3]; 277 const d = &params[3];
283 278
284 try testNoErr( 279 var iter = args.SliceIterator{ .args = &.{
285 &params, 280 "-a", "-b", "-ab", "-ba",
286 &.{ 281 "-c", "0", "-c=0", "-ac",
287 "-a", "-b", "-ab", "-ba", 282 "0", "-ac=0", "-d=0",
288 "-c", "0", "-c=0", "-ac", 283 } };
289 "0", "-ac=0", "-d=0", 284 var parser = Clap(u8, args.SliceIterator){ .params = &params, .iter = &iter };
290 }, 285
291 &.{ 286 try expectArgs(&parser, &.{
292 .{ .param = a }, 287 .{ .param = a },
293 .{ .param = b }, 288 .{ .param = b },
294 .{ .param = a }, 289 .{ .param = a },
295 .{ .param = b }, 290 .{ .param = b },
296 .{ .param = b }, 291 .{ .param = b },
297 .{ .param = a }, 292 .{ .param = a },
298 .{ .param = c, .value = "0" }, 293 .{ .param = c, .value = "0" },
299 .{ .param = c, .value = "0" }, 294 .{ .param = c, .value = "0" },
300 .{ .param = a }, 295 .{ .param = a },
301 .{ .param = c, .value = "0" }, 296 .{ .param = c, .value = "0" },
302 .{ .param = a }, 297 .{ .param = a },
303 .{ .param = c, .value = "0" }, 298 .{ .param = c, .value = "0" },
304 .{ .param = d, .value = "0" }, 299 .{ .param = d, .value = "0" },
305 }, 300 });
306 );
307} 301}
308 302
309test "long params" { 303test "long params" {
@@ -327,21 +321,20 @@ test "long params" {
327 const cc = &params[2]; 321 const cc = &params[2];
328 const dd = &params[3]; 322 const dd = &params[3];
329 323
330 try testNoErr( 324 var iter = args.SliceIterator{ .args = &.{
331 &params, 325 "--aa", "--bb",
332 &.{ 326 "--cc", "0",
333 "--aa", "--bb", 327 "--cc=0", "--dd=0",
334 "--cc", "0", 328 } };
335 "--cc=0", "--dd=0", 329 var parser = Clap(u8, args.SliceIterator){ .params = &params, .iter = &iter };
336 }, 330
337 &.{ 331 try expectArgs(&parser, &.{
338 .{ .param = aa }, 332 .{ .param = aa },
339 .{ .param = bb }, 333 .{ .param = bb },
340 .{ .param = cc, .value = "0" }, 334 .{ .param = cc, .value = "0" },
341 .{ .param = cc, .value = "0" }, 335 .{ .param = cc, .value = "0" },
342 .{ .param = dd, .value = "0" }, 336 .{ .param = dd, .value = "0" },
343 }, 337 });
344 );
345} 338}
346 339
347test "positional params" { 340test "positional params" {
@@ -350,14 +343,16 @@ test "positional params" {
350 .takes_value = .one, 343 .takes_value = .one,
351 }}; 344 }};
352 345
353 try testNoErr( 346 var iter = args.SliceIterator{ .args = &.{
354 &params, 347 "aa",
355 &.{ "aa", "bb" }, 348 "bb",
356 &.{ 349 } };
357 .{ .param = &params[0], .value = "aa" }, 350 var parser = Clap(u8, args.SliceIterator){ .params = &params, .iter = &iter };
358 .{ .param = &params[0], .value = "bb" }, 351
359 }, 352 try expectArgs(&parser, &.{
360 ); 353 .{ .param = &params[0], .value = "aa" },
354 .{ .param = &params[0], .value = "bb" },
355 });
361} 356}
362 357
363test "all params" { 358test "all params" {
@@ -383,38 +378,66 @@ test "all params" {
383 const cc = &params[2]; 378 const cc = &params[2];
384 const positional = &params[3]; 379 const positional = &params[3];
385 380
386 try testNoErr( 381 var iter = args.SliceIterator{ .args = &.{
387 &params, 382 "-a", "-b", "-ab", "-ba",
388 &.{ 383 "-c", "0", "-c=0", "-ac",
389 "-a", "-b", "-ab", "-ba", 384 "0", "-ac=0", "--aa", "--bb",
390 "-c", "0", "-c=0", "-ac", 385 "--cc", "0", "--cc=0", "something",
391 "0", "-ac=0", "--aa", "--bb", 386 "-", "--", "--cc=0", "-a",
392 "--cc", "0", "--cc=0", "something", 387 } };
393 "-", "--", "--cc=0", "-a", 388 var parser = Clap(u8, args.SliceIterator){ .params = &params, .iter = &iter };
394 }, 389
395 &.{ 390 try expectArgs(&parser, &.{
396 .{ .param = aa }, 391 .{ .param = aa },
397 .{ .param = bb }, 392 .{ .param = bb },
398 .{ .param = aa }, 393 .{ .param = aa },
399 .{ .param = bb }, 394 .{ .param = bb },
400 .{ .param = bb }, 395 .{ .param = bb },
401 .{ .param = aa }, 396 .{ .param = aa },
402 .{ .param = cc, .value = "0" }, 397 .{ .param = cc, .value = "0" },
403 .{ .param = cc, .value = "0" }, 398 .{ .param = cc, .value = "0" },
404 .{ .param = aa }, 399 .{ .param = aa },
405 .{ .param = cc, .value = "0" }, 400 .{ .param = cc, .value = "0" },
406 .{ .param = aa }, 401 .{ .param = aa },
407 .{ .param = cc, .value = "0" }, 402 .{ .param = cc, .value = "0" },
408 .{ .param = aa }, 403 .{ .param = aa },
409 .{ .param = bb }, 404 .{ .param = bb },
410 .{ .param = cc, .value = "0" }, 405 .{ .param = cc, .value = "0" },
411 .{ .param = cc, .value = "0" }, 406 .{ .param = cc, .value = "0" },
412 .{ .param = positional, .value = "something" }, 407 .{ .param = positional, .value = "something" },
413 .{ .param = positional, .value = "-" }, 408 .{ .param = positional, .value = "-" },
414 .{ .param = positional, .value = "--cc=0" }, 409 .{ .param = positional, .value = "--cc=0" },
415 .{ .param = positional, .value = "-a" }, 410 .{ .param = positional, .value = "-a" },
411 });
412}
413
414test "different assignment separators" {
415 const params = [_]clap.Param(u8){
416 .{
417 .id = 0,
418 .names = .{ .short = 'a', .long = "aa" },
419 .takes_value = .one,
416 }, 420 },
417 ); 421 };
422
423 const aa = &params[0];
424
425 var iter = args.SliceIterator{ .args = &.{
426 "-a=0", "--aa=0",
427 "-a:0", "--aa:0",
428 } };
429 var parser = Clap(u8, args.SliceIterator){
430 .params = &params,
431 .iter = &iter,
432 .assignment_separators = "=:",
433 };
434
435 try expectArgs(&parser, &.{
436 .{ .param = aa, .value = "0" },
437 .{ .param = aa, .value = "0" },
438 .{ .param = aa, .value = "0" },
439 .{ .param = aa, .value = "0" },
440 });
418} 441}
419 442
420test "errors" { 443test "errors" {
@@ -429,16 +452,36 @@ test "errors" {
429 .takes_value = .one, 452 .takes_value = .one,
430 }, 453 },
431 }; 454 };
432 try testErr(&params, &.{"q"}, "Invalid argument 'q'\n"); 455
433 try testErr(&params, &.{"-q"}, "Invalid argument '-q'\n"); 456 var iter = args.SliceIterator{ .args = &.{"q"} };
434 try testErr(&params, &.{"--q"}, "Invalid argument '--q'\n"); 457 var parser = Clap(u8, args.SliceIterator){ .params = &params, .iter = &iter };
435 try testErr(&params, &.{"--q=1"}, "Invalid argument '--q'\n"); 458 try expectError(&parser, "Invalid argument 'q'\n");
436 try testErr(&params, &.{"-a=1"}, "The argument '-a' does not take a value\n"); 459
437 try testErr(&params, &.{"--aa=1"}, "The argument '--aa' does not take a value\n"); 460 iter = args.SliceIterator{ .args = &.{"-q"} };
438 try testErr(&params, &.{"-c"}, "The argument '-c' requires a value but none was supplied\n"); 461 parser = Clap(u8, args.SliceIterator){ .params = &params, .iter = &iter };
439 try testErr( 462 try expectError(&parser, "Invalid argument '-q'\n");
440 &params, 463
441 &.{"--cc"}, 464 iter = args.SliceIterator{ .args = &.{"--q"} };
442 "The argument '--cc' requires a value but none was supplied\n", 465 parser = Clap(u8, args.SliceIterator){ .params = &params, .iter = &iter };
443 ); 466 try expectError(&parser, "Invalid argument '--q'\n");
467
468 iter = args.SliceIterator{ .args = &.{"--q=1"} };
469 parser = Clap(u8, args.SliceIterator){ .params = &params, .iter = &iter };
470 try expectError(&parser, "Invalid argument '--q'\n");
471
472 iter = args.SliceIterator{ .args = &.{"-a=1"} };
473 parser = Clap(u8, args.SliceIterator){ .params = &params, .iter = &iter };
474 try expectError(&parser, "The argument '-a' does not take a value\n");
475
476 iter = args.SliceIterator{ .args = &.{"--aa=1"} };
477 parser = Clap(u8, args.SliceIterator){ .params = &params, .iter = &iter };
478 try expectError(&parser, "The argument '--aa' does not take a value\n");
479
480 iter = args.SliceIterator{ .args = &.{"-c"} };
481 parser = Clap(u8, args.SliceIterator){ .params = &params, .iter = &iter };
482 try expectError(&parser, "The argument '-c' requires a value but none was supplied\n");
483
484 iter = args.SliceIterator{ .args = &.{"--cc"} };
485 parser = Clap(u8, args.SliceIterator){ .params = &params, .iter = &iter };
486 try expectError(&parser, "The argument '--cc' requires a value but none was supplied\n");
444} 487}