From e73b56aa4bcb7e53144ef96ee978f2a19b32669d Mon Sep 17 00:00:00 2001 From: Jimmi Holst Christensen Date: Tue, 22 Oct 2024 17:46:47 +0200 Subject: refactor: Always access using full namespace This is my new preferred style of programming Zig :) --- README.md | 77 +++++++--------- build.zig | 4 +- clap.zig | 183 ++++++++++++++++++------------------- clap/args.zig | 15 +-- clap/codepoint_counting_writer.zig | 7 +- clap/parsers.zig | 55 ++++++----- clap/streaming.zig | 95 +++++++++---------- example/help.zig | 8 +- example/simple-ex.zig | 22 ++--- example/simple.zig | 19 ++-- example/streaming-clap.zig | 22 ++--- example/usage.zig | 6 +- 12 files changed, 232 insertions(+), 281 deletions(-) diff --git a/README.md b/README.md index bc38b58..c6e14e9 100644 --- a/README.md +++ b/README.md @@ -56,12 +56,6 @@ Note that Zig autodoc is in beta; the website may be broken or incomplete. The simplest way to use this library is to just call the `clap.parse` function. ```zig -const clap = @import("clap"); -const std = @import("std"); - -const debug = std.debug; -const io = std.io; - pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -85,21 +79,24 @@ pub fn main() !void { .allocator = gpa.allocator(), }) catch |err| { // Report useful error and exit - diag.report(io.getStdErr().writer(), err) catch {}; + diag.report(std.io.getStdErr().writer(), err) catch {}; return err; }; defer res.deinit(); if (res.args.help != 0) - debug.print("--help\n", .{}); + std.debug.print("--help\n", .{}); if (res.args.number) |n| - debug.print("--number = {}\n", .{n}); + std.debug.print("--number = {}\n", .{n}); for (res.args.string) |s| - debug.print("--string = {s}\n", .{s}); + std.debug.print("--string = {s}\n", .{s}); for (res.positionals) |pos| - debug.print("{s}\n", .{pos}); + std.debug.print("{s}\n", .{pos}); } +const clap = @import("clap"); +const std = @import("std"); + ``` The result will contain an `args` field and a `positionals` field. `args` will have one field @@ -114,13 +111,6 @@ contains a parser that returns `usize`. You can pass in something other than `clap.parsers.default` if you want some other mapping. ```zig -const clap = @import("clap"); -const std = @import("std"); - -const debug = std.debug; -const io = std.io; -const process = std.process; - pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -154,23 +144,26 @@ pub fn main() !void { // allowed. .assignment_separators = "=:", }) catch |err| { - diag.report(io.getStdErr().writer(), err) catch {}; + diag.report(std.io.getStdErr().writer(), err) catch {}; return err; }; defer res.deinit(); if (res.args.help != 0) - debug.print("--help\n", .{}); + std.debug.print("--help\n", .{}); if (res.args.number) |n| - debug.print("--number = {}\n", .{n}); + std.debug.print("--number = {}\n", .{n}); if (res.args.answer) |a| - debug.print("--answer = {s}\n", .{@tagName(a)}); + std.debug.print("--answer = {s}\n", .{@tagName(a)}); for (res.args.string) |s| - debug.print("--string = {s}\n", .{s}); + std.debug.print("--string = {s}\n", .{s}); for (res.positionals) |pos| - debug.print("{s}\n", .{pos}); + std.debug.print("{s}\n", .{pos}); } +const clap = @import("clap"); +const std = @import("std"); + ``` ### `streaming.Clap` @@ -179,13 +172,6 @@ The `streaming.Clap` is the base of all the other parsers. It's a streaming pars `args.Iterator` to provide it with arguments lazily. ```zig -const clap = @import("clap"); -const std = @import("std"); - -const debug = std.debug; -const io = std.io; -const process = std.process; - pub fn main() !void { const allocator = std.heap.page_allocator; @@ -203,7 +189,7 @@ pub fn main() !void { .{ .id = 'f', .takes_value = .one }, }; - var iter = try process.ArgIterator.initWithAllocator(allocator); + var iter = try std.process.ArgIterator.initWithAllocator(allocator); defer iter.deinit(); // Skip exe argument @@ -213,7 +199,7 @@ pub fn main() !void { // This is optional. You can also leave the `diagnostic` field unset if you // don't care about the extra information `Diagnostic` provides. var diag = clap.Diagnostic{}; - var parser = clap.streaming.Clap(u8, process.ArgIterator){ + var parser = clap.streaming.Clap(u8, std.process.ArgIterator){ .params = ¶ms, .iter = &iter, .diagnostic = &diag, @@ -222,23 +208,26 @@ 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 - diag.report(io.getStdErr().writer(), err) catch {}; + diag.report(std.io.getStdErr().writer(), err) catch {}; return err; }) |arg| { // arg.param will point to the parameter which matched the argument. switch (arg.param.id) { - 'h' => debug.print("Help!\n", .{}), - 'n' => debug.print("--number = {s}\n", .{arg.value.?}), + 'h' => std.debug.print("Help!\n", .{}), + 'n' => std.debug.print("--number = {s}\n", .{arg.value.?}), // 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.print("{s}\n", .{arg.value.?}), + 'f' => std.debug.print("{s}\n", .{arg.value.?}), else => unreachable, } } } +const clap = @import("clap"); +const std = @import("std"); + ``` Currently, this parser is the only parser that allows an array of `Param` that @@ -252,9 +241,6 @@ in the output. `HelpOptions` is passed to `help` to control how the help message printed. ```zig -const clap = @import("clap"); -const std = @import("std"); - pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -271,13 +257,16 @@ pub fn main() !void { defer res.deinit(); // `clap.help` is a function that can print a simple help message. It can print any `Param` - // where `Id` has a `describtion` and `value` method (`Param(Help)` is one such parameter). + // where `Id` has a `description` and `value` method (`Param(Help)` is one such parameter). // The last argument contains options as to how `help` should print those parameters. Using // `.{}` means the default options. if (res.args.help != 0) return clap.help(std.io.getStdErr().writer(), clap.Help, ¶ms, .{}); } +const clap = @import("clap"); +const std = @import("std"); + ``` ``` @@ -295,9 +284,6 @@ The `usage` prints a small abbreviated version of the help message. It expects t to have a `value` method so it can provide that in the output. ```zig -const clap = @import("clap"); -const std = @import("std"); - pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -320,6 +306,9 @@ pub fn main() !void { return clap.usage(std.io.getStdErr().writer(), clap.Help, ¶ms); } +const clap = @import("clap"); +const std = @import("std"); + ``` ``` diff --git a/build.zig b/build.zig index 9035675..b4a8e91 100644 --- a/build.zig +++ b/build.zig @@ -1,5 +1,3 @@ -const std = @import("std"); - pub fn build(b: *std.Build) void { const clap_mod = b.addModule("clap", .{ .root_source_file = b.path("clap.zig") }); @@ -80,3 +78,5 @@ fn readMeStep(b: *std.Build) *std.Build.Step { }); return s; } + +const std = @import("std"); diff --git a/clap.zig b/clap.zig index f7eb5d0..21590a2 100644 --- a/clap.zig +++ b/clap.zig @@ -1,24 +1,3 @@ -const std = @import("std"); - -const builtin = std.builtin; -const debug = std.debug; -const heap = std.heap; -const io = std.io; -const math = std.math; -const mem = std.mem; -const meta = std.meta; -const process = std.process; -const testing = std.testing; - -pub const args = @import("clap/args.zig"); -pub const parsers = @import("clap/parsers.zig"); -pub const streaming = @import("clap/streaming.zig"); -pub const ccw = @import("clap/codepoint_counting_writer.zig"); - -test "clap" { - testing.refAllDecls(@This()); -} - pub const default_assignment_separators = "="; /// The names a `Param` can have. @@ -97,14 +76,14 @@ pub fn Param(comptime Id: type) type { /// Takes a string and parses it into many Param(Help). Returned is a newly allocated slice /// containing all the parsed params. The caller is responsible for freeing the slice. -pub fn parseParams(allocator: mem.Allocator, str: []const u8) ![]Param(Help) { +pub fn parseParams(allocator: std.mem.Allocator, str: []const u8) ![]Param(Help) { var end: usize = undefined; return parseParamsEx(allocator, str, &end); } /// Takes a string and parses it into many Param(Help). Returned is a newly allocated slice /// containing all the parsed params. The caller is responsible for freeing the slice. -pub fn parseParamsEx(allocator: mem.Allocator, str: []const u8, end: *usize) ![]Param(Help) { +pub fn parseParamsEx(allocator: std.mem.Allocator, str: []const u8, end: *usize) ![]Param(Help) { var list = std.ArrayList(Param(Help)).init(allocator); errdefer list.deinit(); @@ -135,11 +114,11 @@ fn countParams(str: []const u8) usize { @setEvalBranchQuota(std.math.maxInt(u32)); var res: usize = 0; - var it = mem.splitScalar(u8, str, '\n'); + var it = std.mem.splitScalar(u8, str, '\n'); while (it.next()) |line| { - const trimmed = mem.trimLeft(u8, line, " \t"); - if (mem.startsWith(u8, trimmed, "-") or - mem.startsWith(u8, trimmed, "<")) + const trimmed = std.mem.trimLeft(u8, line, " \t"); + if (std.mem.startsWith(u8, trimmed, "-") or + std.mem.startsWith(u8, trimmed, "<")) { res += 1; } @@ -152,7 +131,7 @@ fn countParams(str: []const u8) usize { /// is returned, containing all the parameters parsed. This function will fail if the input slice /// is to small. pub fn parseParamsIntoSlice(slice: []Param(Help), str: []const u8) ![]Param(Help) { - var null_alloc = heap.FixedBufferAllocator.init(""); + var null_alloc = std.heap.FixedBufferAllocator.init(""); var list = std.ArrayList(Param(Help)){ .allocator = null_alloc.allocator(), .items = slice[0..0], @@ -167,7 +146,7 @@ pub fn parseParamsIntoSlice(slice: []Param(Help), str: []const u8) ![]Param(Help /// is returned, containing all the parameters parsed. This function will fail if the input slice /// is to small. pub fn parseParamsIntoSliceEx(slice: []Param(Help), str: []const u8, end: *usize) ![]Param(Help) { - var null_alloc = heap.FixedBufferAllocator.init(""); + var null_alloc = std.heap.FixedBufferAllocator.init(""); var list = std.ArrayList(Param(Help)){ .allocator = null_alloc.allocator(), .items = slice[0..0], @@ -410,7 +389,7 @@ pub fn parseParamEx(str: []const u8, end: *usize) !Param(Help) { fn testParseParams(str: []const u8, expected_params: []const Param(Help)) !void { var end: usize = undefined; - const actual_params = parseParamsEx(testing.allocator, str, &end) catch |err| { + const actual_params = parseParamsEx(std.testing.allocator, str, &end) catch |err| { const loc = std.zig.findLineColumn(str, end); std.debug.print("error:{}:{}: Failed to parse parameter:\n{s}\n", .{ loc.line + 1, @@ -419,22 +398,22 @@ fn testParseParams(str: []const u8, expected_params: []const Param(Help)) !void }); return err; }; - defer testing.allocator.free(actual_params); + defer std.testing.allocator.free(actual_params); - try testing.expectEqual(expected_params.len, actual_params.len); + try std.testing.expectEqual(expected_params.len, actual_params.len); for (expected_params, 0..) |_, i| try expectParam(expected_params[i], actual_params[i]); } fn expectParam(expect: Param(Help), actual: Param(Help)) !void { - try testing.expectEqualStrings(expect.id.desc, actual.id.desc); - try testing.expectEqualStrings(expect.id.val, actual.id.val); - try testing.expectEqual(expect.names.short, actual.names.short); - try testing.expectEqual(expect.takes_value, actual.takes_value); + try std.testing.expectEqualStrings(expect.id.desc, actual.id.desc); + try std.testing.expectEqualStrings(expect.id.val, actual.id.val); + try std.testing.expectEqual(expect.names.short, actual.names.short); + try std.testing.expectEqual(expect.takes_value, actual.takes_value); if (expect.names.long) |long| { - try testing.expectEqualStrings(long, actual.names.long.?); + try std.testing.expectEqualStrings(long, actual.names.long.?); } else { - try testing.expectEqual(@as(?[]const u8, null), actual.names.long); + try std.testing.expectEqual(@as(?[]const u8, null), actual.names.long); } } @@ -549,11 +528,11 @@ test "parseParams" { }, }); - try testing.expectError(error.InvalidParameter, parseParam("--long, Help")); - try testing.expectError(error.InvalidParameter, parseParam("-s, Help")); - try testing.expectError(error.InvalidParameter, parseParam("-ss Help")); - try testing.expectError(error.InvalidParameter, parseParam("-ss Help")); - try testing.expectError(error.InvalidParameter, parseParam("- Help")); + try std.testing.expectError(error.InvalidParameter, parseParam("--long, Help")); + try std.testing.expectError(error.InvalidParameter, parseParam("-s, Help")); + try std.testing.expectError(error.InvalidParameter, parseParam("-ss Help")); + try std.testing.expectError(error.InvalidParameter, parseParam("-ss Help")); + try std.testing.expectError(error.InvalidParameter, parseParam("- Help")); } /// Optional diagnostics used for reporting useful errors @@ -588,9 +567,9 @@ pub const Diagnostic = struct { fn testDiag(diag: Diagnostic, err: anyerror, expected: []const u8) !void { var buf: [1024]u8 = undefined; - var slice_stream = io.fixedBufferStream(&buf); + var slice_stream = std.io.fixedBufferStream(&buf); diag.report(slice_stream.writer(), err) catch unreachable; - try testing.expectEqualStrings(expected, slice_stream.getWritten()); + try std.testing.expectEqualStrings(expected, slice_stream.getWritten()); } test "Diagnostic.report" { @@ -644,7 +623,7 @@ test "Diagnostic.report" { /// Options that can be set to customize the behavior of parsing. pub const ParseOptions = struct { - allocator: mem.Allocator, + allocator: std.mem.Allocator, diagnostic: ?*Diagnostic = null, /// The assignment separators, which by default is `=`. This is the separator between the name @@ -666,10 +645,10 @@ pub fn parse( comptime value_parsers: anytype, opt: ParseOptions, ) !Result(Id, params, value_parsers) { - var arena = heap.ArenaAllocator.init(opt.allocator); + var arena = std.heap.ArenaAllocator.init(opt.allocator); errdefer arena.deinit(); - var iter = try process.ArgIterator.initWithAllocator(arena.allocator()); + var iter = try std.process.ArgIterator.initWithAllocator(arena.allocator()); const exe_arg = iter.next(); const result = try parseEx(Id, params, value_parsers, &iter, .{ @@ -745,7 +724,7 @@ pub fn parseEx( var arguments = Arguments(Id, params, value_parsers, .list){}; errdefer deinitArgs(Id, params, allocator, &arguments); - var stream = streaming.Clap(Id, meta.Child(@TypeOf(iter))){ + var stream = streaming.Clap(Id, std.meta.Child(@TypeOf(iter))){ .params = params, .iter = iter, .diagnostic = opt.diagnostic, @@ -785,7 +764,7 @@ pub fn parseEx( // We are done parsing, but our arguments are stored in lists, and not slices. Map the list // fields to slices and return that. var result_args = Arguments(Id, params, value_parsers, .slice){}; - inline for (meta.fields(@TypeOf(arguments))) |field| { + inline for (std.meta.fields(@TypeOf(arguments))) |field| { if (@typeInfo(field.type) == .@"struct" and @hasDecl(field.type, "toOwnedSlice")) { @@ -812,7 +791,7 @@ pub fn ResultEx( return struct { args: Arguments(Id, params, value_parsers, .slice), positionals: []const FindPositionalType(Id, params, value_parsers), - allocator: mem.Allocator, + allocator: std.mem.Allocator, pub fn deinit(result: *@This()) void { deinitArgs(Id, params, result.allocator, &result.args); @@ -859,7 +838,7 @@ fn ParamType( fn deinitArgs( comptime Id: type, comptime params: []const Param(Id), - allocator: mem.Allocator, + allocator: std.mem.Allocator, arguments: anytype, ) void { inline for (params) |param| { @@ -899,7 +878,7 @@ fn Arguments( fields_len += 1; } - var fields: [fields_len]builtin.Type.StructField = undefined; + var fields: [fields_len]std.builtin.Type.StructField = undefined; var i: usize = 0; for (params) |param| { const longest = param.names.longest(); @@ -946,7 +925,7 @@ test "str and u64" { .args = &.{ "--num", "10", "--str", "cooley_rec_inp_ptr" }, }; var res = try parseEx(Help, ¶ms, parsers.default, &iter, .{ - .allocator = testing.allocator, + .allocator = std.testing.allocator, }); defer res.deinit(); } @@ -961,12 +940,12 @@ test "different assignment separators" { .args = &.{ "-a=0", "--aa=1", "-a:2", "--aa:3" }, }; var res = try parseEx(Help, ¶ms, parsers.default, &iter, .{ - .allocator = testing.allocator, + .allocator = std.testing.allocator, .assignment_separators = "=:", }); defer res.deinit(); - try testing.expectEqualSlices(usize, &.{ 0, 1, 2, 3 }, res.args.aa); + try std.testing.expectEqualSlices(usize, &.{ 0, 1, 2, 3 }, res.args.aa); } test "everything" { @@ -984,18 +963,18 @@ test "everything" { .args = &.{ "-a", "--aa", "-c", "0", "something", "-d", "1", "--dd", "2", "-h" }, }; var res = try parseEx(Help, ¶ms, parsers.default, &iter, .{ - .allocator = testing.allocator, + .allocator = std.testing.allocator, }); defer res.deinit(); - try testing.expect(res.args.aa == 2); - try testing.expect(res.args.bb == 0); - try testing.expect(res.args.h == 1); - try testing.expectEqualStrings("0", res.args.cc.?); - try testing.expectEqual(@as(usize, 1), res.positionals.len); - try testing.expectEqualStrings("something", res.positionals[0]); - try testing.expectEqualSlices(usize, &.{ 1, 2 }, res.args.dd); - try testing.expectEqual(@as(usize, 10), iter.index); + try std.testing.expect(res.args.aa == 2); + try std.testing.expect(res.args.bb == 0); + try std.testing.expect(res.args.h == 1); + try std.testing.expectEqualStrings("0", res.args.cc.?); + try std.testing.expectEqual(@as(usize, 1), res.positionals.len); + try std.testing.expectEqualStrings("something", res.positionals[0]); + try std.testing.expectEqualSlices(usize, &.{ 1, 2 }, res.args.dd); + try std.testing.expectEqual(@as(usize, 10), iter.index); } test "terminating positional" { @@ -1013,19 +992,19 @@ test "terminating positional" { .args = &.{ "-a", "--aa", "-c", "0", "something", "-d", "1", "--dd", "2", "-h" }, }; var res = try parseEx(Help, ¶ms, parsers.default, &iter, .{ - .allocator = testing.allocator, + .allocator = std.testing.allocator, .terminating_positional = 0, }); defer res.deinit(); - try testing.expect(res.args.aa == 2); - try testing.expect(res.args.bb == 0); - try testing.expect(res.args.h == 0); - try testing.expectEqualStrings("0", res.args.cc.?); - try testing.expectEqual(@as(usize, 1), res.positionals.len); - try testing.expectEqualStrings("something", res.positionals[0]); - try testing.expectEqualSlices(usize, &.{}, res.args.dd); - try testing.expectEqual(@as(usize, 5), iter.index); + try std.testing.expect(res.args.aa == 2); + try std.testing.expect(res.args.bb == 0); + try std.testing.expect(res.args.h == 0); + try std.testing.expectEqualStrings("0", res.args.cc.?); + try std.testing.expectEqual(@as(usize, 1), res.positionals.len); + try std.testing.expectEqualStrings("something", res.positionals[0]); + try std.testing.expectEqualSlices(usize, &.{}, res.args.dd); + try std.testing.expectEqual(@as(usize, 5), iter.index); } test "overflow-safe" { @@ -1039,7 +1018,7 @@ test "overflow-safe" { // This just needs to not crash var res = try parseEx(Help, ¶ms, parsers.default, &iter, .{ - .allocator = testing.allocator, + .allocator = std.testing.allocator, }); defer res.deinit(); } @@ -1047,7 +1026,7 @@ test "overflow-safe" { test "empty" { var iter = args.SliceIterator{ .args = &.{} }; var res = try parseEx(u8, &[_]Param(u8){}, parsers.default, &iter, .{ - .allocator = testing.allocator, + .allocator = std.testing.allocator, }); defer res.deinit(); } @@ -1060,17 +1039,17 @@ fn testErr( var diag = Diagnostic{}; var iter = args.SliceIterator{ .args = args_strings }; _ = parseEx(Help, params, parsers.default, &iter, .{ - .allocator = testing.allocator, + .allocator = std.testing.allocator, .diagnostic = &diag, }) catch |err| { var buf: [1024]u8 = undefined; - var fbs = io.fixedBufferStream(&buf); + var fbs = std.io.fixedBufferStream(&buf); diag.report(fbs.writer(), err) catch return error.TestFailed; - try testing.expectEqualStrings(expected, fbs.getWritten()); + try std.testing.expectEqualStrings(expected, fbs.getWritten()); return; }; - try testing.expect(false); + try std.testing.expect(false); } test "errors" { @@ -1175,7 +1154,7 @@ pub fn help( const max_spacing = blk: { var res: usize = 0; for (params) |param| { - var cs = ccw.codepointCountingWriter(io.null_writer); + var cs = ccw.codepointCountingWriter(std.io.null_writer); try printParam(cs.writer(), Id, param); if (res < cs.codepoints_written) res = @intCast(cs.codepoints_written); @@ -1215,9 +1194,9 @@ pub fn help( var first_line = true; var res: usize = std.math.maxInt(usize); - var it = mem.tokenizeScalar(u8, description, '\n'); + var it = std.mem.tokenizeScalar(u8, description, '\n'); while (it.next()) |line| : (first_line = false) { - const trimmed = mem.trimLeft(u8, line, " "); + const trimmed = std.mem.trimLeft(u8, line, " "); const indent = line.len - trimmed.len; // If the first line has no indentation, then we ignore the indentation of the @@ -1240,18 +1219,18 @@ pub fn help( }; const description = param.id.description(); - var it = mem.splitScalar(u8, description, '\n'); + var it = std.mem.splitScalar(u8, description, '\n'); var first_line = true; var non_emitted_newlines: usize = 0; var last_line_indentation: usize = 0; while (it.next()) |raw_line| : (first_line = false) { // First line might be special. See comment above. - const indented_line = if (first_line and !mem.startsWith(u8, raw_line, " ")) + const indented_line = if (first_line and !std.mem.startsWith(u8, raw_line, " ")) raw_line else raw_line[@min(min_description_indent, raw_line.len)..]; - const line = mem.trimLeft(u8, indented_line, " "); + const line = std.mem.trimLeft(u8, indented_line, " "); if (line.len == 0) { non_emitted_newlines += 1; continue; @@ -1266,7 +1245,7 @@ pub fn help( const does_not_have_same_indent_as_last_line = line_indentation != last_line_indentation; - const starts_with_control_char = mem.indexOfScalar(u8, "=*", line[0]) != null; + const starts_with_control_char = std.mem.indexOfScalar(u8, "=*", line[0]) != null; // Either the input contains 2 or more newlines, in which case we should start // a new paragraph. @@ -1286,7 +1265,7 @@ pub fn help( try description_writer.newline(); } - var words = mem.tokenizeScalar(u8, line, ' '); + var words = std.mem.tokenizeScalar(u8, line, ' '); while (words.next()) |word| try description_writer.writeWord(word); @@ -1310,7 +1289,7 @@ fn DescriptionWriter(comptime UnderlyingWriter: type) type { printed_chars: usize, pub fn writeWord(writer: *@This(), word: []const u8) !void { - debug.assert(word.len != 0); + std.debug.assert(word.len != 0); var first_word = writer.printed_chars <= writer.indentation; const chars_to_write = try std.unicode.utf8CountCodepoints(word) + @intFromBool(!first_word); @@ -1380,13 +1359,13 @@ fn printParam( } fn testHelp(opt: HelpOptions, str: []const u8) !void { - const params = try parseParams(testing.allocator, str); - defer testing.allocator.free(params); + const params = try parseParams(std.testing.allocator, str); + defer std.testing.allocator.free(params); var buf: [2048]u8 = undefined; - var fbs = io.fixedBufferStream(&buf); + var fbs = std.io.fixedBufferStream(&buf); try help(fbs.writer(), Help, params, opt); - try testing.expectEqualStrings(str, fbs.getWritten()); + try std.testing.expectEqualStrings(str, fbs.getWritten()); } test "clap.help" { @@ -1884,9 +1863,9 @@ pub fn usage(stream: anytype, comptime Id: type, params: []const Param(Id)) !voi fn testUsage(expected: []const u8, params: []const Param(Help)) !void { var buf: [1024]u8 = undefined; - var fbs = io.fixedBufferStream(&buf); + var fbs = std.io.fixedBufferStream(&buf); try usage(fbs.writer(), Help, params); - try testing.expectEqualStrings(expected, fbs.getWritten()); + try std.testing.expectEqualStrings(expected, fbs.getWritten()); } test "usage" { @@ -1948,3 +1927,17 @@ test "usage" { \\ )); } + +test { + _ = args; + _ = parsers; + _ = streaming; + _ = ccw; +} + +pub const args = @import("clap/args.zig"); +pub const parsers = @import("clap/parsers.zig"); +pub const streaming = @import("clap/streaming.zig"); +pub const ccw = @import("clap/codepoint_counting_writer.zig"); + +const std = @import("std"); diff --git a/clap/args.zig b/clap/args.zig index d0aaee3..6a424e3 100644 --- a/clap/args.zig +++ b/clap/args.zig @@ -1,12 +1,3 @@ -const builtin = @import("builtin"); -const std = @import("std"); - -const debug = std.debug; -const heap = std.heap; -const mem = std.mem; -const process = std.process; -const testing = std.testing; - /// An example of what methods should be implemented on an arg iterator. pub const ExampleArgIterator = struct { pub fn next(iter: *ExampleArgIterator) ?[]const u8 { @@ -35,7 +26,9 @@ test "SliceIterator" { var iter = SliceIterator{ .args = &args }; for (args) |a| - try testing.expectEqualStrings(a, iter.next().?); + try std.testing.expectEqualStrings(a, iter.next().?); - try testing.expectEqual(@as(?[]const u8, null), iter.next()); + try std.testing.expectEqual(@as(?[]const u8, null), iter.next()); } + +const std = @import("std"); diff --git a/clap/codepoint_counting_writer.zig b/clap/codepoint_counting_writer.zig index e6b9d1c..c445c90 100644 --- a/clap/codepoint_counting_writer.zig +++ b/clap/codepoint_counting_writer.zig @@ -1,7 +1,3 @@ -const std = @import("std"); -const builtin = @import("builtin"); -const native_endian = builtin.cpu.arch.endian(); - /// A Writer that counts how many codepoints has been written to it. /// Expects valid UTF-8 input, and does not validate the input. pub fn CodepointCountingWriter(comptime WriterType: type) type { @@ -34,6 +30,7 @@ pub fn CodepointCountingWriter(comptime WriterType: type) type { // the number of codepoints up to that point. // Does not validate UTF-8 beyond checking the start byte. fn utf8CountCodepointsAllowTruncate(s: []const u8) !struct { bytes: usize, codepoints: usize } { + const native_endian = @import("builtin").cpu.arch.endian(); var len: usize = 0; const N = @sizeOf(usize); @@ -100,3 +97,5 @@ test "handles partial UTF-8 writes" { try testing.expectEqualSlices(u8, utf8_text, fbs.getWritten()); } + +const std = @import("std"); diff --git a/clap/parsers.zig b/clap/parsers.zig index 8abdf57..2bf8976 100644 --- a/clap/parsers.zig +++ b/clap/parsers.zig @@ -1,8 +1,3 @@ -const std = @import("std"); - -const fmt = std.fmt; -const testing = std.testing; - pub const default = .{ .string = string, .str = string, @@ -26,46 +21,46 @@ pub fn string(in: []const u8) error{}![]const u8 { } test "string" { - try testing.expectEqualStrings("aa", try string("aa")); + try std.testing.expectEqualStrings("aa", try string("aa")); } /// A parser that uses `std.fmt.parseInt` to parse the string into an integer value. /// See `std.fmt.parseInt` documentation for more information. -pub fn int(comptime T: type, comptime base: u8) fn ([]const u8) fmt.ParseIntError!T { +pub fn int(comptime T: type, comptime base: u8) fn ([]const u8) std.fmt.ParseIntError!T { return struct { - fn parse(in: []const u8) fmt.ParseIntError!T { - return fmt.parseInt(T, in, base); + fn parse(in: []const u8) std.fmt.ParseIntError!T { + return std.fmt.parseInt(T, in, base); } }.parse; } test "int" { - try testing.expectEqual(@as(u8, 0), try int(u8, 10)("0")); - try testing.expectEqual(@as(u8, 1), try int(u8, 10)("1")); - try testing.expectEqual(@as(u8, 10), try int(u8, 10)("10")); - try testing.expectEqual(@as(u8, 0b10), try int(u8, 2)("10")); - try testing.expectEqual(@as(u8, 0x10), try int(u8, 0)("0x10")); - try testing.expectEqual(@as(u8, 0b10), try int(u8, 0)("0b10")); - try testing.expectEqual(@as(u16, 0), try int(u16, 10)("0")); - try testing.expectEqual(@as(u16, 1), try int(u16, 10)("1")); - try testing.expectEqual(@as(u16, 10), try int(u16, 10)("10")); - try testing.expectEqual(@as(u16, 0b10), try int(u16, 2)("10")); - try testing.expectEqual(@as(u16, 0x10), try int(u16, 0)("0x10")); - try testing.expectEqual(@as(u16, 0b10), try int(u16, 0)("0b10")); + try std.testing.expectEqual(@as(u8, 0), try int(u8, 10)("0")); + try std.testing.expectEqual(@as(u8, 1), try int(u8, 10)("1")); + try std.testing.expectEqual(@as(u8, 10), try int(u8, 10)("10")); + try std.testing.expectEqual(@as(u8, 0b10), try int(u8, 2)("10")); + try std.testing.expectEqual(@as(u8, 0x10), try int(u8, 0)("0x10")); + try std.testing.expectEqual(@as(u8, 0b10), try int(u8, 0)("0b10")); + try std.testing.expectEqual(@as(u16, 0), try int(u16, 10)("0")); + try std.testing.expectEqual(@as(u16, 1), try int(u16, 10)("1")); + try std.testing.expectEqual(@as(u16, 10), try int(u16, 10)("10")); + try std.testing.expectEqual(@as(u16, 0b10), try int(u16, 2)("10")); + try std.testing.expectEqual(@as(u16, 0x10), try int(u16, 0)("0x10")); + try std.testing.expectEqual(@as(u16, 0b10), try int(u16, 0)("0b10")); } /// A parser that uses `std.fmt.parseFloat` to parse the string into an float value. /// See `std.fmt.parseFloat` documentation for more information. -pub fn float(comptime T: type) fn ([]const u8) fmt.ParseFloatError!T { +pub fn float(comptime T: type) fn ([]const u8) std.fmt.ParseFloatError!T { return struct { - fn parse(in: []const u8) fmt.ParseFloatError!T { - return fmt.parseFloat(T, in); + fn parse(in: []const u8) std.fmt.ParseFloatError!T { + return std.fmt.parseFloat(T, in); } }.parse; } test "float" { - try testing.expectEqual(@as(f32, 0), try float(f32)("0")); + try std.testing.expectEqual(@as(f32, 0), try float(f32)("0")); } pub const EnumError = error{ @@ -85,10 +80,10 @@ pub fn enumeration(comptime T: type) fn ([]const u8) EnumError!T { test "enumeration" { const E = enum { a, b, c }; - try testing.expectEqual(E.a, try enumeration(E)("a")); - try testing.expectEqual(E.b, try enumeration(E)("b")); - try testing.expectEqual(E.c, try enumeration(E)("c")); - try testing.expectError(EnumError.NameNotPartOfEnum, enumeration(E)("d")); + try std.testing.expectEqual(E.a, try enumeration(E)("a")); + try std.testing.expectEqual(E.b, try enumeration(E)("b")); + try std.testing.expectEqual(E.c, try enumeration(E)("c")); + try std.testing.expectError(EnumError.NameNotPartOfEnum, enumeration(E)("d")); } fn ReturnType(comptime P: type) type { @@ -98,3 +93,5 @@ fn ReturnType(comptime P: type) type { pub fn Result(comptime P: type) type { return @typeInfo(ReturnType(P)).error_union.payload; } + +const std = @import("std"); diff --git a/clap/streaming.zig b/clap/streaming.zig index eba84bb..4a687a2 100644 --- a/clap/streaming.zig +++ b/clap/streaming.zig @@ -1,15 +1,3 @@ -const builtin = @import("builtin"); -const clap = @import("../clap.zig"); -const std = @import("std"); - -const args = clap.args; -const debug = std.debug; -const heap = std.heap; -const io = std.io; -const mem = std.mem; -const os = std.os; -const testing = std.testing; - /// The result returned from Clap.next pub fn Arg(comptime Id: type) type { return struct { @@ -71,14 +59,14 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type { const arg = arg_info.arg; switch (arg_info.kind) { .long => { - const eql_index = mem.indexOfAny(u8, arg, parser.assignment_separators); + const eql_index = std.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; for (parser.params) |*param| { const match = param.names.long orelse continue; - if (!mem.eql(u8, name, match)) + if (!std.mem.eql(u8, name, match)) continue; if (param.takes_value == .none) { if (maybe_value != null) @@ -108,7 +96,7 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type { // If we find a positional with the value `--` then we // interpret the rest of the arguments as positional // arguments. - if (mem.eql(u8, arg, "--")) { + if (std.mem.eql(u8, arg, "--")) { parser.state = .rest_are_positional; const value = parser.iter.next() orelse return null; return Arg(Id){ .param = param, .value = value }; @@ -200,11 +188,11 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type { fn parseNextArg(parser: *@This()) !?ArgInfo { const full_arg = parser.iter.next() orelse return null; - if (mem.eql(u8, full_arg, "--") or mem.eql(u8, full_arg, "-")) + if (std.mem.eql(u8, full_arg, "--") or std.mem.eql(u8, full_arg, "-")) return ArgInfo{ .arg = full_arg, .kind = .positional }; - if (mem.startsWith(u8, full_arg, "--")) + if (std.mem.startsWith(u8, full_arg, "--")) return ArgInfo{ .arg = full_arg[2..], .kind = .long }; - if (mem.startsWith(u8, full_arg, "-")) + if (std.mem.startsWith(u8, full_arg, "-")) return ArgInfo{ .arg = full_arg[1..], .kind = .short }; return ArgInfo{ .arg = full_arg, .kind = .positional }; @@ -219,18 +207,18 @@ pub fn Clap(comptime Id: type, comptime ArgIterator: type) type { } fn expectArgs( - parser: *Clap(u8, args.SliceIterator), + parser: *Clap(u8, clap.args.SliceIterator), results: []const Arg(u8), ) !void { for (results) |res| { const arg = (try parser.next()) orelse return error.TestFailed; - try testing.expectEqual(res.param, arg.param); + try std.testing.expectEqual(res.param, arg.param); const expected_value = res.value orelse { - try testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value); + try std.testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value); continue; }; const actual_value = arg.value orelse return error.TestFailed; - try testing.expectEqualSlices(u8, expected_value, actual_value); + try std.testing.expectEqualSlices(u8, expected_value, actual_value); } if (try parser.next()) |_| @@ -238,7 +226,7 @@ fn expectArgs( } fn expectError( - parser: *Clap(u8, args.SliceIterator), + parser: *Clap(u8, clap.args.SliceIterator), expected: []const u8, ) !void { var diag: clap.Diagnostic = .{}; @@ -246,13 +234,13 @@ fn expectError( while (parser.next() catch |err| { var buf: [1024]u8 = undefined; - var fbs = io.fixedBufferStream(&buf); + var fbs = std.io.fixedBufferStream(&buf); diag.report(fbs.writer(), err) catch return error.TestFailed; - try testing.expectEqualStrings(expected, fbs.getWritten()); + try std.testing.expectEqualStrings(expected, fbs.getWritten()); return; }) |_| {} - try testing.expect(false); + try std.testing.expect(false); } test "short params" { @@ -276,12 +264,12 @@ test "short params" { const c = ¶ms[2]; const d = ¶ms[3]; - var iter = args.SliceIterator{ .args = &.{ + var iter = clap.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 }; + var parser = Clap(u8, clap.args.SliceIterator){ .params = ¶ms, .iter = &iter }; try expectArgs(&parser, &.{ .{ .param = a }, @@ -321,12 +309,12 @@ test "long params" { const cc = ¶ms[2]; const dd = ¶ms[3]; - var iter = args.SliceIterator{ .args = &.{ + var iter = clap.args.SliceIterator{ .args = &.{ "--aa", "--bb", "--cc", "0", "--cc=0", "--dd=0", } }; - var parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + var parser = Clap(u8, clap.args.SliceIterator){ .params = ¶ms, .iter = &iter }; try expectArgs(&parser, &.{ .{ .param = aa }, @@ -343,11 +331,11 @@ test "positional params" { .takes_value = .one, }}; - var iter = args.SliceIterator{ .args = &.{ + var iter = clap.args.SliceIterator{ .args = &.{ "aa", "bb", } }; - var parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + var parser = Clap(u8, clap.args.SliceIterator){ .params = ¶ms, .iter = &iter }; try expectArgs(&parser, &.{ .{ .param = ¶ms[0], .value = "aa" }, @@ -378,14 +366,14 @@ test "all params" { const cc = ¶ms[2]; const positional = ¶ms[3]; - var iter = args.SliceIterator{ .args = &.{ + var iter = clap.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 }; + var parser = Clap(u8, clap.args.SliceIterator){ .params = ¶ms, .iter = &iter }; try expectArgs(&parser, &.{ .{ .param = aa }, @@ -422,11 +410,11 @@ test "different assignment separators" { const aa = ¶ms[0]; - var iter = args.SliceIterator{ .args = &.{ + var iter = clap.args.SliceIterator{ .args = &.{ "-a=0", "--aa=0", "-a:0", "--aa:0", } }; - var parser = Clap(u8, args.SliceIterator){ + var parser = Clap(u8, clap.args.SliceIterator){ .params = ¶ms, .iter = &iter, .assignment_separators = "=:", @@ -453,35 +441,38 @@ test "errors" { }, }; - var iter = args.SliceIterator{ .args = &.{"q"} }; - var parser = Clap(u8, args.SliceIterator){ .params = ¶ms, .iter = &iter }; + var iter = clap.args.SliceIterator{ .args = &.{"q"} }; + var parser = Clap(u8, clap.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 }; + iter = clap.args.SliceIterator{ .args = &.{"-q"} }; + parser = Clap(u8, clap.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 }; + iter = clap.args.SliceIterator{ .args = &.{"--q"} }; + parser = Clap(u8, clap.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 }; + iter = clap.args.SliceIterator{ .args = &.{"--q=1"} }; + parser = Clap(u8, clap.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 }; + iter = clap.args.SliceIterator{ .args = &.{"-a=1"} }; + parser = Clap(u8, clap.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 }; + iter = clap.args.SliceIterator{ .args = &.{"--aa=1"} }; + parser = Clap(u8, clap.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 }; + iter = clap.args.SliceIterator{ .args = &.{"-c"} }; + parser = Clap(u8, clap.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 }; + iter = clap.args.SliceIterator{ .args = &.{"--cc"} }; + parser = Clap(u8, clap.args.SliceIterator){ .params = ¶ms, .iter = &iter }; try expectError(&parser, "The argument '--cc' requires a value but none was supplied\n"); } + +const clap = @import("../clap.zig"); +const std = @import("std"); diff --git a/example/help.zig b/example/help.zig index 2f063c5..b80ee35 100644 --- a/example/help.zig +++ b/example/help.zig @@ -1,6 +1,3 @@ -const clap = @import("clap"); -const std = @import("std"); - pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -17,9 +14,12 @@ pub fn main() !void { defer res.deinit(); // `clap.help` is a function that can print a simple help message. It can print any `Param` - // where `Id` has a `describtion` and `value` method (`Param(Help)` is one such parameter). + // where `Id` has a `description` and `value` method (`Param(Help)` is one such parameter). // The last argument contains options as to how `help` should print those parameters. Using // `.{}` means the default options. if (res.args.help != 0) return clap.help(std.io.getStdErr().writer(), clap.Help, ¶ms, .{}); } + +const clap = @import("clap"); +const std = @import("std"); diff --git a/example/simple-ex.zig b/example/simple-ex.zig index 2943f4e..4ca9791 100644 --- a/example/simple-ex.zig +++ b/example/simple-ex.zig @@ -1,10 +1,3 @@ -const clap = @import("clap"); -const std = @import("std"); - -const debug = std.debug; -const io = std.io; -const process = std.process; - pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -38,19 +31,22 @@ pub fn main() !void { // allowed. .assignment_separators = "=:", }) catch |err| { - diag.report(io.getStdErr().writer(), err) catch {}; + diag.report(std.io.getStdErr().writer(), err) catch {}; return err; }; defer res.deinit(); if (res.args.help != 0) - debug.print("--help\n", .{}); + std.debug.print("--help\n", .{}); if (res.args.number) |n| - debug.print("--number = {}\n", .{n}); + std.debug.print("--number = {}\n", .{n}); if (res.args.answer) |a| - debug.print("--answer = {s}\n", .{@tagName(a)}); + std.debug.print("--answer = {s}\n", .{@tagName(a)}); for (res.args.string) |s| - debug.print("--string = {s}\n", .{s}); + std.debug.print("--string = {s}\n", .{s}); for (res.positionals) |pos| - debug.print("{s}\n", .{pos}); + std.debug.print("{s}\n", .{pos}); } + +const clap = @import("clap"); +const std = @import("std"); diff --git a/example/simple.zig b/example/simple.zig index a7207c7..7f1bfc0 100644 --- a/example/simple.zig +++ b/example/simple.zig @@ -1,9 +1,3 @@ -const clap = @import("clap"); -const std = @import("std"); - -const debug = std.debug; -const io = std.io; - pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -27,17 +21,20 @@ pub fn main() !void { .allocator = gpa.allocator(), }) catch |err| { // Report useful error and exit - diag.report(io.getStdErr().writer(), err) catch {}; + diag.report(std.io.getStdErr().writer(), err) catch {}; return err; }; defer res.deinit(); if (res.args.help != 0) - debug.print("--help\n", .{}); + std.debug.print("--help\n", .{}); if (res.args.number) |n| - debug.print("--number = {}\n", .{n}); + std.debug.print("--number = {}\n", .{n}); for (res.args.string) |s| - debug.print("--string = {s}\n", .{s}); + std.debug.print("--string = {s}\n", .{s}); for (res.positionals) |pos| - debug.print("{s}\n", .{pos}); + std.debug.print("{s}\n", .{pos}); } + +const clap = @import("clap"); +const std = @import("std"); diff --git a/example/streaming-clap.zig b/example/streaming-clap.zig index 9d99859..2a20bcb 100644 --- a/example/streaming-clap.zig +++ b/example/streaming-clap.zig @@ -1,10 +1,3 @@ -const clap = @import("clap"); -const std = @import("std"); - -const debug = std.debug; -const io = std.io; -const process = std.process; - pub fn main() !void { const allocator = std.heap.page_allocator; @@ -22,7 +15,7 @@ pub fn main() !void { .{ .id = 'f', .takes_value = .one }, }; - var iter = try process.ArgIterator.initWithAllocator(allocator); + var iter = try std.process.ArgIterator.initWithAllocator(allocator); defer iter.deinit(); // Skip exe argument @@ -32,7 +25,7 @@ pub fn main() !void { // This is optional. You can also leave the `diagnostic` field unset if you // don't care about the extra information `Diagnostic` provides. var diag = clap.Diagnostic{}; - var parser = clap.streaming.Clap(u8, process.ArgIterator){ + var parser = clap.streaming.Clap(u8, std.process.ArgIterator){ .params = ¶ms, .iter = &iter, .diagnostic = &diag, @@ -41,19 +34,22 @@ 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 - diag.report(io.getStdErr().writer(), err) catch {}; + diag.report(std.io.getStdErr().writer(), err) catch {}; return err; }) |arg| { // arg.param will point to the parameter which matched the argument. switch (arg.param.id) { - 'h' => debug.print("Help!\n", .{}), - 'n' => debug.print("--number = {s}\n", .{arg.value.?}), + 'h' => std.debug.print("Help!\n", .{}), + 'n' => std.debug.print("--number = {s}\n", .{arg.value.?}), // 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.print("{s}\n", .{arg.value.?}), + 'f' => std.debug.print("{s}\n", .{arg.value.?}), else => unreachable, } } } + +const clap = @import("clap"); +const std = @import("std"); diff --git a/example/usage.zig b/example/usage.zig index a773dd2..59ac84a 100644 --- a/example/usage.zig +++ b/example/usage.zig @@ -1,6 +1,3 @@ -const clap = @import("clap"); -const std = @import("std"); - pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; defer _ = gpa.deinit(); @@ -22,3 +19,6 @@ pub fn main() !void { if (res.args.help != 0) return clap.usage(std.io.getStdErr().writer(), clap.Help, ¶ms); } + +const clap = @import("clap"); +const std = @import("std"); -- cgit v1.2.3