From c7d83fcce1739271e399260b50c5f68aa03c5908 Mon Sep 17 00:00:00 2001 From: Komari Spaghetti Date: Wed, 26 May 2021 21:06:10 +0200 Subject: Update to latest zig in preperation for 0.8.0 --- .gitignore | 1 + README.md | 16 +++--- build.zig | 18 ++----- clap.zig | 128 ++++++++++++++++++++++----------------------- clap/args.zig | 86 +++++++++++++++--------------- clap/comptime.zig | 70 +++++++++++++++---------- clap/streaming.zig | 66 +++++++++++------------ example/README.md.template | 10 ++-- example/help.zig | 2 +- example/simple-ex.zig | 10 ++-- example/simple.zig | 6 +-- example/streaming-clap.zig | 10 ++-- example/usage.zig | 2 +- 13 files changed, 211 insertions(+), 214 deletions(-) diff --git a/.gitignore b/.gitignore index 2040c29..4c82b07 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ zig-cache +zig-out diff --git a/README.md b/README.md index 398a088..4576ace 100644 --- a/README.md +++ b/README.md @@ -55,11 +55,11 @@ pub fn main() !void { if (args.flag("--help")) debug.warn("--help\n", .{}); if (args.option("--number")) |n| - debug.warn("--number = {}\n", .{n}); + debug.warn("--number = {s}\n", .{n}); for (args.options("--string")) |s| - debug.warn("--string = {}\n", .{s}); + debug.warn("--string = {s}\n", .{s}); for (args.positionals()) |pos| - debug.warn("{}\n", .{pos}); + debug.warn("{s}\n", .{pos}); } ``` @@ -154,12 +154,12 @@ pub fn main() !void { // arg.param will point to the parameter which matched the argument. switch (arg.param.id) { 'h' => debug.warn("Help!\n", .{}), - 'n' => debug.warn("--number = {}\n", .{arg.value.?}), + 'n' => debug.warn("--number = {s}\n", .{arg.value.?}), - // arg.value == null, if arg.param.takes_value == false. + // arg.value == null, if arg.param.takes_value == .none. // Otherwise, arg.value is the value passed with the argument, such as "-a=10" // or "-a 10". - 'f' => debug.warn("{}\n", .{arg.value.?}), + 'f' => debug.warn("{s}\n", .{arg.value.?}), else => unreachable, } } @@ -185,7 +185,7 @@ pub fn main() !void { // help message for any Param, but it is more verbose to call. try clap.help( std.io.getStdErr().writer(), - comptime &[_]clap.Param(clap.Help){ + comptime &.{ clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, clap.parseParam("-v, --version Output version information and exit.") catch unreachable, }, @@ -223,7 +223,7 @@ pub fn main() !void { // usage message for any Param, but it is more verbose to call. try clap.usage( std.io.getStdErr().writer(), - comptime &[_]clap.Param(clap.Help){ + comptime &.{ clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, clap.parseParam("-v, --version Output version information and exit.") catch unreachable, clap.parseParam(" --value Output version information and exit.") catch unreachable, diff --git a/build.zig b/build.zig index bef10be..5cbc731 100644 --- a/build.zig +++ b/build.zig @@ -1,4 +1,3 @@ -const builtin = @import("builtin"); const std = @import("std"); const Builder = std.build.Builder; @@ -9,13 +8,13 @@ pub fn build(b: *Builder) void { const target = b.standardTargetOptions(.{}); const test_all_step = b.step("test", "Run all tests in all modes."); - inline for ([_]Mode{ Mode.Debug, Mode.ReleaseFast, Mode.ReleaseSafe, Mode.ReleaseSmall }) |test_mode| { - const mode_str = comptime modeToString(test_mode); + inline for (@typeInfo(std.builtin.Mode).Enum.fields) |field| { + const test_mode = @field(std.builtin.Mode, field.name); + const mode_str = @tagName(test_mode); const tests = b.addTest("clap.zig"); tests.setBuildMode(test_mode); tests.setTarget(target); - tests.setNamePrefix(mode_str ++ " "); const test_step = b.step("test-" ++ mode_str, "Run all tests in " ++ mode_str ++ "."); test_step.dependOn(&tests.step); @@ -23,7 +22,7 @@ pub fn build(b: *Builder) void { } const example_step = b.step("examples", "Build examples"); - inline for ([_][]const u8{ + inline for (.{ "simple", "simple-ex", //"simple-error", @@ -70,12 +69,3 @@ fn readMeStep(b: *Builder) *std.build.Step { }.make); return s; } - -fn modeToString(mode: Mode) []const u8 { - return switch (mode) { - Mode.Debug => "debug", - Mode.ReleaseFast => "release-fast", - Mode.ReleaseSafe => "release-safe", - Mode.ReleaseSmall => "release-small", - }; -} diff --git a/clap.zig b/clap.zig index 8d721fa..ee713a7 100644 --- a/clap.zig +++ b/clap.zig @@ -122,81 +122,81 @@ fn parseParamRest(line: []const u8) Param(Help) { return .{ .id = .{ .msg = mem.trim(u8, line, " \t") } }; } -fn expectParam(expect: Param(Help), actual: Param(Help)) void { - testing.expectEqualStrings(expect.id.msg, actual.id.msg); - testing.expectEqualStrings(expect.id.value, actual.id.value); - testing.expectEqual(expect.names.short, actual.names.short); - testing.expectEqual(expect.takes_value, actual.takes_value); +fn expectParam(expect: Param(Help), actual: Param(Help)) !void { + try testing.expectEqualStrings(expect.id.msg, actual.id.msg); + try testing.expectEqualStrings(expect.id.value, actual.id.value); + try testing.expectEqual(expect.names.short, actual.names.short); + try testing.expectEqual(expect.takes_value, actual.takes_value); if (expect.names.long) |long| { - testing.expectEqualStrings(long, actual.names.long.?); + try testing.expectEqualStrings(long, actual.names.long.?); } else { - testing.expectEqual(@as(?[]const u8, null), actual.names.long); + try testing.expectEqual(@as(?[]const u8, null), actual.names.long); } } test "parseParam" { - expectParam(Param(Help){ + try expectParam(Param(Help){ .id = .{ .msg = "Help text", .value = "value" }, .names = .{ .short = 's', .long = "long" }, .takes_value = .one, }, try parseParam("-s, --long Help text")); - expectParam(Param(Help){ + try expectParam(Param(Help){ .id = .{ .msg = "Help text", .value = "value" }, .names = .{ .short = 's', .long = "long" }, .takes_value = .many, }, try parseParam("-s, --long ... Help text")); - expectParam(Param(Help){ + try expectParam(Param(Help){ .id = .{ .msg = "Help text", .value = "value" }, .names = .{ .long = "long" }, .takes_value = .one, }, try parseParam("--long Help text")); - expectParam(Param(Help){ + try expectParam(Param(Help){ .id = .{ .msg = "Help text", .value = "value" }, .names = .{ .short = 's' }, .takes_value = .one, }, try parseParam("-s Help text")); - expectParam(Param(Help){ + try expectParam(Param(Help){ .id = .{ .msg = "Help text" }, .names = .{ .short = 's', .long = "long" }, }, try parseParam("-s, --long Help text")); - expectParam(Param(Help){ + try expectParam(Param(Help){ .id = .{ .msg = "Help text" }, .names = .{ .short = 's' }, }, try parseParam("-s Help text")); - expectParam(Param(Help){ + try expectParam(Param(Help){ .id = .{ .msg = "Help text" }, .names = .{ .long = "long" }, }, try parseParam("--long Help text")); - expectParam(Param(Help){ + try expectParam(Param(Help){ .id = .{ .msg = "Help text", .value = "A | B" }, .names = .{ .long = "long" }, .takes_value = .one, }, try parseParam("--long Help text")); - expectParam(Param(Help){ + try expectParam(Param(Help){ .id = .{ .msg = "Help text", .value = "A" }, .names = .{}, .takes_value = .one, }, try parseParam(" Help text")); - expectParam(Param(Help){ + try expectParam(Param(Help){ .id = .{ .msg = "Help text", .value = "A" }, .names = .{}, .takes_value = .many, }, try parseParam("... Help text")); - testing.expectError(error.TrailingComma, parseParam("--long, Help")); - testing.expectError(error.TrailingComma, parseParam("-s, Help")); - testing.expectError(error.InvalidShortParam, parseParam("-ss Help")); - testing.expectError(error.InvalidShortParam, parseParam("-ss Help")); - testing.expectError(error.InvalidShortParam, parseParam("- Help")); + try testing.expectError(error.TrailingComma, parseParam("--long, Help")); + try testing.expectError(error.TrailingComma, parseParam("-s, Help")); + try testing.expectError(error.InvalidShortParam, parseParam("-ss Help")); + try testing.expectError(error.InvalidShortParam, parseParam("-ss Help")); + try testing.expectError(error.InvalidShortParam, parseParam("- Help")); } /// Optional diagnostics used for reporting useful errors @@ -227,24 +227,24 @@ pub const Diagnostic = struct { } }; -fn testDiag(diag: Diagnostic, err: anyerror, expected: []const u8) void { +fn testDiag(diag: Diagnostic, err: anyerror, expected: []const u8) !void { var buf: [1024]u8 = undefined; var slice_stream = io.fixedBufferStream(&buf); diag.report(slice_stream.writer(), err) catch unreachable; - testing.expectEqualStrings(expected, slice_stream.getWritten()); + try testing.expectEqualStrings(expected, slice_stream.getWritten()); } test "Diagnostic.report" { - testDiag(.{ .arg = "c" }, error.InvalidArgument, "Invalid argument 'c'\n"); - testDiag(.{ .name = .{ .long = "cc" } }, error.InvalidArgument, "Invalid argument '--cc'\n"); - testDiag(.{ .name = .{ .short = 'c' } }, error.DoesntTakeValue, "The argument '-c' does not take a value\n"); - testDiag(.{ .name = .{ .long = "cc" } }, error.DoesntTakeValue, "The argument '--cc' does not take a value\n"); - testDiag(.{ .name = .{ .short = 'c' } }, error.MissingValue, "The argument '-c' requires a value but none was supplied\n"); - testDiag(.{ .name = .{ .long = "cc" } }, error.MissingValue, "The argument '--cc' requires a value but none was supplied\n"); - testDiag(.{ .name = .{ .short = 'c' } }, error.InvalidArgument, "Invalid argument '-c'\n"); - testDiag(.{ .name = .{ .long = "cc" } }, error.InvalidArgument, "Invalid argument '--cc'\n"); - testDiag(.{ .name = .{ .short = 'c' } }, error.SomethingElse, "Error while parsing arguments: SomethingElse\n"); - testDiag(.{ .name = .{ .long = "cc" } }, error.SomethingElse, "Error while parsing arguments: SomethingElse\n"); + try testDiag(.{ .arg = "c" }, error.InvalidArgument, "Invalid argument 'c'\n"); + try testDiag(.{ .name = .{ .long = "cc" } }, error.InvalidArgument, "Invalid argument '--cc'\n"); + try testDiag(.{ .name = .{ .short = 'c' } }, error.DoesntTakeValue, "The argument '-c' does not take a value\n"); + try testDiag(.{ .name = .{ .long = "cc" } }, error.DoesntTakeValue, "The argument '--cc' does not take a value\n"); + try testDiag(.{ .name = .{ .short = 'c' } }, error.MissingValue, "The argument '-c' requires a value but none was supplied\n"); + try testDiag(.{ .name = .{ .long = "cc" } }, error.MissingValue, "The argument '--cc' requires a value but none was supplied\n"); + try testDiag(.{ .name = .{ .short = 'c' } }, error.InvalidArgument, "Invalid argument '-c'\n"); + try testDiag(.{ .name = .{ .long = "cc" } }, error.InvalidArgument, "Invalid argument '--cc'\n"); + try testDiag(.{ .name = .{ .short = 'c' } }, error.SomethingElse, "Error while parsing arguments: SomethingElse\n"); + try testDiag(.{ .name = .{ .long = "cc" } }, error.SomethingElse, "Error while parsing arguments: SomethingElse\n"); } pub fn Args(comptime Id: type, comptime params: []const Param(Id)) type { @@ -338,7 +338,7 @@ pub fn helpFull( const max_spacing = blk: { var res: usize = 0; for (params) |param| { - var cs = io.countingOutStream(io.null_writer); + var cs = io.countingWriter(io.null_writer); try printParam(cs.writer(), Id, param, Error, context, valueText); if (res < cs.bytes_written) res = @intCast(usize, cs.bytes_written); @@ -355,7 +355,7 @@ pub fn helpFull( try stream.print("\t", .{}); try printParam(cs.writer(), Id, param, Error, context, valueText); try stream.writeByteNTimes(' ', max_spacing - @intCast(usize, cs.bytes_written)); - try stream.print("\t{}\n", .{try helpText(context, param)}); + try stream.print("\t{s}\n", .{try helpText(context, param)}); } } @@ -450,7 +450,7 @@ test "clap.help" { @setEvalBranchQuota(10000); try help( slice_stream.writer(), - comptime &[_]Param(Help){ + comptime &.{ parseParam("-a Short flag.") catch unreachable, parseParam("-b Short option.") catch unreachable, parseParam("--aa Long flag.") catch unreachable, @@ -471,7 +471,7 @@ test "clap.help" { "\t-d, --dd \tBoth option.\n" ++ "\t-d, --dd ...\tBoth repeated option.\n"; - testing.expectEqualStrings(expected, slice_stream.getWritten()); + try testing.expectEqualStrings(expected, slice_stream.getWritten()); } /// Will print a usage message in the following format: @@ -569,40 +569,40 @@ fn testUsage(expected: []const u8, params: []const Param(Help)) !void { var buf: [1024]u8 = undefined; var fbs = io.fixedBufferStream(&buf); try usage(fbs.writer(), params); - testing.expectEqualStrings(expected, fbs.getWritten()); + try testing.expectEqualStrings(expected, fbs.getWritten()); } test "usage" { @setEvalBranchQuota(100000); - try testUsage("[-ab]", comptime &[_]Param(Help){ - parseParam("-a") catch unreachable, - parseParam("-b") catch unreachable, + try testUsage("[-ab]", &.{ + try parseParam("-a"), + try parseParam("-b"), }); - try testUsage("[-a ] [-b ]", comptime &[_]Param(Help){ - parseParam("-a ") catch unreachable, - parseParam("-b ") catch unreachable, + try testUsage("[-a ] [-b ]", &.{ + try parseParam("-a "), + try parseParam("-b "), }); - try testUsage("[--a] [--b]", comptime &[_]Param(Help){ - parseParam("--a") catch unreachable, - parseParam("--b") catch unreachable, + try testUsage("[--a] [--b]", &.{ + try parseParam("--a"), + try parseParam("--b"), }); - try testUsage("[--a ] [--b ]", comptime &[_]Param(Help){ - parseParam("--a ") catch unreachable, - parseParam("--b ") catch unreachable, + try testUsage("[--a ] [--b ]", &.{ + try parseParam("--a "), + try parseParam("--b "), }); - try testUsage("", comptime &[_]Param(Help){ - parseParam("") catch unreachable, + try testUsage("", &.{ + try parseParam(""), }); - try testUsage("[-ab] [-c ] [-d ] [--e] [--f] [--g ] [--h ] [-i ...] ", comptime &[_]Param(Help){ - parseParam("-a") catch unreachable, - parseParam("-b") catch unreachable, - parseParam("-c ") catch unreachable, - parseParam("-d ") catch unreachable, - parseParam("--e") catch unreachable, - parseParam("--f") catch unreachable, - parseParam("--g ") catch unreachable, - parseParam("--h ") catch unreachable, - parseParam("-i ...") catch unreachable, - parseParam("") catch unreachable, + try testUsage("[-ab] [-c ] [-d ] [--e] [--f] [--g ] [--h ] [-i ...] ", &.{ + try parseParam("-a"), + try parseParam("-b"), + try parseParam("-c "), + try parseParam("-d "), + try parseParam("--e"), + try parseParam("--f"), + try parseParam("--g "), + try parseParam("--h "), + try parseParam("-i ..."), + try parseParam(""), }); } diff --git a/clap/args.zig b/clap/args.zig index f9ad218..555e8ab 100644 --- a/clap/args.zig +++ b/clap/args.zig @@ -34,8 +34,8 @@ pub const SliceIterator = struct { }; test "SliceIterator" { - const args = &[_][]const u8{ "A", "BB", "CCC" }; - var iter = SliceIterator{ .args = args }; + const args = [_][]const u8{ "A", "BB", "CCC" }; + var iter = SliceIterator{ .args = &args }; for (args) |a| { const b = try iter.next(); @@ -266,76 +266,76 @@ pub const ShellIterator = struct { } }; -fn testShellIteratorOk(str: []const u8, allocations: usize, expect: []const []const u8) void { +fn testShellIteratorOk(str: []const u8, allocations: usize, expect: []const []const u8) !void { var allocator = testing.FailingAllocator.init(testing.allocator, allocations); var it = ShellIterator.init(&allocator.allocator, str); defer it.deinit(); for (expect) |e| { if (it.next()) |actual| { - testing.expect(actual != null); - testing.expectEqualStrings(e, actual.?); - } else |err| testing.expectEqual(@as(anyerror![]const u8, e), err); + try testing.expect(actual != null); + try testing.expectEqualStrings(e, actual.?); + } else |err| try testing.expectEqual(@as(anyerror![]const u8, e), err); } if (it.next()) |actual| { - testing.expectEqual(@as(?[]const u8, null), actual); - testing.expectEqual(allocations, allocator.allocations); - } else |err| testing.expectEqual(@as(anyerror!void, {}), err); + try testing.expectEqual(@as(?[]const u8, null), actual); + try testing.expectEqual(allocations, allocator.allocations); + } else |err| try testing.expectEqual(@as(anyerror!void, {}), err); } -fn testShellIteratorErr(str: []const u8, expect: anyerror) void { +fn testShellIteratorErr(str: []const u8, expect: anyerror) !void { var it = ShellIterator.init(testing.allocator, str); defer it.deinit(); while (it.next() catch |err| { - testing.expectError(expect, @as(anyerror!void, err)); + try testing.expectError(expect, @as(anyerror!void, err)); return; }) |_| {} - testing.expectError(expect, @as(anyerror!void, {})); + try testing.expectError(expect, @as(anyerror!void, {})); } test "ShellIterator" { - testShellIteratorOk("a", 0, &[_][]const u8{"a"}); - testShellIteratorOk("'a'", 0, &[_][]const u8{"a"}); - testShellIteratorOk("\"a\"", 0, &[_][]const u8{"a"}); - testShellIteratorOk("a b", 0, &[_][]const u8{ "a", "b" }); - testShellIteratorOk("'a' b", 0, &[_][]const u8{ "a", "b" }); - testShellIteratorOk("\"a\" b", 0, &[_][]const u8{ "a", "b" }); - testShellIteratorOk("a 'b'", 0, &[_][]const u8{ "a", "b" }); - testShellIteratorOk("a \"b\"", 0, &[_][]const u8{ "a", "b" }); - testShellIteratorOk("'a b'", 0, &[_][]const u8{"a b"}); - testShellIteratorOk("\"a b\"", 0, &[_][]const u8{"a b"}); - testShellIteratorOk("\"a\"\"b\"", 1, &[_][]const u8{"ab"}); - testShellIteratorOk("'a''b'", 1, &[_][]const u8{"ab"}); - testShellIteratorOk("'a'b", 1, &[_][]const u8{"ab"}); - testShellIteratorOk("a'b'", 1, &[_][]const u8{"ab"}); - testShellIteratorOk("a\\ b", 1, &[_][]const u8{"a b"}); - testShellIteratorOk("\"a\\ b\"", 1, &[_][]const u8{"a b"}); - testShellIteratorOk("'a\\ b'", 0, &[_][]const u8{"a\\ b"}); - testShellIteratorOk(" a b ", 0, &[_][]const u8{ "a", "b" }); - testShellIteratorOk("\\ \\ ", 0, &[_][]const u8{ " ", " " }); - - testShellIteratorOk( + try testShellIteratorOk("a", 0, &.{"a"}); + try testShellIteratorOk("'a'", 0, &.{"a"}); + try testShellIteratorOk("\"a\"", 0, &.{"a"}); + try testShellIteratorOk("a b", 0, &.{ "a", "b" }); + try testShellIteratorOk("'a' b", 0, &.{ "a", "b" }); + try testShellIteratorOk("\"a\" b", 0, &.{ "a", "b" }); + try testShellIteratorOk("a 'b'", 0, &.{ "a", "b" }); + try testShellIteratorOk("a \"b\"", 0, &.{ "a", "b" }); + try testShellIteratorOk("'a b'", 0, &.{"a b"}); + try testShellIteratorOk("\"a b\"", 0, &.{"a b"}); + try testShellIteratorOk("\"a\"\"b\"", 1, &.{"ab"}); + try testShellIteratorOk("'a''b'", 1, &.{"ab"}); + try testShellIteratorOk("'a'b", 1, &.{"ab"}); + try testShellIteratorOk("a'b'", 1, &.{"ab"}); + try testShellIteratorOk("a\\ b", 1, &.{"a b"}); + try testShellIteratorOk("\"a\\ b\"", 1, &.{"a b"}); + try testShellIteratorOk("'a\\ b'", 0, &.{"a\\ b"}); + try testShellIteratorOk(" a b ", 0, &.{ "a", "b" }); + try testShellIteratorOk("\\ \\ ", 0, &.{ " ", " " }); + + try testShellIteratorOk( \\printf 'run\nuninstall\n' - , 0, &[_][]const u8{ "printf", "run\\nuninstall\\n" }); - testShellIteratorOk( + , 0, &.{ "printf", "run\\nuninstall\\n" }); + try testShellIteratorOk( \\setsid -f steam "steam://$action/$id" - , 0, &[_][]const u8{ "setsid", "-f", "steam", "steam://$action/$id" }); - testShellIteratorOk( + , 0, &.{ "setsid", "-f", "steam", "steam://$action/$id" }); + try testShellIteratorOk( \\xargs -I% rg --no-heading --no-line-number --only-matching \\ --case-sensitive --multiline --text --byte-offset '(?-u)%' $@ \\ - , 0, &[_][]const u8{ + , 0, &.{ "xargs", "-I%", "rg", "--no-heading", "--no-line-number", "--only-matching", "--case-sensitive", "--multiline", "--text", "--byte-offset", "(?-u)%", "$@", }); - testShellIteratorErr("'a", error.QuoteNotClosed); - testShellIteratorErr("'a\\", error.QuoteNotClosed); - testShellIteratorErr("\"a", error.QuoteNotClosed); - testShellIteratorErr("\"a\\", error.QuoteNotClosed); - testShellIteratorErr("a\\", error.DanglingEscape); + try testShellIteratorErr("'a", error.QuoteNotClosed); + try testShellIteratorErr("'a\\", error.QuoteNotClosed); + try testShellIteratorErr("\"a", error.QuoteNotClosed); + try testShellIteratorErr("\"a\\", error.QuoteNotClosed); + try testShellIteratorErr("a\\", error.DanglingEscape); } diff --git a/clap/comptime.zig b/clap/comptime.zig index 122ff16..7808f52 100644 --- a/clap/comptime.zig +++ b/clap/comptime.zig @@ -14,7 +14,7 @@ pub fn ComptimeClap( var flags: usize = 0; var single_options: usize = 0; var multi_options: usize = 0; - var converted_params: []const clap.Param(usize) = &[_]clap.Param(usize){}; + var converted_params: []const clap.Param(usize) = &.{}; for (params) |param| { var index: usize = 0; if (param.names.long != null or param.names.short != null) { @@ -27,18 +27,18 @@ pub fn ComptimeClap( ptr.* += 1; } - const converted = clap.Param(usize){ + converted_params = converted_params ++ [_]clap.Param(usize){.{ .id = index, .names = param.names, .takes_value = param.takes_value, - }; - converted_params = converted_params ++ [_]clap.Param(usize){converted}; + }}; } return struct { - single_options: [single_options]?[]const u8, multi_options: [multi_options][]const []const u8, - flags: [flags]bool, + single_options: [single_options][]const u8, + single_options_is_set: std.PackedIntArray(u1, single_options), + flags: std.PackedIntArray(u1, flags), pos: []const []const u8, allocator: *mem.Allocator, @@ -52,9 +52,12 @@ pub fn ComptimeClap( var pos = std.ArrayList([]const u8).init(allocator); var res = @This(){ - .single_options = [_]?[]const u8{null} ** single_options, - .multi_options = [_][]const []const u8{undefined} ** multi_options, - .flags = [_]bool{false} ** flags, + .multi_options = .{undefined} ** multi_options, + .single_options = .{undefined} ** single_options, + .single_options_is_set = std.PackedIntArray(u1, single_options).init( + .{0} ** single_options, + ), + .flags = std.PackedIntArray(u1, flags).init(.{0} ** flags), .pos = undefined, .allocator = allocator, }; @@ -69,16 +72,18 @@ pub fn ComptimeClap( try pos.append(arg.value.?); } else if (param.takes_value == .one) { debug.assert(res.single_options.len != 0); - if (res.single_options.len != 0) + if (res.single_options.len != 0) { res.single_options[param.id] = arg.value.?; + res.single_options_is_set.set(param.id, 1); + } } else if (param.takes_value == .many) { debug.assert(multis.len != 0); if (multis.len != 0) try multis[param.id].append(arg.value.?); } else { - debug.assert(res.flags.len != 0); - if (res.flags.len != 0) - res.flags[param.id] = true; + debug.assert(res.flags.len() != 0); + if (res.flags.len() != 0) + res.flags.set(param.id, 1); } } @@ -100,7 +105,7 @@ pub fn ComptimeClap( if (param.takes_value != .none) @compileError(name ++ " is an option and not a flag."); - return parser.flags[param.id]; + return parser.flags.get(param.id) != 0; } pub fn option(parser: @This(), comptime name: []const u8) ?[]const u8 { @@ -109,6 +114,8 @@ pub fn ComptimeClap( @compileError(name ++ " is a flag and not an option."); if (param.takes_value == .many) @compileError(name ++ " takes many options, not one."); + if (parser.single_options_is_set.get(param.id) == 0) + return null; return parser.single_options[param.id]; } @@ -146,30 +153,37 @@ pub fn ComptimeClap( } test "" { - const Clap = ComptimeClap(clap.Help, comptime &[_]clap.Param(clap.Help){ - clap.parseParam("-a, --aa ") catch unreachable, - clap.parseParam("-b, --bb ") catch unreachable, + const Clap = ComptimeClap(clap.Help, comptime &.{ + clap.parseParam("-a, --aa") catch unreachable, + clap.parseParam("-b, --bb") catch unreachable, clap.parseParam("-c, --cc ") catch unreachable, clap.parseParam("-d, --dd ...") catch unreachable, clap.parseParam("

") catch unreachable, }); var iter = clap.args.SliceIterator{ - .args = &[_][]const u8{ + .args = &.{ "-a", "-c", "0", "something", "-d", "a", "--dd", "b", }, }; var args = try Clap.parse(&iter, .{ .allocator = testing.allocator }); defer args.deinit(); - testing.expect(args.flag("-a")); - testing.expect(args.flag("--aa")); - testing.expect(!args.flag("-b")); - testing.expect(!args.flag("--bb")); - testing.expectEqualStrings("0", args.option("-c").?); - testing.expectEqualStrings("0", args.option("--cc").?); - testing.expectEqual(@as(usize, 1), args.positionals().len); - testing.expectEqualStrings("something", args.positionals()[0]); - testing.expectEqualSlices([]const u8, &[_][]const u8{ "a", "b" }, args.options("-d")); - testing.expectEqualSlices([]const u8, &[_][]const u8{ "a", "b" }, args.options("--dd")); + try testing.expect(args.flag("-a")); + try testing.expect(args.flag("--aa")); + try testing.expect(!args.flag("-b")); + try testing.expect(!args.flag("--bb")); + try testing.expectEqualStrings("0", args.option("-c").?); + try testing.expectEqualStrings("0", args.option("--cc").?); + try testing.expectEqual(@as(usize, 1), args.positionals().len); + try testing.expectEqualStrings("something", args.positionals()[0]); + try testing.expectEqualSlices([]const u8, &.{ "a", "b" }, args.options("-d")); + try testing.expectEqualSlices([]const u8, &.{ "a", "b" }, args.options("--dd")); +} + +test "empty" { + const Clap = ComptimeClap(clap.Help, comptime &.{}); + var iter = clap.args.SliceIterator{ .args = &.{} }; + var args = try Clap.parse(&iter, .{ .allocator = testing.allocator }); + defer args.deinit(); } diff --git a/clap/streaming.zig b/clap/streaming.zig index a2a0ca8..e2f1311 100644 --- a/clap/streaming.zig +++ b/clap/streaming.zig @@ -203,7 +203,7 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { }; } -fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, results: []const Arg(u8)) void { +fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, results: []const Arg(u8)) !void { var iter = args.SliceIterator{ .args = args_strings }; var c = StreamingClap(u8, args.SliceIterator){ .params = params, @@ -211,22 +211,22 @@ fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, r }; for (results) |res| { - const arg = (c.next() catch unreachable) orelse unreachable; - testing.expectEqual(res.param, arg.param); + const arg = (try c.next()) orelse return error.TestFailed; + try testing.expectEqual(res.param, arg.param); const expected_value = res.value orelse { - testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value); + try testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value); continue; }; - const actual_value = arg.value orelse unreachable; - testing.expectEqualSlices(u8, expected_value, actual_value); + const actual_value = arg.value orelse return error.TestFailed; + try testing.expectEqualSlices(u8, expected_value, actual_value); } - if (c.next() catch unreachable) |_| - unreachable; + if (try c.next()) |_| + return error.TestFailed; } -fn testErr(params: []const clap.Param(u8), args_strings: []const []const u8, expected: []const u8) void { - var diag = clap.Diagnostic{}; +fn testErr(params: []const clap.Param(u8), args_strings: []const []const u8, expected: []const u8) !void { + var diag: clap.Diagnostic = undefined; var iter = args.SliceIterator{ .args = args_strings }; var c = StreamingClap(u8, args.SliceIterator){ .params = params, @@ -236,12 +236,12 @@ fn testErr(params: []const clap.Param(u8), args_strings: []const []const u8, exp while (c.next() catch |err| { var buf: [1024]u8 = undefined; var fbs = io.fixedBufferStream(&buf); - diag.report(fbs.writer(), err) catch unreachable; - testing.expectEqualStrings(expected, fbs.getWritten()); + diag.report(fbs.writer(), err) catch return error.TestFailed; + try testing.expectEqualStrings(expected, fbs.getWritten()); return; }) |_| {} - testing.expect(false); + try testing.expect(false); } test "short params" { @@ -265,14 +265,14 @@ test "short params" { const c = ¶ms[2]; const d = ¶ms[3]; - testNoErr( + try testNoErr( ¶ms, - &[_][]const u8{ + &.{ "-a", "-b", "-ab", "-ba", "-c", "0", "-c=0", "-ac", "0", "-ac=0", "-d=0", }, - &[_]Arg(u8){ + &.{ .{ .param = a }, .{ .param = b }, .{ .param = a }, @@ -311,14 +311,14 @@ test "long params" { const cc = ¶ms[2]; const dd = ¶ms[3]; - testNoErr( + try testNoErr( ¶ms, - &[_][]const u8{ + &.{ "--aa", "--bb", "--cc", "0", "--cc=0", "--dd=0", }, - &[_]Arg(u8){ + &.{ .{ .param = aa }, .{ .param = bb }, .{ .param = cc, .value = "0" }, @@ -334,10 +334,10 @@ test "positional params" { .takes_value = .one, }}; - testNoErr( + try testNoErr( ¶ms, - &[_][]const u8{ "aa", "bb" }, - &[_]Arg(u8){ + &.{ "aa", "bb" }, + &.{ .{ .param = ¶ms[0], .value = "aa" }, .{ .param = ¶ms[0], .value = "bb" }, }, @@ -367,16 +367,16 @@ test "all params" { const cc = ¶ms[2]; const positional = ¶ms[3]; - testNoErr( + try testNoErr( ¶ms, - &[_][]const u8{ + &.{ "-a", "-b", "-ab", "-ba", "-c", "0", "-c=0", "-ac", "0", "-ac=0", "--aa", "--bb", "--cc", "0", "--cc=0", "something", "-", "--", "--cc=0", "-a", }, - &[_]Arg(u8){ + &.{ .{ .param = aa }, .{ .param = bb }, .{ .param = aa }, @@ -413,12 +413,12 @@ test "errors" { .takes_value = .one, }, }; - testErr(¶ms, &[_][]const u8{"q"}, "Invalid argument 'q'\n"); - testErr(¶ms, &[_][]const u8{"-q"}, "Invalid argument '-q'\n"); - testErr(¶ms, &[_][]const u8{"--q"}, "Invalid argument '--q'\n"); - testErr(¶ms, &[_][]const u8{"--q=1"}, "Invalid argument '--q'\n"); - testErr(¶ms, &[_][]const u8{"-a=1"}, "The argument '-a' does not take a value\n"); - testErr(¶ms, &[_][]const u8{"--aa=1"}, "The argument '--aa' does not take a value\n"); - testErr(¶ms, &[_][]const u8{"-c"}, "The argument '-c' requires a value but none was supplied\n"); - testErr(¶ms, &[_][]const u8{"--cc"}, "The argument '--cc' requires a value but none was supplied\n"); + 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"); } diff --git a/example/README.md.template b/example/README.md.template index 530cea4..74a2f1d 100644 --- a/example/README.md.template +++ b/example/README.md.template @@ -25,7 +25,7 @@ into master on every `zig` release. The simplest way to use this library is to just call the `clap.parse` function. ```zig -{} +{s} ``` The data structure returned has lookup speed on par with array access (`arr[i]`) and validates @@ -33,7 +33,7 @@ that the strings you pass to `option`, `options` and `flag` are actually paramet program can take: ```zig -{} +{s} ``` ``` @@ -58,7 +58,7 @@ The `StreamingClap` is the base of all the other parsers. It's a streaming parse `args.Iterator` to provide it with arguments lazily. ```zig -{} +{s} ``` Currently, this parse is the only parser that allow an array of `Param` tha @@ -70,7 +70,7 @@ The `help`, `helpEx` and `helpFull` are functions for printing a simple list of program can take. ```zig -{} +{s} ``` ``` @@ -93,7 +93,7 @@ The `usage`, `usageEx` and `usageFull` are functions for printing a small abbrev of the help message. ```zig -{} +{s} ``` ``` diff --git a/example/help.zig b/example/help.zig index 3cf9e42..d90373a 100644 --- a/example/help.zig +++ b/example/help.zig @@ -7,7 +7,7 @@ pub fn main() !void { // help message for any Param, but it is more verbose to call. try clap.help( std.io.getStdErr().writer(), - comptime &[_]clap.Param(clap.Help){ + comptime &.{ clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, clap.parseParam("-v, --version Output version information and exit.") catch unreachable, }, diff --git a/example/simple-ex.zig b/example/simple-ex.zig index 88598aa..838b9c2 100644 --- a/example/simple-ex.zig +++ b/example/simple-ex.zig @@ -30,11 +30,7 @@ pub fn main() !void { .diagnostic = &diag, }) catch |err| { // Report useful error and exit -<<<<<<< HEAD - diag.report(std.io.getStdErr().writer(), err) catch {}; -======= diag.report(io.getStdErr().writer(), err) catch {}; ->>>>>>> master return err; }; defer args.deinit(); @@ -42,9 +38,9 @@ pub fn main() !void { if (args.flag("--help")) debug.warn("--help\n", .{}); if (args.option("--number")) |n| - debug.warn("--number = {}\n", .{n}); + debug.warn("--number = {s}\n", .{n}); for (args.options("--string")) |s| - debug.warn("--string = {}\n", .{s}); + debug.warn("--string = {s}\n", .{s}); for (args.positionals()) |pos| - debug.warn("{}\n", .{pos}); + debug.warn("{s}\n", .{pos}); } diff --git a/example/simple.zig b/example/simple.zig index 69473fa..78a963c 100644 --- a/example/simple.zig +++ b/example/simple.zig @@ -28,9 +28,9 @@ pub fn main() !void { if (args.flag("--help")) debug.warn("--help\n", .{}); if (args.option("--number")) |n| - debug.warn("--number = {}\n", .{n}); + debug.warn("--number = {s}\n", .{n}); for (args.options("--string")) |s| - debug.warn("--string = {}\n", .{s}); + debug.warn("--string = {s}\n", .{s}); for (args.positionals()) |pos| - debug.warn("{}\n", .{pos}); + debug.warn("{s}\n", .{pos}); } diff --git a/example/streaming-clap.zig b/example/streaming-clap.zig index 32d44c4..5f7f219 100644 --- a/example/streaming-clap.zig +++ b/example/streaming-clap.zig @@ -39,22 +39,18 @@ pub fn main() !void { // Because we use a streaming parser, we have to consume each argument parsed individually. while (parser.next() catch |err| { // Report useful error and exit -<<<<<<< HEAD - diag.report(std.io.getStdErr().writer(), err) catch {}; -======= diag.report(io.getStdErr().writer(), err) catch {}; ->>>>>>> master return err; }) |arg| { // arg.param will point to the parameter which matched the argument. switch (arg.param.id) { 'h' => debug.warn("Help!\n", .{}), - 'n' => debug.warn("--number = {}\n", .{arg.value.?}), + 'n' => debug.warn("--number = {s}\n", .{arg.value.?}), - // arg.value == null, if arg.param.takes_value == false. + // arg.value == null, if arg.param.takes_value == .none. // Otherwise, arg.value is the value passed with the argument, such as "-a=10" // or "-a 10". - 'f' => debug.warn("{}\n", .{arg.value.?}), + 'f' => debug.warn("{s}\n", .{arg.value.?}), else => unreachable, } } diff --git a/example/usage.zig b/example/usage.zig index e044f1d..7956570 100644 --- a/example/usage.zig +++ b/example/usage.zig @@ -7,7 +7,7 @@ pub fn main() !void { // usage message for any Param, but it is more verbose to call. try clap.usage( std.io.getStdErr().writer(), - comptime &[_]clap.Param(clap.Help){ + comptime &.{ clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, clap.parseParam("-v, --version Output version information and exit.") catch unreachable, clap.parseParam(" --value Output version information and exit.") catch unreachable, -- cgit v1.2.3