summaryrefslogtreecommitdiff
path: root/clap/streaming.zig
diff options
context:
space:
mode:
Diffstat (limited to 'clap/streaming.zig')
-rw-r--r--clap/streaming.zig84
1 files changed, 45 insertions, 39 deletions
diff --git a/clap/streaming.zig b/clap/streaming.zig
index b843bff..90c4e02 100644
--- a/clap/streaming.zig
+++ b/clap/streaming.zig
@@ -24,8 +24,8 @@ pub fn Arg(comptime Id: type) type {
24pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type { 24pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
25 return struct { 25 return struct {
26 const State = union(enum) { 26 const State = union(enum) {
27 Normal, 27 normal,
28 Chaining: Chaining, 28 chaining: Chaining,
29 29
30 const Chaining = struct { 30 const Chaining = struct {
31 arg: []const u8, 31 arg: []const u8,
@@ -35,49 +35,48 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
35 35
36 params: []const clap.Param(Id), 36 params: []const clap.Param(Id),
37 iter: *ArgIterator, 37 iter: *ArgIterator,
38 state: State = State.Normal, 38 state: State = .normal,
39 39
40 /// Get the next ::Arg that matches a ::Param. 40 /// Get the next ::Arg that matches a ::Param.
41 pub fn next(parser: *@This()) !?Arg(Id) { 41 pub fn next(parser: *@This(), diag: ?*clap.Diagnostic) !?Arg(Id) {
42 const ArgInfo = struct { 42 const ArgInfo = struct {
43 const Kind = enum {
44 Long,
45 Short,
46 Positional,
47 };
48
49 arg: []const u8, 43 arg: []const u8,
50 kind: Kind, 44 kind: enum {
45 long,
46 short,
47 positional,
48 },
51 }; 49 };
52 50
53 switch (parser.state) { 51 switch (parser.state) {
54 .Normal => { 52 .normal => {
55 const full_arg = (try parser.iter.next()) orelse return null; 53 const full_arg = (try parser.iter.next()) orelse return null;
56 const arg_info = if (mem.eql(u8, full_arg, "--") or mem.eql(u8, full_arg, "-")) 54 const arg_info = if (mem.eql(u8, full_arg, "--") or mem.eql(u8, full_arg, "-"))
57 ArgInfo{ .arg = full_arg, .kind = .Positional } 55 ArgInfo{ .arg = full_arg, .kind = .positional }
58 else if (mem.startsWith(u8, full_arg, "--")) 56 else if (mem.startsWith(u8, full_arg, "--"))
59 ArgInfo{ .arg = full_arg[2..], .kind = .Long } 57 ArgInfo{ .arg = full_arg[2..], .kind = .long }
60 else if (mem.startsWith(u8, full_arg, "-")) 58 else if (mem.startsWith(u8, full_arg, "-"))
61 ArgInfo{ .arg = full_arg[1..], .kind = .Short } 59 ArgInfo{ .arg = full_arg[1..], .kind = .short }
62 else 60 else
63 ArgInfo{ .arg = full_arg, .kind = .Positional }; 61 ArgInfo{ .arg = full_arg, .kind = .positional };
64 62
65 const arg = arg_info.arg; 63 const arg = arg_info.arg;
66 const kind = arg_info.kind; 64 const kind = arg_info.kind;
67 const eql_index = mem.indexOfScalar(u8, arg, '=');
68 65
69 switch (kind) { 66 switch (kind) {
70 ArgInfo.Kind.Long => { 67 .long => {
68 const eql_index = mem.indexOfScalar(u8, arg, '=');
69 const name = if (eql_index) |i| arg[0..i] else arg;
70 const maybe_value = if (eql_index) |i| arg[i + 1 ..] else null;
71
71 for (parser.params) |*param| { 72 for (parser.params) |*param| {
72 const match = param.names.long orelse continue; 73 const match = param.names.long orelse continue;
73 const name = if (eql_index) |i| arg[0..i] else arg;
74 const maybe_value = if (eql_index) |i| arg[i + 1 ..] else null;
75 74
76 if (!mem.eql(u8, name, match)) 75 if (!mem.eql(u8, name, match))
77 continue; 76 continue;
78 if (param.takes_value == .None) { 77 if (param.takes_value == .None) {
79 if (maybe_value != null) 78 if (maybe_value != null)
80 return error.DoesntTakeValue; 79 return err(diag, param.names, error.DoesntTakeValue);
81 80
82 return Arg(Id){ .param = param }; 81 return Arg(Id){ .param = param };
83 } 82 }
@@ -86,19 +85,18 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
86 if (maybe_value) |v| 85 if (maybe_value) |v|
87 break :blk v; 86 break :blk v;
88 87
89 break :blk (try parser.iter.next()) orelse return error.MissingValue; 88 break :blk (try parser.iter.next()) orelse
89 return err(diag, param.names, error.MissingValue);
90 }; 90 };
91 91
92 return Arg(Id){ .param = param, .value = value }; 92 return Arg(Id){ .param = param, .value = value };
93 } 93 }
94 }, 94 },
95 ArgInfo.Kind.Short => { 95 .short => return try parser.chainging(.{
96 return try parser.chainging(State.Chaining{ 96 .arg = full_arg,
97 .arg = full_arg, 97 .index = full_arg.len - arg.len,
98 .index = (full_arg.len - arg.len), 98 }, diag),
99 }); 99 .positional => {
100 },
101 ArgInfo.Kind.Positional => {
102 for (parser.params) |*param| { 100 for (parser.params) |*param| {
103 if (param.names.long) |_| 101 if (param.names.long) |_|
104 continue; 102 continue;
@@ -110,13 +108,13 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
110 }, 108 },
111 } 109 }
112 110
113 return error.InvalidArgument; 111 return err(diag, .{ .long = arg }, error.InvalidArgument);
114 }, 112 },
115 .Chaining => |state| return try parser.chainging(state), 113 .chaining => |state| return try parser.chainging(state, diag),
116 } 114 }
117 } 115 }
118 116
119 fn chainging(parser: *@This(), state: State.Chaining) !?Arg(Id) { 117 fn chainging(parser: *@This(), state: State.Chaining, diag: ?*clap.Diagnostic) !?Arg(Id) {
120 const arg = state.arg; 118 const arg = state.arg;
121 const index = state.index; 119 const index = state.index;
122 const next_index = index + 1; 120 const next_index = index + 1;
@@ -129,10 +127,10 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
129 // Before we return, we have to set the new state of the clap 127 // Before we return, we have to set the new state of the clap
130 defer { 128 defer {
131 if (arg.len <= next_index or param.takes_value != .None) { 129 if (arg.len <= next_index or param.takes_value != .None) {
132 parser.state = State.Normal; 130 parser.state = .normal;
133 } else { 131 } else {
134 parser.state = State{ 132 parser.state = .{
135 .Chaining = State.Chaining{ 133 .chaining = .{
136 .arg = arg, 134 .arg = arg,
137 .index = next_index, 135 .index = next_index,
138 }, 136 },
@@ -144,7 +142,9 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
144 return Arg(Id){ .param = param }; 142 return Arg(Id){ .param = param };
145 143
146 if (arg.len <= next_index) { 144 if (arg.len <= next_index) {
147 const value = (try parser.iter.next()) orelse return error.MissingValue; 145 const value = (try parser.iter.next()) orelse
146 return err(diag, param.names, error.MissingValue);
147
148 return Arg(Id){ .param = param, .value = value }; 148 return Arg(Id){ .param = param, .value = value };
149 } 149 }
150 150
@@ -154,7 +154,13 @@ pub fn StreamingClap(comptime Id: type, comptime ArgIterator: type) type {
154 return Arg(Id){ .param = param, .value = arg[next_index..] }; 154 return Arg(Id){ .param = param, .value = arg[next_index..] };
155 } 155 }
156 156
157 return error.InvalidArgument; 157 return err(diag, .{ .short = arg[index] }, error.InvalidArgument);
158 }
159
160 fn err(diag: ?*clap.Diagnostic, names: clap.Names, _err: var) @TypeOf(_err) {
161 if (diag) |d|
162 d.name = names;
163 return _err;
158 } 164 }
159 }; 165 };
160} 166}
@@ -167,7 +173,7 @@ fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, r
167 }; 173 };
168 174
169 for (results) |res| { 175 for (results) |res| {
170 const arg = (c.next() catch unreachable) orelse unreachable; 176 const arg = (c.next(null) catch unreachable) orelse unreachable;
171 testing.expectEqual(res.param, arg.param); 177 testing.expectEqual(res.param, arg.param);
172 const expected_value = res.value orelse { 178 const expected_value = res.value orelse {
173 testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value); 179 testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value);
@@ -177,7 +183,7 @@ fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, r
177 testing.expectEqualSlices(u8, expected_value, actual_value); 183 testing.expectEqualSlices(u8, expected_value, actual_value);
178 } 184 }
179 185
180 if (c.next() catch unreachable) |_| 186 if (c.next(null) catch unreachable) |_|
181 unreachable; 187 unreachable;
182} 188}
183 189