feat: Added command structure.

This commit is contained in:
2026-04-20 16:14:37 -04:00
parent 43b03e0aca
commit 33b0063c67
2 changed files with 107 additions and 24 deletions

View File

@@ -2,17 +2,92 @@
const std = @import("std");
const Io = std.Io;
/// This is a documentation comment to explain the `printAnotherMessage` function below.
///
/// Accepting an `Io.Writer` instance is a handy way to write reusable code.
pub fn printAnotherMessage(writer: *Io.Writer) Io.Writer.Error!void {
try writer.print("Run `zig build test` to run the tests.\n", .{});
pub const root: Command = .new(.{
.name = "envr",
.subcommands = &[_]CommandOptions{.{ .name = "version" }},
});
const CommandOptions = struct {
name: []const u8,
short: ?[]const u8 = null,
long: ?[]const u8 = null,
subcommands: []const CommandOptions = &[0]CommandOptions{},
fn as_enum(self: @This()) type {
var field_names: [self.subcommands.len + 1][]const u8 = undefined;
var field_values: [self.subcommands.len + 1]u32 = undefined;
field_names[0] = self.name;
field_values[0] = 0;
inline for (self.subcommands, 1..) |cmd, idx| {
field_names[idx] = cmd.name;
field_values[idx] = idx;
}
return @Enum(
u32,
.exhaustive,
&field_names,
&field_values,
);
}
};
pub const Command = struct {
name: []const u8,
short: ?[]const u8 = null,
long: ?[]const u8 = null,
subcommands: []const Command = &[0]Command{},
Type: type,
pub fn new(cmd: CommandOptions) Command {
const subcommands: [cmd.subcommands.len]Command = blk: {
var result: [cmd.subcommands.len]Command = undefined;
inline for (cmd.subcommands, 0..) |sub, idx| {
result[idx] = new(sub);
}
break :blk result;
};
return .{
.name = cmd.name,
.short = cmd.short,
.long = cmd.long,
.subcommands = &subcommands,
.Type = cmd.as_enum(),
};
}
pub fn parse(comptime self: @This(), args: []const []const u8) ParseError!self.Type {
if (args.len == 0) {
return ParseError.InvalidType;
}
const target = args[0];
inline for (self.subcommands, 1..) |cmd, idx| {
if (std.mem.eql(u8, target, cmd.name)) {
return @enumFromInt(idx);
}
}
return @enumFromInt(0);
}
};
pub const ParseError = error{
InvalidType,
};
test "enum type" {
const got: root.Type = @enumFromInt(1);
try std.testing.expectEqual(.version, got);
}
pub fn add(a: i32, b: i32) i32 {
return a + b;
}
test "parse version" {
const args = &[_][]const u8{"version"};
const cmd = root.parse(args);
test "basic add functionality" {
try std.testing.expect(add(3, 7) == 10);
try std.testing.expectEqual(.version, cmd);
}