summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jimmi Holst Christensen2018-05-20 12:51:43 +0200
committerGravatar Jimmi Holst Christensen2018-05-20 12:51:43 +0200
commit661d32ded068ecff486a952626bd209240035781 (patch)
treef2f10528cd2b98bc8ea5b193da54577da094e3bf
parentRemoved false or none tested advertisement from README (diff)
downloadzig-clap-661d32ded068ecff486a952626bd209240035781.tar.gz
zig-clap-661d32ded068ecff486a952626bd209240035781.tar.xz
zig-clap-661d32ded068ecff486a952626bd209240035781.zip
Support for command params in core.zig
* Also refactored structure * related: #1
-rw-r--r--core.zig158
-rw-r--r--example.zig31
-rw-r--r--index.zig (renamed from extended.zig)89
3 files changed, 198 insertions, 80 deletions
diff --git a/core.zig b/core.zig
index 8b953a9..33ba59c 100644
--- a/core.zig
+++ b/core.zig
@@ -18,47 +18,84 @@ const debug = std.debug;
18/// * "-abc value" 18/// * "-abc value"
19/// * "-abc=value" 19/// * "-abc=value"
20/// * "-abcvalue" 20/// * "-abcvalue"
21/// * Long ("--long-arg"): Should be used for less common parameters, or when no single character 21/// * Long ("--long-param"): Should be used for less common parameters, or when no single character
22/// can describe the paramter. 22/// can describe the paramter.
23/// * They can take a value two different ways. 23/// * They can take a value two different ways.
24/// * "--long-arg value" 24/// * "--long-param value"
25/// * "--long-arg=value" 25/// * "--long-param=value"
26/// * Value ("some-value"): Should be used as the primary parameter of the program, like a 26/// * Command ("command"): Should be used as for sub-commands and other keywords.
27/// filename or an expression to parse. 27/// * They can take a value two different ways.
28/// * "command value"
29/// * "command=value"
30/// * Value ("value"): Should be used as the primary parameter of the program, like a filename or
31/// an expression to parse.
28pub fn Param(comptime Id: type) type { 32pub fn Param(comptime Id: type) type {
29 return struct { 33 return struct {
30 const Self = this; 34 const Self = this;
31 35
32 id: Id, 36 id: Id,
37 command: ?[]const u8,
33 short: ?u8, 38 short: ?u8,
34 long: ?[]const u8, 39 long: ?[]const u8,
35 takes_value: bool, 40 takes_value: bool,
36 41
37 /// Initialize a ::Param. 42 pub fn short(id: Id, s: u8, takes_value: bool) Self {
38 /// If ::name.len == 0, then it's a value parameter: "some-command value".
39 /// If ::name.len == 1, then it's a short parameter: "some-command -s".
40 /// If ::name.len > 1, then it's a long parameter: "some-command --long".
41 pub fn init(id: Id, name: []const u8, takes_value: bool) Self {
42 return Self{ 43 return Self{
43 .id = id, 44 .id = id,
44 .short = if (name.len == 1) name[0] else null, 45 .command = null,
45 .long = if (name.len > 1) name else null, 46 .short = s,
47 .long = null,
48 .takes_value = takes_value,
49 };
50 }
51
52 pub fn long(id: Id, l: []const u8, takes_value: bool) Self {
53 return Self{
54 .id = id,
55 .command = null,
56 .short = null,
57 .long = l,
46 .takes_value = takes_value, 58 .takes_value = takes_value,
47 }; 59 };
48 } 60 }
49 61
50 pub fn both(id: Id, short: u8, long: []const u8, takes_value: bool) Self { 62 pub fn command(id: Id, c: []const u8, takes_value: bool) Self {
63 return Self{
64 .id = id,
65 .command = c,
66 .short = null,
67 .long = null,
68 .takes_value = takes_value,
69 };
70 }
71
72 pub fn value(id: Id) Self {
73 return Self{
74 .id = id,
75 .command = null,
76 .short = null,
77 .long = null,
78 .takes_value = true,
79 };
80 }
81
82 /// Initialize a ::Param.
83 /// If ::name.len == 0, then it's a value parameter: "value".
84 /// If ::name.len == 1, then it's a short parameter: "-s".
85 /// If ::name.len > 1, then it's a long parameter: "--long".
86 pub fn smart(id: Id, name: []const u8, takes_value: bool) Self {
51 return Self{ 87 return Self{
52 .id = id, 88 .id = id,
53 .short = short, 89 .command = null,
54 .long = long, 90 .short = if (name.len == 1) name[0] else null,
91 .long = if (name.len > 1) name else null,
55 .takes_value = takes_value, 92 .takes_value = takes_value,
56 }; 93 };
57 } 94 }
58 95
59 pub fn with(param: &const Self, comptime field_name: []const u8, value: var) Self { 96 pub fn with(param: &const Self, comptime field_name: []const u8, v: var) Self {
60 var res = *param; 97 var res = *param;
61 @field(res, field_name) = value; 98 @field(res, field_name) = v;
62 return res; 99 return res;
63 } 100 }
64 }; 101 };
@@ -136,7 +173,7 @@ pub const OsArgIterator = struct {
136 if (builtin.os == builtin.Os.windows) { 173 if (builtin.os == builtin.Os.windows) {
137 return try self.args.next(allocator) ?? return null; 174 return try self.args.next(allocator) ?? return null;
138 } else { 175 } else {
139 return self.args.nextPoxix(); 176 return self.args.nextPosix();
140 } 177 }
141 } 178 }
142}; 179};
@@ -180,7 +217,7 @@ pub fn Iterator(comptime Id: type) type {
180 /// Get the next ::Arg that matches a ::Param. 217 /// Get the next ::Arg that matches a ::Param.
181 pub fn next(iter: &Self) !?Arg(Id) { 218 pub fn next(iter: &Self) !?Arg(Id) {
182 const ArgInfo = struct { 219 const ArgInfo = struct {
183 const Kind = enum { Long, Short, Value }; 220 const Kind = enum { Long, Short, Command };
184 221
185 arg: []const u8, 222 arg: []const u8,
186 kind: Kind, 223 kind: Kind,
@@ -191,7 +228,7 @@ pub fn Iterator(comptime Id: type) type {
191 const full_arg = (try iter.innerNext()) ?? return null; 228 const full_arg = (try iter.innerNext()) ?? return null;
192 const arg_info = blk: { 229 const arg_info = blk: {
193 var arg = full_arg; 230 var arg = full_arg;
194 var kind = ArgInfo.Kind.Value; 231 var kind = ArgInfo.Kind.Command;
195 232
196 if (mem.startsWith(u8, arg, "--")) { 233 if (mem.startsWith(u8, arg, "--")) {
197 arg = arg[2..]; 234 arg = arg[2..];
@@ -213,12 +250,17 @@ pub fn Iterator(comptime Id: type) type {
213 250
214 for (iter.params) |*param| { 251 for (iter.params) |*param| {
215 switch (kind) { 252 switch (kind) {
253 ArgInfo.Kind.Command,
216 ArgInfo.Kind.Long => { 254 ArgInfo.Kind.Long => {
217 const long = param.long ?? continue; 255 const match = switch (kind) {
256 ArgInfo.Kind.Command => param.command ?? continue,
257 ArgInfo.Kind.Long => param.long ?? continue,
258 else => unreachable,
259 };
218 const name = if (eql_index) |i| arg[0..i] else arg; 260 const name = if (eql_index) |i| arg[0..i] else arg;
219 const maybe_value = if (eql_index) |i| arg[i + 1..] else null; 261 const maybe_value = if (eql_index) |i| arg[i + 1..] else null;
220 262
221 if (!mem.eql(u8, name, long)) 263 if (!mem.eql(u8, name, match))
222 continue; 264 continue;
223 if (!param.takes_value) { 265 if (!param.takes_value) {
224 if (maybe_value != null) 266 if (maybe_value != null)
@@ -247,12 +289,17 @@ pub fn Iterator(comptime Id: type) type {
247 .param = param, 289 .param = param,
248 }); 290 });
249 }, 291 },
250 ArgInfo.Kind.Value => { 292 }
251 if (param.long) |_| continue; 293 }
252 if (param.short) |_| continue;
253 294
254 return Arg(Id).init(param.id, arg); 295 // We do a final pass to look for value parameters matches
255 } 296 if (kind == ArgInfo.Kind.Command) {
297 for (iter.params) |*param| {
298 if (param.short) |_| continue;
299 if (param.long) |_| continue;
300 if (param.command) |_| continue;
301
302 return Arg(Id).init(param.id, arg);
256 } 303 }
257 } 304 }
258 305
@@ -327,11 +374,11 @@ fn testNoErr(params: []const Param(u8), args: []const []const u8, ids: []const u
327 } 374 }
328} 375}
329 376
330test "clap.parse: short" { 377test "clap.core: short" {
331 const params = []Param(u8) { 378 const params = []Param(u8) {
332 Param(u8).init(0, "a", false), 379 Param(u8).smart(0, "a", false),
333 Param(u8).init(1, "b", false), 380 Param(u8).smart(1, "b", false),
334 Param(u8).init(2, "c", true), 381 Param(u8).smart(2, "c", true),
335 }; 382 };
336 383
337 testNoErr(params, [][]const u8 { "-a" }, []u8{0}, []?[]const u8{null}); 384 testNoErr(params, [][]const u8 { "-a" }, []u8{0}, []?[]const u8{null});
@@ -345,11 +392,11 @@ test "clap.parse: short" {
345 testNoErr(params, [][]const u8 { "-abc100" }, []u8{0,1,2}, []?[]const u8{null,null,"100"}); 392 testNoErr(params, [][]const u8 { "-abc100" }, []u8{0,1,2}, []?[]const u8{null,null,"100"});
346} 393}
347 394
348test "clap.parse: long" { 395test "clap.core: long" {
349 const params = []Param(u8) { 396 const params = []Param(u8) {
350 Param(u8).init(0, "aa", false), 397 Param(u8).smart(0, "aa", false),
351 Param(u8).init(1, "bb", false), 398 Param(u8).smart(1, "bb", false),
352 Param(u8).init(2, "cc", true), 399 Param(u8).smart(2, "cc", true),
353 }; 400 };
354 401
355 testNoErr(params, [][]const u8 { "--aa" }, []u8{0}, []?[]const u8{null}); 402 testNoErr(params, [][]const u8 { "--aa" }, []u8{0}, []?[]const u8{null});
@@ -358,11 +405,39 @@ test "clap.parse: long" {
358 testNoErr(params, [][]const u8 { "--cc", "100" }, []u8{2}, []?[]const u8{"100"}); 405 testNoErr(params, [][]const u8 { "--cc", "100" }, []u8{2}, []?[]const u8{"100"});
359} 406}
360 407
361test "clap.parse: both" { 408test "clap.core: command" {
409 const params = []Param(u8) {
410 Param(u8).command(0, "aa", false),
411 Param(u8).command(1, "bb", false),
412 Param(u8).command(2, "cc", true),
413 };
414
415 testNoErr(params, [][]const u8 { "aa" }, []u8{0}, []?[]const u8{null});
416 testNoErr(params, [][]const u8 { "aa", "bb" }, []u8{0,1}, []?[]const u8{null,null});
417 testNoErr(params, [][]const u8 { "cc=100" }, []u8{2}, []?[]const u8{"100"});
418 testNoErr(params, [][]const u8 { "cc", "100" }, []u8{2}, []?[]const u8{"100"});
419}
420
421test "clap.core: value" {
422 const params = []Param(u8) {
423 Param(u8).value(0),
424 };
425
426 testNoErr(params, [][]const u8 { "aa" }, []u8{0}, []?[]const u8{"aa"});
427}
428
429test "clap.core: all" {
362 const params = []Param(u8) { 430 const params = []Param(u8) {
363 Param(u8).both(0, 'a', "aa", false), 431 Param(u8).short(0, 'a', false)
364 Param(u8).both(1, 'b', "bb", false), 432 .with("long", "aa"[0..])
365 Param(u8).both(2, 'c', "cc", true), 433 .with("command", "aa"[0..]),
434 Param(u8).short(1, 'b', false)
435 .with("long", "bb"[0..])
436 .with("command", "bb"[0..]),
437 Param(u8).short(2, 'c', true)
438 .with("long", "cc"[0..])
439 .with("command", "cc"[0..]),
440 Param(u8).value(3),
366 }; 441 };
367 442
368 testNoErr(params, [][]const u8 { "-a" }, []u8{0}, []?[]const u8{null}); 443 testNoErr(params, [][]const u8 { "-a" }, []u8{0}, []?[]const u8{null});
@@ -378,4 +453,9 @@ test "clap.parse: both" {
378 testNoErr(params, [][]const u8 { "--aa", "--bb" }, []u8{0,1}, []?[]const u8{null,null}); 453 testNoErr(params, [][]const u8 { "--aa", "--bb" }, []u8{0,1}, []?[]const u8{null,null});
379 testNoErr(params, [][]const u8 { "--cc=100" }, []u8{2}, []?[]const u8{"100"}); 454 testNoErr(params, [][]const u8 { "--cc=100" }, []u8{2}, []?[]const u8{"100"});
380 testNoErr(params, [][]const u8 { "--cc", "100" }, []u8{2}, []?[]const u8{"100"}); 455 testNoErr(params, [][]const u8 { "--cc", "100" }, []u8{2}, []?[]const u8{"100"});
456 testNoErr(params, [][]const u8 { "aa" }, []u8{0}, []?[]const u8{null});
457 testNoErr(params, [][]const u8 { "aa", "bb" }, []u8{0,1}, []?[]const u8{null,null});
458 testNoErr(params, [][]const u8 { "cc=100" }, []u8{2}, []?[]const u8{"100"});
459 testNoErr(params, [][]const u8 { "cc", "100" }, []u8{2}, []?[]const u8{"100"});
460 testNoErr(params, [][]const u8 { "dd" }, []u8{3}, []?[]const u8{"dd"});
381} 461}
diff --git a/example.zig b/example.zig
index 14b5487..4b3fa82 100644
--- a/example.zig
+++ b/example.zig
@@ -1,14 +1,9 @@
1const std = @import("std"); 1const std = @import("std");
2const core = @import("core.zig"); 2const clap = @import("index.zig");
3const clap = @import("extended.zig");
4 3
5const debug = std.debug; 4const debug = std.debug;
6const os = std.os; 5const os = std.os;
7 6
8const Clap = clap.Clap;
9const Param = clap.Param;
10const Parser = clap.Parser;
11
12const Options = struct { 7const Options = struct {
13 print_values: bool, 8 print_values: bool,
14 a: i64, 9 a: i64,
@@ -35,7 +30,7 @@ const Options = struct {
35// d = V=5 30// d = V=5
36 31
37pub fn main() !void { 32pub fn main() !void {
38 const parser = comptime Clap(Options) { 33 const parser = comptime clap.Clap(Options) {
39 .defaults = Options { 34 .defaults = Options {
40 .print_values = false, 35 .print_values = false,
41 .a = 0, 36 .a = 0,
@@ -43,22 +38,22 @@ pub fn main() !void {
43 .c = 0, 38 .c = 0,
44 .d = "", 39 .d = "",
45 }, 40 },
46 .params = []Param { 41 .params = []clap.Param {
47 Param.init("a") 42 clap.Param.smart("a")
48 .with("takes_value", Parser.int(i64, 10)), 43 .with("takes_value", clap.Parser.int(i64, 10)),
49 Param.init("b") 44 clap.Param.smart("b")
50 .with("takes_value", Parser.int(u64, 10)), 45 .with("takes_value", clap.Parser.int(u64, 10)),
51 Param.init("c") 46 clap.Param.smart("c")
52 .with("takes_value", Parser.int(u8, 10)), 47 .with("takes_value", clap.Parser.int(u8, 10)),
53 Param.init("d") 48 clap.Param.smart("d")
54 .with("takes_value", Parser.string), 49 .with("takes_value", clap.Parser.string),
55 Param.init("print_values") 50 clap.Param.smart("print_values")
56 .with("short", 'p') 51 .with("short", 'p')
57 .with("long", "print-values"), 52 .with("long", "print-values"),
58 } 53 }
59 }; 54 };
60 55
61 var arg_iter = core.OsArgIterator.init(); 56 var arg_iter = clap.core.OsArgIterator.init();
62 const iter = &arg_iter.iter; 57 const iter = &arg_iter.iter;
63 const command = iter.next(debug.global_allocator); 58 const command = iter.next(debug.global_allocator);
64 59
diff --git a/extended.zig b/index.zig
index a5c8e89..7b82211 100644
--- a/extended.zig
+++ b/index.zig
@@ -1,6 +1,7 @@
1pub const core = @import("core.zig");
2
1const builtin = @import("builtin"); 3const builtin = @import("builtin");
2const std = @import("std"); 4const std = @import("std");
3const core = @import("core.zig");
4 5
5const mem = std.mem; 6const mem = std.mem;
6const fmt = std.fmt; 7const fmt = std.fmt;
@@ -17,8 +18,45 @@ pub const Param = struct {
17 required: bool, 18 required: bool,
18 position: ?usize, 19 position: ?usize,
19 20
20 pub fn init(name: []const u8) Param { 21 pub fn short(s: u8) Param {
21 return Param { 22 return Param{
23 .field = []u8{s},
24 .short = s,
25 .long = null,
26 .takes_value = null,
27 .required = false,
28 .position = null,
29 };
30 }
31
32 pub fn long(l: []const u8) Param {
33 return Param{
34 .field = l,
35 .short = null,
36 .long = l,
37 .takes_value = null,
38 .required = false,
39 .position = null,
40 };
41 }
42
43 pub fn value(f: []const u8) Param {
44 return Param{
45 .field = f,
46 .short = null,
47 .long = null,
48 .takes_value = null,
49 .required = false,
50 .position = null,
51 };
52 }
53
54 /// Initialize a ::Param.
55 /// If ::name.len == 0, then it's a value parameter: "value".
56 /// If ::name.len == 1, then it's a short parameter: "-s".
57 /// If ::name.len > 1, then it's a long parameter: "--long".
58 pub fn smart(name: []const u8) Param {
59 return Param{
22 .field = name, 60 .field = name,
23 .short = if (name.len == 1) name[0] else null, 61 .short = if (name.len == 1) name[0] else null,
24 .long = if (name.len > 1) name else null, 62 .long = if (name.len > 1) name else null,
@@ -28,9 +66,9 @@ pub const Param = struct {
28 }; 66 };
29 } 67 }
30 68
31 pub fn with(param: &const Param, comptime field_name: []const u8, value: var) Param { 69 pub fn with(param: &const Param, comptime field_name: []const u8, v: var) Param {
32 var res = *param; 70 var res = *param;
33 @field(res, field_name) = value; 71 @field(res, field_name) = v;
34 return res; 72 return res;
35 } 73 }
36}; 74};
@@ -50,6 +88,7 @@ pub fn Clap(comptime Result: type) type {
50 for (clap.params) |p, i| { 88 for (clap.params) |p, i| {
51 res[i] = core.Param(usize) { 89 res[i] = core.Param(usize) {
52 .id = i, 90 .id = i,
91 .command = null,
53 .short = p.short, 92 .short = p.short,
54 .long = p.long, 93 .long = p.long,
55 .takes_value = p.takes_value != null, 94 .takes_value = p.takes_value != null,
@@ -189,13 +228,17 @@ fn testErr(comptime clap: &const Clap(Options), args: []const []const u8, expect
189 } 228 }
190} 229}
191 230
192test "clap.parse: short" { 231test "clap.core" {
232 _ = core;
233}
234
235test "clap: short" {
193 const clap = comptime Clap(Options) { 236 const clap = comptime Clap(Options) {
194 .defaults = default, 237 .defaults = default,
195 .params = []Param { 238 .params = []Param {
196 Param.init("a"), 239 Param.smart("a"),
197 Param.init("b"), 240 Param.smart("b"),
198 Param.init("int") 241 Param.smart("int")
199 .with("short", 'i') 242 .with("short", 'i')
200 .with("takes_value", Parser.int(i64, 10)) 243 .with("takes_value", Parser.int(i64, 10))
201 } 244 }
@@ -212,14 +255,14 @@ test "clap.parse: short" {
212 testNoErr(clap, [][]const u8 { "-abi100" }, default.with("a", true).with("b", true).with("int", 100)); 255 testNoErr(clap, [][]const u8 { "-abi100" }, default.with("a", true).with("b", true).with("int", 100));
213} 256}
214 257
215test "clap.parse: long" { 258test "clap: long" {
216 const clap = comptime Clap(Options) { 259 const clap = comptime Clap(Options) {
217 .defaults = default, 260 .defaults = default,
218 .params = []Param { 261 .params = []Param {
219 Param.init("cc"), 262 Param.smart("cc"),
220 Param.init("int").with("takes_value", Parser.int(i64, 10)), 263 Param.smart("int").with("takes_value", Parser.int(i64, 10)),
221 Param.init("uint").with("takes_value", Parser.int(u64, 10)), 264 Param.smart("uint").with("takes_value", Parser.int(u64, 10)),
222 Param.init("str").with("takes_value", Parser.string), 265 Param.smart("str").with("takes_value", Parser.string),
223 } 266 }
224 }; 267 };
225 268
@@ -227,45 +270,45 @@ test "clap.parse: long" {
227 testNoErr(clap, [][]const u8 { "--int", "100" }, default.with("int", 100)); 270 testNoErr(clap, [][]const u8 { "--int", "100" }, default.with("int", 100));
228} 271}
229 272
230test "clap.parse: value bool" { 273test "clap: value bool" {
231 const clap = comptime Clap(Options) { 274 const clap = comptime Clap(Options) {
232 .defaults = default, 275 .defaults = default,
233 .params = []Param { 276 .params = []Param {
234 Param.init("a"), 277 Param.smart("a"),
235 } 278 }
236 }; 279 };
237 280
238 testNoErr(clap, [][]const u8 { "-a" }, default.with("a", true)); 281 testNoErr(clap, [][]const u8 { "-a" }, default.with("a", true));
239} 282}
240 283
241test "clap.parse: value str" { 284test "clap: value str" {
242 const clap = comptime Clap(Options) { 285 const clap = comptime Clap(Options) {
243 .defaults = default, 286 .defaults = default,
244 .params = []Param { 287 .params = []Param {
245 Param.init("str").with("takes_value", Parser.string), 288 Param.smart("str").with("takes_value", Parser.string),
246 } 289 }
247 }; 290 };
248 291
249 testNoErr(clap, [][]const u8 { "--str", "Hello World!" }, default.with("str", "Hello World!")); 292 testNoErr(clap, [][]const u8 { "--str", "Hello World!" }, default.with("str", "Hello World!"));
250} 293}
251 294
252test "clap.parse: value int" { 295test "clap: value int" {
253 const clap = comptime Clap(Options) { 296 const clap = comptime Clap(Options) {
254 .defaults = default, 297 .defaults = default,
255 .params = []Param { 298 .params = []Param {
256 Param.init("int").with("takes_value", Parser.int(i64, 10)), 299 Param.smart("int").with("takes_value", Parser.int(i64, 10)),
257 } 300 }
258 }; 301 };
259 302
260 testNoErr(clap, [][]const u8 { "--int", "100" }, default.with("int", 100)); 303 testNoErr(clap, [][]const u8 { "--int", "100" }, default.with("int", 100));
261} 304}
262 305
263test "clap.parse: position" { 306test "clap: position" {
264 const clap = comptime Clap(Options) { 307 const clap = comptime Clap(Options) {
265 .defaults = default, 308 .defaults = default,
266 .params = []Param { 309 .params = []Param {
267 Param.init("a").with("position", 0), 310 Param.smart("a").with("position", 0),
268 Param.init("b").with("position", 1), 311 Param.smart("b").with("position", 1),
269 } 312 }
270 }; 313 };
271 314