tiny.zen.diagnostic
Defined in tiny.zen.
API (4)
Types and contracts
Public types and contracts.
Diagnostic: Fixed-capacity detail for a failed page, equation, heading, or inline feature.
Values and defaults
Public values and defaults.
Source
Source: lib/zen/src/diagnostic.zig
zig
const std = @import("std");const math = @import("math/root.zig");pub const max_page_bytes = 256;pub const max_equation_bytes = 256;pub const max_inline_bytes = 256;/// Fixed-capacity detail for a failed page, equation, heading, or inline feature.////// Supply its address through Markdown or site options. After an error, inspect/// `page()`, the feature source, `reason`, and `offset`, then call `reset` before/// reuse.pub const Diagnostic = struct { page_buffer: [max_page_bytes]u8 = undefined, page_len: usize = 0, equation_buffer: [max_equation_bytes]u8 = undefined, equation_len: usize = 0, inline_buffer: [max_inline_bytes]u8 = undefined, inline_len: usize = 0, /// Short cause suitable for a repair message; empty when no detail is captured. reason: []const u8 = "", /// Byte offset in the original inline source, heading feature, or equation. /// It can lie beyond a bounded or sanitized captured excerpt. offset: usize = 0, /// Returns the page path, truncated with an ellipsis if needed. pub fn page(self: *const Diagnostic) []const u8 { return self.page_buffer[0..self.page_len]; } /// Returns the captured equation, truncated with an ellipsis if needed. pub fn equation(self: *const Diagnostic) []const u8 { return self.equation_buffer[0..self.equation_len]; } /// Returns a bounded UTF-8-safe source prefix for context, not indexing. /// Invalid bytes become `?` and excess source ends in `...`. pub fn inlineSource(self: *const Diagnostic) []const u8 { return self.inline_buffer[0..self.inline_len]; } /// Clears captured detail before a retry or unrelated operation. pub fn reset(self: *Diagnostic) void { self.* = .{}; } pub fn setPage(self: *Diagnostic, path: []const u8) void { self.page_len = copyEllipsized(&self.page_buffer, path); } pub fn setEquation(self: *Diagnostic, source: []const u8, detail: math.Diagnostic) void { self.equation_len = copyEllipsized(&self.equation_buffer, source); self.inline_len = 0; self.reason = detail.reason; self.offset = detail.offset; } pub fn setHeading(self: *Diagnostic, reason: []const u8, offset: usize) void { self.equation_len = 0; self.inline_len = 0; self.reason = reason; self.offset = offset; } pub fn setInline(self: *Diagnostic, source: []const u8, reason: []const u8, offset: usize) void { self.equation_len = 0; self.inline_len = copyEllipsized(&self.inline_buffer, source); self.reason = reason; self.offset = offset; }};fn copyEllipsized(buffer: []u8, text: []const u8) usize { std.debug.assert(buffer.len >= 3); const payload_limit = if (text.len > buffer.len) buffer.len - 3 else buffer.len; var source_index: usize = 0; var output_index: usize = 0; while (source_index < text.len) { const sequence_length = std.unicode.utf8ByteSequenceLength(text[source_index]) catch 1; const sequence_end = @min(source_index + sequence_length, text.len); const sequence = text[source_index..sequence_end]; const valid = sequence.len == sequence_length and std.unicode.utf8ValidateSlice(sequence); const replacement = if (valid) sequence else "?"; if (output_index + replacement.len > payload_limit) break; @memcpy(buffer[output_index..][0..replacement.len], replacement); output_index += replacement.len; source_index += if (valid) sequence_length else 1; } if (source_index < text.len) { @memcpy(buffer[output_index..][0..3], "..."); output_index += 3; } std.debug.assert(output_index <= buffer.len); return output_index;}test "diagnostic captures page and equation detail" { var diagnostic: Diagnostic = .{}; try std.testing.expectEqualStrings("", diagnostic.page()); try std.testing.expectEqualStrings("", diagnostic.equation()); try std.testing.expectEqualStrings("", diagnostic.inlineSource()); diagnostic.setPage("writing/mathcheck.md"); diagnostic.setEquation("\\frac{1}", .{ .reason = "missing argument", .offset = 8 }); try std.testing.expectEqualStrings("writing/mathcheck.md", diagnostic.page()); try std.testing.expectEqualStrings("\\frac{1}", diagnostic.equation()); try std.testing.expectEqualStrings("missing argument", diagnostic.reason); try std.testing.expectEqual(@as(usize, 8), diagnostic.offset); diagnostic.setInline("[label](/missing", "link target is missing closing ')'", 7); try std.testing.expectEqualStrings("", diagnostic.equation()); try std.testing.expectEqualStrings("[label](/missing", diagnostic.inlineSource()); try std.testing.expectEqualStrings("link target is missing closing ')'", diagnostic.reason); try std.testing.expectEqual(@as(usize, 7), diagnostic.offset); diagnostic.setHeading("duplicate heading anchor", 17); try std.testing.expectEqualStrings("writing/mathcheck.md", diagnostic.page()); try std.testing.expectEqualStrings("", diagnostic.equation()); try std.testing.expectEqualStrings("", diagnostic.inlineSource()); try std.testing.expectEqualStrings("duplicate heading anchor", diagnostic.reason); try std.testing.expectEqual(@as(usize, 17), diagnostic.offset); diagnostic.reset(); try std.testing.expectEqualStrings("", diagnostic.page()); try std.testing.expectEqualStrings("", diagnostic.reason);}test "diagnostic truncates long captures with an ellipsis" { var diagnostic: Diagnostic = .{}; const long = @as([(300) * ("x").len]u8, @bitCast(@as([300][("x").len]u8, @splat(("x")[0..("x").len].*)))); diagnostic.setEquation(&long, .{ .reason = "unknown command", .offset = 280 }); try std.testing.expectEqual(@as(usize, max_equation_bytes), diagnostic.equation().len); try std.testing.expect(std.mem.endsWith(u8, diagnostic.equation(), "...")); try std.testing.expectEqual(@as(usize, 280), diagnostic.offset); diagnostic.setInline(&long, "link target is missing closing ')'", 280); try std.testing.expectEqual(@as(usize, max_inline_bytes), diagnostic.inlineSource().len); try std.testing.expect(std.mem.endsWith(u8, diagnostic.inlineSource(), "...")); try std.testing.expectEqual(@as(usize, 280), diagnostic.offset);}test "diagnostic truncation preserves valid UTF-8 and replaces invalid bytes" { var diagnostic: Diagnostic = .{}; var source: [max_inline_bytes + 8]u8 = @splat('x'); @memcpy(source[252..254], "ω"); diagnostic.setInline(&source, "invalid inline source", 252); try std.testing.expect(std.unicode.utf8ValidateSlice(diagnostic.inlineSource())); try std.testing.expectEqual(@as(usize, 255), diagnostic.inlineSource().len); try std.testing.expect(std.mem.endsWith(u8, diagnostic.inlineSource(), "...")); try std.testing.expectEqual(@as(u8, 'x'), diagnostic.inlineSource()[251]); const invalid = [_]u8{ 'a', 0xff, 'b' }; diagnostic.setInline(&invalid, "invalid inline source", 1); try std.testing.expectEqualStrings("a?b", diagnostic.inlineSource());}Source: lib/zen/src/root.zig:17
zig
/// Fixed-capacity source-local failure detail.pub const diagnostic = @import("diagnostic.zig");Audit
| Definitions | 4 |
|---|---|
| Public names | 4 |
| Members | 0 |
| Version | 26.7.0 |
| Revision | daab053ee433 |