diff options
| author | 2024-10-22 17:12:50 +0200 | |
|---|---|---|
| committer | 2024-10-22 17:25:39 +0200 | |
| commit | 1e8036c50b3ae32af6998b813b03c3abe599754c (patch) | |
| tree | 6cffa36da3cee28660cb8841d5fed9fe744b0f22 | |
| parent | chore: Correct eval branch quota comment in `countParams` (diff) | |
| download | zig-clap-1e8036c50b3ae32af6998b813b03c3abe599754c.tar.gz zig-clap-1e8036c50b3ae32af6998b813b03c3abe599754c.tar.xz zig-clap-1e8036c50b3ae32af6998b813b03c3abe599754c.zip | |
feat: Add `terminating_positional` to `clap.ParseOptions`
This option makes `clap.parse` and `clap.parseEx` stop parsing after
encountering a certain positional index. Setting
`terminating_positional` to 0 will make them stop parsing after the 0th
positional has been added to `positionals` (aka after parsing 1
positional)
Diffstat (limited to '')
| -rw-r--r-- | clap.zig | 52 |
1 files changed, 49 insertions, 3 deletions
| @@ -646,7 +646,17 @@ test "Diagnostic.report" { | |||
| 646 | pub const ParseOptions = struct { | 646 | pub const ParseOptions = struct { |
| 647 | allocator: mem.Allocator, | 647 | allocator: mem.Allocator, |
| 648 | diagnostic: ?*Diagnostic = null, | 648 | diagnostic: ?*Diagnostic = null, |
| 649 | |||
| 650 | /// The assignment separators, which by default is `=`. This is the separator between the name | ||
| 651 | /// of an argument and its value. For `--arg=value`, `arg` is the name and `value` is the value | ||
| 652 | /// if `=` is one of the assignment separators. | ||
| 649 | assignment_separators: []const u8 = default_assignment_separators, | 653 | assignment_separators: []const u8 = default_assignment_separators, |
| 654 | |||
| 655 | /// This option makes `clap.parse` and `clap.parseEx` stop parsing after encountering a | ||
| 656 | /// certain positional index. Setting `terminating_positional` to 0 will make them stop | ||
| 657 | /// parsing after the 0th positional has been added to `positionals` (aka after parsing 1 | ||
| 658 | /// positional) | ||
| 659 | terminating_positional: usize = std.math.maxInt(usize), | ||
| 650 | }; | 660 | }; |
| 651 | 661 | ||
| 652 | /// Same as `parseEx` but uses the `args.OsIterator` by default. | 662 | /// Same as `parseEx` but uses the `args.OsIterator` by default. |
| @@ -663,10 +673,11 @@ pub fn parse( | |||
| 663 | const exe_arg = iter.next(); | 673 | const exe_arg = iter.next(); |
| 664 | 674 | ||
| 665 | const result = try parseEx(Id, params, value_parsers, &iter, .{ | 675 | const result = try parseEx(Id, params, value_parsers, &iter, .{ |
| 666 | // Let's reuse the arena from the `OSIterator` since we already have it. | 676 | // Let's reuse the arena from the `ArgIterator` since we already have it. |
| 667 | .allocator = arena.allocator(), | 677 | .allocator = arena.allocator(), |
| 668 | .diagnostic = opt.diagnostic, | 678 | .diagnostic = opt.diagnostic, |
| 669 | .assignment_separators = opt.assignment_separators, | 679 | .assignment_separators = opt.assignment_separators, |
| 680 | .terminating_positional = opt.terminating_positional, | ||
| 670 | }); | 681 | }); |
| 671 | 682 | ||
| 672 | return Result(Id, params, value_parsers){ | 683 | return Result(Id, params, value_parsers){ |
| @@ -740,7 +751,7 @@ pub fn parseEx( | |||
| 740 | .diagnostic = opt.diagnostic, | 751 | .diagnostic = opt.diagnostic, |
| 741 | .assignment_separators = opt.assignment_separators, | 752 | .assignment_separators = opt.assignment_separators, |
| 742 | }; | 753 | }; |
| 743 | while (try stream.next()) |arg| { | 754 | arg_loop: while (try stream.next()) |arg| { |
| 744 | inline for (params) |*param| continue_params_loop: { | 755 | inline for (params) |*param| continue_params_loop: { |
| 745 | if (param != arg.param) | 756 | if (param != arg.param) |
| 746 | // This is a trick to emulate a runtime `continue` in an `inline for`. | 757 | // This is a trick to emulate a runtime `continue` in an `inline for`. |
| @@ -762,7 +773,11 @@ pub fn parseEx( | |||
| 762 | try @field(arguments, &name).append(allocator, value); | 773 | try @field(arguments, &name).append(allocator, value); |
| 763 | }, | 774 | }, |
| 764 | }, | 775 | }, |
| 765 | .positional => try positionals.append(try parser(arg.value.?)), | 776 | .positional => { |
| 777 | try positionals.append(try parser(arg.value.?)); | ||
| 778 | if (opt.terminating_positional <= positionals.items.len - 1) | ||
| 779 | break :arg_loop; | ||
| 780 | }, | ||
| 766 | } | 781 | } |
| 767 | } | 782 | } |
| 768 | } | 783 | } |
| @@ -980,6 +995,37 @@ test "everything" { | |||
| 980 | try testing.expectEqual(@as(usize, 1), res.positionals.len); | 995 | try testing.expectEqual(@as(usize, 1), res.positionals.len); |
| 981 | try testing.expectEqualStrings("something", res.positionals[0]); | 996 | try testing.expectEqualStrings("something", res.positionals[0]); |
| 982 | try testing.expectEqualSlices(usize, &.{ 1, 2 }, res.args.dd); | 997 | try testing.expectEqualSlices(usize, &.{ 1, 2 }, res.args.dd); |
| 998 | try testing.expectEqual(@as(usize, 10), iter.index); | ||
| 999 | } | ||
| 1000 | |||
| 1001 | test "terminating positional" { | ||
| 1002 | const params = comptime parseParamsComptime( | ||
| 1003 | \\-a, --aa | ||
| 1004 | \\-b, --bb | ||
| 1005 | \\-c, --cc <str> | ||
| 1006 | \\-d, --dd <usize>... | ||
| 1007 | \\-h | ||
| 1008 | \\<str> | ||
| 1009 | \\ | ||
| 1010 | ); | ||
| 1011 | |||
| 1012 | var iter = args.SliceIterator{ | ||
| 1013 | .args = &.{ "-a", "--aa", "-c", "0", "something", "-d", "1", "--dd", "2", "-h" }, | ||
| 1014 | }; | ||
| 1015 | var res = try parseEx(Help, ¶ms, parsers.default, &iter, .{ | ||
| 1016 | .allocator = testing.allocator, | ||
| 1017 | .terminating_positional = 0, | ||
| 1018 | }); | ||
| 1019 | defer res.deinit(); | ||
| 1020 | |||
| 1021 | try testing.expect(res.args.aa == 2); | ||
| 1022 | try testing.expect(res.args.bb == 0); | ||
| 1023 | try testing.expect(res.args.h == 0); | ||
| 1024 | try testing.expectEqualStrings("0", res.args.cc.?); | ||
| 1025 | try testing.expectEqual(@as(usize, 1), res.positionals.len); | ||
| 1026 | try testing.expectEqualStrings("something", res.positionals[0]); | ||
| 1027 | try testing.expectEqualSlices(usize, &.{}, res.args.dd); | ||
| 1028 | try testing.expectEqual(@as(usize, 5), iter.index); | ||
| 983 | } | 1029 | } |
| 984 | 1030 | ||
| 985 | test "overflow-safe" { | 1031 | test "overflow-safe" { |