summaryrefslogtreecommitdiff
path: root/clap.zig
diff options
context:
space:
mode:
Diffstat (limited to 'clap.zig')
-rw-r--r--clap.zig52
1 files changed, 49 insertions, 3 deletions
diff --git a/clap.zig b/clap.zig
index 44d6d44..f7eb5d0 100644
--- a/clap.zig
+++ b/clap.zig
@@ -646,7 +646,17 @@ test "Diagnostic.report" {
646pub const ParseOptions = struct { 646pub 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
1001test "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, &params, 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
985test "overflow-safe" { 1031test "overflow-safe" {