srctree

Gregory Mullen parent 07908ac4 8be4ac37
make template html comment aware

examples/templates/example.html added: 98, removed: 41, total 57
@@ -32,16 +32,18 @@
 
<!-- Once a name exists, you can't not change the type -->
<!-- The following tags would be invalid and cause a compile error -->
<!-- < SimpleVariable ornull /> -->
<!-- < SimpleVariable default="Invalid" /></p> -->
<!-- < SimpleVariable type="usize" /></p> -->
<!--
<SimpleVariable ornull />
<SimpleVariable default="Invalid" /></p>
<SimpleVariable type="usize" /></p>
-->
 
<!-- Some logic is also supported -->
<!-- TODO Write and Document-->
<With OptionalWith>
<p>These internal tags are only seen if optional is defined</p>
</With>
<!--
<!--
< For Loop></For>
< Split Slices></For>
< Build TemplateVars _template_name.html />
 
src/template-compiler.zig added: 98, removed: 41, total 57
@@ -2,6 +2,8 @@ const std = @import("std");
const Allocator = std.mem.Allocator;
const eql = std.mem.eql;
const bufPrint = std.fmt.bufPrint;
const indexOf = std.mem.indexOf;
const indexOfPos = std.mem.indexOfPos;
const compiled = @import("comptime_templates");
const Template = @import("template.zig");
 
@@ -135,7 +137,7 @@ pub fn main() !void {
fn emitVars(a: Allocator, fdata: []const u8, current: *AbstTree) !void {
var data = fdata;
while (data.len > 0) {
if (std.mem.indexOf(u8, data, "<")) |offset| {
if (indexOf(u8, data, "<")) |offset| {
data = data[offset..];
if (Template.Directive.init(data)) |drct| {
data = data[drct.tag_block.len..];
@@ -203,7 +205,9 @@ fn emitVars(a: Allocator, fdata: []const u8, current: *AbstTree) !void {
}
},
}
} else if (std.mem.indexOfPos(u8, data, 1, "<")) |next| {
} else if (Template.Pages.commentTag(data)) |skip| {
data = data[skip..];
} else if (indexOfPos(u8, data, 1, "<")) |next| {
data = data[next..];
} else return;
} else return;
 
src/template.zig added: 98, removed: 41, total 57
@@ -796,8 +796,8 @@ test "directive typed ?usize null" {
 
const FE = struct { number: ?usize };
 
const t = Template{ .name = "test", .blob = blob };
const page = Page(t, FE);
const Temp = Template{ .name = "test", .blob = blob };
const page = Page(Temp, FE);
 
const slice = FE{ .number = null };
const pg = page.init(slice);
@@ -811,14 +811,55 @@ test "directive typed isize" {
const blob = "<Number type=\"isize\" />";
const expected: []const u8 = "-420";
 
const FE = struct { number: isize };
const PData = struct {
number: isize,
};
const Temp = Template{ .name = "test", .blob = blob };
const PType = Page(Temp, PData);
 
const t = Template{ .name = "test", .blob = blob };
const page = Page(t, FE);
 
const slice = FE{ .number = -420 };
const pg = page.init(slice);
const p = try allocPrint(a, "{}", .{pg});
defer a.free(p);
try std.testing.expectEqualStrings(expected, p);
const data = PData{ .number = -420 };
const print = try allocPrint(a, "{}", .{PType.init(data)});
defer a.free(print);
try std.testing.expectEqualStrings(expected, print);
}
 
test "grouped offsets" {
const blob =
\\<html>
\\ <div>
\\ <p>
\\ <span>text</span>
\\ </p>
\\ </div>
\\</html>
;
const Temp = Template{ .name = "test", .blob = blob };
const PData = struct {};
const PType = Page(Temp, PData);
try std.testing.expectEqual(1, PType.DataOffsets.len);
var a = std.testing.allocator;
const print = try allocPrint(a, "{}", .{PType.init(PData{})});
defer a.free(print);
const expected = blob;
try std.testing.expectEqualStrings(expected, print);
}
 
test "comment tags" {
var a = std.testing.allocator;
 
const blob =
\\<!-- <ValidButInComment /> -->
;
 
const PData = struct {};
const t = Template{ .name = "test", .blob = blob };
const PType = Page(t, PData);
 
const data = PData{};
const expected = blob;
 
const page = try allocPrint(a, "{}", .{PType.init(data)});
defer a.free(page);
 
try std.testing.expectEqualStrings(expected, page);
}
 
src/template/page.zig added: 98, removed: 41, total 57
@@ -65,11 +65,27 @@ pub fn PageRuntime(comptime PageDataType: type) type {
};
}
 
fn getOffset(T: type, name: []const u8) usize {
var local: [0xff]u8 = undefined;
const field = local[0..makeFieldName(name, &local)];
return @offsetOf(T, field);
}
 
pub fn commentTag(blob: []const u8) ?usize {
if (blob.len > 2 and blob[1] == '!' and blob.len > 4 and blob[2] == '-' and blob[3] == '-') {
if (indexOfPosLinear(u8, blob, 4, "-->")) |comment| {
return comment + 3;
}
}
return null;
}
 
pub fn Page(comptime template: Template, comptime PageDataType: type) type {
@setEvalBranchQuota(10000);
var found_offsets: []const Offset = &[0]Offset{};
var pblob = template.blob;
var index: usize = 0;
var open_idx: usize = 0;
var static: bool = true;
// Originally attempted to write this just using index, but got catastrophic
// backtracking errors when compiling. I'd have assumed this version would
@@ -77,15 +93,14 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
while (pblob.len > 0) {
if (indexOfScalar(u8, pblob, '<')) |offset| {
pblob = pblob[offset..];
if (index != offset and offset != 0) {
found_offsets = found_offsets ++ [_]Offset{.{
.start = index,
.end = index + offset,
.kind = .slice,
}};
}
index += offset;
if (Directive.init(pblob)) |drct| {
found_offsets = found_offsets ++ [_]Offset{.{
.start = open_idx,
.end = index,
.kind = .slice,
}};
 
const end = drct.tag_block.len;
var os = Offset{
.start = index,
@@ -93,33 +108,28 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
.kind = .{ .directive = drct },
};
if (drct.verb == .variable) {
var local: [0xff]u8 = undefined;
const name = local[0..makeFieldName(drct.noun, &local)];
os.kind.directive.known_offset = @offsetOf(PageDataType, name);
os.kind.directive.known_offset = getOffset(PageDataType, drct.noun);
}
found_offsets = found_offsets ++ [_]Offset{os};
pblob = pblob[end..];
index += end;
open_idx = index;
static = static and drct.verb == .variable;
} else if (commentTag(pblob)) |skip| {
pblob = pblob[skip..];
index += skip;
} else {
if (indexOfPosLinear(u8, pblob, 1, "<")) |next| {
if (index != next) {
found_offsets = found_offsets ++ [_]Offset{.{
.start = index,
.end = index + next,
.kind = .slice,
}};
}
index += next;
pblob = pblob[next..];
index += next;
} else break;
}
} else break;
}
if (index != pblob.len) {
found_offsets = found_offsets ++ [_]Offset{.{
.start = index,
.end = index + pblob.len,
.start = open_idx,
.end = open_idx + pblob.len,
.kind = .slice,
}};
}