summaryrefslogtreecommitdiff
path: root/clap.zig
diff options
context:
space:
mode:
authorGravatar Jimmi Holst Christensen2020-03-05 23:24:36 +0100
committerGravatar Jimmi Holst Christensen2020-03-05 23:24:36 +0100
commitcc056cf4232721b62b76428d1ada447eecd98421 (patch)
tree56e859d0f91b372c50d6b35818877a4476ded5a1 /clap.zig
parentAdd clap.parse as the simplest way of using the lib (diff)
downloadzig-clap-cc056cf4232721b62b76428d1ada447eecd98421.tar.gz
zig-clap-cc056cf4232721b62b76428d1ada447eecd98421.tar.xz
zig-clap-cc056cf4232721b62b76428d1ada447eecd98421.zip
Add clap.usage
Diffstat (limited to 'clap.zig')
-rw-r--r--clap.zig193
1 files changed, 172 insertions, 21 deletions
diff --git a/clap.zig b/clap.zig
index e0d20e3..40e76f4 100644
--- a/clap.zig
+++ b/clap.zig
@@ -265,25 +265,25 @@ pub fn parse(
265} 265}
266 266
267/// Will print a help message in the following format: 267/// Will print a help message in the following format:
268/// -s, --long <value_text> help_text 268/// -s, --long <valueText> helpText
269/// -s, help_text 269/// -s, helpText
270/// -s <value_text> help_text 270/// -s <valueText> helpText
271/// --long help_text 271/// --long helpText
272/// --long <value_text> help_text 272/// --long <valueText> helpText
273pub fn helpFull( 273pub fn helpFull(
274 stream: var, 274 stream: var,
275 comptime Id: type, 275 comptime Id: type,
276 params: []const Param(Id), 276 params: []const Param(Id),
277 comptime Error: type, 277 comptime Error: type,
278 context: var, 278 context: var,
279 help_text: fn (@typeOf(context), Param(Id)) Error![]const u8, 279 helpText: fn (@typeOf(context), Param(Id)) Error![]const u8,
280 value_text: fn (@typeOf(context), Param(Id)) Error![]const u8, 280 valueText: fn (@typeOf(context), Param(Id)) Error![]const u8,
281) !void { 281) !void {
282 const max_spacing = blk: { 282 const max_spacing = blk: {
283 var res: usize = 0; 283 var res: usize = 0;
284 for (params) |param| { 284 for (params) |param| {
285 var counting_stream = io.CountingOutStream(io.NullOutStream.Error).init(io.null_out_stream); 285 var counting_stream = io.CountingOutStream(io.NullOutStream.Error).init(io.null_out_stream);
286 try printParam(&counting_stream.stream, Id, param, Error, context, value_text); 286 try printParam(&counting_stream.stream, Id, param, Error, context, valueText);
287 if (res < counting_stream.bytes_written) 287 if (res < counting_stream.bytes_written)
288 res = counting_stream.bytes_written; 288 res = counting_stream.bytes_written;
289 } 289 }
@@ -297,9 +297,9 @@ pub fn helpFull(
297 297
298 var counting_stream = io.CountingOutStream(@typeOf(stream.*).Error).init(stream); 298 var counting_stream = io.CountingOutStream(@typeOf(stream.*).Error).init(stream);
299 try stream.print("\t"); 299 try stream.print("\t");
300 try printParam(&counting_stream.stream, Id, param, Error, context, value_text); 300 try printParam(&counting_stream.stream, Id, param, Error, context, valueText);
301 try stream.writeByteNTimes(' ', max_spacing - counting_stream.bytes_written); 301 try stream.writeByteNTimes(' ', max_spacing - counting_stream.bytes_written);
302 try stream.print("\t{}\n", try help_text(context, param)); 302 try stream.print("\t{}\n", try helpText(context, param));
303 } 303 }
304} 304}
305 305
@@ -309,7 +309,7 @@ fn printParam(
309 param: Param(Id), 309 param: Param(Id),
310 comptime Error: type, 310 comptime Error: type,
311 context: var, 311 context: var,
312 value_text: fn (@typeOf(context), Param(Id)) Error![]const u8, 312 valueText: fn (@typeOf(context), Param(Id)) Error![]const u8,
313) @typeOf(stream.*).Error!void { 313) @typeOf(stream.*).Error!void {
314 if (param.names.short) |s| { 314 if (param.names.short) |s| {
315 try stream.print("-{c}", s); 315 try stream.print("-{c}", s);
@@ -326,28 +326,28 @@ fn printParam(
326 try stream.print("--{}", l); 326 try stream.print("--{}", l);
327 } 327 }
328 if (param.takes_value) 328 if (param.takes_value)
329 try stream.print(" <{}>", value_text(context, param)); 329 try stream.print(" <{}>", valueText(context, param));
330} 330}
331 331
332/// A wrapper around helpFull for simple help_text and value_text functions that 332/// A wrapper around helpFull for simple helpText and valueText functions that
333/// cant return an error or take a context. 333/// cant return an error or take a context.
334pub fn helpEx( 334pub fn helpEx(
335 stream: var, 335 stream: var,
336 comptime Id: type, 336 comptime Id: type,
337 params: []const Param(Id), 337 params: []const Param(Id),
338 help_text: fn (Param(Id)) []const u8, 338 helpText: fn (Param(Id)) []const u8,
339 value_text: fn (Param(Id)) []const u8, 339 valueText: fn (Param(Id)) []const u8,
340) !void { 340) !void {
341 const Context = struct { 341 const Context = struct {
342 help_text: fn (Param(Id)) []const u8, 342 helpText: fn (Param(Id)) []const u8,
343 value_text: fn (Param(Id)) []const u8, 343 valueText: fn (Param(Id)) []const u8,
344 344
345 pub fn help(c: @This(), p: Param(Id)) error{}![]const u8 { 345 pub fn help(c: @This(), p: Param(Id)) error{}![]const u8 {
346 return c.help_text(p); 346 return c.helpText(p);
347 } 347 }
348 348
349 pub fn value(c: @This(), p: Param(Id)) error{}![]const u8 { 349 pub fn value(c: @This(), p: Param(Id)) error{}![]const u8 {
350 return c.value_text(p); 350 return c.valueText(p);
351 } 351 }
352 }; 352 };
353 353
@@ -357,8 +357,8 @@ pub fn helpEx(
357 params, 357 params,
358 error{}, 358 error{},
359 Context{ 359 Context{
360 .help_text = help_text, 360 .helpText = helpText,
361 .value_text = value_text, 361 .valueText = valueText,
362 }, 362 },
363 Context.help, 363 Context.help,
364 Context.value, 364 Context.value,
@@ -429,3 +429,154 @@ test "clap.help" {
429 testing.expect(false); 429 testing.expect(false);
430 } 430 }
431} 431}
432
433/// Will print a usage message in the following format:
434/// [-abc] [--longa] [-d <valueText>] [--longb <valueText>] <valueText>
435///
436/// First all none value taking parameters, which have a short name are
437/// printed, then non positional parameters and finally the positinal.
438pub fn usageFull(
439 stream: var,
440 comptime Id: type,
441 params: []const Param(Id),
442 comptime Error: type,
443 context: var,
444 valueText: fn (@typeOf(context), Param(Id)) Error![]const u8,
445) !void {
446 var cs = io.CountingOutStream(@typeOf(stream.*).Error).init(stream);
447 for (params) |param| {
448 const name = param.names.short orelse continue;
449 if (param.takes_value)
450 continue;
451
452 if (cs.bytes_written == 0)
453 try stream.write("[-");
454 try cs.stream.write([_]u8{name});
455 }
456 if (cs.bytes_written != 0)
457 try cs.stream.write("]");
458
459 var positional: ?Param(Id) = null;
460 for (params) |param| {
461 if (!param.takes_value and param.names.short != null)
462 continue;
463
464 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 {
466 positional = param;
467 continue;
468 };
469 if (cs.bytes_written != 0)
470 try cs.stream.write(" ");
471
472 try cs.stream.print("[{}{}", prefix, name);
473 if (param.takes_value)
474 try cs.stream.print(" <{}>", try valueText(context, param));
475
476 try cs.stream.write("]");
477 }
478
479 if (positional) |p| {
480 if (cs.bytes_written != 0)
481 try cs.stream.write(" ");
482 try cs.stream.print("<{}>", try valueText(context, p));
483 }
484}
485
486/// A wrapper around usageFull for a simple valueText functions that
487/// cant return an error or take a context.
488pub fn usageEx(
489 stream: var,
490 comptime Id: type,
491 params: []const Param(Id),
492 valueText: fn (Param(Id)) []const u8,
493) !void {
494 const Context = struct {
495 valueText: fn (Param(Id)) []const u8,
496
497 pub fn value(c: @This(), p: Param(Id)) error{}![]const u8 {
498 return c.valueText(p);
499 }
500 };
501
502 return usageFull(
503 stream,
504 Id,
505 params,
506 error{},
507 Context{ .valueText = valueText },
508 Context.value,
509 );
510}
511
512/// A wrapper around usageEx that takes a Param(Help).
513pub fn usage(stream: var, params: []const Param(Help)) !void {
514 try usageEx(stream, Help, params, getValueSimple);
515}
516
517fn testUsage(expected: []const u8, params: []const Param(Help)) !void {
518 var buf: [1024]u8 = undefined;
519 var slice_stream = io.SliceOutStream.init(buf[0..]);
520 try usage(&slice_stream.stream, params);
521
522 const actual = slice_stream.getWritten();
523 if (!mem.eql(u8, actual, expected)) {
524 debug.warn("\n============ Expected ============\n");
525 debug.warn("{}\n", expected);
526 debug.warn("============= Actual =============\n");
527 debug.warn("{}\n", actual);
528
529 var buffer: [1024 * 2]u8 = undefined;
530 var fba = std.heap.FixedBufferAllocator.init(&buffer);
531
532 debug.warn("============ Expected (escaped) ============\n");
533 debug.warn("{x}\n", expected);
534 debug.warn("============ Actual (escaped) ============\n");
535 debug.warn("{x}\n", actual);
536 testing.expect(false);
537 }
538}
539
540test "usage" {
541 @setEvalBranchQuota(100000);
542 try testUsage("[-ab]", comptime [_]Param(Help){
543 parseParam("-a") catch unreachable,
544 parseParam("-b") catch unreachable,
545 });
546 try testUsage("[-a <value>] [-b <v>]", comptime [_]Param(Help){
547 parseParam("-a <value>") catch unreachable,
548 parseParam("-b <v>") catch unreachable,
549 });
550 try testUsage("[--a] [--b]", comptime [_]Param(Help){
551 parseParam("--a") catch unreachable,
552 parseParam("--b") catch unreachable,
553 });
554 try testUsage("[--a <value>] [--b <v>]", comptime [_]Param(Help){
555 parseParam("--a <value>") catch unreachable,
556 parseParam("--b <v>") catch unreachable,
557 });
558 try testUsage("<file>", comptime [_]Param(Help){
559 Param(Help){
560 .id = Help{
561 .value = "file",
562 },
563 .takes_value = true,
564 },
565 });
566 try testUsage("[-ab] [-c <value>] [-d <v>] [--e] [--f] [--g <value>] [--h <v>] <file>", comptime [_]Param(Help){
567 parseParam("-a") catch unreachable,
568 parseParam("-b") catch unreachable,
569 parseParam("-c <value>") catch unreachable,
570 parseParam("-d <v>") catch unreachable,
571 parseParam("--e") catch unreachable,
572 parseParam("--f") catch unreachable,
573 parseParam("--g <value>") catch unreachable,
574 parseParam("--h <v>") catch unreachable,
575 Param(Help){
576 .id = Help{
577 .value = "file",
578 },
579 .takes_value = true,
580 },
581 });
582}