diff options
| author | 2020-11-02 18:04:30 +0000 | |
|---|---|---|
| committer | 2020-11-02 18:04:30 +0000 | |
| commit | 093d29899b8fdf449b944e973b07b5992be2144a (patch) | |
| tree | fb669157fa6e17523b22635c93f920bd4cc57760 /clap.zig | |
| parent | adjust examples, README template (diff) | |
| download | zig-clap-093d29899b8fdf449b944e973b07b5992be2144a.tar.gz zig-clap-093d29899b8fdf449b944e973b07b5992be2144a.tar.xz zig-clap-093d29899b8fdf449b944e973b07b5992be2144a.zip | |
Report error context in Diagnostic (#26)
Diffstat (limited to '')
| -rw-r--r-- | clap.zig | 51 |
1 files changed, 49 insertions, 2 deletions
| @@ -261,7 +261,7 @@ fn find(str: []const u8, f: []const u8) []const u8 { | |||
| 261 | pub fn Args(comptime Id: type, comptime params: []const Param(Id)) type { | 261 | pub 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 | ||
| 291 | pub 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 | |||
| 309 | fn 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 | |||
| 324 | test "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. |
| 292 | pub fn parse( | 337 | pub 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, |