summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/main.yml6
-rw-r--r--README.md47
-rw-r--r--build.zig13
-rw-r--r--clap.zig141
-rw-r--r--clap/args.zig6
-rw-r--r--clap/comptime.zig8
-rw-r--r--clap/streaming.zig26
-rw-r--r--example/README.md.template4
-rw-r--r--example/comptime-clap.zig10
-rw-r--r--example/help.zig7
-rw-r--r--example/simple-error.zig2
-rw-r--r--example/simple.zig8
-rw-r--r--example/streaming-clap.zig10
-rw-r--r--example/usage.zig6
14 files changed, 153 insertions, 141 deletions
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 93d00fc..7418c8c 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -4,7 +4,7 @@ jobs:
4 test: 4 test:
5 strategy: 5 strategy:
6 matrix: 6 matrix:
7 os: [ubuntu-latest, macos-latest, windows-latest] 7 os: [ubuntu-latest, macos-latest]
8 runs-on: ${{matrix.os}} 8 runs-on: ${{matrix.os}}
9 steps: 9 steps:
10 - uses: actions/checkout@v1 10 - uses: actions/checkout@v1
@@ -12,7 +12,7 @@ jobs:
12 submodules: recursive 12 submodules: recursive
13 - uses: goto-bus-stop/setup-zig@v1.0.0 13 - uses: goto-bus-stop/setup-zig@v1.0.0
14 with: 14 with:
15 version: 0.5.0 15 version: 0.6.0
16 - run: zig build 16 - run: zig build
17 lint: 17 lint:
18 runs-on: ubuntu-latest 18 runs-on: ubuntu-latest
@@ -20,5 +20,5 @@ jobs:
20 - uses: actions/checkout@v1 20 - uses: actions/checkout@v1
21 - uses: goto-bus-stop/setup-zig@v1.0.0 21 - uses: goto-bus-stop/setup-zig@v1.0.0
22 with: 22 with:
23 version: 0.5.0 23 version: 0.6.0
24 - run: zig fmt --check . 24 - run: zig fmt --check .
diff --git a/README.md b/README.md
index 12d691d..2b38281 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,10 @@
2 2
3A simple and easy to use command line argument parser library for Zig. 3A simple and easy to use command line argument parser library for Zig.
4 4
5Looking for a version that works with `zig master`? The `zig-master` branch has
6you covered. It is maintained by people who live at head (not me) and is merged
7into master on every `zig` release.
8
5## Features 9## Features
6 10
7* Short arguments `-a` 11* Short arguments `-a`
@@ -36,15 +40,15 @@ pub fn main() !void {
36 }, 40 },
37 }; 41 };
38 42
39 var args = try clap.parse(clap.Help, params, std.heap.direct_allocator); 43 var args = try clap.parse(clap.Help, &params, std.heap.page_allocator);
40 defer args.deinit(); 44 defer args.deinit();
41 45
42 if (args.flag("--help")) 46 if (args.flag("--help"))
43 debug.warn("--help\n"); 47 debug.warn("--help\n", .{});
44 if (args.option("--number")) |n| 48 if (args.option("--number")) |n|
45 debug.warn("--number = {}\n", n); 49 debug.warn("--number = {}\n", .{ n });
46 for (args.positionals()) |pos| 50 for (args.positionals()) |pos|
47 debug.warn("{}\n", pos); 51 debug.warn("{}\n", .{ pos });
48} 52}
49 53
50``` 54```
@@ -63,7 +67,7 @@ pub fn main() !void {
63 clap.parseParam("-h, --help Display this help and exit.") catch unreachable, 67 clap.parseParam("-h, --help Display this help and exit.") catch unreachable,
64 }; 68 };
65 69
66 var args = try clap.parse(clap.Help, params, std.heap.direct_allocator); 70 var args = try clap.parse(clap.Help, &params, std.heap.direct_allocator);
67 defer args.deinit(); 71 defer args.deinit();
68 72
69 _ = args.flag("--helps"); 73 _ = args.flag("--helps");
@@ -97,7 +101,7 @@ const clap = @import("clap");
97const debug = std.debug; 101const debug = std.debug;
98 102
99pub fn main() !void { 103pub fn main() !void {
100 const allocator = std.heap.direct_allocator; 104 const allocator = std.heap.page_allocator;
101 105
102 // First we specify what parameters our program can take. 106 // First we specify what parameters our program can take.
103 // We can use `parseParam` to parse a string to a `Param(Help)` 107 // We can use `parseParam` to parse a string to a `Param(Help)`
@@ -115,15 +119,15 @@ pub fn main() !void {
115 defer iter.deinit(); 119 defer iter.deinit();
116 120
117 // Parse the arguments 121 // Parse the arguments
118 var args = try clap.ComptimeClap(clap.Help, params).parse(allocator, clap.args.OsIterator, &iter); 122 var args = try clap.ComptimeClap(clap.Help, &params).parse(allocator, clap.args.OsIterator, &iter);
119 defer args.deinit(); 123 defer args.deinit();
120 124
121 if (args.flag("--help")) 125 if (args.flag("--help"))
122 debug.warn("--help\n"); 126 debug.warn("--help\n", .{});
123 if (args.option("--number")) |n| 127 if (args.option("--number")) |n|
124 debug.warn("--number = {}\n", n); 128 debug.warn("--number = {}\n", .{ n });
125 for (args.positionals()) |pos| 129 for (args.positionals()) |pos|
126 debug.warn("{}\n", pos); 130 debug.warn("{}\n", .{ pos });
127} 131}
128 132
129``` 133```
@@ -140,7 +144,7 @@ const clap = @import("clap");
140const debug = std.debug; 144const debug = std.debug;
141 145
142pub fn main() !void { 146pub fn main() !void {
143 const allocator = std.heap.direct_allocator; 147 const allocator = std.heap.page_allocator;
144 148
145 // First we specify what parameters our program can take. 149 // First we specify what parameters our program can take.
146 const params = [_]clap.Param(u8){ 150 const params = [_]clap.Param(u8){
@@ -166,7 +170,7 @@ pub fn main() !void {
166 170
167 // Initialize our streaming parser. 171 // Initialize our streaming parser.
168 var parser = clap.StreamingClap(u8, clap.args.OsIterator){ 172 var parser = clap.StreamingClap(u8, clap.args.OsIterator){
169 .params = params, 173 .params = &params,
170 .iter = &iter, 174 .iter = &iter,
171 }; 175 };
172 176
@@ -174,13 +178,13 @@ pub fn main() !void {
174 while (try parser.next()) |arg| { 178 while (try parser.next()) |arg| {
175 // arg.param will point to the parameter which matched the argument. 179 // arg.param will point to the parameter which matched the argument.
176 switch (arg.param.id) { 180 switch (arg.param.id) {
177 'h' => debug.warn("Help!\n"), 181 'h' => debug.warn("Help!\n", .{}),
178 'n' => debug.warn("--number = {}\n", arg.value.?), 182 'n' => debug.warn("--number = {}\n", .{ arg.value.? }),
179 183
180 // arg.value == null, if arg.param.takes_value == false. 184 // arg.value == null, if arg.param.takes_value == false.
181 // Otherwise, arg.value is the value passed with the argument, such as "-a=10" 185 // Otherwise, arg.value is the value passed with the argument, such as "-a=10"
182 // or "-a 10". 186 // or "-a 10".
183 'f' => debug.warn("{}\n", arg.value.?), 187 'f' => debug.warn("{}\n", .{ arg.value.? }),
184 else => unreachable, 188 else => unreachable,
185 } 189 }
186 } 190 }
@@ -201,16 +205,15 @@ const std = @import("std");
201const clap = @import("clap"); 205const clap = @import("clap");
202 206
203pub fn main() !void { 207pub fn main() !void {
204 const stderr_file = try std.io.getStdErr(); 208 const stderr_file = std.io.getStdErr();
205 var stderr_out_stream = stderr_file.outStream(); 209 var stderr_out_stream = stderr_file.outStream();
206 const stderr = &stderr_out_stream.stream;
207 210
208 // clap.help is a function that can print a simple help message, given a 211 // clap.help is a function that can print a simple help message, given a
209 // slice of Param(Help). There is also a helpEx, which can print a 212 // slice of Param(Help). There is also a helpEx, which can print a
210 // help message for any Param, but it is more verbose to call. 213 // help message for any Param, but it is more verbose to call.
211 try clap.help( 214 try clap.help(
212 stderr, 215 stderr_out_stream,
213 comptime [_]clap.Param(clap.Help){ 216 comptime &[_]clap.Param(clap.Help){
214 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, 217 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable,
215 clap.parseParam("-v, --version Output version information and exit.") catch unreachable, 218 clap.parseParam("-v, --version Output version information and exit.") catch unreachable,
216 }, 219 },
@@ -243,16 +246,14 @@ const std = @import("std");
243const clap = @import("clap"); 246const clap = @import("clap");
244 247
245pub fn main() !void { 248pub fn main() !void {
246 const stderr_file = try std.io.getStdErr(); 249 const stderr = std.io.getStdErr().outStream();
247 var stderr_out_stream = stderr_file.outStream();
248 const stderr = &stderr_out_stream.stream;
249 250
250 // clap.usage is a function that can print a simple usage message, given a 251 // clap.usage is a function that can print a simple usage message, given a
251 // slice of Param(Help). There is also a usageEx, which can print a 252 // slice of Param(Help). There is also a usageEx, which can print a
252 // usage message for any Param, but it is more verbose to call. 253 // usage message for any Param, but it is more verbose to call.
253 try clap.usage( 254 try clap.usage(
254 stderr, 255 stderr,
255 comptime [_]clap.Param(clap.Help){ 256 comptime &[_]clap.Param(clap.Help){
256 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, 257 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable,
257 clap.parseParam("-v, --version Output version information and exit.") catch unreachable, 258 clap.parseParam("-v, --version Output version information and exit.") catch unreachable,
258 clap.parseParam(" --value <N> Output version information and exit.") catch unreachable, 259 clap.parseParam(" --value <N> Output version information and exit.") catch unreachable,
diff --git a/build.zig b/build.zig
index e65df7f..f468fb6 100644
--- a/build.zig
+++ b/build.zig
@@ -7,7 +7,7 @@ const Builder = std.build.Builder;
7pub fn build(b: *Builder) void { 7pub fn build(b: *Builder) void {
8 const mode = b.standardReleaseOptions(); 8 const mode = b.standardReleaseOptions();
9 9
10 const fmt_step = b.addFmt([_][]const u8{ 10 const fmt_step = b.addFmt(&[_][]const u8{
11 "build.zig", 11 "build.zig",
12 "clap", 12 "clap",
13 }); 13 });
@@ -41,7 +41,7 @@ pub fn build(b: *Builder) void {
41 example_step.dependOn(&example.step); 41 example_step.dependOn(&example.step);
42 } 42 }
43 43
44 const readme_step = b.step("test", "Remake README."); 44 const readme_step = b.step("readme", "Remake README.");
45 const readme = readMeStep(b); 45 const readme = readMeStep(b);
46 readme.dependOn(example_step); 46 readme.dependOn(example_step);
47 readme_step.dependOn(readme); 47 readme_step.dependOn(readme);
@@ -59,17 +59,16 @@ fn readMeStep(b: *Builder) *std.build.Step {
59 s.* = std.build.Step.init("ReadMeStep", b.allocator, struct { 59 s.* = std.build.Step.init("ReadMeStep", b.allocator, struct {
60 fn make(step: *std.build.Step) anyerror!void { 60 fn make(step: *std.build.Step) anyerror!void {
61 @setEvalBranchQuota(10000); 61 @setEvalBranchQuota(10000);
62 const file = try std.fs.File.openWrite("README.md"); 62 const file = try std.fs.cwd().createFile("README.md", .{});
63 const stream = &file.outStream().stream; 63 const stream = &file.outStream();
64 try stream.print( 64 try stream.print(@embedFile("example/README.md.template"), .{
65 @embedFile("example/README.md.template"),
66 @embedFile("example/simple.zig"), 65 @embedFile("example/simple.zig"),
67 @embedFile("example/simple-error.zig"), 66 @embedFile("example/simple-error.zig"),
68 @embedFile("example/comptime-clap.zig"), 67 @embedFile("example/comptime-clap.zig"),
69 @embedFile("example/streaming-clap.zig"), 68 @embedFile("example/streaming-clap.zig"),
70 @embedFile("example/help.zig"), 69 @embedFile("example/help.zig"),
71 @embedFile("example/usage.zig"), 70 @embedFile("example/usage.zig"),
72 ); 71 });
73 } 72 }
74 }.make); 73 }.make);
75 return s; 74 return s;
diff --git a/clap.zig b/clap.zig
index 40e76f4..ff423cc 100644
--- a/clap.zig
+++ b/clap.zig
@@ -57,10 +57,14 @@ pub fn Param(comptime Id: type) type {
57/// Takes a string and parses it to a Param(Help). 57/// Takes a string and parses it to a Param(Help).
58/// This is the reverse of 'help' but for at single parameter only. 58/// This is the reverse of 'help' but for at single parameter only.
59pub fn parseParam(line: []const u8) !Param(Help) { 59pub fn parseParam(line: []const u8) !Param(Help) {
60 var z: usize = 0;
60 var res = Param(Help){ 61 var res = Param(Help){
61 .id = Help{ 62 .id = Help{
62 .msg = line[0..0], 63 // For testing, i want to be able to easily compare slices just by pointer,
63 .value = line[0..0], 64 // so I slice by a runtime value here, so that zig does not optimize this
65 // out. Maybe I should write the test better, geeh.
66 .msg = line[z..z],
67 .value = line[z..z],
64 }, 68 },
65 }; 69 };
66 70
@@ -119,6 +123,7 @@ pub fn parseParam(line: []const u8) !Param(Help) {
119} 123}
120 124
121test "parseParam" { 125test "parseParam" {
126 var z: usize = 0;
122 var text: []const u8 = "-s, --long <value> Help text"; 127 var text: []const u8 = "-s, --long <value> Help text";
123 testing.expectEqual(Param(Help){ 128 testing.expectEqual(Param(Help){
124 .id = Help{ 129 .id = Help{
@@ -162,7 +167,7 @@ test "parseParam" {
162 testing.expectEqual(Param(Help){ 167 testing.expectEqual(Param(Help){
163 .id = Help{ 168 .id = Help{
164 .msg = find(text, "Help text"), 169 .msg = find(text, "Help text"),
165 .value = text[0..0], 170 .value = text[z..z],
166 }, 171 },
167 .names = Names{ 172 .names = Names{
168 .short = 's', 173 .short = 's',
@@ -175,7 +180,7 @@ test "parseParam" {
175 testing.expectEqual(Param(Help){ 180 testing.expectEqual(Param(Help){
176 .id = Help{ 181 .id = Help{
177 .msg = find(text, "Help text"), 182 .msg = find(text, "Help text"),
178 .value = text[0..0], 183 .value = text[z..z],
179 }, 184 },
180 .names = Names{ 185 .names = Names{
181 .short = 's', 186 .short = 's',
@@ -188,7 +193,7 @@ test "parseParam" {
188 testing.expectEqual(Param(Help){ 193 testing.expectEqual(Param(Help){
189 .id = Help{ 194 .id = Help{
190 .msg = find(text, "Help text"), 195 .msg = find(text, "Help text"),
191 .value = text[0..0], 196 .value = text[z..z],
192 }, 197 },
193 .names = Names{ 198 .names = Names{
194 .short = null, 199 .short = null,
@@ -276,14 +281,14 @@ pub fn helpFull(
276 params: []const Param(Id), 281 params: []const Param(Id),
277 comptime Error: type, 282 comptime Error: type,
278 context: var, 283 context: var,
279 helpText: fn (@typeOf(context), Param(Id)) Error![]const u8, 284 helpText: fn (@TypeOf(context), Param(Id)) Error![]const u8,
280 valueText: fn (@typeOf(context), Param(Id)) Error![]const u8, 285 valueText: fn (@TypeOf(context), Param(Id)) Error![]const u8,
281) !void { 286) !void {
282 const max_spacing = blk: { 287 const max_spacing = blk: {
283 var res: usize = 0; 288 var res: usize = 0;
284 for (params) |param| { 289 for (params) |param| {
285 var counting_stream = io.CountingOutStream(io.NullOutStream.Error).init(io.null_out_stream); 290 var counting_stream = io.countingOutStream(io.null_out_stream);
286 try printParam(&counting_stream.stream, Id, param, Error, context, valueText); 291 try printParam(counting_stream.outStream(), Id, param, Error, context, valueText);
287 if (res < counting_stream.bytes_written) 292 if (res < counting_stream.bytes_written)
288 res = counting_stream.bytes_written; 293 res = counting_stream.bytes_written;
289 } 294 }
@@ -295,11 +300,11 @@ pub fn helpFull(
295 if (param.names.short == null and param.names.long == null) 300 if (param.names.short == null and param.names.long == null)
296 continue; 301 continue;
297 302
298 var counting_stream = io.CountingOutStream(@typeOf(stream.*).Error).init(stream); 303 var counting_stream = io.countingOutStream(stream);
299 try stream.print("\t"); 304 try stream.print("\t", .{});
300 try printParam(&counting_stream.stream, Id, param, Error, context, valueText); 305 try printParam(counting_stream.outStream(), Id, param, Error, context, valueText);
301 try stream.writeByteNTimes(' ', max_spacing - counting_stream.bytes_written); 306 try stream.writeByteNTimes(' ', max_spacing - counting_stream.bytes_written);
302 try stream.print("\t{}\n", try helpText(context, param)); 307 try stream.print("\t{}\n", .{try helpText(context, param)});
303 } 308 }
304} 309}
305 310
@@ -309,24 +314,24 @@ fn printParam(
309 param: Param(Id), 314 param: Param(Id),
310 comptime Error: type, 315 comptime Error: type,
311 context: var, 316 context: var,
312 valueText: fn (@typeOf(context), Param(Id)) Error![]const u8, 317 valueText: fn (@TypeOf(context), Param(Id)) Error![]const u8,
313) @typeOf(stream.*).Error!void { 318) !void {
314 if (param.names.short) |s| { 319 if (param.names.short) |s| {
315 try stream.print("-{c}", s); 320 try stream.print("-{c}", .{s});
316 } else { 321 } else {
317 try stream.print(" "); 322 try stream.print(" ", .{});
318 } 323 }
319 if (param.names.long) |l| { 324 if (param.names.long) |l| {
320 if (param.names.short) |_| { 325 if (param.names.short) |_| {
321 try stream.print(", "); 326 try stream.print(", ", .{});
322 } else { 327 } else {
323 try stream.print(" "); 328 try stream.print(" ", .{});
324 } 329 }
325 330
326 try stream.print("--{}", l); 331 try stream.print("--{}", .{l});
327 } 332 }
328 if (param.takes_value) 333 if (param.takes_value)
329 try stream.print(" <{}>", valueText(context, param)); 334 try stream.print(" <{}>", .{valueText(context, param)});
330} 335}
331 336
332/// A wrapper around helpFull for simple helpText and valueText functions that 337/// A wrapper around helpFull for simple helpText and valueText functions that
@@ -385,10 +390,12 @@ fn getValueSimple(param: Param(Help)) []const u8 {
385 390
386test "clap.help" { 391test "clap.help" {
387 var buf: [1024]u8 = undefined; 392 var buf: [1024]u8 = undefined;
388 var slice_stream = io.SliceOutStream.init(buf[0..]); 393 var slice_stream = io.fixedBufferStream(&buf);
394
395 @setEvalBranchQuota(10000);
389 try help( 396 try help(
390 &slice_stream.stream, 397 slice_stream.outStream(),
391 comptime [_]Param(Help){ 398 comptime &[_]Param(Help){
392 parseParam("-a Short flag. ") catch unreachable, 399 parseParam("-a Short flag. ") catch unreachable,
393 parseParam("-b <V1> Short option.") catch unreachable, 400 parseParam("-b <V1> Short option.") catch unreachable,
394 parseParam("--aa Long flag. ") catch unreachable, 401 parseParam("--aa Long flag. ") catch unreachable,
@@ -414,18 +421,18 @@ test "clap.help" {
414 421
415 const actual = slice_stream.getWritten(); 422 const actual = slice_stream.getWritten();
416 if (!mem.eql(u8, actual, expected)) { 423 if (!mem.eql(u8, actual, expected)) {
417 debug.warn("\n============ Expected ============\n"); 424 debug.warn("\n============ Expected ============\n", .{});
418 debug.warn("{}", expected); 425 debug.warn("{}", .{expected});
419 debug.warn("============= Actual =============\n"); 426 debug.warn("============= Actual =============\n", .{});
420 debug.warn("{}", actual); 427 debug.warn("{}", .{actual});
421 428
422 var buffer: [1024 * 2]u8 = undefined; 429 var buffer: [1024 * 2]u8 = undefined;
423 var fba = std.heap.FixedBufferAllocator.init(&buffer); 430 var fba = std.heap.FixedBufferAllocator.init(&buffer);
424 431
425 debug.warn("============ Expected (escaped) ============\n"); 432 debug.warn("============ Expected (escaped) ============\n", .{});
426 debug.warn("{x}\n", expected); 433 debug.warn("{x}\n", .{expected});
427 debug.warn("============ Actual (escaped) ============\n"); 434 debug.warn("============ Actual (escaped) ============\n", .{});
428 debug.warn("{x}\n", actual); 435 debug.warn("{x}\n", .{actual});
429 testing.expect(false); 436 testing.expect(false);
430 } 437 }
431} 438}
@@ -441,20 +448,21 @@ pub fn usageFull(
441 params: []const Param(Id), 448 params: []const Param(Id),
442 comptime Error: type, 449 comptime Error: type,
443 context: var, 450 context: var,
444 valueText: fn (@typeOf(context), Param(Id)) Error![]const u8, 451 valueText: fn (@TypeOf(context), Param(Id)) Error![]const u8,
445) !void { 452) !void {
446 var cs = io.CountingOutStream(@typeOf(stream.*).Error).init(stream); 453 var cos = io.countingOutStream(stream);
454 const cs = cos.outStream();
447 for (params) |param| { 455 for (params) |param| {
448 const name = param.names.short orelse continue; 456 const name = param.names.short orelse continue;
449 if (param.takes_value) 457 if (param.takes_value)
450 continue; 458 continue;
451 459
452 if (cs.bytes_written == 0) 460 if (cos.bytes_written == 0)
453 try stream.write("[-"); 461 try stream.writeAll("[-");
454 try cs.stream.write([_]u8{name}); 462 try cs.writeByte(name);
455 } 463 }
456 if (cs.bytes_written != 0) 464 if (cos.bytes_written != 0)
457 try cs.stream.write("]"); 465 try cs.writeByte(']');
458 466
459 var positional: ?Param(Id) = null; 467 var positional: ?Param(Id) = null;
460 for (params) |param| { 468 for (params) |param| {
@@ -462,24 +470,27 @@ pub fn usageFull(
462 continue; 470 continue;
463 471
464 const prefix = if (param.names.short) |_| "-" else "--"; 472 const prefix = if (param.names.short) |_| "-" else "--";
465 const name = if (param.names.short) |*s| (*const [1]u8)(s)[0..] else param.names.long orelse { 473
474 // Seems the zig compiler is being a little wierd. I doesn't allow me to write
475 // @as(*const [1]u8, s) VVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
476 const name = if (param.names.short) |*s| @ptrCast([*]const u8, s)[0..1] else param.names.long orelse {
466 positional = param; 477 positional = param;
467 continue; 478 continue;
468 }; 479 };
469 if (cs.bytes_written != 0) 480 if (cos.bytes_written != 0)
470 try cs.stream.write(" "); 481 try cs.writeByte(' ');
471 482
472 try cs.stream.print("[{}{}", prefix, name); 483 try cs.print("[{}{}", .{ prefix, name });
473 if (param.takes_value) 484 if (param.takes_value)
474 try cs.stream.print(" <{}>", try valueText(context, param)); 485 try cs.print(" <{}>", .{try valueText(context, param)});
475 486
476 try cs.stream.write("]"); 487 try cs.writeByte(']');
477 } 488 }
478 489
479 if (positional) |p| { 490 if (positional) |p| {
480 if (cs.bytes_written != 0) 491 if (cos.bytes_written != 0)
481 try cs.stream.write(" "); 492 try cs.writeByte(' ');
482 try cs.stream.print("<{}>", try valueText(context, p)); 493 try cs.print("<{}>", .{try valueText(context, p)});
483 } 494 }
484} 495}
485 496
@@ -516,46 +527,46 @@ pub fn usage(stream: var, params: []const Param(Help)) !void {
516 527
517fn testUsage(expected: []const u8, params: []const Param(Help)) !void { 528fn testUsage(expected: []const u8, params: []const Param(Help)) !void {
518 var buf: [1024]u8 = undefined; 529 var buf: [1024]u8 = undefined;
519 var slice_stream = io.SliceOutStream.init(buf[0..]); 530 var fbs = io.fixedBufferStream(&buf);
520 try usage(&slice_stream.stream, params); 531 try usage(fbs.outStream(), params);
521 532
522 const actual = slice_stream.getWritten(); 533 const actual = fbs.getWritten();
523 if (!mem.eql(u8, actual, expected)) { 534 if (!mem.eql(u8, actual, expected)) {
524 debug.warn("\n============ Expected ============\n"); 535 debug.warn("\n============ Expected ============\n", .{});
525 debug.warn("{}\n", expected); 536 debug.warn("{}\n", .{expected});
526 debug.warn("============= Actual =============\n"); 537 debug.warn("============= Actual =============\n", .{});
527 debug.warn("{}\n", actual); 538 debug.warn("{}\n", .{actual});
528 539
529 var buffer: [1024 * 2]u8 = undefined; 540 var buffer: [1024 * 2]u8 = undefined;
530 var fba = std.heap.FixedBufferAllocator.init(&buffer); 541 var fba = std.heap.FixedBufferAllocator.init(&buffer);
531 542
532 debug.warn("============ Expected (escaped) ============\n"); 543 debug.warn("============ Expected (escaped) ============\n", .{});
533 debug.warn("{x}\n", expected); 544 debug.warn("{x}\n", .{expected});
534 debug.warn("============ Actual (escaped) ============\n"); 545 debug.warn("============ Actual (escaped) ============\n", .{});
535 debug.warn("{x}\n", actual); 546 debug.warn("{x}\n", .{actual});
536 testing.expect(false); 547 testing.expect(false);
537 } 548 }
538} 549}
539 550
540test "usage" { 551test "usage" {
541 @setEvalBranchQuota(100000); 552 @setEvalBranchQuota(100000);
542 try testUsage("[-ab]", comptime [_]Param(Help){ 553 try testUsage("[-ab]", comptime &[_]Param(Help){
543 parseParam("-a") catch unreachable, 554 parseParam("-a") catch unreachable,
544 parseParam("-b") catch unreachable, 555 parseParam("-b") catch unreachable,
545 }); 556 });
546 try testUsage("[-a <value>] [-b <v>]", comptime [_]Param(Help){ 557 try testUsage("[-a <value>] [-b <v>]", comptime &[_]Param(Help){
547 parseParam("-a <value>") catch unreachable, 558 parseParam("-a <value>") catch unreachable,
548 parseParam("-b <v>") catch unreachable, 559 parseParam("-b <v>") catch unreachable,
549 }); 560 });
550 try testUsage("[--a] [--b]", comptime [_]Param(Help){ 561 try testUsage("[--a] [--b]", comptime &[_]Param(Help){
551 parseParam("--a") catch unreachable, 562 parseParam("--a") catch unreachable,
552 parseParam("--b") catch unreachable, 563 parseParam("--b") catch unreachable,
553 }); 564 });
554 try testUsage("[--a <value>] [--b <v>]", comptime [_]Param(Help){ 565 try testUsage("[--a <value>] [--b <v>]", comptime &[_]Param(Help){
555 parseParam("--a <value>") catch unreachable, 566 parseParam("--a <value>") catch unreachable,
556 parseParam("--b <v>") catch unreachable, 567 parseParam("--b <v>") catch unreachable,
557 }); 568 });
558 try testUsage("<file>", comptime [_]Param(Help){ 569 try testUsage("<file>", comptime &[_]Param(Help){
559 Param(Help){ 570 Param(Help){
560 .id = Help{ 571 .id = Help{
561 .value = "file", 572 .value = "file",
@@ -563,7 +574,7 @@ test "usage" {
563 .takes_value = true, 574 .takes_value = true,
564 }, 575 },
565 }); 576 });
566 try testUsage("[-ab] [-c <value>] [-d <v>] [--e] [--f] [--g <value>] [--h <v>] <file>", comptime [_]Param(Help){ 577 try testUsage("[-ab] [-c <value>] [-d <v>] [--e] [--f] [--g <value>] [--h <v>] <file>", comptime &[_]Param(Help){
567 parseParam("-a") catch unreachable, 578 parseParam("-a") catch unreachable,
568 parseParam("-b") catch unreachable, 579 parseParam("-b") catch unreachable,
569 parseParam("-c <value>") catch unreachable, 580 parseParam("-c <value>") catch unreachable,
diff --git a/clap/args.zig b/clap/args.zig
index b699438..0141d86 100644
--- a/clap/args.zig
+++ b/clap/args.zig
@@ -1,6 +1,6 @@
1const builtin = @import("builtin");
2const std = @import("std"); 1const std = @import("std");
3 2
3const builtin = std.builtin;
4const debug = std.debug; 4const debug = std.debug;
5const heap = std.heap; 5const heap = std.heap;
6const mem = std.mem; 6const mem = std.mem;
@@ -33,7 +33,7 @@ pub const SliceIterator = struct {
33}; 33};
34 34
35test "clap.args.SliceIterator" { 35test "clap.args.SliceIterator" {
36 const args = [_][]const u8{ "A", "BB", "CCC" }; 36 const args = &[_][]const u8{ "A", "BB", "CCC" };
37 var iter = SliceIterator{ .args = args }; 37 var iter = SliceIterator{ .args = args };
38 38
39 for (args) |a| { 39 for (args) |a| {
@@ -70,7 +70,7 @@ pub const OsIterator = struct {
70 } 70 }
71 71
72 pub fn next(iter: *OsIterator) Error!?[]const u8 { 72 pub fn next(iter: *OsIterator) Error!?[]const u8 {
73 if (builtin.os == builtin.Os.windows) { 73 if (builtin.os.tag == .windows) {
74 return try iter.args.next(&iter.arena.allocator) orelse return null; 74 return try iter.args.next(&iter.arena.allocator) orelse return null;
75 } else { 75 } else {
76 return iter.args.nextPosix(); 76 return iter.args.nextPosix();
diff --git a/clap/comptime.zig b/clap/comptime.zig
index f5c2762..c25659b 100644
--- a/clap/comptime.zig
+++ b/clap/comptime.zig
@@ -9,7 +9,7 @@ const debug = std.debug;
9pub fn ComptimeClap(comptime Id: type, comptime params: []const clap.Param(Id)) type { 9pub fn ComptimeClap(comptime Id: type, comptime params: []const clap.Param(Id)) type {
10 var flags: usize = 0; 10 var flags: usize = 0;
11 var options: usize = 0; 11 var options: usize = 0;
12 var converted_params: []const clap.Param(usize) = [_]clap.Param(usize){}; 12 var converted_params: []const clap.Param(usize) = &[_]clap.Param(usize){};
13 for (params) |param| { 13 for (params) |param| {
14 var index: usize = 0; 14 var index: usize = 0;
15 if (param.names.long != null or param.names.short != null) { 15 if (param.names.long != null or param.names.short != null) {
@@ -113,7 +113,7 @@ pub fn ComptimeClap(comptime Id: type, comptime params: []const clap.Param(Id))
113} 113}
114 114
115test "clap.comptime.ComptimeClap" { 115test "clap.comptime.ComptimeClap" {
116 const Clap = ComptimeClap(clap.Help, comptime [_]clap.Param(clap.Help){ 116 const Clap = ComptimeClap(clap.Help, comptime &[_]clap.Param(clap.Help){
117 clap.parseParam("-a, --aa ") catch unreachable, 117 clap.parseParam("-a, --aa ") catch unreachable,
118 clap.parseParam("-b, --bb ") catch unreachable, 118 clap.parseParam("-b, --bb ") catch unreachable,
119 clap.parseParam("-c, --cc <V>") catch unreachable, 119 clap.parseParam("-c, --cc <V>") catch unreachable,
@@ -125,7 +125,7 @@ test "clap.comptime.ComptimeClap" {
125 var buf: [1024]u8 = undefined; 125 var buf: [1024]u8 = undefined;
126 var fb_allocator = heap.FixedBufferAllocator.init(buf[0..]); 126 var fb_allocator = heap.FixedBufferAllocator.init(buf[0..]);
127 var iter = clap.args.SliceIterator{ 127 var iter = clap.args.SliceIterator{
128 .args = [_][]const u8{ 128 .args = &[_][]const u8{
129 "-a", "-c", "0", "something", 129 "-a", "-c", "0", "something",
130 }, 130 },
131 }; 131 };
@@ -138,6 +138,6 @@ test "clap.comptime.ComptimeClap" {
138 testing.expect(!args.flag("--bb")); 138 testing.expect(!args.flag("--bb"));
139 testing.expectEqualSlices(u8, "0", args.option("-c").?); 139 testing.expectEqualSlices(u8, "0", args.option("-c").?);
140 testing.expectEqualSlices(u8, "0", args.option("--cc").?); 140 testing.expectEqualSlices(u8, "0", args.option("--cc").?);
141 testing.expectEqual(usize(1), args.positionals().len); 141 testing.expectEqual(@as(usize, 1), args.positionals().len);
142 testing.expectEqualSlices(u8, "something", args.positionals()[0]); 142 testing.expectEqualSlices(u8, "something", args.positionals()[0]);
143} 143}
diff --git a/clap/streaming.zig b/clap/streaming.zig
index fa7ce80..95ee581 100644
--- a/clap/streaming.zig
+++ b/clap/streaming.zig
@@ -170,7 +170,7 @@ fn testNoErr(params: []const clap.Param(u8), args_strings: []const []const u8, r
170 const arg = (c.next() catch unreachable) orelse unreachable; 170 const arg = (c.next() catch unreachable) orelse unreachable;
171 testing.expectEqual(res.param, arg.param); 171 testing.expectEqual(res.param, arg.param);
172 const expected_value = res.value orelse { 172 const expected_value = res.value orelse {
173 testing.expectEqual(@typeOf(arg.value)(null), arg.value); 173 testing.expectEqual(@as(@TypeOf(arg.value), null), arg.value);
174 continue; 174 continue;
175 }; 175 };
176 const actual_value = arg.value orelse unreachable; 176 const actual_value = arg.value orelse unreachable;
@@ -203,13 +203,13 @@ test "clap.streaming.StreamingClap: short params" {
203 const c = &params[2]; 203 const c = &params[2];
204 204
205 testNoErr( 205 testNoErr(
206 params, 206 &params,
207 [_][]const u8{ 207 &[_][]const u8{
208 "-a", "-b", "-ab", "-ba", 208 "-a", "-b", "-ab", "-ba",
209 "-c", "0", "-c=0", "-ac", 209 "-c", "0", "-c=0", "-ac",
210 "0", "-ac=0", 210 "0", "-ac=0",
211 }, 211 },
212 [_]Arg(u8){ 212 &[_]Arg(u8){
213 Arg(u8){ .param = a }, 213 Arg(u8){ .param = a },
214 Arg(u8){ .param = b }, 214 Arg(u8){ .param = b },
215 Arg(u8){ .param = a }, 215 Arg(u8){ .param = a },
@@ -248,13 +248,13 @@ test "clap.streaming.StreamingClap: long params" {
248 const cc = &params[2]; 248 const cc = &params[2];
249 249
250 testNoErr( 250 testNoErr(
251 params, 251 &params,
252 [_][]const u8{ 252 &[_][]const u8{
253 "--aa", "--bb", 253 "--aa", "--bb",
254 "--cc", "0", 254 "--cc", "0",
255 "--cc=0", 255 "--cc=0",
256 }, 256 },
257 [_]Arg(u8){ 257 &[_]Arg(u8){
258 Arg(u8){ .param = aa }, 258 Arg(u8){ .param = aa },
259 Arg(u8){ .param = bb }, 259 Arg(u8){ .param = bb },
260 Arg(u8){ .param = cc, .value = "0" }, 260 Arg(u8){ .param = cc, .value = "0" },
@@ -270,9 +270,9 @@ test "clap.streaming.StreamingClap: positional params" {
270 }}; 270 }};
271 271
272 testNoErr( 272 testNoErr(
273 params, 273 &params,
274 [_][]const u8{ "aa", "bb" }, 274 &[_][]const u8{ "aa", "bb" },
275 [_]Arg(u8){ 275 &[_]Arg(u8){
276 Arg(u8){ .param = &params[0], .value = "aa" }, 276 Arg(u8){ .param = &params[0], .value = "aa" },
277 Arg(u8){ .param = &params[0], .value = "bb" }, 277 Arg(u8){ .param = &params[0], .value = "bb" },
278 }, 278 },
@@ -315,15 +315,15 @@ test "clap.streaming.StreamingClap: all params" {
315 const positional = &params[3]; 315 const positional = &params[3];
316 316
317 testNoErr( 317 testNoErr(
318 params, 318 &params,
319 [_][]const u8{ 319 &[_][]const u8{
320 "-a", "-b", "-ab", "-ba", 320 "-a", "-b", "-ab", "-ba",
321 "-c", "0", "-c=0", "-ac", 321 "-c", "0", "-c=0", "-ac",
322 "0", "-ac=0", "--aa", "--bb", 322 "0", "-ac=0", "--aa", "--bb",
323 "--cc", "0", "--cc=0", "something", 323 "--cc", "0", "--cc=0", "something",
324 "--", "-", 324 "--", "-",
325 }, 325 },
326 [_]Arg(u8){ 326 &[_]Arg(u8){
327 Arg(u8){ .param = aa }, 327 Arg(u8){ .param = aa },
328 Arg(u8){ .param = bb }, 328 Arg(u8){ .param = bb },
329 Arg(u8){ .param = aa }, 329 Arg(u8){ .param = aa },
diff --git a/example/README.md.template b/example/README.md.template
index 5e75d5d..2afbe86 100644
--- a/example/README.md.template
+++ b/example/README.md.template
@@ -2,6 +2,10 @@
2 2
3A simple and easy to use command line argument parser library for Zig. 3A simple and easy to use command line argument parser library for Zig.
4 4
5Looking for a version that works with `zig master`? The `zig-master` branch has
6you covered. It is maintained by people who live at head (not me) and is merged
7into master on every `zig` release.
8
5## Features 9## Features
6 10
7* Short arguments `-a` 11* Short arguments `-a`
diff --git a/example/comptime-clap.zig b/example/comptime-clap.zig
index 4d0ace3..f5c0221 100644
--- a/example/comptime-clap.zig
+++ b/example/comptime-clap.zig
@@ -4,7 +4,7 @@ const clap = @import("clap");
4const debug = std.debug; 4const debug = std.debug;
5 5
6pub fn main() !void { 6pub fn main() !void {
7 const allocator = std.heap.direct_allocator; 7 const allocator = std.heap.page_allocator;
8 8
9 // First we specify what parameters our program can take. 9 // First we specify what parameters our program can take.
10 // We can use `parseParam` to parse a string to a `Param(Help)` 10 // We can use `parseParam` to parse a string to a `Param(Help)`
@@ -22,13 +22,13 @@ pub fn main() !void {
22 defer iter.deinit(); 22 defer iter.deinit();
23 23
24 // Parse the arguments 24 // Parse the arguments
25 var args = try clap.ComptimeClap(clap.Help, params).parse(allocator, clap.args.OsIterator, &iter); 25 var args = try clap.ComptimeClap(clap.Help, &params).parse(allocator, clap.args.OsIterator, &iter);
26 defer args.deinit(); 26 defer args.deinit();
27 27
28 if (args.flag("--help")) 28 if (args.flag("--help"))
29 debug.warn("--help\n"); 29 debug.warn("--help\n", .{});
30 if (args.option("--number")) |n| 30 if (args.option("--number")) |n|
31 debug.warn("--number = {}\n", n); 31 debug.warn("--number = {}\n", .{ n });
32 for (args.positionals()) |pos| 32 for (args.positionals()) |pos|
33 debug.warn("{}\n", pos); 33 debug.warn("{}\n", .{ pos });
34} 34}
diff --git a/example/help.zig b/example/help.zig
index de8a55a..2775177 100644
--- a/example/help.zig
+++ b/example/help.zig
@@ -2,16 +2,15 @@ const std = @import("std");
2const clap = @import("clap"); 2const clap = @import("clap");
3 3
4pub fn main() !void { 4pub fn main() !void {
5 const stderr_file = try std.io.getStdErr(); 5 const stderr_file = std.io.getStdErr();
6 var stderr_out_stream = stderr_file.outStream(); 6 var stderr_out_stream = stderr_file.outStream();
7 const stderr = &stderr_out_stream.stream;
8 7
9 // clap.help is a function that can print a simple help message, given a 8 // clap.help is a function that can print a simple help message, given a
10 // slice of Param(Help). There is also a helpEx, which can print a 9 // slice of Param(Help). There is also a helpEx, which can print a
11 // help message for any Param, but it is more verbose to call. 10 // help message for any Param, but it is more verbose to call.
12 try clap.help( 11 try clap.help(
13 stderr, 12 stderr_out_stream,
14 comptime [_]clap.Param(clap.Help){ 13 comptime &[_]clap.Param(clap.Help){
15 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, 14 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable,
16 clap.parseParam("-v, --version Output version information and exit.") catch unreachable, 15 clap.parseParam("-v, --version Output version information and exit.") catch unreachable,
17 }, 16 },
diff --git a/example/simple-error.zig b/example/simple-error.zig
index fc72a03..2c403fc 100644
--- a/example/simple-error.zig
+++ b/example/simple-error.zig
@@ -8,7 +8,7 @@ pub fn main() !void {
8 clap.parseParam("-h, --help Display this help and exit.") catch unreachable, 8 clap.parseParam("-h, --help Display this help and exit.") catch unreachable,
9 }; 9 };
10 10
11 var args = try clap.parse(clap.Help, params, std.heap.direct_allocator); 11 var args = try clap.parse(clap.Help, &params, std.heap.direct_allocator);
12 defer args.deinit(); 12 defer args.deinit();
13 13
14 _ = args.flag("--helps"); 14 _ = args.flag("--helps");
diff --git a/example/simple.zig b/example/simple.zig
index f791447..d546223 100644
--- a/example/simple.zig
+++ b/example/simple.zig
@@ -14,13 +14,13 @@ pub fn main() !void {
14 }, 14 },
15 }; 15 };
16 16
17 var args = try clap.parse(clap.Help, params, std.heap.direct_allocator); 17 var args = try clap.parse(clap.Help, &params, std.heap.page_allocator);
18 defer args.deinit(); 18 defer args.deinit();
19 19
20 if (args.flag("--help")) 20 if (args.flag("--help"))
21 debug.warn("--help\n"); 21 debug.warn("--help\n", .{});
22 if (args.option("--number")) |n| 22 if (args.option("--number")) |n|
23 debug.warn("--number = {}\n", n); 23 debug.warn("--number = {}\n", .{ n });
24 for (args.positionals()) |pos| 24 for (args.positionals()) |pos|
25 debug.warn("{}\n", pos); 25 debug.warn("{}\n", .{ pos });
26} 26}
diff --git a/example/streaming-clap.zig b/example/streaming-clap.zig
index 0361d46..4cc43d1 100644
--- a/example/streaming-clap.zig
+++ b/example/streaming-clap.zig
@@ -4,7 +4,7 @@ const clap = @import("clap");
4const debug = std.debug; 4const debug = std.debug;
5 5
6pub fn main() !void { 6pub fn main() !void {
7 const allocator = std.heap.direct_allocator; 7 const allocator = std.heap.page_allocator;
8 8
9 // First we specify what parameters our program can take. 9 // First we specify what parameters our program can take.
10 const params = [_]clap.Param(u8){ 10 const params = [_]clap.Param(u8){
@@ -30,7 +30,7 @@ pub fn main() !void {
30 30
31 // Initialize our streaming parser. 31 // Initialize our streaming parser.
32 var parser = clap.StreamingClap(u8, clap.args.OsIterator){ 32 var parser = clap.StreamingClap(u8, clap.args.OsIterator){
33 .params = params, 33 .params = &params,
34 .iter = &iter, 34 .iter = &iter,
35 }; 35 };
36 36
@@ -38,13 +38,13 @@ pub fn main() !void {
38 while (try parser.next()) |arg| { 38 while (try parser.next()) |arg| {
39 // arg.param will point to the parameter which matched the argument. 39 // arg.param will point to the parameter which matched the argument.
40 switch (arg.param.id) { 40 switch (arg.param.id) {
41 'h' => debug.warn("Help!\n"), 41 'h' => debug.warn("Help!\n", .{}),
42 'n' => debug.warn("--number = {}\n", arg.value.?), 42 'n' => debug.warn("--number = {}\n", .{ arg.value.? }),
43 43
44 // arg.value == null, if arg.param.takes_value == false. 44 // arg.value == null, if arg.param.takes_value == false.
45 // Otherwise, arg.value is the value passed with the argument, such as "-a=10" 45 // Otherwise, arg.value is the value passed with the argument, such as "-a=10"
46 // or "-a 10". 46 // or "-a 10".
47 'f' => debug.warn("{}\n", arg.value.?), 47 'f' => debug.warn("{}\n", .{ arg.value.? }),
48 else => unreachable, 48 else => unreachable,
49 } 49 }
50 } 50 }
diff --git a/example/usage.zig b/example/usage.zig
index 734d741..25e1a34 100644
--- a/example/usage.zig
+++ b/example/usage.zig
@@ -2,16 +2,14 @@ const std = @import("std");
2const clap = @import("clap"); 2const clap = @import("clap");
3 3
4pub fn main() !void { 4pub fn main() !void {
5 const stderr_file = try std.io.getStdErr(); 5 const stderr = std.io.getStdErr().outStream();
6 var stderr_out_stream = stderr_file.outStream();
7 const stderr = &stderr_out_stream.stream;
8 6
9 // clap.usage is a function that can print a simple usage message, given a 7 // clap.usage is a function that can print a simple usage message, given a
10 // slice of Param(Help). There is also a usageEx, which can print a 8 // slice of Param(Help). There is also a usageEx, which can print a
11 // usage message for any Param, but it is more verbose to call. 9 // usage message for any Param, but it is more verbose to call.
12 try clap.usage( 10 try clap.usage(
13 stderr, 11 stderr,
14 comptime [_]clap.Param(clap.Help){ 12 comptime &[_]clap.Param(clap.Help){
15 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, 13 clap.parseParam("-h, --help Display this help and exit. ") catch unreachable,
16 clap.parseParam("-v, --version Output version information and exit.") catch unreachable, 14 clap.parseParam("-v, --version Output version information and exit.") catch unreachable,
17 clap.parseParam(" --value <N> Output version information and exit.") catch unreachable, 15 clap.parseParam(" --value <N> Output version information and exit.") catch unreachable,