summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jimmi Holst Christensen2025-07-22 10:44:11 +0200
committerGravatar Jimmi Holst Christensen2025-07-22 10:44:11 +0200
commit095409eb0421f0f970c246b371b39dab2ff912aa (patch)
tree08ed3d08575d8a3b2613874a01dc7f98312bf272
parentUpdate to Zig 0.15.0-dev.1147 (diff)
downloadzig-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.md25
-rw-r--r--clap.zig12
-rw-r--r--clap/streaming.zig2
-rw-r--r--example/simple-ex.zig5
-rw-r--r--example/simple.zig6
-rw-r--r--example/streaming-clap.zig6
-rw-r--r--example/subcommands.zig11
7 files changed, 24 insertions, 43 deletions
diff --git a/README.md b/README.md
index 2e64264..8db67c9 100644
--- a/README.md
+++ b/README.md
@@ -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.
diff --git a/clap.zig b/clap.zig
index 3863087..c4dd801 100644
--- a/clap.zig
+++ b/clap.zig
@@ -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
568fn testDiag(diag: Diagnostic, err: anyerror, expected: []const u8) !void { 576fn 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();