summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jimmi Holst Christensen2018-03-20 10:40:43 +0100
committerGravatar Jimmi Holst Christensen2018-03-20 10:40:43 +0100
commitc362215f7433950152d56fc0f28929c72701128b (patch)
tree3b7cabe20bc956dab12ae8cba0de2caab9b16785
parentUpdated help function to not use inline loop. (diff)
downloadzig-clap-c362215f7433950152d56fc0f28929c72701128b.tar.gz
zig-clap-c362215f7433950152d56fc0f28929c72701128b.tar.xz
zig-clap-c362215f7433950152d56fc0f28929c72701128b.zip
We now handle arguments "--arg=VALUE"
Diffstat (limited to '')
-rw-r--r--clap.zig69
1 files changed, 48 insertions, 21 deletions
diff --git a/clap.zig b/clap.zig
index 410a65f..2c78e95 100644
--- a/clap.zig
+++ b/clap.zig
@@ -11,7 +11,6 @@ const assert = debug.assert;
11// TODO: Missing a few convinient features 11// TODO: Missing a few convinient features
12// * Short arguments that doesn't take values should probably be able to be 12// * Short arguments that doesn't take values should probably be able to be
13// chain like many linux programs: "rm -rf" 13// chain like many linux programs: "rm -rf"
14// * Handle "--something=VALUE"
15pub fn Option(comptime Result: type, comptime ParseError: type) type { 14pub fn Option(comptime Result: type, comptime ParseError: type) type {
16 return struct { 15 return struct {
17 const Self = this; 16 const Self = this;
@@ -75,7 +74,20 @@ pub fn Parser(comptime Result: type, comptime ParseError: type, comptime default
75 const Kind = enum { Long, Short, None }; 74 const Kind = enum { Long, Short, None };
76 75
77 arg: []const u8, 76 arg: []const u8,
78 kind: Kind 77 kind: Kind,
78 after_eql: ?[]const u8,
79 };
80
81 const Iterator = struct {
82 slice: []const []const u8,
83
84 pub fn next(it: &this) ?[]const u8 {
85 if (it.slice.len == 0)
86 return null;
87
88 defer it.slice = it.slice[1..];
89 return it.slice[0];
90 }
79 }; 91 };
80 92
81 // NOTE: For now, a bitfield is used to keep track of the required arguments. 93 // NOTE: For now, a bitfield is used to keep track of the required arguments.
@@ -109,19 +121,33 @@ pub fn Parser(comptime Result: type, comptime ParseError: type, comptime default
109 var result = *defaults; 121 var result = *defaults;
110 var required = required_mask; 122 var required = required_mask;
111 123
112 var arg_i = usize(0); 124 var it = Iterator { .slice = args };
113 while (arg_i < args.len) : (arg_i += 1) { 125 while (it.next()) |item| {
114 const pair = blk: { 126 const arg_info = blk: {
115 const tmp = args[arg_i]; 127 var arg = item;
116 if (mem.startsWith(u8, tmp, "--")) 128 var kind = Arg.Kind.None;
117 break :blk Arg { .arg = tmp[2..], .kind = Arg.Kind.Long }; 129
118 if (mem.startsWith(u8, tmp, "-")) 130 if (mem.startsWith(u8, arg, "--")) {
119 break :blk Arg { .arg = tmp[1..], .kind = Arg.Kind.Short }; 131 arg = arg[2..];
132 kind = Arg.Kind.Long;
133 } else if (mem.startsWith(u8, arg, "-")) {
134 arg = arg[1..];
135 kind = Arg.Kind.Short;
136 }
137
138 if (kind == Arg.Kind.None)
139 break :blk Arg { .arg = arg, .kind = kind, .after_eql = null };
120 140
121 break :blk Arg { .arg = tmp, .kind = Arg.Kind.None }; 141
142 if (mem.indexOfScalar(u8, arg, '=')) |index| {
143 break :blk Arg { .arg = arg[0..index], .kind = kind, .after_eql = arg[index + 1..] };
144 } else {
145 break :blk Arg { .arg = arg, .kind = kind, .after_eql = null };
146 }
122 }; 147 };
123 const arg = pair.arg; 148 const arg = arg_info.arg;
124 const kind = pair.kind; 149 const kind = arg_info.kind;
150 const after_eql = arg_info.after_eql;
125 151
126 success: { 152 success: {
127 var required_index = usize(0); 153 var required_index = usize(0);
@@ -144,10 +170,8 @@ pub fn Parser(comptime Result: type, comptime ParseError: type, comptime default
144 const short = option.short ?? continue; 170 const short = option.short ?? continue;
145 if (arg.len == 1 and arg[0] == short) { 171 if (arg.len == 1 and arg[0] == short) {
146 if (option.takes_value) { 172 if (option.takes_value) {
147 arg_i += 1; 173 const value = after_eql ?? it.next() ?? return error.OptionMissingValue;
148 if (args.len <= arg_i) return error.OptionMissingValue; 174 try option.parse(&result, value);
149
150 try option.parse(&result, args[arg_i]);
151 } else { 175 } else {
152 try option.parse(&result, []u8{}); 176 try option.parse(&result, []u8{});
153 } 177 }
@@ -163,10 +187,8 @@ pub fn Parser(comptime Result: type, comptime ParseError: type, comptime default
163 const long = option.long ?? continue; 187 const long = option.long ?? continue;
164 if (mem.eql(u8, arg, long)) { 188 if (mem.eql(u8, arg, long)) {
165 if (option.takes_value) { 189 if (option.takes_value) {
166 arg_i += 1; 190 const value = after_eql ?? it.next() ?? return error.OptionMissingValue;
167 if (args.len <= arg_i) return error.OptionMissingValue; 191 try option.parse(&result, value);
168
169 try option.parse(&result, args[arg_i]);
170 } else { 192 } else {
171 try option.parse(&result, []u8{}); 193 try option.parse(&result, []u8{});
172 } 194 }
@@ -285,6 +307,11 @@ test "clap.parse.Example" {
285 .err = null, 307 .err = null,
286 }, 308 },
287 Case { 309 Case {
310 .args = [][]const u8 { "--red=100", "-g=100", "--blue=50", },
311 .res = Color { .r = 100, .g = 100, .b = 50 },
312 .err = null,
313 },
314 Case {
288 .args = [][]const u8 { "-g", "200", "--blue", "100", "--red", "100", }, 315 .args = [][]const u8 { "-g", "200", "--blue", "100", "--red", "100", },
289 .res = Color { .r = 100, .g = 200, .b = 100 }, 316 .res = Color { .r = 100, .g = 200, .b = 100 },
290 .err = null, 317 .err = null,