lib/zen/src/footnote/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, source: []const u8) model.Error!model.Set {
 7     const regions = try storage.acquire(source);
 8     var definition_index: usize = 0;
 9     var joined_text_index: usize = 0;
10     var current_index: ?usize = null;
11     var current_joined_start: ?usize = null;
12     var iterator = scan.Iterator.init(source);
13     while (iterator.next()) |event| switch (event) {
14         .definition => |definition| {
15             const active = findActive(regions.definitions[0..definition_index], definition.key) == null;
16             regions.definitions[definition_index] = .{
17                 .key = definition.key,
18                 .text = definition.text,
19                 .active = active,
20             };
21             current_index = definition_index;
22             current_joined_start = null;
23             definition_index += 1;
24         },
25         .continuation => |text| {
26             const index = current_index orelse unreachable;
27             const definition = &regions.definitions[index];
28             if (current_joined_start == null) {
29                 current_joined_start = joined_text_index;
30                 if (definition.text.len != 0) {
31                     copy(regions.joined_text, &joined_text_index, definition.text);
32                     regions.joined_text[joined_text_index] = ' ';
33                     joined_text_index += 1;
34                 }
35             } else {
36                 regions.joined_text[joined_text_index] = ' ';
37                 joined_text_index += 1;
38             }
39             copy(regions.joined_text, &joined_text_index, text);
40             definition.text = regions.joined_text[current_joined_start.?..joined_text_index];
41         },
42     };
43     std.debug.assert(definition_index == regions.plan.definitions);
44     std.debug.assert(joined_text_index == regions.plan.joined_text_bytes);
45     return .{ .definitions = regions.definitions };
46 }
47 
48 fn findActive(definitions: []const model.Definition, key: []const u8) ?usize {
49     for (definitions, 0..) |definition, index| {
50         if (definition.active and std.mem.eql(u8, definition.key, key)) return index;
51     }
52     return null;
53 }
54 
55 fn copy(destination: []u8, index: *usize, source: []const u8) void {
56     @memcpy(destination[index.*..][0..source.len], source);
57     index.* += source.len;
58 }