aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/libghostty-vt/src/synthetic/cli.zig
blob: 560896030261d4fe6f7295edf2b5eac4c3bc327e (plain) (blame)
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
const std = @import("std");
const Allocator = std.mem.Allocator;
const cli = @import("../cli.zig");

/// The available actions for the CLI. This is the list of available
/// synthetic generators. View docs for each individual one in the
/// predictably named files under `cli/`.
pub const Action = enum {
    ascii,
    kitty,
    osc,
    styled,
    utf8,

    /// Returns the struct associated with the action. The struct
    /// should have a few decls:
    ///
    ///   - `const Options`: The CLI options for the action.
    ///   - `fn create`: Create a new instance of the action from options.
    ///   - `fn destroy`: Destroy the instance of the action.
    ///
    /// See TerminalStream for an example.
    pub fn Struct(comptime action: Action) type {
        return switch (action) {
            .ascii => @import("cli/Ascii.zig"),
            .kitty => @import("cli/Kitty.zig"),
            .osc => @import("cli/Osc.zig"),
            .styled => @import("cli/Styled.zig"),
            .utf8 => @import("cli/Utf8.zig"),
        };
    }
};

/// An entrypoint for the synthetic generator CLI.
pub fn main(init: std.process.Init) !void {
    const alloc = std.heap.c_allocator;
    const action_ = try cli.action.detectArgs(Action, alloc, init.minimal.args);
    const action = action_ orelse return error.NoAction;
    try mainAction(init.io, alloc, action, .{ .cli = init.minimal.args });
}

pub const Args = union(enum) {
    /// The arguments passed to the CLI via argc/argv.
    cli: std.process.Args,

    /// Simple string arguments, parsed via ArgIteratorGeneral.
    string: []const u8,
};

pub fn mainAction(
    io: std.Io,
    alloc: Allocator,
    action: Action,
    args: Args,
) !void {
    switch (action) {
        inline else => |comptime_action| {
            const Impl = Action.Struct(comptime_action);
            try mainActionImpl(Impl, io, alloc, args);
        },
    }
}

fn mainActionImpl(
    comptime Impl: type,
    io: std.Io,
    alloc: Allocator,
    args: Args,
) !void {
    // First, parse our CLI options.
    const Options = Impl.Options;
    var opts: Options = .{};
    defer if (@hasDecl(Options, "deinit")) opts.deinit();
    switch (args) {
        .cli => |process_args| {
            var iter = try cli.args.argsIterator(alloc, process_args);
            defer iter.deinit();
            try cli.args.parse(Options, alloc, &opts, &iter);
        },
        .string => |str| {
            var iter = try std.process.Args.IteratorGeneral(.{}).init(
                alloc,
                str,
            );
            defer iter.deinit();
            try cli.args.parse(Options, alloc, &opts, &iter);
        },
    }

    // TODO: Make this a command line option.
    const seed: u64 = @truncate(@as(u96, @bitCast(std.Io.Timestamp.now(io, .real).toNanoseconds())));
    var prng = std.Random.DefaultPrng.init(seed);
    const rand = prng.random();

    // Our output always goes to stdout.
    var buffer: [2048]u8 = undefined;
    var stdout_writer = std.Io.File.stdout().writer(io, &buffer);
    const writer = &stdout_writer.interface;

    // Create our implementation
    const impl = try Impl.create(alloc, opts);
    defer impl.destroy(alloc);
    try impl.run(writer, rand);

    // Always flush
    writer.flush() catch |err| switch (err) {
        error.WriteFailed => return,
    };
}

test {
    // Make sure we ref all our actions
    inline for (@typeInfo(Action).@"enum".fields) |field| {
        const action = @field(Action, field.name);
        const Impl = Action.Struct(action);
        _ = Impl;
    }
}