mirror of
https://github.com/sbrow/envr.git
synced 2026-06-28 02:58:33 -04:00
feat: Added command structure.
This commit is contained in:
30
src/main.zig
30
src/main.zig
@@ -13,28 +13,36 @@ pub fn main(init: std.process.Init) !void {
|
|||||||
|
|
||||||
const args = try init.minimal.args.toSlice(arena);
|
const args = try init.minimal.args.toSlice(arena);
|
||||||
|
|
||||||
if (args.len > 1 and std.mem.eql(u8, args[1], "version")) {
|
run(init.io, args) catch return fallback_to_go(init.io, arena, args);
|
||||||
return version(init.io);
|
|
||||||
} else {
|
|
||||||
return fallback_to_go(init.io, args, arena);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version(io: Io) !void {
|
/// Attempt to run the requested command.
|
||||||
// std.debug.print("hello from Zig!\n", .{});
|
fn run(io: Io, args: []const [:0]const u8) !void {
|
||||||
|
const cmd = try envr.root.parse(args[1..]);
|
||||||
|
switch (cmd) {
|
||||||
|
.envr => {
|
||||||
|
// TODO: Print help
|
||||||
|
return envr.ParseError.InvalidType;
|
||||||
|
},
|
||||||
|
.version => {
|
||||||
var stdout_buffer: [1024]u8 = undefined;
|
var stdout_buffer: [1024]u8 = undefined;
|
||||||
var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer);
|
var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer);
|
||||||
const stdout_writer = &stdout_file_writer.interface;
|
const stdout_writer = &stdout_file_writer.interface;
|
||||||
|
|
||||||
try stdout_writer.print("{s}\n", .{config.version});
|
return version(stdout_writer);
|
||||||
try stdout_writer.flush();
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version(writer: *Io.Writer) !void {
|
||||||
|
try writer.print("{s}\n", .{config.version});
|
||||||
|
try writer.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fallback_to_go(
|
fn fallback_to_go(
|
||||||
io: Io,
|
io: Io,
|
||||||
args: []const [:0]const u8,
|
|
||||||
arena: std.mem.Allocator,
|
arena: std.mem.Allocator,
|
||||||
|
args: []const [:0]const u8,
|
||||||
) std.process.ReplaceError {
|
) std.process.ReplaceError {
|
||||||
// Remap args
|
// Remap args
|
||||||
var childArgs = try std.ArrayList([]const u8).initCapacity(arena, args.len);
|
var childArgs = try std.ArrayList([]const u8).initCapacity(arena, args.len);
|
||||||
|
|||||||
95
src/root.zig
95
src/root.zig
@@ -2,17 +2,92 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Io = std.Io;
|
const Io = std.Io;
|
||||||
|
|
||||||
/// This is a documentation comment to explain the `printAnotherMessage` function below.
|
pub const root: Command = .new(.{
|
||||||
///
|
.name = "envr",
|
||||||
/// Accepting an `Io.Writer` instance is a handy way to write reusable code.
|
.subcommands = &[_]CommandOptions{.{ .name = "version" }},
|
||||||
pub fn printAnotherMessage(writer: *Io.Writer) Io.Writer.Error!void {
|
});
|
||||||
try writer.print("Run `zig build test` to run the tests.\n", .{});
|
|
||||||
|
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 {
|
test "parse version" {
|
||||||
return a + b;
|
const args = &[_][]const u8{"version"};
|
||||||
}
|
const cmd = root.parse(args);
|
||||||
|
|
||||||
test "basic add functionality" {
|
try std.testing.expectEqual(.version, cmd);
|
||||||
try std.testing.expect(add(3, 7) == 10);
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user