~novakane/zelbar

c5098c95449f4d1d3c159aa0c2f60622b893e74f — Hugo Machet 1 year, 10 months ago 5b0f2f1
common: Update flags to latest upstream
2 files changed, 100 insertions(+), 108 deletions(-)

M common/flags.zig
M src/main.zig
M common/flags.zig => common/flags.zig +68 -74
@@ 1,7 1,7 @@
// Zero allocation argument parsing for unix-like systems.
// Released under the Zero Clause BSD (0BSD) license:
//
// Copyright 2022 Isaac Freund
// Copyright 2023 Isaac Freund
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted.


@@ 15,91 15,85 @@
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

const std = @import("std");
const cstr = std.cstr;
const mem = std.mem;

pub const Flag = struct {
    name: [*:0]const u8,
    name: []const u8,
    kind: enum { boolean, arg },
};

pub fn ParseResult(comptime flags: []const Flag) type {
pub fn parser(comptime Arg: type, comptime flags: []const Flag) type {
    switch (Arg) {
        // TODO consider allowing []const u8
        [:0]const u8, [*:0]const u8 => {}, // ok
        else => @compileError("invalid argument type: " ++ @typeName(Arg)),
    }
    return struct {
        const Self = @This();

        const FlagData = struct {
            name: [*:0]const u8,
            value: union {
                boolean: bool,
                arg: ?[*:0]const u8,
            },
        };

        /// Remaining args after the recognized flags
        args: [][*:0]const u8,
        /// Data obtained from parsed flags
        flag_data: [flags.len]FlagData = blk: {
            // Init all flags to false/null
            var flag_data: [flags.len]FlagData = undefined;
            inline for (flags) |flag, i| {
                flag_data[i] = switch (flag.kind) {
                    .boolean => .{
                        .name = flag.name,
                        .value = .{ .boolean = false },
                    },
                    .arg => .{
                        .name = flag.name,
                        .value = .{ .arg = null },
                    },
                };
            }
            break :blk flag_data;
        },
        pub const Result = struct {
            /// Remaining args after the recognized flags
            args: []const Arg,
            /// Data obtained from parsed flags
            flags: Flags,

        pub fn boolFlag(self: Self, flag_name: [*:0]const u8) bool {
            for (self.flag_data) |flag_data| {
                if (cstr.cmp(flag_data.name, flag_name) == 0) return flag_data.value.boolean;
            }
            unreachable; // Invalid flag_name
        }

        pub fn argFlag(self: Self, flag_name: [*:0]const u8) ?[:0]const u8 {
            for (self.flag_data) |flag_data| {
                if (cstr.cmp(flag_data.name, flag_name) == 0) {
                    return std.mem.span(flag_data.value.arg);
            pub const Flags = flags_type: {
                var fields: []const std.builtin.Type.StructField = &.{};
                inline for (flags) |flag| {
                    const field: std.builtin.Type.StructField = switch (flag.kind) {
                        .boolean => .{
                            .name = flag.name,
                            .field_type = bool,
                            .default_value = &false,
                            .is_comptime = false,
                            .alignment = @alignOf(bool),
                        },
                        .arg => .{
                            .name = flag.name,
                            .field_type = ?[:0]const u8,
                            .default_value = &@as(?[:0]const u8, null),
                            .is_comptime = false,
                            .alignment = @alignOf(?[:0]const u8),
                        },
                    };
                    fields = fields ++ [_]std.builtin.Type.StructField{field};
                }
            }
            unreachable; // Invalid flag_name
        }
    };
}
                break :flags_type @Type(.{ .Struct = .{
                    .layout = .Auto,
                    .fields = fields,
                    .decls = &.{},
                    .is_tuple = false,
                } });
            };
        };

pub fn parse(args: [][*:0]const u8, comptime flags: []const Flag) !ParseResult(flags) {
    var ret: ParseResult(flags) = .{ .args = undefined };
        pub fn parse(args: []const Arg) !Result {
            var result_flags: Result.Flags = .{};

    var arg_idx: usize = 0;
    while (arg_idx < args.len) : (arg_idx += 1) {
        var parsed_flag = false;
        inline for (flags) |flag, flag_idx| {
            if (cstr.cmp(flag.name, args[arg_idx]) == 0) {
                switch (flag.kind) {
                    .boolean => ret.flag_data[flag_idx].value.boolean = true,
                    .arg => {
                        arg_idx += 1;
                        if (arg_idx == args.len) {
                            std.log.err("option '" ++ flag.name ++
                                "' requires an argument but none was provided!", .{});
                            return error.MissingFlagArgument;
            var i: usize = 0;
            outer: while (i < args.len) : (i += 1) {
                inline for (flags) |flag| {
                    if (mem.eql(u8, "-" ++ flag.name, mem.span(args[i]))) {
                        switch (flag.kind) {
                            .boolean => @field(result_flags, flag.name) = true,
                            .arg => {
                                i += 1;
                                if (i == args.len) {
                                    std.log.err("option '-" ++ flag.name ++
                                        "' requires an argument but none was provided!", .{});
                                    return error.MissingFlagArgument;
                                }
                                @field(result_flags, flag.name) = mem.span(args[i]);
                            },
                        }
                        ret.flag_data[flag_idx].value.arg = args[arg_idx];
                    },
                        continue :outer;
                    }
                }
                parsed_flag = true;
                break;
            }
        }
        if (!parsed_flag) break;
    }

    ret.args = args[arg_idx..];

    return ret;
            return Result{
                .args = args[i..],
                .flags = result_flags,
            };
        }
    };
}

M src/main.zig => src/main.zig +32 -34
@@ 94,25 94,23 @@ pub fn main() anyerror!void {
    try default_cfg.colors.putNoClobber(context.gpa, .line, line);

    // Parse cli options.
    // https://github.com/ziglang/zig/issues/7807
    const argv: [][*:0]const u8 = os.argv;
    const result = flags.parse(argv[1..], &[_]flags.Flag{
        .{ .name = "-h", .kind = .boolean },
        .{ .name = "-version", .kind = .boolean },
        .{ .name = "-o", .kind = .arg },
        .{ .name = "-btm", .kind = .boolean },
        .{ .name = "-L", .kind = .arg },
        .{ .name = "-g", .kind = .arg },
        .{ .name = "-a", .kind = .arg },
        .{ .name = "-m", .kind = .arg },
        .{ .name = "-fn", .kind = .arg },
        .{ .name = "-B", .kind = .arg },
        .{ .name = "-F", .kind = .arg },
        .{ .name = "-bs", .kind = .arg },
        .{ .name = "-bc", .kind = .arg },
        .{ .name = "-lh", .kind = .arg },
        .{ .name = "-lc", .kind = .arg },
    }) catch {
    const result = flags.parser([*:0]const u8, &.{
        .{ .name = "h", .kind = .boolean },
        .{ .name = "version", .kind = .boolean },
        .{ .name = "o", .kind = .arg },
        .{ .name = "btm", .kind = .boolean },
        .{ .name = "L", .kind = .arg },
        .{ .name = "g", .kind = .arg },
        .{ .name = "a", .kind = .arg },
        .{ .name = "m", .kind = .arg },
        .{ .name = "fn", .kind = .arg },
        .{ .name = "B", .kind = .arg },
        .{ .name = "F", .kind = .arg },
        .{ .name = "bs", .kind = .arg },
        .{ .name = "bc", .kind = .arg },
        .{ .name = "lh", .kind = .arg },
        .{ .name = "lc", .kind = .arg },
    }).parse(os.argv[1..]) catch {
        try io.getStdErr().writeAll(usage);
        os.exit(1);
    };


@@ 122,17 120,17 @@ pub fn main() anyerror!void {
        os.exit(1);
    }

    if (result.boolFlag("-h")) {
    if (result.flags.h) {
        try io.getStdOut().writeAll(usage);
        os.exit(0);
    }
    if (result.boolFlag("-version")) {
    if (result.flags.version) {
        try io.getStdOut().writeAll(build_options.version ++ "\n");
        os.exit(0);
    }
    if (result.argFlag("-o")) |raw| default_cfg.output_name = raw;
    if (result.boolFlag("-btm")) default_cfg.location = .bottom;
    if (result.argFlag("-L")) |raw| {
    if (result.flags.o) |raw| default_cfg.output_name = raw;
    if (result.flags.btm) default_cfg.location = .bottom;
    if (result.flags.L) |raw| {
        const n = try fmt.parseUnsigned(u16, raw, 10);
        switch (n) {
            0 => default_cfg.layer = .bottom,


@@ 141,12 139,12 @@ pub fn main() anyerror!void {
            else => context.fatal(.config, "unknown layer value: {s}", .{raw}),
        }
    }
    if (result.argFlag("-g")) |raw| {
    if (result.flags.g) |raw| {
        const arr = try parse_string(2, raw);
        default_cfg.width = arr[0];
        default_cfg.height = arr[1];
    }
    if (result.argFlag("-a")) |raw| {
    if (result.flags.a) |raw| {
        if (default_cfg.width == 0) {
            context.fatal(.config, "'-a' can only be used when width is not 0", .{});
        }


@@ 159,7 157,7 @@ pub fn main() anyerror!void {
            else => context.fatal(.config, "unknown alignment value: {s}", .{raw}),
        }
    }
    if (result.argFlag("-m")) |raw| {
    if (result.flags.m) |raw| {
        const arr = try parse_string(4, raw);
        default_cfg.margins = .{
            .top = arr[0],


@@ 168,16 166,16 @@ pub fn main() anyerror!void {
            .left = arr[3],
        };
    }
    if (result.argFlag("-fn")) |raw| default_cfg.fonts_name = raw;
    if (result.argFlag("-B")) |raw| {
    if (result.flags.@"fn") |raw| default_cfg.fonts_name = raw;
    if (result.flags.B) |raw| {
        decorations.check_rgba(.main, raw);
        try default_cfg.colors.put(context.gpa, .bg, raw);
    }
    if (result.argFlag("-F")) |raw| {
    if (result.flags.F) |raw| {
        decorations.check_rgba(.main, raw);
        try default_cfg.colors.put(context.gpa, .fg, raw);
    }
    if (result.argFlag("-bs")) |raw| {
    if (result.flags.bs) |raw| {
        const arr = try parse_string(4, raw);
        default_cfg.border = .{
            .top = arr[0],


@@ 186,14 184,14 @@ pub fn main() anyerror!void {
            .left = arr[3],
        };
    }
    if (result.argFlag("-bc")) |raw| {
    if (result.flags.bc) |raw| {
        decorations.check_rgba(.main, raw);
        default_cfg.border.color = raw;
    }
    if (result.argFlag("-lh")) |raw| {
    if (result.flags.lh) |raw| {
        default_cfg.line_height = try fmt.parseUnsigned(u16, raw, 10);
    }
    if (result.argFlag("-lc")) |raw| {
    if (result.flags.lc) |raw| {
        decorations.check_rgba(.main, raw);
        try default_cfg.colors.put(context.gpa, .line, raw);
    }