From 8a503cedfbf541f8c923a2fe50cd6c69c83e3f2e Mon Sep 17 00:00:00 2001 From: Spencer Brower Date: Mon, 20 Apr 2026 17:08:20 -0400 Subject: [PATCH] refactor: Broke comma into a separate package. --- build.zig | 9 ++++++ src/comma.zig | 75 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main.zig | 3 +- src/root.zig | 77 +++------------------------------------------------ 4 files changed, 90 insertions(+), 74 deletions(-) create mode 100644 src/comma.zig diff --git a/build.zig b/build.zig index 11330bf..515eb28 100644 --- a/build.zig +++ b/build.zig @@ -21,6 +21,11 @@ pub fn build(b: *std.Build) void { // target and optimize options) will be listed when running `zig build --help` // in this directory. + const comma = b.addModule("comma", .{ + .root_source_file = b.path("src/comma.zig"), + .target = target, + }); + // This creates a module, which represents a collection of source files alongside // some compilation options, such as optimization mode and linked system libraries. // Zig modules are the preferred way of making Zig code available to consumers. @@ -39,6 +44,9 @@ pub fn build(b: *std.Build) void { // Later on we'll use this module as the root module of a test executable // which requires us to specify a target. .target = target, + .imports = &.{ + .{ .name = "comma", .module = comma }, + }, }); // Here we define an executable. An executable needs to have a root module @@ -78,6 +86,7 @@ pub fn build(b: *std.Build) void { // repeated because you are allowed to rename your imports, which // can be extremely useful in case of collisions (which can happen // importing modules from different packages). + .{ .name = "comma", .module = comma }, .{ .name = "envr", .module = mod }, }, }), diff --git a/src/comma.zig b/src/comma.zig new file mode 100644 index 0000000..9ea66c6 --- /dev/null +++ b/src/comma.zig @@ -0,0 +1,75 @@ +//! By convention, root.zig is the root source file when making a package. +const std = @import("std"); +// const Io = std.Io; + +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, +}; + +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, + ); + } +}; diff --git a/src/main.zig b/src/main.zig index 0056943..79953b5 100644 --- a/src/main.zig +++ b/src/main.zig @@ -3,6 +3,7 @@ const Io = std.Io; const config = @import("config"); +const comma = @import("comma"); const envr = @import("envr"); const goBinary = "envr-go"; @@ -22,7 +23,7 @@ fn run(io: Io, args: []const [:0]const u8) !void { switch (cmd) { .envr => { // TODO: Print help - return envr.ParseError.InvalidType; + return comma.ParseError.InvalidType; }, .version => { var stdout_buffer: [1024]u8 = undefined; diff --git a/src/root.zig b/src/root.zig index 450274f..1715fd9 100644 --- a/src/root.zig +++ b/src/root.zig @@ -2,83 +2,14 @@ const std = @import("std"); const Io = std.Io; +const comma = @import("comma"); +const Command = comma.Command; + pub const root: Command = .new(.{ .name = "envr", - .subcommands = &[_]CommandOptions{.{ .name = "version" }}, + .subcommands = &.{.{ .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);