diff --git a/src/comma.zig b/src/comma.zig index 9d83f0c..f501033 100644 --- a/src/comma.zig +++ b/src/comma.zig @@ -1,6 +1,6 @@ //! By convention, root.zig is the root source file when making a package. const std = @import("std"); -// const Io = std.Io; +const Io = std.Io; pub const Command = struct { name: []const u8, @@ -8,7 +8,10 @@ pub const Command = struct { long: ?[]const u8 = null, subcommands: []const Command = &.{}, examples: [][]const u8 = &.{}, + /// The enum type of the command Type: type, + /// The type of struct that holds the Commands's flags and arguments + // Params: type, pub fn new(cmd: CommandOptions) Command { const subcommands: [cmd.subcommands.len]Command = blk: { @@ -43,6 +46,65 @@ pub const Command = struct { return @enumFromInt(self.subcommands.len + 1); } + + /// Used for indentation when printing command help + const tab = " "; + + /// Print usage information to the console. + pub fn help(self: @This(), w: *Io.Writer) !void { + defer w.flush() catch {}; + + if (self.long) |long| { + try w.print("{s}\n\n", .{long}); + } + + try w.print("Usage:\n{s}{s}\n", .{ tab, self.name }); + + if (self.subcommands.len > 0) { + try w.print("\nAvailable Commands:\n", .{}); + + var max_width: u8 = 0; + + inline for (self.subcommands) |cmd| { + max_width = @max(max_width, cmd.name.len); + } + + // Print short command description + inline for (self.subcommands) |cmd| { + try w.print( + "{s}{s}", + .{ + tab, + cmd.name, + }, + ); + + for (0..(max_width - cmd.name.len)) |_| { + try w.print(" ", .{}); + } + + try w.print( + " {s}\n", + .{ + cmd.short orelse "", + }, + ); + } + + try w.print("\n", .{}); + } + + // TODO: Print flags + + // TODO: Print arguments + + if (self.subcommands.len > 0) { + try w.print( + "Use \"{s} [command] --help\" for more information about a command.", + .{self.name}, + ); + } + } }; pub const ParseError = error{ @@ -78,3 +140,7 @@ const CommandOptions = struct { ); } }; + +// /// parses the args into params +// pub fn params(cmd: Command, args: [][]const u8) cmd.Params { +// } diff --git a/src/main.zig b/src/main.zig index 581a36f..3da4333 100644 --- a/src/main.zig +++ b/src/main.zig @@ -26,8 +26,12 @@ fn run( ) !void { const cmd = envr.root.parse(args[1..]); switch (cmd) { - .envr, .unknown => { - return fallback_to_go(io, arena, args); + .envr => { + var stdout_buffer: [4096]u8 = undefined; + var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer); + const stdout_writer = &stdout_file_writer.interface; + + return envr.root.help(stdout_writer); }, .version => { var stdout_buffer: [1024]u8 = undefined; @@ -47,6 +51,9 @@ fn run( environ_map.get("PATH").?, ); }, + .unknown => { + return fallback_to_go(io, arena, args); + }, } } diff --git a/src/root.zig b/src/root.zig index 22c3e27..c65ddcc 100644 --- a/src/root.zig +++ b/src/root.zig @@ -7,6 +7,38 @@ const Command = comma.Command; pub const root: Command = .new(.{ .name = "envr", + .short = "Manage your .env files.", + .long = + \\envr keeps your .env synced to a local, age encrypted database. + \\It is a safe and eay way to gather all your .env files in one place where they can + \\easily be backed by another tool such as restic or git. + \\All your data is stored in ~/data.age + \\ + \\Getting started is easy: + \\ + \\1. Create your configuration file and set up encrypted storage: + \\ + \\> envr init + \\ + \\2. Scan for existing .env files: + \\ + \\> envr scan + \\ + \\Select the files you want to back up from the interactive list. + \\ + \\3. Verify that it worked: + \\ + \\> envr list + \\ + \\4. After changing any of your .env files, update the backup with: + \\ + \\> envr sync + \\ + \\5. If you lose a repository, after re-cloning the repo into the same path it was + \\at before, restore your backup with: + \\ + \\> envr restore .env + , .subcommands = &.{ .{ .name = "deps", @@ -17,7 +49,10 @@ pub const root: Command = .new(.{ \\ The deps command reports which binaries are available and which are not." , }, - .{ .name = "version" }, + .{ + .name = "version", + .short = "Show envr's version", + }, }, }); @@ -35,7 +70,7 @@ test "parse version" { } test "parse unknown" { - const args = &[_][]const u8{"bad", "value"}; + const args = &[_][]const u8{ "bad", "value" }; const cmd = root.parse(args); try std.testing.expectEqual(.unknown, cmd);