diff options
| author | 2024-10-24 15:36:55 +0200 | |
|---|---|---|
| committer | 2024-10-24 16:35:47 +0200 | |
| commit | 4e293092fc56ebf46d9c17e4e203ca54c63a0b09 (patch) | |
| tree | fc400c62cb7f96f0cc475162c7084dadb1f3b029 | |
| parent | refactor: positonals type now depend on the number of values taken (diff) | |
| download | zig-clap-4e293092fc56ebf46d9c17e4e203ca54c63a0b09.tar.gz zig-clap-4e293092fc56ebf46d9c17e4e203ca54c63a0b09.tar.xz zig-clap-4e293092fc56ebf46d9c17e4e203ca54c63a0b09.zip | |
feat: Support multiple positionals of different types
Diffstat (limited to '')
| -rw-r--r-- | README.md | 10 | ||||
| -rw-r--r-- | clap.zig | 250 | ||||
| -rw-r--r-- | example/README.md.template | 6 | ||||
| -rw-r--r-- | example/simple-ex.zig | 2 | ||||
| -rw-r--r-- | example/simple.zig | 2 |
5 files changed, 192 insertions, 78 deletions
| @@ -90,7 +90,7 @@ pub fn main() !void { | |||
| 90 | std.debug.print("--number = {}\n", .{n}); | 90 | std.debug.print("--number = {}\n", .{n}); |
| 91 | for (res.args.string) |s| | 91 | for (res.args.string) |s| |
| 92 | std.debug.print("--string = {s}\n", .{s}); | 92 | std.debug.print("--string = {s}\n", .{s}); |
| 93 | for (res.positionals) |pos| | 93 | for (res.positionals[0]) |pos| |
| 94 | std.debug.print("{s}\n", .{pos}); | 94 | std.debug.print("{s}\n", .{pos}); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| @@ -101,10 +101,10 @@ const std = @import("std"); | |||
| 101 | 101 | ||
| 102 | The result will contain an `args` field and a `positionals` field. `args` will have one field | 102 | The result will contain an `args` field and a `positionals` field. `args` will have one field |
| 103 | for each none positional parameter of your program. The name of the field will be the longest | 103 | for each none positional parameter of your program. The name of the field will be the longest |
| 104 | name of the parameter. | 104 | name of the parameter. `positionals` be a tuple with one field for each positional parameter. |
| 105 | 105 | ||
| 106 | The fields in `args` are typed. The type is based on the name of the value the parameter takes. | 106 | The fields in `args` and `psotionals` are typed. The type is based on the name of the value the |
| 107 | Since `--number` takes a `usize` the field `res.args.number` has the type `usize`. | 107 | parameter takes. Since `--number` takes a `usize` the field `res.args.number` has the type `usize`. |
| 108 | 108 | ||
| 109 | Note that this is only the case because `clap.parsers.default` has a field called `usize` which | 109 | Note that this is only the case because `clap.parsers.default` has a field called `usize` which |
| 110 | contains a parser that returns `usize`. You can pass in something other than | 110 | contains a parser that returns `usize`. You can pass in something other than |
| @@ -157,7 +157,7 @@ pub fn main() !void { | |||
| 157 | std.debug.print("--answer = {s}\n", .{@tagName(a)}); | 157 | std.debug.print("--answer = {s}\n", .{@tagName(a)}); |
| 158 | for (res.args.string) |s| | 158 | for (res.args.string) |s| |
| 159 | std.debug.print("--string = {s}\n", .{s}); | 159 | std.debug.print("--string = {s}\n", .{s}); |
| 160 | for (res.positionals) |pos| | 160 | for (res.positionals[0]) |pos| |
| 161 | std.debug.print("{s}\n", .{pos}); | 161 | std.debug.print("{s}\n", .{pos}); |
| 162 | } | 162 | } |
| 163 | 163 | ||
| @@ -709,6 +709,30 @@ pub fn Result( | |||
| 709 | /// `T` can be any type and `Error` can be any error. You can pass `clap.parsers.default` if you | 709 | /// `T` can be any type and `Error` can be any error. You can pass `clap.parsers.default` if you |
| 710 | /// just wonna get something up and running. | 710 | /// just wonna get something up and running. |
| 711 | /// | 711 | /// |
| 712 | /// The result will also contain a `positionals` field which contains all positional arguments | ||
| 713 | /// passed. This field will be a tuple with one field for each positional parameter. | ||
| 714 | /// | ||
| 715 | /// Example: | ||
| 716 | /// -h, --help | ||
| 717 | /// -s, --str <str> | ||
| 718 | /// -i, --int <usize> | ||
| 719 | /// -m, --many <usize>... | ||
| 720 | /// <u8> | ||
| 721 | /// <str>... | ||
| 722 | /// | ||
| 723 | /// struct { | ||
| 724 | /// args: struct { | ||
| 725 | /// help: u8, | ||
| 726 | /// str: ?[]const u8, | ||
| 727 | /// int: ?usize, | ||
| 728 | /// many: []const usize, | ||
| 729 | /// }, | ||
| 730 | /// positionals: struct { | ||
| 731 | /// ?u8, | ||
| 732 | /// []const []const u8, | ||
| 733 | /// }, | ||
| 734 | /// } | ||
| 735 | /// | ||
| 712 | /// Caller owns the result and should free it by calling `result.deinit()` | 736 | /// Caller owns the result and should free it by calling `result.deinit()` |
| 713 | pub fn parseEx( | 737 | pub fn parseEx( |
| 714 | comptime Id: type, | 738 | comptime Id: type, |
| @@ -720,7 +744,7 @@ pub fn parseEx( | |||
| 720 | const allocator = opt.allocator; | 744 | const allocator = opt.allocator; |
| 721 | 745 | ||
| 722 | var positional_count: usize = 0; | 746 | var positional_count: usize = 0; |
| 723 | var positionals = initPositionals(Positionals(Id, params, value_parsers, .list)); | 747 | var positionals = Positionals(Id, params, value_parsers, .list){}; |
| 724 | errdefer deinitPositionals(&positionals, allocator); | 748 | errdefer deinitPositionals(&positionals, allocator); |
| 725 | 749 | ||
| 726 | var arguments = Arguments(Id, params, value_parsers, .list){}; | 750 | var arguments = Arguments(Id, params, value_parsers, .list){}; |
| @@ -733,7 +757,13 @@ pub fn parseEx( | |||
| 733 | .assignment_separators = opt.assignment_separators, | 757 | .assignment_separators = opt.assignment_separators, |
| 734 | }; | 758 | }; |
| 735 | arg_loop: while (try stream.next()) |arg| { | 759 | arg_loop: while (try stream.next()) |arg| { |
| 760 | // This loop checks if we got a short or long parameter. If so, the value is parsed and | ||
| 761 | // stored in `arguments` | ||
| 736 | inline for (params) |*param| continue_params_loop: { | 762 | inline for (params) |*param| continue_params_loop: { |
| 763 | const longest = comptime param.names.longest(); | ||
| 764 | if (longest.kind == .positional) | ||
| 765 | continue; | ||
| 766 | |||
| 737 | if (param != arg.param) | 767 | if (param != arg.param) |
| 738 | // This is a trick to emulate a runtime `continue` in an `inline for`. | 768 | // This is a trick to emulate a runtime `continue` in an `inline for`. |
| 739 | break :continue_params_loop; | 769 | break :continue_params_loop; |
| @@ -743,50 +773,75 @@ pub fn parseEx( | |||
| 743 | .one, .many => @field(value_parsers, param.id.value()), | 773 | .one, .many => @field(value_parsers, param.id.value()), |
| 744 | }; | 774 | }; |
| 745 | 775 | ||
| 746 | const longest = comptime param.names.longest(); | ||
| 747 | const name = longest.name[0..longest.name.len].*; | 776 | const name = longest.name[0..longest.name.len].*; |
| 748 | switch (longest.kind) { | 777 | switch (param.takes_value) { |
| 749 | .short, .long => switch (param.takes_value) { | 778 | .none => @field(arguments, &name) +|= 1, |
| 750 | .none => @field(arguments, &name) +|= 1, | 779 | .one => @field(arguments, &name) = try parser(arg.value.?), |
| 751 | .one => @field(arguments, &name) = try parser(arg.value.?), | 780 | .many => { |
| 752 | .many => { | 781 | const value = try parser(arg.value.?); |
| 753 | const value = try parser(arg.value.?); | 782 | try @field(arguments, &name).append(allocator, value); |
| 754 | try @field(arguments, &name).append(allocator, value); | ||
| 755 | }, | ||
| 756 | }, | ||
| 757 | .positional => { | ||
| 758 | switch (@typeInfo(@TypeOf(positionals))) { | ||
| 759 | .optional => positionals = try parser(arg.value.?), | ||
| 760 | else => try positionals.append(allocator, try parser(arg.value.?)), | ||
| 761 | } | ||
| 762 | if (opt.terminating_positional <= positional_count) | ||
| 763 | break :arg_loop; | ||
| 764 | |||
| 765 | positional_count += 1; | ||
| 766 | }, | 783 | }, |
| 767 | } | 784 | } |
| 768 | } | 785 | } |
| 786 | |||
| 787 | // This loop checks if we got a positional parameter. If so, the value is parsed and | ||
| 788 | // stored in `positionals` | ||
| 789 | comptime var positionals_index = 0; | ||
| 790 | inline for (params) |*param| continue_params_loop: { | ||
| 791 | const longest = comptime param.names.longest(); | ||
| 792 | if (longest.kind != .positional) | ||
| 793 | continue; | ||
| 794 | |||
| 795 | const i = positionals_index; | ||
| 796 | positionals_index += 1; | ||
| 797 | |||
| 798 | if (stream.positional != arg.param) | ||
| 799 | // This is a trick to emulate a runtime `continue` in an `inline for`. | ||
| 800 | break :continue_params_loop; | ||
| 801 | |||
| 802 | const parser = comptime switch (param.takes_value) { | ||
| 803 | .none => null, | ||
| 804 | .one, .many => @field(value_parsers, param.id.value()), | ||
| 805 | }; | ||
| 806 | |||
| 807 | // We keep track of how many positionals we have received. This is used to pick which | ||
| 808 | // `positional` field to store to. Once `positional_count` exceeds the number of | ||
| 809 | // positional parameters, the rest are stored in the last `positional` field. | ||
| 810 | const pos = &positionals[i]; | ||
| 811 | const last = positionals.len == i + 1; | ||
| 812 | if ((last and positional_count >= i) or positional_count == i) | ||
| 813 | switch (@typeInfo(@TypeOf(pos.*))) { | ||
| 814 | .optional => pos.* = try parser(arg.value.?), | ||
| 815 | else => try pos.append(allocator, try parser(arg.value.?)), | ||
| 816 | }; | ||
| 817 | |||
| 818 | if (opt.terminating_positional <= positional_count) | ||
| 819 | break :arg_loop; | ||
| 820 | positional_count += 1; | ||
| 821 | } | ||
| 769 | } | 822 | } |
| 770 | 823 | ||
| 771 | // We are done parsing, but our arguments are stored in lists, and not slices. Map the list | 824 | // We are done parsing, but our arguments are stored in lists, and not slices. Map the list |
| 772 | // fields to slices and return that. | 825 | // fields to slices and return that. |
| 773 | var result_args = Arguments(Id, params, value_parsers, .slice){}; | 826 | var result_args = Arguments(Id, params, value_parsers, .slice){}; |
| 774 | inline for (std.meta.fields(@TypeOf(arguments))) |field| { | 827 | inline for (std.meta.fields(@TypeOf(arguments))) |field| { |
| 775 | if (@typeInfo(field.type) == .@"struct" and | 828 | switch (@typeInfo(field.type)) { |
| 776 | @hasDecl(field.type, "toOwnedSlice")) | 829 | .@"struct" => { |
| 777 | { | 830 | const slice = try @field(arguments, field.name).toOwnedSlice(allocator); |
| 778 | const slice = try @field(arguments, field.name).toOwnedSlice(allocator); | 831 | @field(result_args, field.name) = slice; |
| 779 | @field(result_args, field.name) = slice; | 832 | }, |
| 780 | } else { | 833 | else => @field(result_args, field.name) = @field(arguments, field.name), |
| 781 | @field(result_args, field.name) = @field(arguments, field.name); | ||
| 782 | } | 834 | } |
| 783 | } | 835 | } |
| 784 | 836 | ||
| 785 | // We are done parsing, but our positionals are stored in lists, and not slices. | 837 | // We are done parsing, but our positionals are stored in lists, and not slices. |
| 786 | const result_positionals = switch (@typeInfo(@TypeOf(positionals))) { | 838 | var result_positionals = Positionals(Id, params, value_parsers, .slice){}; |
| 787 | .optional => positionals, | 839 | inline for (&result_positionals, &positionals) |*res_pos, *pos| { |
| 788 | else => try positionals.toOwnedSlice(allocator), | 840 | switch (@typeInfo(@TypeOf(pos.*))) { |
| 789 | }; | 841 | .@"struct" => res_pos.* = try pos.toOwnedSlice(allocator), |
| 842 | else => res_pos.* = pos.*, | ||
| 843 | } | ||
| 844 | } | ||
| 790 | 845 | ||
| 791 | return ResultEx(Id, params, value_parsers){ | 846 | return ResultEx(Id, params, value_parsers){ |
| 792 | .args = result_args, | 847 | .args = result_args, |
| @@ -813,55 +868,72 @@ pub fn ResultEx( | |||
| 813 | }; | 868 | }; |
| 814 | } | 869 | } |
| 815 | 870 | ||
| 871 | /// Turn a list of parameters into a tuple with one field for each positional parameter. | ||
| 872 | /// The type of each parameter field is determined by `ParamType`. | ||
| 816 | fn Positionals( | 873 | fn Positionals( |
| 817 | comptime Id: type, | 874 | comptime Id: type, |
| 818 | comptime params: []const Param(Id), | 875 | comptime params: []const Param(Id), |
| 819 | comptime value_parsers: anytype, | 876 | comptime value_parsers: anytype, |
| 820 | comptime multi_arg_kind: MultiArgKind, | 877 | comptime multi_arg_kind: MultiArgKind, |
| 821 | ) type { | 878 | ) type { |
| 822 | const pos = findPositional(Id, params) orelse return ?void; | 879 | var fields_len: usize = 0; |
| 823 | const T = ParamType(Id, pos, value_parsers); | 880 | for (params) |param| { |
| 824 | if (pos.takes_value == .many) | 881 | const longest = param.names.longest(); |
| 825 | return switch (multi_arg_kind) { | 882 | if (longest.kind != .positional) |
| 826 | .slice => []const T, | 883 | continue; |
| 827 | .list => std.ArrayListUnmanaged(T), | 884 | fields_len += 1; |
| 828 | }; | 885 | } |
| 829 | 886 | ||
| 830 | return ?T; | 887 | var fields: [fields_len]std.builtin.Type.StructField = undefined; |
| 831 | } | 888 | var i: usize = 0; |
| 889 | for (params) |param| { | ||
| 890 | const longest = param.names.longest(); | ||
| 891 | if (longest.kind != .positional) | ||
| 892 | continue; | ||
| 832 | 893 | ||
| 833 | fn initPositionals(comptime T: type) T { | 894 | const T = ParamType(Id, param, value_parsers); |
| 834 | return switch (@typeInfo(T)) { | 895 | const default_value = switch (param.takes_value) { |
| 835 | .optional => null, | 896 | .none => continue, |
| 836 | else => .{}, | 897 | .one => @as(?T, null), |
| 837 | }; | 898 | .many => switch (multi_arg_kind) { |
| 838 | } | 899 | .slice => @as([]const T, &[_]T{}), |
| 900 | .list => std.ArrayListUnmanaged(T){}, | ||
| 901 | }, | ||
| 902 | }; | ||
| 839 | 903 | ||
| 840 | fn deinitPositionals(positionals: anytype, allocator: std.mem.Allocator) void { | 904 | fields[i] = .{ |
| 841 | switch (@typeInfo(@TypeOf(positionals.*))) { | 905 | .name = std.fmt.comptimePrint("{}", .{i}), |
| 842 | .optional => {}, | 906 | .type = @TypeOf(default_value), |
| 843 | .@"struct" => positionals.deinit(allocator), | 907 | .default_value = @ptrCast(&default_value), |
| 844 | else => allocator.free(positionals.*), | 908 | .is_comptime = false, |
| 909 | .alignment = @alignOf(@TypeOf(default_value)), | ||
| 910 | }; | ||
| 911 | i += 1; | ||
| 845 | } | 912 | } |
| 913 | |||
| 914 | return @Type(.{ .@"struct" = .{ | ||
| 915 | .layout = .auto, | ||
| 916 | .fields = &fields, | ||
| 917 | .decls = &.{}, | ||
| 918 | .is_tuple = true, | ||
| 919 | } }); | ||
| 846 | } | 920 | } |
| 847 | 921 | ||
| 848 | fn findPositional(comptime Id: type, params: []const Param(Id)) ?Param(Id) { | 922 | /// Deinitializes a tuple of type `Positionals`. Since the `Positionals` type is generated, and we |
| 849 | for (params) |param| { | 923 | /// cannot add the deinit declaration to it, we declare it here instead. |
| 850 | const longest = param.names.longest(); | 924 | fn deinitPositionals(positionals: anytype, allocator: std.mem.Allocator) void { |
| 851 | if (longest.kind == .positional) | 925 | inline for (positionals) |*pos| { |
| 852 | return param; | 926 | switch (@typeInfo(@TypeOf(pos.*))) { |
| 927 | .optional => {}, | ||
| 928 | .@"struct" => pos.deinit(allocator), | ||
| 929 | else => allocator.free(pos.*), | ||
| 930 | } | ||
| 853 | } | 931 | } |
| 854 | |||
| 855 | return null; | ||
| 856 | } | 932 | } |
| 857 | 933 | ||
| 858 | /// Given a parameter figure out which type that parameter is parsed into when using the correct | 934 | /// Given a parameter figure out which type that parameter is parsed into when using the correct |
| 859 | /// parser from `value_parsers`. | 935 | /// parser from `value_parsers`. |
| 860 | fn ParamType( | 936 | fn ParamType(comptime Id: type, comptime param: Param(Id), comptime value_parsers: anytype) type { |
| 861 | comptime Id: type, | ||
| 862 | comptime param: Param(Id), | ||
| 863 | comptime value_parsers: anytype, | ||
| 864 | ) type { | ||
| 865 | const parser = switch (param.takes_value) { | 937 | const parser = switch (param.takes_value) { |
| 866 | .none => parsers.string, | 938 | .none => parsers.string, |
| 867 | .one, .many => @field(value_parsers, param.id.value()), | 939 | .one, .many => @field(value_parsers, param.id.value()), |
| @@ -983,7 +1055,7 @@ test "single positional" { | |||
| 983 | }); | 1055 | }); |
| 984 | defer res.deinit(); | 1056 | defer res.deinit(); |
| 985 | 1057 | ||
| 986 | try std.testing.expect(res.positionals == null); | 1058 | try std.testing.expect(res.positionals[0] == null); |
| 987 | } | 1059 | } |
| 988 | 1060 | ||
| 989 | { | 1061 | { |
| @@ -993,7 +1065,7 @@ test "single positional" { | |||
| 993 | }); | 1065 | }); |
| 994 | defer res.deinit(); | 1066 | defer res.deinit(); |
| 995 | 1067 | ||
| 996 | try std.testing.expectEqualStrings("a", res.positionals.?); | 1068 | try std.testing.expectEqualStrings("a", res.positionals[0].?); |
| 997 | } | 1069 | } |
| 998 | 1070 | ||
| 999 | { | 1071 | { |
| @@ -1003,7 +1075,48 @@ test "single positional" { | |||
| 1003 | }); | 1075 | }); |
| 1004 | defer res.deinit(); | 1076 | defer res.deinit(); |
| 1005 | 1077 | ||
| 1006 | try std.testing.expectEqualStrings("b", res.positionals.?); | 1078 | try std.testing.expectEqualStrings("b", res.positionals[0].?); |
| 1079 | } | ||
| 1080 | } | ||
| 1081 | |||
| 1082 | test "multiple positionals" { | ||
| 1083 | const params = comptime parseParamsComptime( | ||
| 1084 | \\<u8> | ||
| 1085 | \\<str> | ||
| 1086 | \\ | ||
| 1087 | ); | ||
| 1088 | |||
| 1089 | // { | ||
| 1090 | // var iter = args.SliceIterator{ .args = &.{} }; | ||
| 1091 | // var res = try parseEx(Help, ¶ms, parsers.default, &iter, .{ | ||
| 1092 | // .allocator = std.testing.allocator, | ||
| 1093 | // }); | ||
| 1094 | // defer res.deinit(); | ||
| 1095 | |||
| 1096 | // try std.testing.expect(res.positionals[0] == null); | ||
| 1097 | // try std.testing.expect(res.positionals[1] == null); | ||
| 1098 | // } | ||
| 1099 | |||
| 1100 | // { | ||
| 1101 | // var iter = args.SliceIterator{ .args = &.{"1"} }; | ||
| 1102 | // var res = try parseEx(Help, ¶ms, parsers.default, &iter, .{ | ||
| 1103 | // .allocator = std.testing.allocator, | ||
| 1104 | // }); | ||
| 1105 | // defer res.deinit(); | ||
| 1106 | |||
| 1107 | // try std.testing.expectEqual(@as(u8, 1), res.positionals[0].?); | ||
| 1108 | // try std.testing.expect(res.positionals[1] == null); | ||
| 1109 | // } | ||
| 1110 | |||
| 1111 | { | ||
| 1112 | var iter = args.SliceIterator{ .args = &.{ "1", "b" } }; | ||
| 1113 | var res = try parseEx(Help, ¶ms, parsers.default, &iter, .{ | ||
| 1114 | .allocator = std.testing.allocator, | ||
| 1115 | }); | ||
| 1116 | defer res.deinit(); | ||
| 1117 | |||
| 1118 | try std.testing.expectEqual(@as(u8, 1), res.positionals[0].?); | ||
| 1119 | try std.testing.expectEqualStrings("b", res.positionals[1].?); | ||
| 1007 | } | 1120 | } |
| 1008 | } | 1121 | } |
| 1009 | 1122 | ||
| @@ -1031,7 +1144,7 @@ test "everything" { | |||
| 1031 | try std.testing.expect(res.args.h == 1); | 1144 | try std.testing.expect(res.args.h == 1); |
| 1032 | try std.testing.expectEqualStrings("0", res.args.cc.?); | 1145 | try std.testing.expectEqualStrings("0", res.args.cc.?); |
| 1033 | try std.testing.expectEqual(@as(usize, 1), res.positionals.len); | 1146 | try std.testing.expectEqual(@as(usize, 1), res.positionals.len); |
| 1034 | try std.testing.expectEqualStrings("something", res.positionals[0]); | 1147 | try std.testing.expectEqualStrings("something", res.positionals[0][0]); |
| 1035 | try std.testing.expectEqualSlices(usize, &.{ 1, 2 }, res.args.dd); | 1148 | try std.testing.expectEqualSlices(usize, &.{ 1, 2 }, res.args.dd); |
| 1036 | try std.testing.expectEqual(@as(usize, 10), iter.index); | 1149 | try std.testing.expectEqual(@as(usize, 10), iter.index); |
| 1037 | } | 1150 | } |
| @@ -1061,7 +1174,8 @@ test "terminating positional" { | |||
| 1061 | try std.testing.expect(res.args.h == 0); | 1174 | try std.testing.expect(res.args.h == 0); |
| 1062 | try std.testing.expectEqualStrings("0", res.args.cc.?); | 1175 | try std.testing.expectEqualStrings("0", res.args.cc.?); |
| 1063 | try std.testing.expectEqual(@as(usize, 1), res.positionals.len); | 1176 | try std.testing.expectEqual(@as(usize, 1), res.positionals.len); |
| 1064 | try std.testing.expectEqualStrings("something", res.positionals[0]); | 1177 | try std.testing.expectEqual(@as(usize, 1), res.positionals[0].len); |
| 1178 | try std.testing.expectEqualStrings("something", res.positionals[0][0]); | ||
| 1065 | try std.testing.expectEqualSlices(usize, &.{}, res.args.dd); | 1179 | try std.testing.expectEqualSlices(usize, &.{}, res.args.dd); |
| 1066 | try std.testing.expectEqual(@as(usize, 5), iter.index); | 1180 | try std.testing.expectEqual(@as(usize, 5), iter.index); |
| 1067 | } | 1181 | } |
diff --git a/example/README.md.template b/example/README.md.template index dda0cc9..d234dcd 100644 --- a/example/README.md.template +++ b/example/README.md.template | |||
| @@ -61,10 +61,10 @@ The simplest way to use this library is to just call the `clap.parse` function. | |||
| 61 | 61 | ||
| 62 | The result will contain an `args` field and a `positionals` field. `args` will have one field | 62 | The result will contain an `args` field and a `positionals` field. `args` will have one field |
| 63 | for each none positional parameter of your program. The name of the field will be the longest | 63 | for each none positional parameter of your program. The name of the field will be the longest |
| 64 | name of the parameter. | 64 | name of the parameter. `positionals` be a tuple with one field for each positional parameter. |
| 65 | 65 | ||
| 66 | The fields in `args` are typed. The type is based on the name of the value the parameter takes. | 66 | The fields in `args` and `psotionals` are typed. The type is based on the name of the value the |
| 67 | Since `--number` takes a `usize` the field `res.args.number` has the type `usize`. | 67 | parameter takes. Since `--number` takes a `usize` the field `res.args.number` has the type `usize`. |
| 68 | 68 | ||
| 69 | Note that this is only the case because `clap.parsers.default` has a field called `usize` which | 69 | Note that this is only the case because `clap.parsers.default` has a field called `usize` which |
| 70 | contains a parser that returns `usize`. You can pass in something other than | 70 | contains a parser that returns `usize`. You can pass in something other than |
diff --git a/example/simple-ex.zig b/example/simple-ex.zig index 4ca9791..154e486 100644 --- a/example/simple-ex.zig +++ b/example/simple-ex.zig | |||
| @@ -44,7 +44,7 @@ pub fn main() !void { | |||
| 44 | std.debug.print("--answer = {s}\n", .{@tagName(a)}); | 44 | std.debug.print("--answer = {s}\n", .{@tagName(a)}); |
| 45 | for (res.args.string) |s| | 45 | for (res.args.string) |s| |
| 46 | std.debug.print("--string = {s}\n", .{s}); | 46 | std.debug.print("--string = {s}\n", .{s}); |
| 47 | for (res.positionals) |pos| | 47 | for (res.positionals[0]) |pos| |
| 48 | std.debug.print("{s}\n", .{pos}); | 48 | std.debug.print("{s}\n", .{pos}); |
| 49 | } | 49 | } |
| 50 | 50 | ||
diff --git a/example/simple.zig b/example/simple.zig index 7f1bfc0..74157a6 100644 --- a/example/simple.zig +++ b/example/simple.zig | |||
| @@ -32,7 +32,7 @@ pub fn main() !void { | |||
| 32 | std.debug.print("--number = {}\n", .{n}); | 32 | std.debug.print("--number = {}\n", .{n}); |
| 33 | for (res.args.string) |s| | 33 | for (res.args.string) |s| |
| 34 | std.debug.print("--string = {s}\n", .{s}); | 34 | std.debug.print("--string = {s}\n", .{s}); |
| 35 | for (res.positionals) |pos| | 35 | for (res.positionals[0]) |pos| |
| 36 | std.debug.print("{s}\n", .{pos}); | 36 | std.debug.print("{s}\n", .{pos}); |
| 37 | } | 37 | } |
| 38 | 38 | ||