about summary refs log tree commit diff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/main.zig151
1 files changed, 92 insertions, 59 deletions
diff --git a/src/main.zig b/src/main.zig
index 53048df..b99f28c 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -24,6 +24,77 @@ pub fn main(init: std.process.Init) !void {
 var FORCE: bool = false;
 
 const Cli = struct {
+    const FlagSet = std.BufSet;
+
+    const Flag = struct {
+        name: []const u8,
+        help: []const u8 = "",
+    };
+
+    const Command = struct {
+        name: []const u8,
+        help: []const u8 = "",
+        flags: []const Flag = &.{},
+        subcommands: []const Command = &.{},
+        handler: *const fn (io: Io, gpa: Allocator, flags: FlagSet, args: [][]const u8) anyerror!void,
+
+        fn run(self: Command, io: Io, gpa: Allocator, opts: *std.process.Args.Iterator) !void {
+            var flags: std.BufSet = .init(gpa);
+            defer flags.deinit();
+            var args: std.ArrayList([]const u8) = .empty;
+            defer args.deinit(gpa);
+
+            optLoop: while (opts.next()) |o| {
+                if (std.mem.eql(u8, o, "help")) return Cli.usage();
+                if (std.mem.eql(u8, o, "--help")) return Cli.usage();
+                if (std.mem.eql(u8, o, "-h")) return Cli.usage();
+
+                for (self.flags) |f|
+                    if (std.mem.eql(u8, o, f.name)) {
+                        try flags.insert(f.name);
+                        continue :optLoop;
+                    };
+                for (self.subcommands) |c|
+                    if (std.mem.eql(u8, o, c.name)) {
+                        try c.run(io, gpa, opts);
+                        return; // terminate with subcommand
+                    };
+                try args.append(gpa, o);
+            }
+
+            try self.handler(io, gpa, flags, args.items);
+            return;
+        }
+    };
+
+    const root = Command{
+        .name = "rbc",
+        .subcommands = &.{
+            .{
+                .name = "build",
+                .flags = &.{ .{ .name = "-f" }, .{ .name = "--force" } },
+                .handler = &Cli.build,
+            },
+            .{
+                .name = "mdn",
+                .handler = &Cli.markdown,
+            },
+            .{
+                .name = "gen",
+                .flags = &.{
+                    .{ .name = "-f" },
+                    .{ .name = "--force" },
+                },
+                .handler = &Cli.gen,
+            },
+        },
+        .handler = struct {
+            fn inner(_: Io, _: Allocator, _: std.BufSet, _: [][]const u8) anyerror!void {
+                return Cli.usage();
+            }
+        }.inner,
+    };
+
     fn usage() void {
         std.debug.print(
             \\usage: rbc [command] [options]
@@ -43,42 +114,21 @@ const Cli = struct {
     }
 
     fn run(init: std.process.Init) !void {
-        const io = init.io;
-        const gpa = init.gpa;
-
         if (init.environ_map.get("RBC_FORCE")) |_| FORCE = true;
 
         // parse options
         var opts = init.minimal.args.iterate();
-        _ = opts.skip();
-        while (opts.next()) |o| {
-            if (std.mem.eql(u8, o, "help")) return Cli.usage();
-            if (std.mem.eql(u8, o, "--help")) return Cli.usage();
-            if (std.mem.eql(u8, o, "-h")) return Cli.usage();
-            if (std.mem.eql(u8, o, "build")) return Cli.build(io, gpa, &opts);
-            if (std.mem.eql(u8, o, "gen")) return Cli.gen(io, gpa, &opts);
-            if (std.mem.eql(u8, o, "mdn")) return Cli.markdown(io, gpa, &opts);
-        }
-        return Cli.usage();
+        _ = opts.skip(); // skip arg0
+        return Cli.root.run(init.io, init.gpa, &opts);
     }
 
-    fn build(io: Io, gpa: Allocator, opts: *std.process.Args.Iterator) !void {
-        var args: std.ArrayList([]const u8) = .empty;
-        defer args.deinit(gpa);
-
-        while (opts.next()) |o| {
-            if (std.mem.eql(u8, o, "help")) return Cli.usage();
-            if (std.mem.eql(u8, o, "--help")) return Cli.usage();
-            if (std.mem.eql(u8, o, "-h")) return Cli.usage();
-            if (std.mem.eql(u8, o, "--force")) FORCE = true and continue;
-            if (std.mem.eql(u8, o, "-f")) FORCE = true and continue;
-            try args.append(gpa, o);
-        }
-
-        if (args.items.len < 2) return Cli.usage();
+    fn build(io: Io, gpa: Allocator, flags: FlagSet, args: [][]const u8) !void {
+        if (flags.contains("--force")) FORCE = true;
+        if (flags.contains("-f")) FORCE = true;
+        if (args.len < 2) return Cli.usage();
 
-        const source_path = args.items[0];
-        const target_path = args.items[1];
+        const source_path = args[0];
+        const target_path = args[1];
 
         log.info("build : target={s} source={s}", .{ target_path, source_path });
 
@@ -99,23 +149,18 @@ const Cli = struct {
         try b.build(io, gpa);
     }
 
-    fn gen(io: Io, gpa: Allocator, opts: *std.process.Args.Iterator) !void {
-        var args: std.ArrayList([]const u8) = .empty;
-        defer args.deinit(gpa);
+    fn gen(io: Io, gpa: Allocator, flags: FlagSet, args: [][]const u8) !void {
+        if (flags.contains("--force")) FORCE = true;
+        if (flags.contains("-f")) FORCE = true;
 
-        while (opts.next()) |o| {
-            if (std.mem.eql(u8, o, "help")) return Cli.usage();
-            if (std.mem.eql(u8, o, "--help")) return Cli.usage();
-            if (std.mem.eql(u8, o, "-h")) return Cli.usage();
-            if (std.mem.eql(u8, o, "--force")) FORCE = true and continue;
-            if (std.mem.eql(u8, o, "-f")) FORCE = true and continue;
-            try args.append(gpa, o);
-        }
+        var LIST = false;
+        if (flags.contains("-l")) LIST = true;
+        if (flags.contains("--list")) LIST = true;
 
-        if (args.items.len < 2) return Cli.usage();
+        if (args.len < 2) return Cli.usage();
 
-        const root_path = args.items[0];
-        const target_path = args.items[1];
+        const root_path = args[0];
+        const target_path = args[1];
 
         log.info("gen : target={s} root={s}", .{ target_path, root_path });
 
@@ -183,23 +228,11 @@ const Cli = struct {
         }
     }
 
-    fn markdown(io: Io, gpa: Allocator, opts: *std.process.Args.Iterator) !void {
-        var args: std.ArrayList([]const u8) = .empty;
-        defer args.deinit(gpa);
-
-        while (opts.next()) |o| {
-            if (std.mem.eql(u8, o, "help")) return Cli.usage();
-            if (std.mem.eql(u8, o, "--help")) return Cli.usage();
-            if (std.mem.eql(u8, o, "-h")) return Cli.usage();
-            // if (std.mem.eql(u8, o, "--force")) FORCE = true and continue;
-            // if (std.mem.eql(u8, o, "-f")) FORCE = true and continue;
-            try args.append(gpa, o);
-        }
-
-        if (args.items.len < 2) return Cli.usage();
+    fn markdown(io: Io, gpa: Allocator, _: FlagSet, args: [][]const u8) !void {
+        if (args.len < 2) return Cli.usage();
 
-        const source_path = args.items[0];
-        const target_path = args.items[1];
+        const source_path = args[0];
+        const target_path = args[1];
 
         log.info("mdn : target={s} source={s}", .{ target_path, source_path });