~gpanders/wk

ref: 55fa3e61b4c6bf191efd0e3e27d31aa124929eff wk/src/cmd.zig -rw-r--r-- 2.5 KiB
55fa3e61 — Greg Anders Simplify 'show' command logic 2 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
const std = @import("std");
const fmt = std.fmt;
const fs = std.fs;
const mem = std.mem;
const stdout = std.io.getStdOut().outStream();
const warn = std.debug.warn;
const ChildProcess = std.ChildProcess;

const commands = .{
    @import("cmd/backlinks.zig").cmd,
    @import("cmd/list.zig").cmd,
    @import("cmd/new.zig").cmd,
    @import("cmd/open.zig").cmd,
    @import("cmd/preview.zig").cmd,
    @import("cmd/sync.zig").cmd,
    @import("cmd/show.zig").cmd,
    @import("cmd/tags.zig").cmd,
};

pub const Command = struct {
    name: []const u8,
    aliases: []const []const u8,
    usage: []const u8,
    desc: []const u8,
    run: fn (allocator: *mem.Allocator, args: ?[]const []const u8) Error!void,

    const Self = @This();

    pub const Error = error{
        MissingRequiredArgument,
        CommandFailed,
        NoMatches,
        StreamTooLong,
        InvalidFormat,
    } || mem.Allocator.Error || fs.File.OpenError || fs.File.StatError || fs.File.ReadError || fs.File.WriteError || ChildProcess.SpawnError;

    fn parse(str: []const u8) !Self {
        inline for (commands) |cmd| {
            if (mem.eql(u8, str, cmd.name)) return cmd;
            inline for (cmd.aliases) |alias| {
                if (mem.eql(u8, str, alias)) return cmd;
            }
        }

        warn("Error: unknown command: {}\n", .{str});
        return error.UnknownCommand;
    }
};

pub fn printUsage(cmd: ?Command) void {
    stdout.print("Usage: zet {}\n\n", .{if (cmd) |_| cmd.?.usage else "COMMAND"}) catch return;

    if (cmd) |_| {
        stdout.print("{}\n", .{cmd.?.desc}) catch return;
    } else {
        stdout.print("Available commands:\n", .{}) catch return;
        inline for (commands) |command| {
            // TODO (zig 0.7.0) Replace with format string specifier
            // stdout.print("{: 8}{: <16}{}\n", ...)
            stdout.print("        {}{}{}\n", .{
                command.name,
                " " ** (16 - command.name.len),
                command.desc,
            }) catch return;
        }
        stdout.print("\n", .{}) catch return;
        stdout.print("Use \"zet help COMMAND\" for more information about a command.\n", .{}) catch return;
    }
}

pub fn handleCommand(allocator: *mem.Allocator, command: []const u8, args: ?[]const []const u8) !void {
    if (mem.eql(u8, command, "help")) {
        const subcmd = if (args) |_| try Command.parse(args.?[0]) else null;
        printUsage(subcmd);
        return;
    }

    const cmd = try Command.parse(command);
    try cmd.run(allocator, args);
}