summaryrefslogtreecommitdiff
path: root/clap.zig
diff options
context:
space:
mode:
authorGravatar Komari Spaghetti2020-11-02 18:04:30 +0000
committerGravatar Jimmi Holst Christensen2020-11-02 19:05:41 +0100
commit42894f6c8b957541ac0b1830139312047cd8fdc6 (patch)
treef5c6c839334b863f77e665879be0d467614543f2 /clap.zig
parentuse null sentinel in OsIterator (#27) (diff)
downloadzig-clap-42894f6c8b957541ac0b1830139312047cd8fdc6.tar.gz
zig-clap-42894f6c8b957541ac0b1830139312047cd8fdc6.tar.xz
zig-clap-42894f6c8b957541ac0b1830139312047cd8fdc6.zip
Report error context in Diagnostic (#26)
Diffstat (limited to 'clap.zig')
-rw-r--r--clap.zig51
1 files changed, 49 insertions, 2 deletions
diff --git a/clap.zig b/clap.zig
index 34b398b..f883858 100644
--- a/clap.zig
+++ b/clap.zig
@@ -261,7 +261,7 @@ fn find(str: []const u8, f: []const u8) []const u8 {
261pub fn Args(comptime Id: type, comptime params: []const Param(Id)) type { 261pub fn Args(comptime Id: type, comptime params: []const Param(Id)) type {
262 return struct { 262 return struct {
263 arena: std.heap.ArenaAllocator, 263 arena: std.heap.ArenaAllocator,
264 clap: ComptimeClap(Id, params), 264 clap: ComptimeClap(Id, args.OsIterator, params),
265 exe_arg: ?[]const u8, 265 exe_arg: ?[]const u8,
266 266
267 pub fn deinit(a: *@This()) void { 267 pub fn deinit(a: *@This()) void {
@@ -287,15 +287,62 @@ pub fn Args(comptime Id: type, comptime params: []const Param(Id)) type {
287 }; 287 };
288} 288}
289 289
290/// Optional diagnostics used for reporting useful errors
291pub const Diagnostic = struct {
292 name: Names,
293
294 /// Default diagnostics reporter when all you want is English with no colors.
295 /// Use this as a reference for implementing your own if needed.
296 pub fn report(diag: Diagnostic, stream: var, err: anyerror) !void {
297 const prefix = if (diag.name.short) |_| "-" else "--";
298 const name = if (diag.name.short) |*c| @as(*const [1]u8, c)[0..] else diag.name.long.?;
299
300 switch (err) {
301 error.DoesntTakeValue => try stream.print("The argument '{}{}' does not take a value\n", .{ prefix, name }),
302 error.MissingValue => try stream.print("The argument '{}{}' requires a value but none was supplied\n", .{ prefix, name }),
303 error.InvalidArgument => try stream.print("Invalid argument '{}{}'\n", .{ prefix, name }),
304 else => try stream.print("Error while parsing arguments: {}\n", .{@errorName(err)}),
305 }
306 }
307};
308
309fn testDiag(names: Names, err: anyerror, expected: []const u8) void {
310 var buf: [1024]u8 = undefined;
311 var slice_stream = io.fixedBufferStream(&buf);
312 (Diagnostic{ .name = names }).report(slice_stream.outStream(), err) catch unreachable;
313
314 const actual = slice_stream.getWritten();
315 if (!mem.eql(u8, actual, expected)) {
316 debug.warn("\n============ Expected ============\n", .{});
317 debug.warn("{}", .{expected});
318 debug.warn("============= Actual =============\n", .{});
319 debug.warn("{}", .{actual});
320 testing.expect(false);
321 }
322}
323
324test "Diagnostic.report" {
325 testDiag(.{ .short = 'c' }, error.DoesntTakeValue, "The argument '-c' does not take a value\n");
326 testDiag(.{ .long = "cc" }, error.DoesntTakeValue, "The argument '--cc' does not take a value\n");
327 testDiag(.{ .short = 'c' }, error.MissingValue, "The argument '-c' requires a value but none was supplied\n");
328 testDiag(.{ .long = "cc" }, error.MissingValue, "The argument '--cc' requires a value but none was supplied\n");
329 testDiag(.{ .short = 'c' }, error.InvalidArgument, "Invalid argument '-c'\n");
330 testDiag(.{ .long = "cc" }, error.InvalidArgument, "Invalid argument '--cc'\n");
331 testDiag(.{ .short = 'c' }, error.SomethingElse, "Error while parsing arguments: SomethingElse\n");
332 testDiag(.{ .long = "cc" }, error.SomethingElse, "Error while parsing arguments: SomethingElse\n");
333}
334
290/// Parses the command line arguments passed into the program based on an 335/// Parses the command line arguments passed into the program based on an
291/// array of `Param`s. 336/// array of `Param`s.
292pub fn parse( 337pub fn parse(
293 comptime Id: type, 338 comptime Id: type,
294 comptime params: []const Param(Id), 339 comptime params: []const Param(Id),
295 allocator: *mem.Allocator, 340 allocator: *mem.Allocator,
341 diag: ?*Diagnostic,
296) !Args(Id, params) { 342) !Args(Id, params) {
297 var iter = try args.OsIterator.init(allocator); 343 var iter = try args.OsIterator.init(allocator);
298 const clap = try ComptimeClap(Id, params).parse(allocator, args.OsIterator, &iter); 344 const Clap = ComptimeClap(Id, args.OsIterator, params);
345 const clap = try Clap.parse(allocator, &iter, diag);
299 return Args(Id, params){ 346 return Args(Id, params){
300 .arena = iter.arena, 347 .arena = iter.arena,
301 .clap = clap, 348 .clap = clap,