NOTE: Accord was made for use with zig master, it is not guaranteed to and likely will not work on release versions
- Automatically generate and fill a struct based on input parameters.
- Short and long options.
- Short options work with both
-a -b -c -d 12
and-abcd12
. - Long options work with both
--option long
and--option=long
. - Everything after a standalone
--
will be considered a positional argument. The index for this will also be stored, so you can slice the positionals before or after--
if you want to have a distinction between them. - Positional arguments stored in a struct with
items
storing the actual slice,separator_index
storing the aforementioned index of--
if it exists, andbeforeSeparator
andafterSeparator
functions to get the positionals before and after the--
(if there's no--
, then before will return everything and after will return nothing).- Positional arguments must be manually freed using
positionals.deinit(allocator)
.
- Positional arguments must be manually freed using
- Strings (
[]const u8
) - Signed and unsigned integers
- Floats
- Booleans
- Flags with no arguments via
accord.Flag
, when a flag argument is used it will return the opposite of its default value - Enums by name, value, or both
- Optionals of any of these types (except
Flag
) - Mask type via
accord.Mask(int or enum type)
- Takes a delimited list of ints/enums and bitwise ORs them together
- Array of any of these types (except
Flag
)- Not filling out every value in the array will return an error
- Booleans have
true_strings
andfalse_strings
settings to determine what is considered as true/false. Note that these are case insensitive.- Defaults:
true_strings = &.{ "true", "t", "yes", "1" }
false_strings &.{ "false", "f", "no", "0" }
- Defaults:
- Integers have a
radix
u8 setting, defaults to 0.- A radix of 0 means assume base 10 unless the value starts with:
0b
= binary0o
= octal0x
= hexadecimal
- A radix of 0 means assume base 10 unless the value starts with:
- Enums have an
enum_parsing
enum setting with the valuesname
,value
, andboth
, defaults toname
. Enums also inherit integer parsing settings for when parsing byvalue
.name
means it will try to match the value with the names of the fields in the enum.value
means it will try to match the values of the fields.both
means it will first try to match the field values, and if that fails it will try to match the field names.
- Optionals have the
null_strings
to determine when the value is parsed asnull
. Note that these are case insensitive. Optionals also inherit options from their child type.- Default
null_strings = &.{ "null", "nul", "nil" }
- Default
- Arrays and masks have an
array_delimiter
andmask_delimiter
setting respectively, defaults to","
for arrays and"|"
for masks. They will also inherit any settings from their child type (e.g. an array or mask of enums would also have theenum_parsing
andradix
settings available)
In addition to all default types built into the library, you can also easily define your own custom parsing by fulfilling a particular interface.
All basic types supported in the library are also implemented through this system, so you can reference all of them for examples, the following is how the parsing interface for integers is implemented:
pub fn IntegerInterface(comptime T: type) type {
return struct {
pub const AccordParseSettings = struct {
radix: u8 = 0,
};
pub fn accordParse(parse_string: []const u8, comptime settings: anytype) AccordError!T {
const result = (if (settings.radix == 16)
std.fmt.parseInt(T, std.mem.trimLeft(u8, parse_string, "#"), settings.radix)
else
std.fmt.parseInt(T, parse_string, settings.radix));
return result catch error.OptionUnexpectedValue;
}
};
}
You can also implement custom no-argument flags by omitting the first argument in the function. The implementation of Flag
is as follows:
pub const Flag = struct {
pub fn accordParse(comptime settings: anytype) !bool {
return !settings.default_value;
}
};
The following is a truncated example of the enum parsing interface which demonstrates merging settings from other types. When merging settings like this, you may have the same field in multiple structs so long as they have the same type, and it will prioritize the default value of the setting of the earliest struct that has the field.
pub fn EnumInterface(comptime T: type) type {
const Tag = @typeInfo(T).Enum.tag_type;
returnt struct {
pub const AccordParseSettings = MergeStructs(&.{
struct {
const EnumSetting = enum { name, value, both };
enum_parsing: EnumSetting = .name,
},
InterfaceSettings(GetInterface(Tag)),
});
};
const allocator = std.heap.page_allocator;
var args_iterator = std.process.args();
const options = try accord.parse(&.{
//short name //long name //type //default value //parse options
accord.option('s', "string", []const u8, "default", .{}),
accord.option('c', "color", u32, 0x000000, .{ .radix = 16 }),
accord.option('f', "float", f32, 0.0, .{}),
accord.option('m', "mask", accord.Mask(u8), 0, .{}),
accord.option('a', "", accord.Flag, false, .{}), // option without long option
accord.option(0, "option", accord.Flag, false, .{}), // option without short option
accord.option('i', "optionalintarray", [2]?u32, .{ 0, 0 }, .{ .array_delimiter = "%" }),
}, allocator, &args_iterator);
defer options.positionals.deinit(allocator);
The above example called as
command positional1 -s"some string" --color ff0000 positional2 -f 1.2e4 --mask="2|3" -a positional3 --optionalintarray="null%23" -- --option positional4 positional5
would result in the following value:
{
string = "some string"
color = 0xff0000
float = 12000.0
mask = 3
a = true
option = false
intarray = { null, 23 }
positionals.items = { "command", "positional1", "positional2", "positional3", "--option", "positional4", "positional5" }
positionals.beforeSeparator() = { "command", "positional1", "positional2", "positional3" }
positionals.afterSeparator() = { "--option", "positional4", "positional5" }
}
- Subcommands
- Parsable union containing an Option and Subcommand field
- Flags before a subcommand use top level flags
- Flags after a subcommand apply to the subcommand
- Subcommands after -- are considered normal positionals
- Subcommand stored as a sub-struct in the parse return struct. Possibly store it's own return value?
- A way to define help strings per argument and print them all nicely
- Required arguments