Zig 0.17.0-dev (Split by item)

This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig library itself.

Arg

cli.Arg
pub const Arg = struct

File

Code

pub const Arg = struct {
    prefix: enum { long, short, slash },
    name_offset: usize,
    full: []const u8,

    pub fn fromString(str: []const u8) ?@This() {
        if (std.mem.startsWith(u8, str, "--")) {
            return .{ .prefix = .long, .name_offset = 2, .full = str };
        } else if (std.mem.startsWith(u8, str, "-")) {
            return .{ .prefix = .short, .name_offset = 1, .full = str };
        } else if (std.mem.startsWith(u8, str, "/")) {
            return .{ .prefix = .slash, .name_offset = 1, .full = str };
        }
        return null;
    }

    pub fn prefixSlice(self: Arg) []const u8 {
        return self.full[0..(if (self.prefix == .long) 2 else 1)];
    }

    pub fn name(self: Arg) []const u8 {
        return self.full[self.name_offset..];
    }

    pub fn optionWithoutPrefix(self: Arg, option_len: usize) []const u8 {
        if (option_len == 0) return self.name();
        return self.name()[0..option_len];
    }

    pub fn missingSpan(self: Arg) Diagnostics.ErrorDetails.ArgSpan {
        return .{
            .point_at_next_arg = true,
            .value_offset = 0,
            .name_offset = self.name_offset,
            .prefix_len = self.prefixSlice().len,
        };
    }

    pub fn optionAndAfterSpan(self: Arg) Diagnostics.ErrorDetails.ArgSpan {
        return self.optionSpan(0);
    }

    pub fn optionSpan(self: Arg, option_len: usize) Diagnostics.ErrorDetails.ArgSpan {
        return .{
            .name_offset = self.name_offset,
            .prefix_len = self.prefixSlice().len,
            .name_len = option_len,
        };
    }

    pub fn looksLikeFilepath(self: Arg, io: Io) bool {
        const meets_min_requirements = self.prefix == .slash and isSupportedInputExtension(std.fs.path.extension(self.full));
        if (!meets_min_requirements) return false;

        const could_be_fo_option = could_be_fo_option: {
            var window_it = std.mem.window(u8, self.full[1..], 2, 1);
            while (window_it.next()) |window| {
                if (std.ascii.eqlIgnoreCase(window, "fo")) break :could_be_fo_option true;
                // If we see '/' before "fo", then it's not possible for this to be a valid
                // `/fo` option.
                if (window[0] == '/') break;
            }
            break :could_be_fo_option false;
        };
        if (!could_be_fo_option) return true;

        // It's still possible for a file path to look like a /fo option but not actually
        // be one, e.g. `/foo/bar.rc`. As a last ditch effort to reduce false negatives,
        // check if the file path exists and, if so, then we ignore the 'could be /fo option'-ness
        Io.Dir.accessAbsolute(io, self.full, .{}) catch return false;
        return true;
    }

    pub const Value = struct {
        slice: []const u8,
        /// Amount to increment the arg index to skip over both the option and the value arg(s)
        /// e.g. 1 if /<option><value>, 2 if /<option> <value>
        index_increment: u2 = 1,

        pub fn argSpan(self: Value, arg: Arg) Diagnostics.ErrorDetails.ArgSpan {
            const prefix_len = arg.prefixSlice().len;
            switch (self.index_increment) {
                1 => return .{
                    .value_offset = @intFromPtr(self.slice.ptr) - @intFromPtr(arg.full.ptr),
                    .prefix_len = prefix_len,
                    .name_offset = arg.name_offset,
                },
                2 => return .{
                    .point_at_next_arg = true,
                    .prefix_len = prefix_len,
                    .name_offset = arg.name_offset,
                },
                else => unreachable,
            }
        }

        pub fn index(self: Value, arg_index: usize) usize {
            if (self.index_increment == 2) return arg_index + 1;
            return arg_index;
        }
    };

    pub fn value(self: Arg, option_len: usize, index: usize, args: []const []const u8) error{MissingValue}!Value {
        const rest = self.full[self.name_offset + option_len ..];
        if (rest.len > 0) return .{ .slice = rest };
        if (index + 1 >= args.len) return error.MissingValue;
        return .{ .slice = args[index + 1], .index_increment = 2 };
    }

    pub const Context = struct {
        index: usize,
        option_len: usize,
        arg: Arg,
        value: Value,
    };
}