lib/zen/src/frontmatter/parse.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const model = @import("model.zig");
3 const scan = @import("scan.zig");
4 const storage_mod = @import("storage.zig");
5
6 pub fn parse(storage: *storage_mod.Storage, markdown: []const u8) model.Error!model.Parsed {
7 const regions = try storage.acquire(markdown);
8 var iterator = scan.Iterator.init(markdown[regions.plan.metadata_start..regions.plan.metadata_end]);
9 var pair_index: usize = 0;
10 var byte_index: usize = 0;
11 var current: ?usize = null;
12 var continuation_start: usize = 0;
13 var continuing = false;
14
15 while (iterator.next()) |field| switch (field) {
16 .pair => |pair| {
17 std.debug.assert(pair_index < regions.pairs.len);
18 regions.pairs[pair_index] = .{ .key = pair.key, .value = pair.value };
19 current = pair_index;
20 continuing = false;
21 pair_index += 1;
22 },
23 .continuation => |value| if (current) |index| {
24 const active = ®ions.pairs[index];
25 if (!continuing) {
26 continuation_start = byte_index;
27 append(regions.continuation, &byte_index, active.value);
28 if (active.value.len != 0) append(regions.continuation, &byte_index, " ");
29 continuing = true;
30 } else {
31 append(regions.continuation, &byte_index, " ");
32 }
33 append(regions.continuation, &byte_index, value);
34 active.value = regions.continuation[continuation_start..byte_index];
35 },
36 };
37 std.debug.assert(pair_index == regions.pairs.len);
38 std.debug.assert(byte_index == regions.continuation.len);
39 return .{
40 .metadata = .{ .pairs = regions.pairs },
41 .body = markdown[regions.plan.body_start..],
42 };
43 }
44
45 fn append(destination: []u8, index: *usize, bytes: []const u8) void {
46 std.debug.assert(index.* <= destination.len);
47 std.debug.assert(bytes.len <= destination.len - index.*);
48 @memcpy(destination[index.*..][0..bytes.len], bytes);
49 index.* += bytes.len;
50 }