The bakery bakes the user context type into an object so that it doesn't have to be specified over and over again. This ends up being a nicer way of specifying the CLI parameters, except for the fact that it requires a slightly odd comptime block construct due to `var` not working at the top level for some reason (and `comptime var` also not working).
65 lines
3.0 KiB
Zig
65 lines
3.0 KiB
Zig
const meta = @import("./meta.zig");
|
|
const params = @import("./params.zig");
|
|
const noclip = @import("./noclip.zig");
|
|
|
|
fn GenCommand(comptime UserContext: type, comptime cData: params.CommandData) type {
|
|
return struct {
|
|
argspec: meta.MutableTuple = .{},
|
|
|
|
StringOption: type = params.Option(.{ .Output = []const u8, .UserContext = UserContext }),
|
|
StringArgument: type = params.Argument(.{ .Output = []const u8, .UserContext = UserContext }),
|
|
Flag: type = params.Flag(UserContext),
|
|
defaultHelpFlag: params.Flag(UserContext) = HelpFlag(.{}),
|
|
|
|
// have to provide the first argument in order for these functions to be
|
|
// accessible from an instance, which is kind of annoying.
|
|
pub fn Option(comptime _: @This(), comptime Output: type) type {
|
|
return params.Option(.{ .Output = Output, .UserContext = UserContext });
|
|
}
|
|
pub fn Argument(comptime _: @This(), comptime Output: type) type {
|
|
return params.Argument(.{ .Output = Output, .UserContext = UserContext });
|
|
}
|
|
|
|
pub fn HelpFlag(comptime args: params.HelpFlagArgs) params.Flag(UserContext) {
|
|
return params.HelpFlag(UserContext, args);
|
|
}
|
|
|
|
// This is really only sort of conditionally useful. It would be nice
|
|
// to add the Subcommand directly to the argspec, except what we
|
|
// actually have to have is the subcommand.Parser, and that can't be
|
|
// created until all of the options are attached to that command. I
|
|
// believe we could handle it with an `inline for` construct in the
|
|
// parser executor, but I'm not particularly convinced that those
|
|
// contortions provide a particularly real benefit. The main change
|
|
// would be specifying the subcommands after the main command, whereas
|
|
// in the current state of things, they're generally defined before the
|
|
// main command.
|
|
pub fn Subcommand(comptime subData: params.CommandData) GenCommand(UserContext, subData) {
|
|
return Command(UserContext, subData);
|
|
}
|
|
|
|
pub fn add(comptime self: *@This(), comptime parameter: anytype) void {
|
|
self.argspec.add(parameter);
|
|
}
|
|
|
|
pub fn commandSpec(comptime self: @This()) self.argspec.TupleType() {
|
|
return self.argspec.realTuple();
|
|
}
|
|
|
|
pub fn CommandResult(comptime self: @This()) type {
|
|
return noclip.CommandResult(self.commandSpec(), UserContext);
|
|
}
|
|
|
|
pub fn Parser(
|
|
comptime self: @This(),
|
|
comptime callback: *const fn (UserContext, noclip.CommandResult(self.commandSpec(), UserContext)) anyerror!void,
|
|
) noclip.CommandParser(cData, self.commandSpec(), UserContext, callback) {
|
|
return noclip.CommandParser(cData, self.commandSpec(), UserContext, callback){};
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn Command(comptime UserContext: type, comptime cData: params.CommandData) GenCommand(UserContext, cData) {
|
|
return GenCommand(UserContext, cData){};
|
|
}
|