summaryrefslogtreecommitdiff
path: root/clap.zig
diff options
context:
space:
mode:
Diffstat (limited to 'clap.zig')
-rw-r--r--clap.zig128
1 files changed, 62 insertions, 66 deletions
diff --git a/clap.zig b/clap.zig
index b666f56..3863087 100644
--- a/clap.zig
+++ b/clap.zig
@@ -542,7 +542,7 @@ pub const Diagnostic = struct {
542 542
543 /// Default diagnostics reporter when all you want is English with no colors. 543 /// Default diagnostics reporter when all you want is English with no colors.
544 /// Use this as a reference for implementing your own if needed. 544 /// Use this as a reference for implementing your own if needed.
545 pub fn report(diag: Diagnostic, stream: anytype, err: anyerror) !void { 545 pub fn report(diag: Diagnostic, stream: *std.Io.Writer, err: anyerror) !void {
546 var longest = diag.name.longest(); 546 var longest = diag.name.longest();
547 if (longest.kind == .positional) 547 if (longest.kind == .positional)
548 longest.name = diag.arg; 548 longest.name = diag.arg;
@@ -567,9 +567,9 @@ pub const Diagnostic = struct {
567 567
568fn testDiag(diag: Diagnostic, err: anyerror, expected: []const u8) !void { 568fn testDiag(diag: Diagnostic, err: anyerror, expected: []const u8) !void {
569 var buf: [1024]u8 = undefined; 569 var buf: [1024]u8 = undefined;
570 var slice_stream = std.io.fixedBufferStream(&buf); 570 var writer = std.Io.Writer.fixed(&buf);
571 diag.report(slice_stream.writer(), err) catch unreachable; 571 diag.report(&writer, err) catch unreachable;
572 try std.testing.expectEqualStrings(expected, slice_stream.getWritten()); 572 try std.testing.expectEqualStrings(expected, writer.buffered());
573} 573}
574 574
575test "Diagnostic.report" { 575test "Diagnostic.report" {
@@ -1263,9 +1263,9 @@ fn testErr(
1263 .diagnostic = &diag, 1263 .diagnostic = &diag,
1264 }) catch |err| { 1264 }) catch |err| {
1265 var buf: [1024]u8 = undefined; 1265 var buf: [1024]u8 = undefined;
1266 var fbs = std.io.fixedBufferStream(&buf); 1266 var writer = std.Io.Writer.fixed(&buf);
1267 diag.report(fbs.writer(), err) catch return error.TestFailed; 1267 diag.report(&writer, err) catch return error.TestFailed;
1268 try std.testing.expectEqualStrings(expected, fbs.getWritten()); 1268 try std.testing.expectEqualStrings(expected, writer.buffered());
1269 return; 1269 return;
1270 }; 1270 };
1271 1271
@@ -1366,7 +1366,7 @@ pub const HelpOptions = struct {
1366/// The output can be constumized with the `opt` parameter. For default formatting `.{}` can 1366/// The output can be constumized with the `opt` parameter. For default formatting `.{}` can
1367/// be passed. 1367/// be passed.
1368pub fn help( 1368pub fn help(
1369 writer: anytype, 1369 writer: *std.Io.Writer,
1370 comptime Id: type, 1370 comptime Id: type,
1371 params: []const Param(Id), 1371 params: []const Param(Id),
1372 opt: HelpOptions, 1372 opt: HelpOptions,
@@ -1374,8 +1374,9 @@ pub fn help(
1374 const max_spacing = blk: { 1374 const max_spacing = blk: {
1375 var res: usize = 0; 1375 var res: usize = 0;
1376 for (params) |param| { 1376 for (params) |param| {
1377 var cs = ccw.codepointCountingWriter(std.io.null_writer); 1377 var discarding = std.Io.Writer.Discarding.init(&.{});
1378 try printParam(cs.writer(), Id, param); 1378 var cs = ccw.CodepointCountingWriter.init(&discarding.writer);
1379 try printParam(&cs.interface, Id, param);
1379 if (res < cs.codepoints_written) 1380 if (res < cs.codepoints_written)
1380 res = @intCast(cs.codepoints_written); 1381 res = @intCast(cs.codepoints_written);
1381 } 1382 }
@@ -1390,16 +1391,15 @@ pub fn help(
1390 var first_parameter: bool = true; 1391 var first_parameter: bool = true;
1391 for (params) |param| { 1392 for (params) |param| {
1392 if (!first_parameter) 1393 if (!first_parameter)
1393 try writer.writeByteNTimes('\n', opt.spacing_between_parameters); 1394 try writer.splatByteAll('\n', opt.spacing_between_parameters);
1394 1395
1395 first_parameter = false; 1396 first_parameter = false;
1396 try writer.writeByteNTimes(' ', opt.indent); 1397 try writer.splatByteAll(' ', opt.indent);
1397 1398
1398 var cw = ccw.codepointCountingWriter(writer); 1399 var cw = ccw.CodepointCountingWriter.init(writer);
1399 try printParam(cw.writer(), Id, param); 1400 try printParam(&cw.interface, Id, param);
1400 1401
1401 const Writer = DescriptionWriter(@TypeOf(writer)); 1402 var description_writer = DescriptionWriter{
1402 var description_writer = Writer{
1403 .underlying_writer = writer, 1403 .underlying_writer = writer,
1404 .indentation = description_indentation, 1404 .indentation = description_indentation,
1405 .printed_chars = @intCast(cw.codepoints_written), 1405 .printed_chars = @intCast(cw.codepoints_written),
@@ -1498,57 +1498,53 @@ pub fn help(
1498 } 1498 }
1499} 1499}
1500 1500
1501fn DescriptionWriter(comptime UnderlyingWriter: type) type { 1501const DescriptionWriter = struct {
1502 return struct { 1502 underlying_writer: *std.Io.Writer,
1503 pub const WriteError = UnderlyingWriter.Error;
1504
1505 underlying_writer: UnderlyingWriter,
1506
1507 indentation: usize,
1508 max_width: usize,
1509 printed_chars: usize,
1510
1511 pub fn writeWord(writer: *@This(), word: []const u8) !void {
1512 std.debug.assert(word.len != 0);
1513 1503
1514 var first_word = writer.printed_chars <= writer.indentation; 1504 indentation: usize,
1515 const chars_to_write = try std.unicode.utf8CountCodepoints(word) + @intFromBool(!first_word); 1505 max_width: usize,
1516 if (chars_to_write + writer.printed_chars > writer.max_width) { 1506 printed_chars: usize,
1517 // If the word does not fit on this line, then we insert a new line and print
1518 // it on that line. The only exception to this is if this was the first word.
1519 // If the first word does not fit on this line, then it will also not fit on the
1520 // next one. In that case, all we can really do is just output the word.
1521 if (!first_word)
1522 try writer.newline();
1523 1507
1524 first_word = true; 1508 pub fn writeWord(writer: *@This(), word: []const u8) !void {
1525 } 1509 std.debug.assert(word.len != 0);
1526 1510
1511 var first_word = writer.printed_chars <= writer.indentation;
1512 const chars_to_write = try std.unicode.utf8CountCodepoints(word) + @intFromBool(!first_word);
1513 if (chars_to_write + writer.printed_chars > writer.max_width) {
1514 // If the word does not fit on this line, then we insert a new line and print
1515 // it on that line. The only exception to this is if this was the first word.
1516 // If the first word does not fit on this line, then it will also not fit on the
1517 // next one. In that case, all we can really do is just output the word.
1527 if (!first_word) 1518 if (!first_word)
1528 try writer.underlying_writer.writeAll(" "); 1519 try writer.newline();
1529 1520
1530 try writer.ensureIndented(); 1521 first_word = true;
1531 try writer.underlying_writer.writeAll(word);
1532 writer.printed_chars += chars_to_write;
1533 } 1522 }
1534 1523
1535 pub fn newline(writer: *@This()) !void { 1524 if (!first_word)
1536 try writer.underlying_writer.writeAll("\n"); 1525 try writer.underlying_writer.writeAll(" ");
1537 writer.printed_chars = 0;
1538 }
1539 1526
1540 fn ensureIndented(writer: *@This()) !void { 1527 try writer.ensureIndented();
1541 if (writer.printed_chars < writer.indentation) { 1528 try writer.underlying_writer.writeAll(word);
1542 const to_indent = writer.indentation - writer.printed_chars; 1529 writer.printed_chars += chars_to_write;
1543 try writer.underlying_writer.writeByteNTimes(' ', to_indent); 1530 }
1544 writer.printed_chars += to_indent; 1531
1545 } 1532 pub fn newline(writer: *@This()) !void {
1533 try writer.underlying_writer.writeAll("\n");
1534 writer.printed_chars = 0;
1535 }
1536
1537 fn ensureIndented(writer: *@This()) !void {
1538 if (writer.printed_chars < writer.indentation) {
1539 const to_indent = writer.indentation - writer.printed_chars;
1540 try writer.underlying_writer.splatByteAll(' ', to_indent);
1541 writer.printed_chars += to_indent;
1546 } 1542 }
1547 }; 1543 }
1548} 1544};
1549 1545
1550fn printParam( 1546fn printParam(
1551 stream: anytype, 1547 stream: *std.Io.Writer,
1552 comptime Id: type, 1548 comptime Id: type,
1553 param: Param(Id), 1549 param: Param(Id),
1554) !void { 1550) !void {
@@ -1583,9 +1579,9 @@ fn testHelp(opt: HelpOptions, str: []const u8) !void {
1583 defer std.testing.allocator.free(params); 1579 defer std.testing.allocator.free(params);
1584 1580
1585 var buf: [2048]u8 = undefined; 1581 var buf: [2048]u8 = undefined;
1586 var fbs = std.io.fixedBufferStream(&buf); 1582 var writer = std.Io.Writer.fixed(&buf);
1587 try help(fbs.writer(), Help, params, opt); 1583 try help(&writer, Help, params, opt);
1588 try std.testing.expectEqualStrings(str, fbs.getWritten()); 1584 try std.testing.expectEqualStrings(str, writer.buffered());
1589} 1585}
1590 1586
1591test "clap.help" { 1587test "clap.help" {
@@ -2015,9 +2011,9 @@ test "clap.help" {
2015/// 2011///
2016/// First all none value taking parameters, which have a short name are printed, then non 2012/// First all none value taking parameters, which have a short name are printed, then non
2017/// positional parameters and finally the positional. 2013/// positional parameters and finally the positional.
2018pub fn usage(stream: anytype, comptime Id: type, params: []const Param(Id)) !void { 2014pub fn usage(stream: *std.Io.Writer, comptime Id: type, params: []const Param(Id)) !void {
2019 var cos = ccw.codepointCountingWriter(stream); 2015 var cos = ccw.CodepointCountingWriter.init(stream);
2020 const cs = cos.writer(); 2016 const cs = &cos.interface;
2021 for (params) |param| { 2017 for (params) |param| {
2022 const name = param.names.short orelse continue; 2018 const name = param.names.short orelse continue;
2023 if (param.takes_value != .none) 2019 if (param.takes_value != .none)
@@ -2060,7 +2056,7 @@ pub fn usage(stream: anytype, comptime Id: type, params: []const Param(Id)) !voi
2060 try cs.writeAll("..."); 2056 try cs.writeAll("...");
2061 } 2057 }
2062 2058
2063 try cs.writeByte(']'); 2059 try cs.writeAll("]");
2064 } 2060 }
2065 2061
2066 if (!has_positionals) 2062 if (!has_positionals)
@@ -2083,9 +2079,9 @@ pub fn usage(stream: anytype, comptime Id: type, params: []const Param(Id)) !voi
2083 2079
2084fn testUsage(expected: []const u8, params: []const Param(Help)) !void { 2080fn testUsage(expected: []const u8, params: []const Param(Help)) !void {
2085 var buf: [1024]u8 = undefined; 2081 var buf: [1024]u8 = undefined;
2086 var fbs = std.io.fixedBufferStream(&buf); 2082 var writer = std.Io.Writer.fixed(&buf);
2087 try usage(fbs.writer(), Help, params); 2083 try usage(&writer, Help, params);
2088 try std.testing.expectEqualStrings(expected, fbs.getWritten()); 2084 try std.testing.expectEqualStrings(expected, writer.buffered());
2089} 2085}
2090 2086
2091test "usage" { 2087test "usage" {