summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md160
-rw-r--r--build.zig8
-rw-r--r--clap.zig41
-rw-r--r--example/README.md.template50
-rw-r--r--example/comptime-clap-error.zig19
-rw-r--r--example/simple-error.zig15
-rw-r--r--example/simple.zig26
7 files changed, 213 insertions, 106 deletions
diff --git a/README.md b/README.md
index 6c556b9..0555a0f 100644
--- a/README.md
+++ b/README.md
@@ -15,10 +15,9 @@ A simple and easy to use command line argument parser library for Zig.
15 15
16## Examples 16## Examples
17 17
18### `StreamingClap` 18### `clap.parse`
19 19
20The `StreamingClap` is the base of all the other parsers. It's a streaming parser that uses an 20The simplest way to use this library is to just call the `clap.parse` function.
21`args.Iterator` to provide it with arguments lazily.
22 21
23```zig 22```zig
24const std = @import("std"); 23const std = @import("std");
@@ -27,58 +26,69 @@ const clap = @import("clap");
27const debug = std.debug; 26const debug = std.debug;
28 27
29pub fn main() !void { 28pub fn main() !void {
30 const allocator = std.heap.direct_allocator;
31
32 // First we specify what parameters our program can take. 29 // First we specify what parameters our program can take.
33 const params = [_]clap.Param(u8){ 30 // We can use `parseParam` to parse a string to a `Param(Help)`
34 clap.Param(u8){ 31 const params = comptime [_]clap.Param(clap.Help){
35 .id = 'h', 32 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable,
36 .names = clap.Names{ .short = 'h', .long = "help" }, 33 clap.parseParam("-n, --number <NUM> An option parameter, which takes a value.") catch unreachable,
37 }, 34 clap.Param(clap.Help){
38 clap.Param(u8){
39 .id = 'n',
40 .names = clap.Names{ .short = 'n', .long = "number" },
41 .takes_value = true,
42 },
43 clap.Param(u8){
44 .id = 'f',
45 .takes_value = true, 35 .takes_value = true,
46 }, 36 },
47 }; 37 };
48 38
49 // We then initialize an argument iterator. We will use the OsIterator as it nicely 39 var args = try clap.parse(clap.Help, params, std.heap.direct_allocator);
50 // wraps iterating over arguments the most efficient way on each os. 40 defer args.deinit();
51 var iter = try clap.args.OsIterator.init(allocator);
52 defer iter.deinit();
53 41
54 // Initialize our streaming parser. 42 if (args.flag("--help"))
55 var parser = clap.StreamingClap(u8, clap.args.OsIterator){ 43 debug.warn("--help\n");
56 .params = params, 44 if (args.option("--number")) |n|
57 .iter = &iter, 45 debug.warn("--number = {}\n", n);
46 for (args.positionals()) |pos|
47 debug.warn("{}\n", pos);
48}
49
50```
51
52The data structure returned has lookup speed on par with array access (`arr[i]`) and validates
53that the strings you pass to `option` and `flag` are actually parameters that the program can take:
54
55```zig
56const std = @import("std");
57const clap = @import("clap");
58
59pub fn main() !void {
60 // First we specify what parameters our program can take.
61 // We can use `parseParam` to parse a string to a `Param(Help)`
62 const params = comptime [_]clap.Param(clap.Help){
63 clap.parseParam("-h, --help Display this help and exit.") catch unreachable,
58 }; 64 };
59 65
60 // Because we use a streaming parser, we have to consume each argument parsed individually. 66 var args = try clap.parse(clap.Help, params, std.heap.direct_allocator);
61 while (try parser.next()) |arg| { 67 defer args.deinit();
62 // arg.param will point to the parameter which matched the argument.
63 switch (arg.param.id) {
64 'h' => debug.warn("Help!\n"),
65 'n' => debug.warn("--number = {}\n", arg.value.?),
66 68
67 // arg.value == null, if arg.param.takes_value == false. 69 _ = args.flag("--helps");
68 // Otherwise, arg.value is the value passed with the argument, such as "-a=10"
69 // or "-a 10".
70 'f' => debug.warn("{}\n", arg.value.?),
71 else => unreachable,
72 }
73 }
74} 70}
75 71
76``` 72```
77 73
74```
75zig-clap/clap/comptime.zig:109:17: error: --helps is not a parameter.
76 @compileError(name ++ " is not a parameter.");
77 ^
78zig-clap/clap/comptime.zig:77:45: note: called from here
79 const param = comptime findParam(name);
80 ^
81zig-clap/clap.zig:238:31: note: called from here
82 return a.clap.flag(name);
83 ^
84zig-clap/example/simple-error.zig:16:18: note: called from here
85 _ = args.flag("--helps");
86```
87
78### `ComptimeClap` 88### `ComptimeClap`
79 89
80The `ComptimeClap` is a wrapper for `StreamingClap`, which parses all the arguments and makes 90The `ComptimeClap` is the parser used by `clap.parse`. It allows the user to use a custom argument
81them available through three functions (`flag`, `option`, `positionals`). 91iterator.
82 92
83```zig 93```zig
84const std = @import("std"); 94const std = @import("std");
@@ -118,46 +128,68 @@ pub fn main() !void {
118 128
119``` 129```
120 130
121The data structure returned from this parser has lookup speed on par with array access (`arr[i]`) 131### `StreamingClap`
122and validates that the strings you pass to `option` and `flag` are actually parameters that the 132
123program can take: 133The `StreamingClap` is the base of all the other parsers. It's a streaming parser that uses an
134`args.Iterator` to provide it with arguments lazily.
124 135
125```zig 136```zig
126const std = @import("std"); 137const std = @import("std");
127const clap = @import("clap"); 138const clap = @import("clap");
128 139
140const debug = std.debug;
141
129pub fn main() !void { 142pub fn main() !void {
130 const allocator = std.heap.direct_allocator; 143 const allocator = std.heap.direct_allocator;
131 144
132 const params = [_]clap.Param(void){clap.Param(void){ 145 // First we specify what parameters our program can take.
133 .names = clap.Names{ .short = 'h', .long = "help" }, 146 const params = [_]clap.Param(u8){
134 }}; 147 clap.Param(u8){
148 .id = 'h',
149 .names = clap.Names{ .short = 'h', .long = "help" },
150 },
151 clap.Param(u8){
152 .id = 'n',
153 .names = clap.Names{ .short = 'n', .long = "number" },
154 .takes_value = true,
155 },
156 clap.Param(u8){
157 .id = 'f',
158 .takes_value = true,
159 },
160 };
135 161
136 var iter = clap.args.OsIterator.init(allocator); 162 // We then initialize an argument iterator. We will use the OsIterator as it nicely
163 // wraps iterating over arguments the most efficient way on each os.
164 var iter = try clap.args.OsIterator.init(allocator);
137 defer iter.deinit(); 165 defer iter.deinit();
138 const exe = try iter.next();
139 166
140 var args = try clap.ComptimeClap(void, params).parse(allocator, clap.args.OsIterator, &iter); 167 // Initialize our streaming parser.
141 defer args.deinit(); 168 var parser = clap.StreamingClap(u8, clap.args.OsIterator){
169 .params = params,
170 .iter = &iter,
171 };
142 172
143 _ = args.flag("--helps"); 173 // Because we use a streaming parser, we have to consume each argument parsed individually.
144} 174 while (try parser.next()) |arg| {
175 // arg.param will point to the parameter which matched the argument.
176 switch (arg.param.id) {
177 'h' => debug.warn("Help!\n"),
178 'n' => debug.warn("--number = {}\n", arg.value.?),
145 179
146``` 180 // arg.value == null, if arg.param.takes_value == false.
181 // Otherwise, arg.value is the value passed with the argument, such as "-a=10"
182 // or "-a 10".
183 'f' => debug.warn("{}\n", arg.value.?),
184 else => unreachable,
185 }
186 }
187}
147 188
148``` 189```
149zig-clap/src/comptime.zig:109:17: error: --helps is not a parameter.
150 @compileError(name ++ " is not a parameter.");
151 ^
152zig-clap/src/comptime.zig:77:45: note: called from here
153 const param = comptime findParam(name);
154 ^
155zig-clap/example/comptime-clap-error.zig:18:18: note: called from here
156 _ = args.flag("--helps");
157 ^
158```
159 190
160Ofc, this limits you to parameters that are comptime known. 191Currently, this parse is the only parser that allow an array of `Param` that
192is generated at runtime.
161 193
162### `help` 194### `help`
163 195
diff --git a/build.zig b/build.zig
index 9d2ef7b..1a6fe09 100644
--- a/build.zig
+++ b/build.zig
@@ -27,8 +27,9 @@ pub fn build(b: *Builder) void {
27 27
28 const example_step = b.step("examples", "Build examples"); 28 const example_step = b.step("examples", "Build examples");
29 inline for ([_][]const u8{ 29 inline for ([_][]const u8{
30 "simple",
31 //"simple-error",
30 "comptime-clap", 32 "comptime-clap",
31 //"comptime-clap-error",
32 "streaming-clap", 33 "streaming-clap",
33 "help", 34 "help",
34 }) |example_name| { 35 }) |example_name| {
@@ -61,9 +62,10 @@ fn readMeStep(b: *Builder) *std.build.Step {
61 const stream = &file.outStream().stream; 62 const stream = &file.outStream().stream;
62 try stream.print( 63 try stream.print(
63 @embedFile("example/README.md.template"), 64 @embedFile("example/README.md.template"),
64 @embedFile("example/streaming-clap.zig"), 65 @embedFile("example/simple.zig"),
66 @embedFile("example/simple-error.zig"),
65 @embedFile("example/comptime-clap.zig"), 67 @embedFile("example/comptime-clap.zig"),
66 @embedFile("example/comptime-clap-error.zig"), 68 @embedFile("example/streaming-clap.zig"),
67 @embedFile("example/help.zig"), 69 @embedFile("example/help.zig"),
68 ); 70 );
69 } 71 }
diff --git a/clap.zig b/clap.zig
index 1a6a95d..e0d20e3 100644
--- a/clap.zig
+++ b/clap.zig
@@ -223,6 +223,47 @@ fn find(str: []const u8, f: []const u8) []const u8 {
223 return str[i..][0..f.len]; 223 return str[i..][0..f.len];
224} 224}
225 225
226pub fn Args(comptime Id: type, comptime params: []const Param(Id)) type {
227 return struct {
228 arena: std.heap.ArenaAllocator,
229 clap: ComptimeClap(Id, params),
230 exe_arg: ?[]const u8,
231
232 pub fn deinit(a: *@This()) void {
233 a.clap.deinit();
234 a.arena.deinit();
235 }
236
237 pub fn flag(a: @This(), comptime name: []const u8) bool {
238 return a.clap.flag(name);
239 }
240
241 pub fn option(a: @This(), comptime name: []const u8) ?[]const u8 {
242 return a.clap.option(name);
243 }
244
245 pub fn positionals(a: @This()) []const []const u8 {
246 return a.clap.positionals();
247 }
248 };
249}
250
251/// Parses the command line arguments passed into the program based on an
252/// array of `Param`s.
253pub fn parse(
254 comptime Id: type,
255 comptime params: []const Param(Id),
256 allocator: *mem.Allocator,
257) !Args(Id, params) {
258 var iter = try args.OsIterator.init(allocator);
259 const clap = try ComptimeClap(Id, params).parse(allocator, args.OsIterator, &iter);
260 return Args(Id, params){
261 .arena = iter.arena,
262 .clap = clap,
263 .exe_arg = iter.exe_arg,
264 };
265}
266
226/// Will print a help message in the following format: 267/// Will print a help message in the following format:
227/// -s, --long <value_text> help_text 268/// -s, --long <value_text> help_text
228/// -s, help_text 269/// -s, help_text
diff --git a/example/README.md.template b/example/README.md.template
index 373a037..1fd90b0 100644
--- a/example/README.md.template
+++ b/example/README.md.template
@@ -15,45 +15,55 @@ A simple and easy to use command line argument parser library for Zig.
15 15
16## Examples 16## Examples
17 17
18### `StreamingClap` 18### `clap.parse`
19 19
20The `StreamingClap` is the base of all the other parsers. It's a streaming parser that uses an 20The simplest way to use this library is to just call the `clap.parse` function.
21`args.Iterator` to provide it with arguments lazily.
22 21
23```zig 22```zig
24{} 23{}
25``` 24```
26 25
27### `ComptimeClap` 26The data structure returned has lookup speed on par with array access (`arr[i]`) and validates
28 27that the strings you pass to `option` and `flag` are actually parameters that the program can take:
29The `ComptimeClap` is a wrapper for `StreamingClap`, which parses all the arguments and makes
30them available through three functions (`flag`, `option`, `positionals`).
31
32```zig
33{}
34```
35
36The data structure returned from this parser has lookup speed on par with array access (`arr[i]`)
37and validates that the strings you pass to `option` and `flag` are actually parameters that the
38program can take:
39 28
40```zig 29```zig
41{} 30{}
42``` 31```
43 32
44``` 33```
45zig-clap/src/comptime.zig:109:17: error: --helps is not a parameter. 34zig-clap/clap/comptime.zig:109:17: error: --helps is not a parameter.
46 @compileError(name ++ " is not a parameter."); 35 @compileError(name ++ " is not a parameter.");
47 ^ 36 ^
48zig-clap/src/comptime.zig:77:45: note: called from here 37zig-clap/clap/comptime.zig:77:45: note: called from here
49 const param = comptime findParam(name); 38 const param = comptime findParam(name);
50 ^ 39 ^
51zig-clap/example/comptime-clap-error.zig:18:18: note: called from here 40zig-clap/clap.zig:238:31: note: called from here
41 return a.clap.flag(name);
42 ^
43zig-clap/example/simple-error.zig:16:18: note: called from here
52 _ = args.flag("--helps"); 44 _ = args.flag("--helps");
53 ^
54``` 45```
55 46
56Ofc, this limits you to parameters that are comptime known. 47### `ComptimeClap`
48
49The `ComptimeClap` is the parser used by `clap.parse`. It allows the user to use a custom argument
50iterator.
51
52```zig
53{}
54```
55
56### `StreamingClap`
57
58The `StreamingClap` is the base of all the other parsers. It's a streaming parser that uses an
59`args.Iterator` to provide it with arguments lazily.
60
61```zig
62{}
63```
64
65Currently, this parse is the only parser that allow an array of `Param` that
66is generated at runtime.
57 67
58### `help` 68### `help`
59 69
diff --git a/example/comptime-clap-error.zig b/example/comptime-clap-error.zig
deleted file mode 100644
index 3209b74..0000000
--- a/example/comptime-clap-error.zig
+++ /dev/null
@@ -1,19 +0,0 @@
1const std = @import("std");
2const clap = @import("clap");
3
4pub fn main() !void {
5 const allocator = std.heap.direct_allocator;
6
7 const params = [_]clap.Param(void){clap.Param(void){
8 .names = clap.Names{ .short = 'h', .long = "help" },
9 }};
10
11 var iter = clap.args.OsIterator.init(allocator);
12 defer iter.deinit();
13 const exe = try iter.next();
14
15 var args = try clap.ComptimeClap(void, params).parse(allocator, clap.args.OsIterator, &iter);
16 defer args.deinit();
17
18 _ = args.flag("--helps");
19}
diff --git a/example/simple-error.zig b/example/simple-error.zig
new file mode 100644
index 0000000..fc72a03
--- /dev/null
+++ b/example/simple-error.zig
@@ -0,0 +1,15 @@
1const std = @import("std");
2const clap = @import("clap");
3
4pub fn main() !void {
5 // First we specify what parameters our program can take.
6 // We can use `parseParam` to parse a string to a `Param(Help)`
7 const params = comptime [_]clap.Param(clap.Help){
8 clap.parseParam("-h, --help Display this help and exit.") catch unreachable,
9 };
10
11 var args = try clap.parse(clap.Help, params, std.heap.direct_allocator);
12 defer args.deinit();
13
14 _ = args.flag("--helps");
15}
diff --git a/example/simple.zig b/example/simple.zig
new file mode 100644
index 0000000..f791447
--- /dev/null
+++ b/example/simple.zig
@@ -0,0 +1,26 @@
1const std = @import("std");
2const clap = @import("clap");
3
4const debug = std.debug;
5
6pub fn main() !void {
7 // First we specify what parameters our program can take.
8 // We can use `parseParam` to parse a string to a `Param(Help)`
9 const params = comptime [_]clap.Param(clap.Help){
10 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable,
11 clap.parseParam("-n, --number <NUM> An option parameter, which takes a value.") catch unreachable,
12 clap.Param(clap.Help){
13 .takes_value = true,
14 },
15 };
16
17 var args = try clap.parse(clap.Help, params, std.heap.direct_allocator);
18 defer args.deinit();
19
20 if (args.flag("--help"))
21 debug.warn("--help\n");
22 if (args.option("--number")) |n|
23 debug.warn("--number = {}\n", n);
24 for (args.positionals()) |pos|
25 debug.warn("{}\n", pos);
26}