Skip to content

Commit

Permalink
Add diagnostics and error handling example
Browse files Browse the repository at this point in the history
  • Loading branch information
n0s4 committed Sep 17, 2024
1 parent 519f304 commit 85fce07
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 4 deletions.
1 change: 1 addition & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pub fn build(b: *std.Build) void {
const example_option = b.option(
enum {
overview,
error_handling,
},
"example",
"Example to run for example step (default = overview)",
Expand Down
60 changes: 60 additions & 0 deletions examples/error_handling.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
const std = @import("std");
const flags = @import("flags");

pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();

var args = try std.process.argsWithAllocator(gpa.allocator());
defer args.deinit();

// Contains info about a (sub)command where a parsing error occured.
var diagnositics: flags.Diagnostics = undefined;

// Replace with your writer for reporting errors.
// Using stderr explicitly is redundant as flags uses stderr by default.
var error_writer = std.io.getStdErr().writer();

const options = flags.parse(&args, "error-handling", Flags, .{
.diagnostics = &diagnositics,
.stderr = error_writer.any(),
}) catch |err| {
// When parsing is stopped due to --help being passed, this special error is returned.
if (err == flags.Error.PrintedHelp) {
// In this case help has already been printed to stdout and
// no actual parsing error has occured so we exit.
std.posix.exit(0);
}

std.debug.print(
"caught {!} while parsing command \"{s}\"\n",
.{ err, diagnositics.command },
);

std.debug.print("command help:\n{s}", .{diagnositics.help});

std.posix.exit(1);
};

try std.json.stringify(
options,
.{ .whitespace = .indent_2 },
std.io.getStdOut().writer(),
);
}

const Flags = struct {
pub const description = "Test program to showcase error handling.";

foo: bool,
bar: ?[]const u8,

command: union(enum) {
baz: struct {
a: bool,
},
qux: struct {
b: bool,
},
},
};
15 changes: 15 additions & 0 deletions src/parse.zig
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,19 @@ pub const Error = error{
MissingCommand,
} || std.fmt.ParseIntError || std.fmt.ParseFloatError;

pub const Diagnostics = struct {
/// The command name in which an error occured.
command: []const u8,
/// The help message for the command.
help: []const u8,
};

const Env = struct {
args: *ArgIterator,
stdout: AnyWriter,
stderr: AnyWriter,
/// Gives information about the command if a parsing error occurs.
diagnostics: ?*Diagnostics,
};

var env: Env = undefined;
Expand All @@ -47,6 +56,7 @@ fn report(comptime message: []const u8, args: anytype) void {
pub const Options = struct {
stdout: ?AnyWriter = null,
stderr: ?AnyWriter = null,
diagnostics: ?*Diagnostics = null,
skip_first_arg: bool = true,
};

Expand All @@ -63,6 +73,7 @@ pub fn parse(args: *ArgIterator, comptime exe_name: []const u8, Flags: type, opt
.args = args,
.stdout = options.stdout orelse std.io.getStdOut().writer().any(),
.stderr = options.stderr orelse std.io.getStdErr().writer().any(),
.diagnostics = options.diagnostics,
};
return parse2(Flags, exe_name);
}
Expand All @@ -74,6 +85,10 @@ fn parse2(Flags: type, comptime command_name: []const u8) Error!Flags {
else
comptime help.generate(Flags, info, command_name);

if (env.diagnostics) |error_info| {
error_info.* = .{ .command = command_name, .help = help_message };
}

var flags: Flags = undefined;

var passed: std.enums.EnumFieldStruct(std.meta.FieldEnum(Flags), bool, false) = .{};
Expand Down
5 changes: 1 addition & 4 deletions src/root.zig
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
const help = @import("help.zig");
const parse_mod = @import("parse.zig");

pub const parse = parse_mod.parse;
pub const parseOrExit = parse_mod.parseOrExit;
pub usingnamespace @import("parse.zig");

test {
_ = help;
_ = parse_mod;
}

0 comments on commit 85fce07

Please sign in to comment.