diff options
| author | 2025-07-22 10:44:11 +0200 | |
|---|---|---|
| committer | 2025-07-22 10:44:11 +0200 | |
| commit | 095409eb0421f0f970c246b371b39dab2ff912aa (patch) | |
| tree | 08ed3d08575d8a3b2613874a01dc7f98312bf272 | |
| parent | Update to Zig 0.15.0-dev.1147 (diff) | |
| download | zig-clap-095409eb0421f0f970c246b371b39dab2ff912aa.tar.gz zig-clap-095409eb0421f0f970c246b371b39dab2ff912aa.tar.xz zig-clap-095409eb0421f0f970c246b371b39dab2ff912aa.zip | |
feat: Add `Diagnostic.reportToFile`
The code for reporting errors became quite verbose after writegate.
Reporting to stderr is very common, so this wrapper provides a default,
buffered way to report to a file.
| -rw-r--r-- | README.md | 25 | ||||
| -rw-r--r-- | clap.zig | 12 | ||||
| -rw-r--r-- | clap/streaming.zig | 2 | ||||
| -rw-r--r-- | example/simple-ex.zig | 5 | ||||
| -rw-r--r-- | example/simple.zig | 6 | ||||
| -rw-r--r-- | example/streaming-clap.zig | 6 | ||||
| -rw-r--r-- | example/subcommands.zig | 11 |
7 files changed, 24 insertions, 43 deletions
| @@ -77,10 +77,7 @@ pub fn main() !void { | |||
| 77 | .allocator = gpa.allocator(), | 77 | .allocator = gpa.allocator(), |
| 78 | }) catch |err| { | 78 | }) catch |err| { |
| 79 | // Report useful error and exit. | 79 | // Report useful error and exit. |
| 80 | var buf: [1024]u8 = undefined; | 80 | try diag.reportToFile(.stderr(), err); |
| 81 | var stderr = std.fs.File.stderr().writer(&buf); | ||
| 82 | diag.report(&stderr.interface, err) catch {}; | ||
| 83 | try stderr.interface.flush(); | ||
| 84 | return err; | 81 | return err; |
| 85 | }; | 82 | }; |
| 86 | defer res.deinit(); | 83 | defer res.deinit(); |
| @@ -144,10 +141,7 @@ pub fn main() !void { | |||
| 144 | // allowed. | 141 | // allowed. |
| 145 | .assignment_separators = "=:", | 142 | .assignment_separators = "=:", |
| 146 | }) catch |err| { | 143 | }) catch |err| { |
| 147 | var buf: [1024]u8 = undefined; | 144 | try diag.reportToFile(.stderr(), err); |
| 148 | var stderr = std.fs.File.stderr().writer(&buf); | ||
| 149 | diag.report(&stderr.interface, err) catch {}; | ||
| 150 | try stderr.interface.flush(); | ||
| 151 | return err; | 145 | return err; |
| 152 | }; | 146 | }; |
| 153 | defer res.deinit(); | 147 | defer res.deinit(); |
| @@ -217,10 +211,7 @@ pub fn main() !void { | |||
| 217 | // not fully consumed. It can then be reused to parse the arguments for subcommands. | 211 | // not fully consumed. It can then be reused to parse the arguments for subcommands. |
| 218 | .terminating_positional = 0, | 212 | .terminating_positional = 0, |
| 219 | }) catch |err| { | 213 | }) catch |err| { |
| 220 | var buf: [1024]u8 = undefined; | 214 | try diag.reportToFile(.stderr(), err); |
| 221 | var stderr = std.fs.File.stderr().writer(&buf); | ||
| 222 | diag.report(&stderr.interface, err) catch {}; | ||
| 223 | try stderr.interface.flush(); | ||
| 224 | return err; | 215 | return err; |
| 225 | }; | 216 | }; |
| 226 | defer res.deinit(); | 217 | defer res.deinit(); |
| @@ -256,10 +247,7 @@ fn mathMain(gpa: std.mem.Allocator, iter: *std.process.ArgIterator, main_args: M | |||
| 256 | .diagnostic = &diag, | 247 | .diagnostic = &diag, |
| 257 | .allocator = gpa, | 248 | .allocator = gpa, |
| 258 | }) catch |err| { | 249 | }) catch |err| { |
| 259 | var buf: [1024]u8 = undefined; | 250 | try diag.reportToFile(.stderr(), err); |
| 260 | var stderr = std.fs.File.stderr().writer(&buf); | ||
| 261 | diag.report(&stderr.interface, err) catch {}; | ||
| 262 | try stderr.interface.flush(); | ||
| 263 | return err; // propagate error | 251 | return err; // propagate error |
| 264 | }; | 252 | }; |
| 265 | defer res.deinit(); | 253 | defer res.deinit(); |
| @@ -320,10 +308,7 @@ pub fn main() !void { | |||
| 320 | // Because we use a streaming parser, we have to consume each argument parsed individually. | 308 | // Because we use a streaming parser, we have to consume each argument parsed individually. |
| 321 | while (parser.next() catch |err| { | 309 | while (parser.next() catch |err| { |
| 322 | // Report useful error and exit. | 310 | // Report useful error and exit. |
| 323 | var buf: [1024]u8 = undefined; | 311 | try diag.reportToFile(.stderr(), err); |
| 324 | var stderr = std.fs.File.stderr().writer(&buf); | ||
| 325 | diag.report(&stderr.interface, err) catch {}; | ||
| 326 | try stderr.interface.flush(); | ||
| 327 | return err; | 312 | return err; |
| 328 | }) |arg| { | 313 | }) |arg| { |
| 329 | // arg.param will point to the parameter which matched the argument. | 314 | // arg.param will point to the parameter which matched the argument. |
| @@ -563,12 +563,20 @@ pub const Diagnostic = struct { | |||
| 563 | else => try stream.print("Error while parsing arguments: {s}\n", .{@errorName(err)}), | 563 | else => try stream.print("Error while parsing arguments: {s}\n", .{@errorName(err)}), |
| 564 | } | 564 | } |
| 565 | } | 565 | } |
| 566 | |||
| 567 | /// Wrapper around `report`, which writes to a file in a buffered manner | ||
| 568 | pub fn reportToFile(diag: Diagnostic, file: std.fs.File, err: anyerror) !void { | ||
| 569 | var buf: [1024]u8 = undefined; | ||
| 570 | var writer = file.writer(&buf); | ||
| 571 | try diag.report(&writer.interface, err); | ||
| 572 | return writer.end(); | ||
| 573 | } | ||
| 566 | }; | 574 | }; |
| 567 | 575 | ||
| 568 | fn testDiag(diag: Diagnostic, err: anyerror, expected: []const u8) !void { | 576 | fn testDiag(diag: Diagnostic, err: anyerror, expected: []const u8) !void { |
| 569 | var buf: [1024]u8 = undefined; | 577 | var buf: [1024]u8 = undefined; |
| 570 | var writer = std.Io.Writer.fixed(&buf); | 578 | var writer = std.Io.Writer.fixed(&buf); |
| 571 | diag.report(&writer, err) catch unreachable; | 579 | try diag.report(&writer, err); |
| 572 | try std.testing.expectEqualStrings(expected, writer.buffered()); | 580 | try std.testing.expectEqualStrings(expected, writer.buffered()); |
| 573 | } | 581 | } |
| 574 | 582 | ||
| @@ -1264,7 +1272,7 @@ fn testErr( | |||
| 1264 | }) catch |err| { | 1272 | }) catch |err| { |
| 1265 | var buf: [1024]u8 = undefined; | 1273 | var buf: [1024]u8 = undefined; |
| 1266 | var writer = std.Io.Writer.fixed(&buf); | 1274 | var writer = std.Io.Writer.fixed(&buf); |
| 1267 | diag.report(&writer, err) catch return error.TestFailed; | 1275 | try diag.report(&writer, err); |
| 1268 | try std.testing.expectEqualStrings(expected, writer.buffered()); | 1276 | try std.testing.expectEqualStrings(expected, writer.buffered()); |
| 1269 | return; | 1277 | return; |
| 1270 | }; | 1278 | }; |
diff --git a/clap/streaming.zig b/clap/streaming.zig index fa5ec70..ec53bf5 100644 --- a/clap/streaming.zig +++ b/clap/streaming.zig | |||
| @@ -235,7 +235,7 @@ fn expectError( | |||
| 235 | while (parser.next() catch |err| { | 235 | while (parser.next() catch |err| { |
| 236 | var buf: [1024]u8 = undefined; | 236 | var buf: [1024]u8 = undefined; |
| 237 | var fbs = std.Io.Writer.fixed(&buf); | 237 | var fbs = std.Io.Writer.fixed(&buf); |
| 238 | diag.report(&fbs, err) catch return error.TestFailed; | 238 | try diag.report(&fbs, err); |
| 239 | try std.testing.expectEqualStrings(expected, fbs.buffered()); | 239 | try std.testing.expectEqualStrings(expected, fbs.buffered()); |
| 240 | return; | 240 | return; |
| 241 | }) |_| {} | 241 | }) |_| {} |
diff --git a/example/simple-ex.zig b/example/simple-ex.zig index a993868..77d8d09 100644 --- a/example/simple-ex.zig +++ b/example/simple-ex.zig | |||
| @@ -32,10 +32,7 @@ pub fn main() !void { | |||
| 32 | .assignment_separators = "=:", | 32 | .assignment_separators = "=:", |
| 33 | }) catch |err| { | 33 | }) catch |err| { |
| 34 | // Report useful error and exit. | 34 | // Report useful error and exit. |
| 35 | var buf: [1024]u8 = undefined; | 35 | try diag.reportToFile(.stderr(), err); |
| 36 | var stderr = std.fs.File.stderr().writer(&buf); | ||
| 37 | try diag.report(&stderr.interface, err); | ||
| 38 | try stderr.interface.flush(); | ||
| 39 | return err; | 36 | return err; |
| 40 | }; | 37 | }; |
| 41 | defer res.deinit(); | 38 | defer res.deinit(); |
diff --git a/example/simple.zig b/example/simple.zig index ca6bd75..1834396 100644 --- a/example/simple.zig +++ b/example/simple.zig | |||
| @@ -21,10 +21,8 @@ pub fn main() !void { | |||
| 21 | .allocator = gpa.allocator(), | 21 | .allocator = gpa.allocator(), |
| 22 | }) catch |err| { | 22 | }) catch |err| { |
| 23 | // Report useful error and exit. | 23 | // Report useful error and exit. |
| 24 | var buf: [1024]u8 = undefined; | 24 | try diag.reportToFile(.stderr(), err); |
| 25 | var stderr = std.fs.File.stderr().writer(&buf); | 25 | return err; |
| 26 | try diag.report(&stderr.interface, err); | ||
| 27 | return stderr.interface.flush(); | ||
| 28 | }; | 26 | }; |
| 29 | defer res.deinit(); | 27 | defer res.deinit(); |
| 30 | 28 | ||
diff --git a/example/streaming-clap.zig b/example/streaming-clap.zig index d60167c..4cd6962 100644 --- a/example/streaming-clap.zig +++ b/example/streaming-clap.zig | |||
| @@ -34,10 +34,8 @@ pub fn main() !void { | |||
| 34 | // Because we use a streaming parser, we have to consume each argument parsed individually. | 34 | // Because we use a streaming parser, we have to consume each argument parsed individually. |
| 35 | while (parser.next() catch |err| { | 35 | while (parser.next() catch |err| { |
| 36 | // Report useful error and exit. | 36 | // Report useful error and exit. |
| 37 | var buf: [1024]u8 = undefined; | 37 | try diag.reportToFile(.stderr(), err); |
| 38 | var stderr = std.fs.File.stderr().writer(&buf); | 38 | return err; |
| 39 | try diag.report(&stderr.interface, err); | ||
| 40 | return stderr.interface.flush(); | ||
| 41 | }) |arg| { | 39 | }) |arg| { |
| 42 | // arg.param will point to the parameter which matched the argument. | 40 | // arg.param will point to the parameter which matched the argument. |
| 43 | switch (arg.param.id) { | 41 | switch (arg.param.id) { |
diff --git a/example/subcommands.zig b/example/subcommands.zig index 644e371..7d9f5f1 100644 --- a/example/subcommands.zig +++ b/example/subcommands.zig | |||
| @@ -41,10 +41,8 @@ pub fn main() !void { | |||
| 41 | // not fully consumed. It can then be reused to parse the arguments for subcommands. | 41 | // not fully consumed. It can then be reused to parse the arguments for subcommands. |
| 42 | .terminating_positional = 0, | 42 | .terminating_positional = 0, |
| 43 | }) catch |err| { | 43 | }) catch |err| { |
| 44 | var buf: [1024]u8 = undefined; | 44 | try diag.reportToFile(.stderr(), err); |
| 45 | var stderr = std.fs.File.stderr().writer(&buf); | 45 | return err; |
| 46 | try diag.report(&stderr.interface, err); | ||
| 47 | return stderr.interface.flush(); | ||
| 48 | }; | 46 | }; |
| 49 | defer res.deinit(); | 47 | defer res.deinit(); |
| 50 | 48 | ||
| @@ -79,10 +77,7 @@ fn mathMain(gpa: std.mem.Allocator, iter: *std.process.ArgIterator, main_args: M | |||
| 79 | .diagnostic = &diag, | 77 | .diagnostic = &diag, |
| 80 | .allocator = gpa, | 78 | .allocator = gpa, |
| 81 | }) catch |err| { | 79 | }) catch |err| { |
| 82 | var buf: [1024]u8 = undefined; | 80 | try diag.reportToFile(.stderr(), err); |
| 83 | var stderr = std.fs.File.stderr().writer(&buf); | ||
| 84 | try diag.report(&stderr.interface, err); | ||
| 85 | try stderr.interface.flush(); | ||
| 86 | return err; // propagate error | 81 | return err; // propagate error |
| 87 | }; | 82 | }; |
| 88 | defer res.deinit(); | 83 | defer res.deinit(); |