lib/pretty/core/src/compact/cap.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 
 3 const footer_dash = "\xE2\x80\x94";
 4 pub const truncation_line = "(output truncated at 16 KB " ++ footer_dash ++
 5     " use filters or --limit to scope down, --json for exact records)";
 6 pub const full_cap = 16 * 1024;
 7 const reserved = truncation_line.len + 1;
 8 pub const body_budget = full_cap - reserved;
 9 
10 pub fn cap16kb(allocator: std.mem.Allocator, output: []const u8) ![]u8 {
11     if (output.len <= body_budget) return try allocator.dupe(u8, output);
12     var end: usize = 0;
13     var next: usize = 0;
14     while (next < output.len and next < body_budget) {
15         const line_end = std.mem.indexOfScalarPos(u8, output, next, '\n') orelse break;
16         if (line_end + 1 > body_budget) break;
17         end = line_end + 1;
18         next = line_end + 1;
19     }
20     var out = std.Io.Writer.Allocating.init(allocator);
21     errdefer out.deinit();
22     if (end != 0) try out.writer.writeAll(output[0..end]);
23     try out.writer.writeAll(truncation_line);
24     try out.writer.writeByte('\n');
25     return try out.toOwnedSlice();
26 }
27 
28 test "output cap keeps line boundary" {
29     const allocator = std.testing.allocator;
30     var source: std.ArrayList(u8) = .empty;
31     defer source.deinit(allocator);
32     for (0..4000) |_| try source.appendSlice(allocator, "line\n");
33     const out = try cap16kb(allocator, source.items);
34     defer allocator.free(out);
35     try std.testing.expect(std.mem.endsWith(u8, out, truncation_line ++ "\n"));
36 }