From 80c48531716a8ead2f415af7dff849d397c6fc5a Mon Sep 17 00:00:00 2001 From: torque Date: Sat, 5 Aug 2023 13:41:21 -0700 Subject: [PATCH] style: use conventional camelCase naming for functions I think I still prefer snake_case stylistically, but this style fits in a lot better with other zig code and is the officially endorsed style, so it makes sense to use it. Since I don't have good test coverage, some conversions may have been missed, but the demo still builds, which is a decent amount of coverage. This was pretty easy to do with a find and replace, so it should be reasonably thorough. --- demo/demo.zig | 30 +++---- source/command.zig | 72 ++++++++-------- source/converters.zig | 36 ++++---- source/help.zig | 78 ++++++++--------- source/meta.zig | 4 +- source/parameters.zig | 29 ++++--- source/parser.zig | 192 ++++++++++++++++++++++-------------------- 7 files changed, 226 insertions(+), 215 deletions(-) diff --git a/demo/demo.zig b/demo/demo.zig index 8663b35..a8db216 100644 --- a/demo/demo.zig +++ b/demo/demo.zig @@ -13,7 +13,7 @@ const cli = cmd: { \\This command demonstrates the functionality of the noclip library. cool! , }; - cmd.add_option(.{ .OutputType = struct { u8, u8 } }, .{ + cmd.addOption(.{ .OutputType = struct { u8, u8 } }, .{ .name = "test", .short_tag = "-t", .long_tag = "--test", @@ -21,7 +21,7 @@ const cli = cmd: { .description = "multi-value test option", .nice_type_name = "int> flag_converter(gen), - .Int => int_converter(gen), + .Bool => FlagConverter(gen), + .Int => IntConverter(gen), .Pointer => |info| if (info.size == .Slice and info.child == u8) - string_converter(gen) + StringConverter(gen) else null, - .Enum => |info| if (info.is_exhaustive) choice_converter(gen) else null, + .Enum => |info| if (info.is_exhaustive) ChoiceConverter(gen) else null, // TODO: how to handle structs with field defaults? maybe this should only work // for tuples, which I don't think can have defaults. .Struct => |info| if (gen.value_count == .fixed and gen.value_count.fixed == info.fields.len) - struct_converter(gen) + StructConverter(gen) else null, else => null, }; } -fn multi_converter(comptime gen: ParameterGenerics) ?ConverterSignature(gen) { - const converter = default_converter( - ncmeta.copy_struct(ParameterGenerics, gen, .{ .multi = false }), +fn MultiConverter(comptime gen: ParameterGenerics) ?ConverterSignature(gen) { + const converter = DefaultConverter( + ncmeta.copyStruct(ParameterGenerics, gen, .{ .multi = false }), ) orelse @compileError("no default converter"); const Intermediate = gen.IntermediateType(); @@ -59,7 +59,7 @@ fn multi_converter(comptime gen: ParameterGenerics) ?ConverterSignature(gen) { }.handler; } -fn flag_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) { +fn FlagConverter(comptime gen: ParameterGenerics) ConverterSignature(gen) { return struct { pub fn handler(_: gen.UserContext, input: []const u8, _: ErrorWriter) ConversionError!bool { // treat an empty string as falsy @@ -79,7 +79,7 @@ fn flag_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) { }.handler; } -fn string_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) { +fn StringConverter(comptime gen: ParameterGenerics) ConverterSignature(gen) { return struct { pub fn handler(_: gen.UserContext, input: []const u8, _: ErrorWriter) ConversionError![]const u8 { return input; @@ -87,7 +87,7 @@ fn string_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) { }.handler; } -fn int_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) { +fn IntConverter(comptime gen: ParameterGenerics) ConverterSignature(gen) { const IntType = gen.OutputType; return struct { @@ -100,7 +100,7 @@ fn int_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) { }.handler; } -fn struct_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) { +fn StructConverter(comptime gen: ParameterGenerics) ConverterSignature(gen) { const StructType = gen.OutputType; const type_info = @typeInfo(StructType).Struct; const Intermediate = gen.IntermediateType(); @@ -117,15 +117,15 @@ fn struct_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) { var result: StructType = undefined; inline for (comptime type_info.fields, 0..) |field, idx| { - const converter = comptime default_converter( - ncmeta.copy_struct(ParameterGenerics, gen, .{ + const Converter = comptime DefaultConverter( + ncmeta.copyStruct(ParameterGenerics, gen, .{ .OutputType = field.type, .value_count = .{ .fixed = 1 }, }), ) orelse @compileError("cannot get converter for field" ++ field.name); - @field(result, field.name) = try converter(context, input.items[idx], failure); + @field(result, field.name) = try Converter(context, input.items[idx], failure); } return result; @@ -133,7 +133,7 @@ fn struct_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) { }.handler; } -fn choice_converter(comptime gen: ParameterGenerics) ConverterSignature(gen) { +fn ChoiceConverter(comptime gen: ParameterGenerics) ConverterSignature(gen) { const EnumType = gen.OutputType; return struct { diff --git a/source/help.zig b/source/help.zig index f115af4..f0cfedd 100644 --- a/source/help.zig +++ b/source/help.zig @@ -20,7 +20,7 @@ pub fn StructuredPrinter(comptime Writer: type) type { wrap_width: usize = 100, writer: Writer, - pub fn print_pair(self: *@This(), pair: AlignablePair, leading_indent: u8, tabstop: usize) !void { + pub fn printPair(self: *@This(), pair: AlignablePair, leading_indent: u8, tabstop: usize) !void { try self.writer.writeByteNTimes(' ', leading_indent); const left = std.mem.trim(u8, pair.left, " \n"); try self.writer.writeAll(left); @@ -30,26 +30,26 @@ pub fn StructuredPrinter(comptime Writer: type) type { if (offset > tabstop) return NoclipError.UnexpectedFailure; try self.writer.writeByteNTimes(' ', tabstop - offset); - try self.print_rewrap(std.mem.trim(u8, pair.right, " \n"), tabstop); + try self.printRewrap(std.mem.trim(u8, pair.right, " \n"), tabstop); try self.writer.writeByte('\n'); } - pub fn print_pair_brief(self: *@This(), pair: AlignablePair, leading_indent: u8, tabstop: usize) !void { + pub fn printPairBrief(self: *@This(), pair: AlignablePair, leading_indent: u8, tabstop: usize) !void { const brief = ncmeta.partition(u8, pair.right, &[_][]const u8{"\n\n"})[0]; const simulacrum: AlignablePair = .{ .left = pair.left, .right = brief, }; - try self.print_pair(simulacrum, leading_indent, tabstop); + try self.printPair(simulacrum, leading_indent, tabstop); } - pub fn print_wrapped(self: *@This(), text: []const u8, leading_indent: usize) !void { + pub fn printWrapped(self: *@This(), text: []const u8, leading_indent: usize) !void { try self.writer.writeByteNTimes(' ', leading_indent); - try self.print_rewrap(std.mem.trim(u8, text, "\n"), leading_indent); + try self.printRewrap(std.mem.trim(u8, text, "\n"), leading_indent); } - fn print_rewrap(self: *@This(), text: []const u8, indent: usize) !void { + fn printRewrap(self: *@This(), text: []const u8, indent: usize) !void { // TODO: lol return a real error if (indent >= self.wrap_width) return NoclipError.UnexpectedFailure; @@ -62,8 +62,8 @@ pub fn StructuredPrinter(comptime Writer: type) type { if (line.len == 0) { // we have a trailing line that needs to be cleaned up if (location > indent) - _ = try self.clear_line(indent); - location = try self.clear_line(indent); + _ = try self.clearLine(indent); + location = try self.clearLine(indent); continue; } @@ -91,7 +91,7 @@ pub fn StructuredPrinter(comptime Writer: type) type { break; } if (location != indent) - location = try self.clear_line(indent); + location = try self.clearLine(indent); need_forced_break = true; continue :choppa; @@ -100,13 +100,13 @@ pub fn StructuredPrinter(comptime Writer: type) type { if (location > indent) try self.writer.writeByte(' '); try self.writer.writeAll(choppee[0..split]); - location = try self.clear_line(indent); + location = try self.clearLine(indent); choppee = choppee[split + 1 ..]; } } } - fn clear_line(self: *@This(), indent: usize) !usize { + fn clearLine(self: *@This(), indent: usize) !usize { try self.writer.writeByte('\n'); try self.writer.writeByteNTimes(' ', indent); return indent; @@ -115,7 +115,7 @@ pub fn StructuredPrinter(comptime Writer: type) type { } pub fn HelpBuilder(comptime command: anytype) type { - const help_info = opt_info(command.generate()); + const help_info = optInfo(command.generate()); return struct { writebuffer: std.ArrayList(u8), @@ -126,7 +126,7 @@ pub fn HelpBuilder(comptime command: anytype) type { }; } - pub fn build_message( + pub fn buildMessage( self: *@This(), name: []const u8, subcommands: parser.CommandMap, @@ -136,26 +136,26 @@ pub fn HelpBuilder(comptime command: anytype) type { "Usage: {s}{s}{s}{s}\n\n", .{ name, - self.option_brief(), - try self.args_brief(), - self.subcommands_brief(subcommands), + self.optionBrief(), + try self.argsBrief(), + self.subcommandsBrief(subcommands), }, ); var printer = StructuredPrinter(@TypeOf(writer)){ .writer = writer }; - try printer.print_wrapped(command.description, 2); + try printer.printWrapped(command.description, 2); try writer.writeAll("\n\n"); - const arguments = try self.describe_arguments(); - const options = try self.describe_options(); - const env_vars = try self.describe_env(); - const subcs = try self.describe_subcommands(subcommands); + const arguments = try self.describeArguments(); + const options = try self.describeOptions(); + const env_vars = try self.describeEnv(); + const subcs = try self.describeSubcommands(subcommands); const max_just = @max(arguments.just, @max(options.just, @max(env_vars.just, subcs.just))); if (arguments.pairs.len > 0) { try writer.writeAll("Arguments:\n"); for (arguments.pairs) |pair| - try printer.print_pair(pair, 2, max_just + 4); + try printer.printPair(pair, 2, max_just + 4); try writer.writeAll("\n"); } @@ -163,7 +163,7 @@ pub fn HelpBuilder(comptime command: anytype) type { if (options.pairs.len > 0) { try writer.writeAll("Options:\n"); for (options.pairs) |pair| - try printer.print_pair(pair, 2, max_just + 4); + try printer.printPair(pair, 2, max_just + 4); try writer.writeAll("\n"); } @@ -171,7 +171,7 @@ pub fn HelpBuilder(comptime command: anytype) type { if (env_vars.pairs.len > 0) { try writer.writeAll("Environment variables:\n"); for (env_vars.pairs) |pair| - try printer.print_pair(pair, 2, max_just + 4); + try printer.printPair(pair, 2, max_just + 4); try writer.writeAll("\n"); } @@ -179,7 +179,7 @@ pub fn HelpBuilder(comptime command: anytype) type { if (subcs.pairs.len > 0) { try writer.writeAll("Subcommands:\n"); for (subcs.pairs) |pair| - try printer.print_pair_brief(pair, 2, max_just + 4); + try printer.printPairBrief(pair, 2, max_just + 4); try writer.writeAll("\n"); } @@ -187,14 +187,14 @@ pub fn HelpBuilder(comptime command: anytype) type { return self.writebuffer.toOwnedSlice(); } - fn option_brief(_: @This()) []const u8 { + fn optionBrief(_: @This()) []const u8 { return if (comptime help_info.options.len > 0) " [options...]" else ""; } - fn args_brief(self: @This()) ![]const u8 { + fn argsBrief(self: @This()) ![]const u8 { var buf = std.ArrayList(u8).init(self.writebuffer.allocator); defer buf.deinit(); @@ -214,14 +214,14 @@ pub fn HelpBuilder(comptime command: anytype) type { return buf.toOwnedSlice(); } - fn subcommands_brief(_: @This(), subcommands: parser.CommandMap) []const u8 { + fn subcommandsBrief(_: @This(), subcommands: parser.CommandMap) []const u8 { return if (subcommands.count() > 0) " " else ""; } - fn describe_arguments(self: @This()) !OptionDescription { + fn describeArguments(self: @This()) !OptionDescription { var pairs = std.ArrayList(AlignablePair).init(self.writebuffer.allocator); defer pairs.deinit(); @@ -243,13 +243,13 @@ pub fn HelpBuilder(comptime command: anytype) type { }; } - fn describe_options(self: @This()) !OptionDescription { + fn describeOptions(self: @This()) !OptionDescription { var pairs = std.ArrayList(AlignablePair).init(self.writebuffer.allocator); defer pairs.deinit(); var just: usize = 0; inline for (help_info.options) |opt| { - const pair = try self.describe_option(opt); + const pair = try self.describeOption(opt); if (pair.left.len > just) just = pair.left.len; try pairs.append(pair); } @@ -260,7 +260,7 @@ pub fn HelpBuilder(comptime command: anytype) type { }; } - fn describe_option(self: @This(), comptime opt: OptHelp) !AlignablePair { + fn describeOption(self: @This(), comptime opt: OptHelp) !AlignablePair { var buffer = std.ArrayList(u8).init(self.writebuffer.allocator); defer buffer.deinit(); const writer = buffer.writer(); @@ -321,7 +321,7 @@ pub fn HelpBuilder(comptime command: anytype) type { return .{ .left = left, .right = right }; } - fn describe_env(self: @This()) !OptionDescription { + fn describeEnv(self: @This()) !OptionDescription { var pairs = std.ArrayList(AlignablePair).init(self.writebuffer.allocator); defer pairs.deinit(); @@ -343,7 +343,7 @@ pub fn HelpBuilder(comptime command: anytype) type { }; } - fn describe_subcommands(self: @This(), subcommands: parser.CommandMap) !OptionDescription { + fn describeSubcommands(self: @This(), subcommands: parser.CommandMap) !OptionDescription { var pairs = std.ArrayList(AlignablePair).init(self.writebuffer.allocator); defer pairs.deinit(); @@ -402,7 +402,7 @@ const ArgHelp = struct { required: bool = true, }; -pub fn opt_info(comptime command: anytype) CommandHelp { +pub fn optInfo(comptime command: anytype) CommandHelp { // TODO: this could be runtime and it would be slightly simpler. comptime { var options: []const OptHelp = &[_]OptHelp{}; @@ -428,7 +428,7 @@ pub fn opt_info(comptime command: anytype) CommandHelp { if (!std.mem.eql(u8, last_name, param.name)) { if (last_name.len > 0) { - if (env_only(last_option)) { + if (envOnly(last_option)) { env_vars = env_vars ++ &[_]EnvHelp{.{ .env_var = last_option.env_var, .description = last_option.description, @@ -487,7 +487,7 @@ pub fn opt_info(comptime command: anytype) CommandHelp { } if (last_name.len > 0) { - if (env_only(last_option)) { + if (envOnly(last_option)) { env_vars = env_vars ++ &[_]EnvHelp{.{ .env_var = last_option.env_var.?, .description = last_option.description, @@ -506,7 +506,7 @@ pub fn opt_info(comptime command: anytype) CommandHelp { } } -inline fn env_only(option: OptHelp) bool { +inline fn envOnly(option: OptHelp) bool { return option.short_truthy == null and option.long_truthy == null and option.short_falsy == null and diff --git a/source/meta.zig b/source/meta.zig index 027564e..733ddba 100644 --- a/source/meta.zig +++ b/source/meta.zig @@ -48,7 +48,7 @@ pub fn UpdateDefaults(comptime input: type, comptime defaults: anytype) type { } } -pub fn enum_length(comptime T: type) comptime_int { +pub fn enumLength(comptime T: type) comptime_int { return @typeInfo(T).Enum.fields.len; } @@ -174,7 +174,7 @@ pub fn SliceIterator(comptime T: type) type { }; } -pub fn copy_struct(comptime T: type, source: T, field_overrides: anytype) T { +pub fn copyStruct(comptime T: type, source: T, field_overrides: anytype) T { var result: T = undefined; comptime inline for (@typeInfo(@TypeOf(field_overrides)).Struct.fields) |field| { diff --git a/source/parameters.zig b/source/parameters.zig index 32a0161..0c314d4 100644 --- a/source/parameters.zig +++ b/source/parameters.zig @@ -34,6 +34,7 @@ pub const ParameterGenerics = struct { /// useful for implementing complex conversion that produces output through its /// side effects or by modifying the user context. OutputType: type = void, + param_type: ParameterType, value_count: ValueCount, /// allow this named parameter to be passed multiple times. @@ -44,7 +45,7 @@ pub const ParameterGenerics = struct { // many-to-many and the many-to-one cases. multi: bool, - pub fn fixed_value_count(comptime OutputType: type, comptime value_count: ValueCount) ValueCount { + pub fn fixedValueCount(comptime OutputType: type, comptime value_count: ValueCount) ValueCount { return comptime if (value_count == .fixed) switch (@typeInfo(OutputType)) { .Struct => |info| .{ .fixed = info.fields.len }, @@ -58,15 +59,15 @@ pub const ParameterGenerics = struct { value_count; } - pub fn has_context(comptime self: @This()) bool { + pub fn hasContext(comptime self: @This()) bool { return comptime self.UserContext != void; } - pub fn has_output(comptime self: @This()) bool { + pub fn hasOutput(comptime self: @This()) bool { return self.OutputType != void; } - pub fn is_flag(comptime self: @This()) bool { + pub fn isFlag(comptime self: @This()) bool { return comptime switch (self.value_count) { .flag, .count => true, .fixed => false, @@ -185,10 +186,10 @@ fn OptionType(comptime generics: ParameterGenerics) type { return struct { pub const G: ParameterGenerics = generics; pub const param_type: ParameterType = generics.param_type; - pub const is_flag: bool = generics.is_flag(); + pub const is_flag: bool = generics.isFlag(); pub const value_count: ValueCount = generics.value_count; pub const multi: bool = generics.multi; - pub const has_output: bool = generics.has_output(); + pub const has_output: bool = generics.hasOutput(); name: []const u8, short_tag: ?[]const u8, @@ -228,17 +229,17 @@ fn OptionType(comptime generics: ParameterGenerics) type { }; } -fn check_short(comptime short_tag: ?[]const u8) void { +fn checkShort(comptime short_tag: ?[]const u8) void { const short = comptime short_tag orelse return; if (short.len != 2 or short[0] != '-') @compileError("bad short tag: " ++ short); } -fn check_long(comptime long_tag: ?[]const u8) void { +fn checkLong(comptime long_tag: ?[]const u8) void { const long = comptime long_tag orelse return; if (long.len < 3 or long[0] != '-' or long[1] != '-') @compileError("bad long tag: " ++ long); } -pub fn make_option(comptime generics: ParameterGenerics, comptime opts: OptionConfig(generics)) OptionType(generics) { +pub fn makeOption(comptime generics: ParameterGenerics, comptime opts: OptionConfig(generics)) OptionType(generics) { if (opts.short_tag == null and opts.long_tag == null and opts.env_var == null) { @compileError( "option " ++ @@ -247,8 +248,8 @@ pub fn make_option(comptime generics: ParameterGenerics, comptime opts: OptionCo ); } - check_short(opts.short_tag); - check_long(opts.long_tag); + checkShort(opts.short_tag); + checkLong(opts.long_tag); // perform the logic to create the default converter here? Could be done // when creating the OptionConfig instead. Need to do it here because there @@ -257,7 +258,7 @@ pub fn make_option(comptime generics: ParameterGenerics, comptime opts: OptionCo // whereas the OptionType is an instance of an object that has been // validated. const converter = opts.converter orelse - (converters.default_converter(generics) orelse @compileError( + (converters.DefaultConverter(generics) orelse @compileError( "no converter provided for " ++ opts.name ++ "and no default exists", @@ -284,7 +285,7 @@ pub fn make_option(comptime generics: ParameterGenerics, comptime opts: OptionCo }; } -pub fn make_argument( +pub fn makeArgument( comptime generics: ParameterGenerics, comptime opts: OptionConfig(generics), ) OptionType(generics) { @@ -298,7 +299,7 @@ pub fn make_argument( } const converter = opts.converter orelse - (converters.default_converter(generics) orelse @compileError( + (converters.DefaultConverter(generics) orelse @compileError( "no converter provided for " ++ opts.name ++ "and no default exists", diff --git a/source/parser.zig b/source/parser.zig index 345daa3..71c9749 100644 --- a/source/parser.zig +++ b/source/parser.zig @@ -27,13 +27,13 @@ pub const ParserInterface = struct { .parser = parser, .context = context, .methods = &.{ - .execute = ParserType.wrap_execute, - .parse = ParserType.wrap_parse, - .finish = ParserType.wrap_finish, - .getChild = ParserType.wrap_getChild, - .describe = ParserType.describe, - .deinit = ParserType.wrap_deinit, - .deinitTree = ParserType.wrap_deinitTree, + .execute = ParserType._wrapExecute, + .parse = ParserType._wrapParse, + .finish = ParserType._wrapFinish, + .getChild = ParserType._wrapGetChild, + .describe = ParserType._wrapDescribe, + .deinit = ParserType._wrapDeinit, + .deinitTree = ParserType._wrapDeinitTree, }, }; } @@ -67,6 +67,58 @@ pub const ParserInterface = struct { } }; +fn InterfaceWrappers(comptime ParserType: type) type { + return struct { + inline fn castInterfaceParser(parser: *anyopaque) *ParserType { + return @ptrCast(@alignCast(parser)); + } + + fn _wrapExecute(parser: *anyopaque, ctx: *anyopaque) anyerror!void { + const self = castInterfaceParser(parser); + + const context = self.castContext(ctx); + return try self.execute(context); + } + + fn _wrapParse( + parser: *anyopaque, + ctx: *anyopaque, + name: []const u8, + args: [][:0]u8, + env: std.process.EnvMap, + ) anyerror!void { + const self = castInterfaceParser(parser); + const context = self.castContext(ctx); + return try self.subparse(context, name, args, env); + } + + fn _wrapFinish(parser: *anyopaque, ctx: *anyopaque) anyerror!void { + const self = castInterfaceParser(parser); + const context = self.castContext(ctx); + return try self.finish(context); + } + + fn _wrapGetChild(parser: *anyopaque, name: []const u8) ?ParserInterface { + const self = castInterfaceParser(parser); + return self.getChild(name); + } + + fn _wrapDeinit(parser: *anyopaque) void { + const self = castInterfaceParser(parser); + self.deinit(); + } + + fn _wrapDeinitTree(parser: *anyopaque) void { + const self = castInterfaceParser(parser); + self.deinitTree(); + } + + fn _wrapDescribe() []const u8 { + return ParserType.command_description; + } + }; +} + fn InterfaceGen(comptime ParserType: type, comptime UserContext: type) type { const CtxInfo = @typeInfo(UserContext); @@ -75,7 +127,7 @@ fn InterfaceGen(comptime ParserType: type, comptime UserContext: type) type { return ParserInterface.create(ParserType, self, @constCast(&void{})); } - fn cast_context(_: *anyopaque) void { + fn castContext(_: ParserType, _: *anyopaque) void { return void{}; } } else if (CtxInfo == .Pointer and CtxInfo.Pointer.size != .Slice) struct { @@ -83,7 +135,7 @@ fn InterfaceGen(comptime ParserType: type, comptime UserContext: type) type { return ParserInterface.create(ParserType, self, @constCast(context)); } - fn cast_context(ctx: *anyopaque) UserContext { + fn castContext(_: ParserType, ctx: *anyopaque) UserContext { return @ptrCast(@alignCast(ctx)); } } else struct { @@ -91,7 +143,7 @@ fn InterfaceGen(comptime ParserType: type, comptime UserContext: type) type { return ParserInterface.create(ParserType, self, @ptrCast(@constCast(context))); } - fn cast_context(ctx: *anyopaque) UserContext { + fn castContext(_: ParserType, ctx: *anyopaque) UserContext { return @as(*const UserContext, @ptrCast(@alignCast(ctx))).*; } }; @@ -108,6 +160,8 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { const Output = command.Output(); return struct { + const command_description = command.description; + intermediate: Intermediate = .{}, output: Output = undefined, consumed_args: u32 = 0, @@ -119,63 +173,19 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { subcommand: ?ParserInterface = null, help_builder: help.HelpBuilder(command), - pub fn add_subcommand(self: *@This(), verb: []const u8, parser: ParserInterface) !void { + pub fn addSubcommand(self: *@This(), verb: []const u8, parser: ParserInterface) !void { try self.subcommands.put(verb, parser); } // This is a slightly annoying hack to work around the fact that there's no way to // provide a method signature conditionally. - const Interface = InterfaceGen(@This(), UserContext); - pub usingnamespace Interface; - - inline fn cast_interface_parser(parser: *anyopaque) *@This() { - return @ptrCast(@alignCast(parser)); - } - - fn wrap_execute(parser: *anyopaque, ctx: *anyopaque) anyerror!void { - const self = cast_interface_parser(parser); - - // this is a slightly annoying hack to work around the problem that void has - // 0 alignment, which alignCast chokes on. - const context = Interface.cast_context(ctx); - return try self.execute(context); - } - - fn wrap_parse(parser: *anyopaque, ctx: *anyopaque, name: []const u8, args: [][:0]u8, env: std.process.EnvMap) anyerror!void { - const self = cast_interface_parser(parser); - const context = Interface.cast_context(ctx); - return try self.subparse(context, name, args, env); - } - - fn wrap_finish(parser: *anyopaque, ctx: *anyopaque) anyerror!void { - const self = cast_interface_parser(parser); - const context = Interface.cast_context(ctx); - return try self.finish(context); - } - - fn wrap_getChild(parser: *anyopaque, name: []const u8) ?ParserInterface { - const self = cast_interface_parser(parser); - return self.getChild(name); - } - - fn wrap_deinit(parser: *anyopaque) void { - const self = cast_interface_parser(parser); - self.deinit(); - } - - fn wrap_deinitTree(parser: *anyopaque) void { - const self = cast_interface_parser(parser); - self.deinitTree(); - } - - fn describe() []const u8 { - return command.description; - } + pub usingnamespace InterfaceGen(@This(), UserContext); + pub usingnamespace InterfaceWrappers(@This()); pub fn subparse(self: *@This(), context: UserContext, name: []const u8, args: [][:0]u8, env: std.process.EnvMap) anyerror!void { const sliceto = try self.parse(name, args); - try self.read_environment(env); - try self.convert_eager(context); + try self.readEnvironment(env); + try self.convertEager(context); if (self.subcommand) |verb| { const verbname = try std.mem.join( @@ -188,7 +198,7 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { const stderr = std.io.getStdErr().writer(); try stderr.writeAll("A subcommand is required.\n\n"); - self.print_help(name); + self.printHelp(name); } } @@ -227,11 +237,11 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { try self.finish(context); } - fn print_value(self: @This(), value: anytype, comptime indent: []const u8) void { + fn printValue(self: @This(), value: anytype, comptime indent: []const u8) void { if (comptime @hasField(@TypeOf(value), "items")) { std.debug.print("{s}[\n", .{indent}); for (value.items) |item| { - self.print_value(item, indent ++ " "); + self.printValue(item, indent ++ " "); } std.debug.print("{s}]\n", .{indent}); } else { @@ -285,11 +295,11 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { if (!forced_ordinal and arg.len > 1 and arg[0] == '-') { if (arg.len > 2 and arg[1] == '-') { - try self.parse_long_tag(name, arg, &argit); + try self.parseLongTag(name, arg, &argit); continue :argloop; } else if (arg.len > 1) { for (arg[1..], 1..) |short, idx| { - try self.parse_short_tag(name, short, arg.len - idx - 1, &argit); + try self.parseShortTag(name, short, arg.len - idx - 1, &argit); } continue :argloop; } @@ -299,7 +309,7 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { forced_ordinal = true; } - if (try self.parse_ordinals(arg, &argit)) |verb| { + if (try self.parseOrdinals(arg, &argit)) |verb| { self.subcommand = verb; // TODO: return slice of remaining or offset index return argit.index; @@ -309,7 +319,7 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { return 0; } - fn parse_long_tag( + fn parseLongTag( self: *@This(), name: []const u8, arg: []const u8, @@ -317,7 +327,7 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { ) ParseError!void { if (comptime command.help_flag.long_tag) |long| if (std.mem.eql(u8, arg, long)) - self.print_help(name); + self.printHelp(name); inline for (comptime parameters) |param| { const PType = @TypeOf(param); @@ -327,9 +337,9 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { if (std.mem.startsWith(u8, arg, tag)) match: { if (arg.len == tag.len) { - try self.apply_param_values(param, argit, false); + try self.applyParamValues(param, argit, false); } else if (arg[tag.len] == '=') { - try self.apply_fused_values(param, arg[tag.len + 1 ..]); + try self.applyFusedValues(param, arg[tag.len + 1 ..]); } else break :match; return; @@ -339,7 +349,7 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { return ParseError.UnknownLongTagParameter; } - fn parse_short_tag( + fn parseShortTag( self: *@This(), name: []const u8, arg: u8, @@ -348,7 +358,7 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { ) ParseError!void { if (comptime command.help_flag.short_tag) |short| if (arg == short[1]) - self.print_help(name); + self.printHelp(name); inline for (comptime parameters) |param| { const PType = @TypeOf(param); @@ -361,7 +371,7 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { if (remaining > 0) return ParseError.FusedShortTagValueMissing; - try self.apply_param_values(param, argit, false); + try self.applyParamValues(param, argit, false); return; } } @@ -369,7 +379,7 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { return ParseError.UnknownShortTagParameter; } - fn parse_ordinals( + fn parseOrdinals( self: *@This(), arg: []const u8, argit: *ncmeta.SliceIterator([][:0]u8), @@ -381,9 +391,9 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { if (self.consumed_args == arg_index) { argit.rewind(); if (comptime @TypeOf(param).G.multi) { - while (argit.peek()) |_| try self.apply_param_values(param, argit, false); + while (argit.peek()) |_| try self.applyParamValues(param, argit, false); } else { - try self.apply_param_values(param, argit, false); + try self.applyParamValues(param, argit, false); } self.consumed_args += 1; return null; @@ -395,7 +405,7 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { return self.subcommands.get(arg) orelse ParseError.ExtraValue; } - fn push_intermediate_value( + fn pushIntermediateValue( self: *@This(), comptime param: anytype, // @TypeOf(param).G.IntermediateValue() should work but appears to trigger a @@ -416,18 +426,18 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { } } - fn apply_param_values( + fn applyParamValues( self: *@This(), comptime param: anytype, argit: anytype, bounded: bool, ) ParseError!void { switch (comptime @TypeOf(param).G.value_count) { - .flag => try self.push_intermediate_value(param, comptime param.flag_bias.string()), + .flag => try self.pushIntermediateValue(param, comptime param.flag_bias.string()), .count => @field(self.intermediate, param.name) += 1, .fixed => |count| switch (count) { 0 => return ParseError.ExtraValue, - 1 => try self.push_intermediate_value(param, argit.next() orelse return ParseError.MissingValue), + 1 => try self.pushIntermediateValue(param, argit.next() orelse return ParseError.MissingValue), else => |total| { var list = std.ArrayList([]const u8).initCapacity(self.allocator, total) catch return ParseError.UnexpectedFailure; @@ -439,39 +449,39 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { } if (bounded and argit.next() != null) return ParseError.ExtraValue; - try self.push_intermediate_value(param, list); + try self.pushIntermediateValue(param, list); }, }, } } - fn apply_fused_values( + fn applyFusedValues( self: *@This(), comptime param: anytype, value: []const u8, ) ParseError!void { var iter = std.mem.split(u8, value, ","); - return try self.apply_param_values(param, &iter, true); + return try self.applyParamValues(param, &iter, true); } - fn read_environment(self: *@This(), env: std.process.EnvMap) !void { + fn readEnvironment(self: *@This(), env: std.process.EnvMap) !void { inline for (comptime parameters) |param| { if (comptime param.env_var) |env_var| blk: { if (@field(self.intermediate, param.name) != null) break :blk; const val = env.get(env_var) orelse break :blk; if (comptime @TypeOf(param).G.value_count == .flag) { - try self.push_intermediate_value(param, val); + try self.pushIntermediateValue(param, val); } else { - try self.apply_fused_values(param, val); + try self.applyFusedValues(param, val); } } } } - fn convert_eager(self: *@This(), context: UserContext) NoclipError!void { + fn convertEager(self: *@This(), context: UserContext) NoclipError!void { inline for (comptime parameters) |param| { if (comptime param.eager) { - try self.convert_param(param, context); + try self.convertParam(param, context); } } } @@ -479,12 +489,12 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { fn convert(self: *@This(), context: UserContext) NoclipError!void { inline for (comptime parameters) |param| { if (comptime !param.eager) { - try self.convert_param(param, context); + try self.convertParam(param, context); } } } - fn convert_param(self: *@This(), comptime param: anytype, context: UserContext) NoclipError!void { + fn convertParam(self: *@This(), comptime param: anytype, context: UserContext) NoclipError!void { if (@field(self.intermediate, param.name)) |intermediate| { var buffer = std.ArrayList(u8).init(self.allocator); const writer = buffer.writer(); @@ -519,11 +529,11 @@ pub fn Parser(comptime command: anytype, comptime callback: anytype) type { } } - fn print_help(self: *@This(), name: []const u8) noreturn { + fn printHelp(self: *@This(), name: []const u8) noreturn { defer std.process.exit(0); const stderr = std.io.getStdErr().writer(); - if (self.help_builder.build_message(name, self.subcommands)) |message| + if (self.help_builder.buildMessage(name, self.subcommands)) |message| stderr.writeAll(message) catch return else |_| stderr.writeAll("There was a problem generating the help.") catch return;