From 2998679eb1a5d75c5c1043c0fc8470eb9c946b70 Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Thu, 18 Jul 2024 16:56:11 +0200 Subject: feat: Allow for the assignment separator to be configured --- clap/streaming.zig | 275 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 159 insertions(+), 116 deletions(-) (limited to 'clap/streaming.zig') 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 { }; }; + state: State = .normal, + params: []const clap.Param(Id), iter: *ArgIterator, - state: State = .normal, + positional: ?*const clap.Param(Id) = null, diagnostic: ?*clap.Diagnostic = null, + assignment_separators: []const u8 = clap.default_assignment_separators, /// Get the next Arg that matches a Param. pub fn next(parser: *@This()) !?Arg(Id) { @@ -68,7 +71,7 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type { const arg = arg_info.arg; switch (arg_info.kind) { .long => { - const eql_index = mem.indexOfScalar(u8, arg, '='); + const eql_index = mem.indexOfAny(u8, arg, parser.assignment_separators); const name = if (eql_index) |i| arg[0..i] else arg; const maybe_value = if (eql_index) |i| arg[i + 1 ..] else null; @@ -142,9 +145,13 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type { } } - const next_is_eql = if (next_index < arg.len) arg[next_index] == '=' else false; + const next_is_separator = if (next_index < arg.len) + std.mem.indexOfScalar(u8, parser.assignment_separators, arg[next_index]) != null + else + false; + if (param.takes_value == .none) { - if (next_is_eql) + if (next_is_separator) return parser.err(arg, .{ .short = short }, Error.DoesntTakeValue); return Arg(Id){ .param = param }; } @@ -156,7 +163,7 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type { return Arg(Id){ .param = param, .value = value }; } - if (next_is_eql) + if (next_is_separator) return Arg(Id){ .param = param, .value = arg[next_index + 1 ..] }; return Arg(Id){ .param = param, .value = arg[next_index..] }; @@ -211,19 +218,12 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type { }; } -fn testNoErr( - params: []const clap.Param(u8), - args_strings: []const []const u8, +fn expectArgs( + parser: *Clap(u8, args.SliceIterator), results: []const Arg(u8), ) !void { - var iter = args.SliceIterator{ .args = args_strings }; - var c = Clap(u8, args.SliceIterator){ - .params = params, - .iter = &iter, - }; - for (results) |res| { - const arg = (try c.next()) orelse return error.TestFailed; + const arg = (try parser.next()) orelse return error.TestFailed; try testing.expectEqual(res.param, arg.param); const expected_value = res.value orelse { try testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value); @@ -233,23 +233,18 @@ fn testNoErr( try testing.expectEqualSlices(u8, expected_value, actual_value); } - if (try c.next()) |_| + if (try parser.next()) |_| return error.TestFailed; } -fn testErr( - params: []const clap.Param(u8), - args_strings: []const []const u8, +fn expectError( + parser: *Clap(u8, args.SliceIterator), expected: []const u8, ) !void { - var diag: clap.Diagnostic = undefined; - var iter = args.SliceIterator{ .args = args_strings }; - var c = Clap(u8, args.SliceIterator){ - .params = params, - .iter = &iter, - .diagnostic = &diag, - }; - while (c.next() catch |err| { + var diag: clap.Diagnostic = .{}; + parser.diagnostic = &diag; + + while (parser.next() catch |err| { var buf: [1024]u8 = undefined; var fbs = io.fixedBufferStream(&buf); diag.report(fbs.writer(), err) catch return error.TestFailed; @@ -281,29 +276,28 @@ test "short params" { const c = ¶ms[2]; const d = ¶ms[3]; - try testNoErr( - ¶ms, - &.{ - "-a", "-b", "-ab", "-ba", - "-c", "0", "-c=0", "-ac", - "0", "-ac=0", "-d=0", - }, - &.{ - .{ .param = a }, - .{ .param = b }, - .{ .param = a }, - .{ .param = b }, - .{ .param = b }, - .{ .param = a }, - .{ .param = c, .value = "0" }, - .{ .param = c, .value = "0" }, - .{ .param = a }, - .{ .param = c, .value = "0" }, - .{ .param = a }, - .{ .param = c, .value = "0" }, - .{ .param = d, .value = "0" }, - }, - ); + var iter = args.SliceIterator{ .args = &.{ + "-a", "-b", "-ab", "-ba", + "-c", "0", "-c=0", "-ac", + "0", "-ac=0", "-d=0", + } }; + var parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + + try expectArgs(&parser, &.{ + .{ .param = a }, + .{ .param = b }, + .{ .param = a }, + .{ .param = b }, + .{ .param = b }, + .{ .param = a }, + .{ .param = c, .value = "0" }, + .{ .param = c, .value = "0" }, + .{ .param = a }, + .{ .param = c, .value = "0" }, + .{ .param = a }, + .{ .param = c, .value = "0" }, + .{ .param = d, .value = "0" }, + }); } test "long params" { @@ -327,21 +321,20 @@ test "long params" { const cc = ¶ms[2]; const dd = ¶ms[3]; - try testNoErr( - ¶ms, - &.{ - "--aa", "--bb", - "--cc", "0", - "--cc=0", "--dd=0", - }, - &.{ - .{ .param = aa }, - .{ .param = bb }, - .{ .param = cc, .value = "0" }, - .{ .param = cc, .value = "0" }, - .{ .param = dd, .value = "0" }, - }, - ); + var iter = args.SliceIterator{ .args = &.{ + "--aa", "--bb", + "--cc", "0", + "--cc=0", "--dd=0", + } }; + var parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + + try expectArgs(&parser, &.{ + .{ .param = aa }, + .{ .param = bb }, + .{ .param = cc, .value = "0" }, + .{ .param = cc, .value = "0" }, + .{ .param = dd, .value = "0" }, + }); } test "positional params" { @@ -350,14 +343,16 @@ test "positional params" { .takes_value = .one, }}; - try testNoErr( - ¶ms, - &.{ "aa", "bb" }, - &.{ - .{ .param = ¶ms[0], .value = "aa" }, - .{ .param = ¶ms[0], .value = "bb" }, - }, - ); + var iter = args.SliceIterator{ .args = &.{ + "aa", + "bb", + } }; + var parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + + try expectArgs(&parser, &.{ + .{ .param = ¶ms[0], .value = "aa" }, + .{ .param = ¶ms[0], .value = "bb" }, + }); } test "all params" { @@ -383,38 +378,66 @@ test "all params" { const cc = ¶ms[2]; const positional = ¶ms[3]; - try testNoErr( - ¶ms, - &.{ - "-a", "-b", "-ab", "-ba", - "-c", "0", "-c=0", "-ac", - "0", "-ac=0", "--aa", "--bb", - "--cc", "0", "--cc=0", "something", - "-", "--", "--cc=0", "-a", - }, - &.{ - .{ .param = aa }, - .{ .param = bb }, - .{ .param = aa }, - .{ .param = bb }, - .{ .param = bb }, - .{ .param = aa }, - .{ .param = cc, .value = "0" }, - .{ .param = cc, .value = "0" }, - .{ .param = aa }, - .{ .param = cc, .value = "0" }, - .{ .param = aa }, - .{ .param = cc, .value = "0" }, - .{ .param = aa }, - .{ .param = bb }, - .{ .param = cc, .value = "0" }, - .{ .param = cc, .value = "0" }, - .{ .param = positional, .value = "something" }, - .{ .param = positional, .value = "-" }, - .{ .param = positional, .value = "--cc=0" }, - .{ .param = positional, .value = "-a" }, + var iter = args.SliceIterator{ .args = &.{ + "-a", "-b", "-ab", "-ba", + "-c", "0", "-c=0", "-ac", + "0", "-ac=0", "--aa", "--bb", + "--cc", "0", "--cc=0", "something", + "-", "--", "--cc=0", "-a", + } }; + var parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + + try expectArgs(&parser, &.{ + .{ .param = aa }, + .{ .param = bb }, + .{ .param = aa }, + .{ .param = bb }, + .{ .param = bb }, + .{ .param = aa }, + .{ .param = cc, .value = "0" }, + .{ .param = cc, .value = "0" }, + .{ .param = aa }, + .{ .param = cc, .value = "0" }, + .{ .param = aa }, + .{ .param = cc, .value = "0" }, + .{ .param = aa }, + .{ .param = bb }, + .{ .param = cc, .value = "0" }, + .{ .param = cc, .value = "0" }, + .{ .param = positional, .value = "something" }, + .{ .param = positional, .value = "-" }, + .{ .param = positional, .value = "--cc=0" }, + .{ .param = positional, .value = "-a" }, + }); +} + +test "different assignment separators" { + const params = [_]clap.Param(u8){ + .{ + .id = 0, + .names = .{ .short = 'a', .long = "aa" }, + .takes_value = .one, }, - ); + }; + + const aa = ¶ms[0]; + + var iter = args.SliceIterator{ .args = &.{ + "-a=0", "--aa=0", + "-a:0", "--aa:0", + } }; + var parser = Clap(u8, args.SliceIterator){ + .params = ¶ms, + .iter = &iter, + .assignment_separators = "=:", + }; + + try expectArgs(&parser, &.{ + .{ .param = aa, .value = "0" }, + .{ .param = aa, .value = "0" }, + .{ .param = aa, .value = "0" }, + .{ .param = aa, .value = "0" }, + }); } test "errors" { @@ -429,16 +452,36 @@ test "errors" { .takes_value = .one, }, }; - try testErr(¶ms, &.{"q"}, "Invalid argument 'q'\n"); - try testErr(¶ms, &.{"-q"}, "Invalid argument '-q'\n"); - try testErr(¶ms, &.{"--q"}, "Invalid argument '--q'\n"); - try testErr(¶ms, &.{"--q=1"}, "Invalid argument '--q'\n"); - try testErr(¶ms, &.{"-a=1"}, "The argument '-a' does not take a value\n"); - try testErr(¶ms, &.{"--aa=1"}, "The argument '--aa' does not take a value\n"); - try testErr(¶ms, &.{"-c"}, "The argument '-c' requires a value but none was supplied\n"); - try testErr( - ¶ms, - &.{"--cc"}, - "The argument '--cc' requires a value but none was supplied\n", - ); + + var iter = args.SliceIterator{ .args = &.{"q"} }; + var parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + try expectError(&parser, "Invalid argument 'q'\n"); + + iter = args.SliceIterator{ .args = &.{"-q"} }; + parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + try expectError(&parser, "Invalid argument '-q'\n"); + + iter = args.SliceIterator{ .args = &.{"--q"} }; + parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + try expectError(&parser, "Invalid argument '--q'\n"); + + iter = args.SliceIterator{ .args = &.{"--q=1"} }; + parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + try expectError(&parser, "Invalid argument '--q'\n"); + + iter = args.SliceIterator{ .args = &.{"-a=1"} }; + parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + try expectError(&parser, "The argument '-a' does not take a value\n"); + + iter = args.SliceIterator{ .args = &.{"--aa=1"} }; + parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + try expectError(&parser, "The argument '--aa' does not take a value\n"); + + iter = args.SliceIterator{ .args = &.{"-c"} }; + parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + try expectError(&parser, "The argument '-c' requires a value but none was supplied\n"); + + iter = args.SliceIterator{ .args = &.{"--cc"} }; + parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + try expectError(&parser, "The argument '--cc' requires a value but none was supplied\n"); } -- cgit v1.2.3