srctree

Gregory Mullen parent 57a432d3 604694eb
rewrite template printing code to new typed html syntax

src/context.zig added: 288, removed: 211, total 77
@@ -57,7 +57,7 @@ pub fn sendPage(ctx: *Context, page: anytype) Error!void {
const loggedin = if (ctx.request.auth.valid()) "<a href=\"#\">Logged In</a>" else "Public";
const T = @TypeOf(page.*);
if (@hasField(T, "data") and @hasField(@TypeOf(page.data), "body_header")) {
page.data.body_header.?.nav.?.nav_auth = loggedin;
page.data.body_header.nav.nav_auth = loggedin;
}
 
const page_compiled = try page.build(ctx.alloc);
 
src/template-compiler.zig added: 288, removed: 211, total 77
@@ -49,8 +49,15 @@ const AbstTree = struct {
for (self.children) |child| {
if (std.mem.eql(u8, child.name, name)) {
if (!std.mem.eql(u8, child.kind, kind)) {
std.debug.print("Error: kind mismatch while building ", .{});
var par = self.parent;
while (par != null) {
par = par.?.parent;
std.debug.print("{s}.", .{par.?.name});
}
 
std.debug.print(
"Error: kind mismatch \n {s}.{s}\n {s} != {s}\n",
"{s}.{s}\n {s} != {s}\n",
.{ self.name, name, child.kind, kind },
);
return error.KindMismatch;
@@ -130,74 +137,73 @@ fn emitVars(a: Allocator, fdata: []const u8, current: *AbstTree) !void {
while (data.len > 0) {
if (std.mem.indexOf(u8, data, "<")) |offset| {
data = data[offset..];
if (Template.Directive.init(data)) |drct| switch (drct.verb) {
.variable => |_| {
data = data[drct.end..];
switch (drct.otherwise) {
.ign => {
try current.append(makeFieldName(drct.noun), ": []const u8,\n");
},
.str => |str| {
var buffer: [0xFF]u8 = undefined;
const kind = try bufPrint(&buffer, ": []const u8 = \"{s}\",\n", .{str});
try current.append(makeFieldName(drct.noun), kind);
},
.del => {
try current.append(makeFieldName(drct.noun), ": ?[]const u8 = null,\n");
},
.template => |_| {
var buffer: [0xFF]u8 = undefined;
const kind = try bufPrint(&buffer, ": ?{s},\n", .{makeStructName(drct.noun)});
try current.append(makeFieldName(drct.noun[1 .. drct.noun.len - 5]), kind);
},
.blob => unreachable,
}
},
else => |verb| {
data = data[drct.end..];
const name = makeStructName(drct.noun);
const field = makeFieldName(drct.noun);
var this = try AbstTree.init(a, name, current);
const gop = try tree.getOrPut(this.name);
if (!gop.found_existing) {
gop.value_ptr.* = this;
} else {
this = gop.value_ptr.*;
}
if (Template.Directive.init(data)) |drct| {
const s_name = makeStructName(drct.noun);
var f_name = makeFieldName(drct.noun);
switch (drct.verb) {
.variable => |_| {
data = data[drct.tag_block.len..];
var buffer: [0xFF]u8 = undefined;
var kind = try bufPrint(&buffer, ": []const u8,\n", .{});
 
switch (verb) {
.variable => unreachable,
.foreach => {
var buffer: [0xFF]u8 = undefined;
const kind = try bufPrint(&buffer, ": []const {s},\n", .{name});
try current.append(field, kind);
try emitVars(a, drct.otherwise.blob.trimmed, this);
},
.split => {
var buffer: [0xFF]u8 = undefined;
const kind = try bufPrint(&buffer, ": []const []const u8,\n", .{});
try current.append(field, kind);
},
.with => {
var buffer: [0xFF]u8 = undefined;
const kind = try bufPrint(&buffer, ": ?{s},\n", .{name});
try current.append(field, kind);
try emitVars(a, drct.otherwise.blob.trimmed, this);
},
.build => {
var buffer: [0xFF]u8 = undefined;
const tmpl_name = makeStructName(drct.otherwise.template.name);
const kind = try bufPrint(&buffer, ": {s},\n", .{tmpl_name});
try current.append(field, kind);
//try emitVars(a, drct.otherwise.template.blob, this);
},
.typed => {
var buffer: [0xFF]u8 = undefined;
const kind = try bufPrint(&buffer, ": {s},\n", .{@tagName(drct.known_type.?)});
try current.append(field, kind);
},
}
},
switch (drct.otherwise) {
.required, .ignore => {},
.default => |str| {
kind = try bufPrint(&buffer, ": []const u8 = \"{s}\",\n", .{str});
},
.delete => {
kind = try bufPrint(&buffer, ": ?[]const u8 = null,\n", .{});
},
.template => |_| {
kind = try bufPrint(&buffer, ": {s},\n", .{s_name});
f_name = makeFieldName(drct.noun[1 .. drct.noun.len - 5]);
},
.blob => unreachable,
}
if (drct.known_type) |kt| {
kind = try bufPrint(&buffer, ": {s},\n", .{@tagName(kt)});
}
try current.append(f_name, kind);
},
else => |verb| {
data = data[drct.tag_block.len..];
var this = try AbstTree.init(a, s_name, current);
const gop = try tree.getOrPut(this.name);
if (!gop.found_existing) {
gop.value_ptr.* = this;
} else {
this = gop.value_ptr.*;
}
 
switch (verb) {
.variable => unreachable,
.foreach => {
var buffer: [0xFF]u8 = undefined;
const kind = try bufPrint(&buffer, ": []const {s},\n", .{s_name});
try current.append(f_name, kind);
try emitVars(a, drct.otherwise.blob, this);
},
.split => {
var buffer: [0xFF]u8 = undefined;
const kind = try bufPrint(&buffer, ": []const []const u8,\n", .{});
try current.append(f_name, kind);
},
.with => {
var buffer: [0xFF]u8 = undefined;
const kind = try bufPrint(&buffer, ": ?{s},\n", .{s_name});
try current.append(f_name, kind);
try emitVars(a, drct.otherwise.blob, this);
},
.build => {
var buffer: [0xFF]u8 = undefined;
const tmpl_name = makeStructName(drct.otherwise.template.name);
const kind = try bufPrint(&buffer, ": {s},\n", .{tmpl_name});
try current.append(f_name, kind);
//try emitVars(a, drct.otherwise.template.blob, this);
},
}
},
}
} else if (std.mem.indexOfPos(u8, data, 1, "<")) |next| {
data = data[next..];
} else return;
 
src/template.zig added: 288, removed: 211, total 77
@@ -346,7 +346,7 @@ test "directive nothing" {
}
 
test "directive nothing new" {
var a = std.testing.allocator;
const a = std.testing.allocator;
const t = Template{
//.path = "/dev/null",
.name = "test",
@@ -356,6 +356,9 @@ test "directive nothing new" {
const ctx = .{};
 
// TODO is this still the expected behavior
//const p = Page(t, @TypeOf(ctx)).init(.{}).build(a);
//try std.testing.expectError(error.VariableMissing, p);
 
const p = try Page(t, @TypeOf(ctx)).init(.{}).build(a);
defer a.free(p);
try std.testing.expectEqualStrings("<Nothing>", p);
@@ -366,7 +369,7 @@ test "directive ORELSE" {
const t = Template{
//.path = "/dev/null",
.name = "test",
.blob = "<This ORELSE string until end>",
.blob = "<This default='string until end'>",
};
 
const ctx = .{
@@ -384,7 +387,7 @@ test "directive ORNULL" {
//.path = "/dev/null",
.name = "test",
// Invalid because 'string until end' is known to be unreachable
.blob = "<This ORNULL string until end>",
.blob = "<This ornull string until end>",
};
 
const ctx = .{
@@ -393,12 +396,12 @@ test "directive ORNULL" {
 
const p = try Page(t, @TypeOf(ctx)).init(ctx).build(a);
defer a.free(p);
try std.testing.expectEqualStrings("<This ORNULL string until end>", p);
try std.testing.expectEqualStrings("", p);
 
const t2 = Template{
//.path = "/dev/null",
.name = "test",
.blob = "<This ORNULL>",
.blob = "<This ornull>",
};
 
const nullpage = try Page(t2, @TypeOf(ctx)).init(ctx).build(a);
@@ -626,7 +629,6 @@ test "directive With" {
const expected_thing: []const u8 =
\\<div>
\\ <span>THING</span>
++ "\n \n" ++
\\</div>
;
 
 
src/template/directive.zig added: 288, removed: 211, total 77
@@ -9,6 +9,9 @@ const indexOfScalarPos = std.mem.indexOfScalarPos;
const isUpper = std.ascii.isUpper;
const count = std.mem.count;
const isWhitespace = std.ascii.isWhitespace;
const trim = std.mem.trim;
const trimLeft = std.mem.trimLeft;
const whitespace = std.ascii.whitespace[0..];
 
pub const Directive = @This();
 
@@ -22,20 +25,17 @@ const makeFieldName = Template.makeFieldName;
 
verb: Verb,
noun: []const u8,
otherwise: Otherwise = .{ .ign = {} },
otherwise: Otherwise,
known_type: ?KnownType = null,
end: usize,
tag_block: []const u8,
 
pub const Otherwise = union(enum) {
ign: void,
del: void,
str: []const u8,
required: void,
ignore: void,
delete: void,
default: []const u8,
template: Template.Template,
blob: Blob,
pub const Blob = struct {
trimmed: []const u8,
whitespace: []const u8,
};
blob: []const u8,
};
 
pub const Verb = enum {
@@ -44,13 +44,19 @@ pub const Verb = enum {
split,
with,
build,
typed,
};
 
pub const KnownType = enum {
usize,
isize,
@"?usize",
 
pub fn nullable(kt: KnownType) bool {
return switch (kt) {
.usize, .isize => false,
.@"?usize" => true,
};
}
};
 
const Positions = struct {
@@ -64,85 +70,80 @@ const Positions = struct {
pub fn init(str: []const u8) ?Directive {
if (str.len < 2) return null;
if (!isUpper(str[1]) and str[1] != '_') return null;
const end = 1 + (indexOf(u8, str, ">") orelse return null);
const end = findTag(str) catch return null;
const tag = str[0..end];
const verb = tag[1 .. indexOfScalar(u8, tag, ' ') orelse tag.len - 1];
const verb = tag[1 .. indexOfAnyPos(u8, tag, 1, " /") orelse tag.len - 1];
 
if (verb.len == tag.len - 2) {
if (verb[0] == '_') {
if (getBuiltin(verb)) |bi| {
return Directive{
.noun = verb,
.verb = .variable,
.otherwise = .{ .template = bi },
.end = end,
};
}
}
return Directive{
.verb = .variable,
.noun = verb,
.end = end,
};
if (initNoun(verb, tag)) |noun| {
return noun;
} else unreachable;
}
 
var width: usize = 1;
while (width < str.len and validChar(str[width])) {
width += 1;
}
 
const noun = tag[verb.len + 1 ..];
const noun = tag[verb.len + 1 .. tag.len - 1];
if (initVerb(verb, noun, str)) |kind| {
return kind;
}
 
var known: ?KnownType = null;
if (indexOfScalar(u8, noun, '=')) |i| {
if (i >= 4 and eql(u8, noun[i - 4 .. i], "type")) {
const i_end = indexOfAnyPos(u8, noun, i, " /") orelse end - 1;
const requested_type = std.mem.trim(u8, noun[i..i_end], " ='\"");
inline for (std.meta.fields(KnownType)) |kt| {
if (eql(u8, requested_type, kt.name)) {
known = @enumFromInt(kt.value);
break;
if (initNoun(verb, tag)) |kind| {
return kind;
}
return null;
}
 
fn initNoun(noun: []const u8, tag: []const u8) ?Directive {
//std.debug.print("init noun {s}\n", .{noun});
if (noun[0] == '_') if (getBuiltin(noun)) |bi| {
return Directive{
.noun = noun,
.verb = .variable,
.otherwise = .{ .template = bi },
.tag_block = tag,
};
};
 
var default_str: ?[]const u8 = null;
var knownt: ?KnownType = null;
var rem_attr = tag[noun.len + 1 .. tag.len - 1];
while (indexOfScalar(u8, rem_attr, '=') != null) {
if (findAttribute(rem_attr)) |attr| {
if (eql(u8, attr.name, "type")) {
inline for (std.meta.fields(KnownType)) |kt| {
if (eql(u8, attr.value, kt.name)) {
knownt = @enumFromInt(kt.value);
break;
}
} else {
std.debug.print("Unable to resolve requested type '{s}'\n", .{attr.value});
unreachable;
}
} else {
std.debug.print("Unable to resolve requested type {s}\n", .{requested_type});
unreachable;
} else if (eql(u8, attr.name, "default")) {
default_str = attr.value;
}
rem_attr = rem_attr[attr.len..];
} else |err| switch (err) {
error.AttrInvalid => break,
else => unreachable,
}
}
if (startsWith(u8, noun, " ORELSE ")) {
return Directive{
.verb = .variable,
.noun = verb,
.otherwise = .{ .str = tag[width + 8 .. end - 1] },
.end = end,
.known_type = known,
};
} else if (startsWith(u8, noun, " ORNULL>")) {
return Directive{
.verb = .variable,
.noun = verb,
.otherwise = .{ .del = {} },
.end = end,
.known_type = known,
};
} else if (startsWith(u8, noun, " />")) {
return Directive{
.verb = .variable,
.noun = verb,
.end = end,
.known_type = known,
};
} else if (known != null) {
return Directive{
.verb = .typed,
.noun = verb,
.end = end,
.known_type = known,
};
} else return null;
 
return Directive{
.verb = .variable,
.noun = noun,
.otherwise = if (default_str) |str|
.{ .default = str }
else if (indexOf(u8, tag, " ornull")) |_|
.delete
else if (knownt) |kn|
if (kn.nullable())
.delete
else
.required
else
.required,
.known_type = knownt,
.tag_block = tag,
};
}
 
pub fn initVerb(verb: []const u8, noun: []const u8, blob: []const u8) ?Directive {
@@ -169,14 +170,14 @@ pub fn initVerb(verb: []const u8, noun: []const u8, blob: []const u8) ?Directive
.verb = .build,
.noun = b_noun,
.otherwise = .{ .template = bi },
.end = verb.len + 1 + noun.len,
.tag_block = blob[0 .. verb.len + 2 + noun.len],
};
} else if (getDynamic(b_html)) |bi| {
return Directive{
.verb = .build,
.noun = b_noun,
.otherwise = .{ .template = bi },
.end = verb.len + 1 + noun.len,
.tag_block = blob[0 .. verb.len + 2 + noun.len],
};
} else return null;
} else return null;
@@ -190,16 +191,70 @@ pub fn initVerb(verb: []const u8, noun: []const u8, blob: []const u8) ?Directive
// }
//} else return null;
 
var start = (indexOf(u8, noun, ">") orelse return null);
if (noun[start - 1] == '/') start -= 1;
var end = (indexOf(u8, noun, ">") orelse noun.len);
if (noun[end - 1] == '/') end -= 1;
return .{
.verb = word,
.noun = noun[1..start],
.noun = noun[1..end],
.otherwise = otherw[0],
.end = otherw[1],
.tag_block = blob[0..otherw[1]],
};
}
 
fn findTag(blob: []const u8) !usize {
return 1 + (indexOf(u8, blob, ">") orelse return error.TagInvalid);
}
 
const TAttr = struct {
name: []const u8,
value: []const u8,
len: usize,
};
 
fn findAttribute(tag: []const u8) !TAttr {
const equi = indexOfScalar(u8, tag, '=') orelse return error.AttrInvalid;
const name = trim(u8, tag[0..equi], whitespace);
var value = trim(u8, tag[equi + 1 ..], whitespace);
 
var end: usize = equi + 1;
while (end < tag.len and isWhitespace(tag[end])) end += 1;
while (end < tag.len) {
// TODO rewrite with tagged switch syntax
switch (tag[end]) {
'\n', '\r', '\t', ' ' => end += 1,
'\'', '"' => |qut| {
end += 1;
while (end <= tag.len and tag[end] != qut) end += 1;
if (end == tag.len) return error.AttrInvalid;
if (tag[end] != qut) return error.AttrInvalid else end += 1;
value = trim(u8, tag[equi + 1 .. end], whitespace.* ++ &[_]u8{ qut, '=', '<', '>', '/' });
break;
},
else => {
while (end < tag.len and !isWhitespace(tag[end])) end += 1;
},
}
}
return .{
.name = name,
.value = value,
.len = end,
};
}
 
test findAttribute {
var attr = try findAttribute("type=\"usize\"");
try std.testing.expectEqualDeep(TAttr{ .name = "type", .value = "usize", .len = 12 }, attr);
attr = try findAttribute("type=\"isize\"");
try std.testing.expectEqualDeep(TAttr{ .name = "type", .value = "isize", .len = 12 }, attr);
attr = try findAttribute("type=\"?usize\"");
try std.testing.expectEqualDeep(TAttr{ .name = "type", .value = "?usize", .len = 13 }, attr);
attr = try findAttribute("default=\"text\"");
try std.testing.expectEqualDeep(TAttr{ .name = "default", .value = "text", .len = 14 }, attr);
attr = try findAttribute("default=\"text\" />");
try std.testing.expectEqualDeep(TAttr{ .name = "default", .value = "text", .len = 14 }, attr);
}
 
fn validChar(c: u8) bool {
return switch (c) {
'A'...'Z', 'a'...'z' => true,
@@ -210,7 +265,10 @@ fn validChar(c: u8) bool {
 
fn calcBodyS(comptime _: []const u8, _: []const u8, blob: []const u8, end: usize) ?struct { Otherwise, usize } {
if (blob.len <= end) return null;
return .{ .{ .ign = {} }, end + 1 };
return .{
.{ .ignore = {} },
end + 1,
};
}
 
fn calcBody(comptime keyword: []const u8, noun: []const u8, blob: []const u8) ?struct { Otherwise, usize } {
@@ -246,10 +304,10 @@ fn calcBody(comptime keyword: []const u8, noun: []const u8, blob: []const u8) ?s
while (width < noun.len and validChar(noun[width])) {
width += 1;
}
return .{ .{ .blob = .{
.trimmed = blob[start..end_ws],
.whitespace = blob[start_ws..end_ws],
} }, end };
return .{
.{ .blob = blob[start_ws..end_ws] },
end,
};
}
 
fn isStringish(t: type) bool {
@@ -329,7 +387,7 @@ pub fn forEachTyped(self: Directive, T: type, data: T, out: anytype) anyerror!vo
.data = data,
.template = .{
.name = self.noun,
.blob = self.otherwise.blob.trimmed,
.blob = trimLeft(u8, self.otherwise.blob, whitespace),
},
};
try p.format("", .{}, out);
@@ -340,7 +398,7 @@ pub fn withTyped(self: Directive, T: type, block: T, out: anytype) anyerror!void
.data = block,
.template = if (self.otherwise == .template) self.otherwise.template else .{
.name = self.noun,
.blob = self.otherwise.blob.trimmed,
.blob = trim(u8, self.otherwise.blob, whitespace),
},
};
try p.format("", .{}, out);
@@ -391,6 +449,7 @@ pub fn format(d: Directive, comptime _: []const u8, _: std.fmt.FormatOptions, ou
pub fn formatTyped(d: Directive, comptime T: type, ctx: T, out: anytype) !void {
switch (d.verb) {
.variable => {
if (d.known_type) |_| return d.doTyped(T, ctx, out);
const noun = d.noun;
const var_name = typeField(T, noun, ctx);
if (var_name) |data_blob| {
@@ -398,10 +457,11 @@ pub fn formatTyped(d: Directive, comptime T: type, ctx: T, out: anytype) !void {
} else {
//if (DEBUG) std.debug.print("[missing var {s}]\n", .{noun.vari});
switch (d.otherwise) {
.str => |str| try out.writeAll(str),
.default => |str| try out.writeAll(str),
// Not really an error, just instruct caller to print original text
.ign => return error.IgnoreDirective,
.del => {},
.ignore => return error.IgnoreDirective,
.required => return error.VariableMissing,
.delete => {},
.template => |subt| {
if (T == usize) unreachable;
inline for (std.meta.fields(T)) |field|
 
src/template/page.zig added: 288, removed: 211, total 77
@@ -1,4 +1,5 @@
const std = @import("std");
const is_test = @import("builtin").is_test;
const Allocator = std.mem.Allocator;
const eql = std.mem.eql;
 
@@ -32,9 +33,13 @@ pub fn PageRuntime(comptime PageDataType: type) type {
try out.writeAll(blob[0..offset]);
blob = blob[offset..];
if (Directive.init(blob)) |drct| {
const end = drct.end;
const end = drct.tag_block.len;
drct.formatTyped(PageDataType, self.data, out) catch |err| switch (err) {
error.IgnoreDirective => try out.writeAll(blob[0..end]),
error.VariableMissing => {
if (!is_test) std.debug.print("Template Error, variable missing {{{s}}}\n", .{blob[0..end]});
try out.writeAll(blob[0..end]);
},
else => return err,
};
 
@@ -78,9 +83,13 @@ pub fn Page(comptime template: Template, comptime PageDataType: type) type {
blob = blob[offset..];
 
if (Directive.init(blob)) |drct| {
const end = drct.end;
const end = drct.tag_block.len;
drct.formatTyped(PageDataType, self.data, out) catch |err| switch (err) {
error.IgnoreDirective => try out.writeAll(blob[0..end]),
error.VariableMissing => {
if (!is_test) std.debug.print("Template Error, variable missing {{{s}}}\n", .{blob[0..end]});
try out.writeAll(blob[0..end]);
},
else => return err,
};
 
 
templates/5XX.html added: 288, removed: 211, total 77
@@ -18,7 +18,7 @@ really weird, because it was so full of life just the other day!</p>
that's just more blame for you! Is that a risk you're willing to take?!</p>
<p>If you are the system administrator you should already know why <br/>
it's broken what are you still reading this for?!</p>
<p><ErrorString ORNULL></p>
<p><ErrorString ornull></p>
<p><em>Never in your debt, Aye-Aye-Ron from Human Resources.</em></p>
</body>
</html>
 
templates/_meta_head.html added: 288, removed: 211, total 77
@@ -1,7 +1,7 @@
<link href="/static/main.css" rel="stylesheet">
<link href="/static/icons.css" rel="stylesheet">
<With OpenGraph>
<meta property="og:site_name" content="srctree // share your code">
<meta property="og:title" content="<Title ORELSE srctree>">
<meta property="og:description" content="<Desc ORELSE Making git distributed since 2023>">
<meta property="og:site_name" content="srctree // share your code">
<meta property="og:title" content="<Title default='srctree'>">
<meta property="og:description" content="<Desc default='Making git distributed since 2023'>">
</With>
 
templates/blame.html added: 288, removed: 211, total 77
@@ -13,7 +13,7 @@
<code>
<For BlameLines><span class="blame-line">
<span class="blame-header">
<time><Time ORNULL></time>
<time><Time ornull></time>
<a href="/repo/<RepoName>/commit/<Sha>"><Sha>&nbsp;</a>
<With AuthorEmail><author class="muted"><a href="/user?user=<Email>"><Author></a></author></With>
</span>
 
templates/commit-list.html added: 288, removed: 211, total 77
@@ -10,8 +10,8 @@
<For Commits>
<commit>
<data>
<a href="<Uri ORELSE #>" class=muted><Sha></a>
<span><MsgTitle ORNULL></span>
<a href="<Uri>" class=muted><Sha></a>
<span><MsgTitle ornull></span>
<br />
<Msg>
</data>
 
templates/delta-issue.html added: 288, removed: 211, total 77
@@ -15,7 +15,7 @@
<comments>
<Build Comments _comment_thread.html />
<form class="pretty" action="add-comment" method="POST">
<context><CurrentUsername ORNULL></context>
<context><CurrentUsername ornull></context>
<textarea name="comment"></textarea>
<button type="submit" name="comment">Comment</button>
<input type="hidden" name="did" value="<Delta_id>" />
 
templates/delta-list.html added: 288, removed: 211, total 77
@@ -9,7 +9,7 @@
<content>
<search>
<form action="/search" style="width:95%">
<input name="q" type="text" placeholder="Search" value="<Search ORNULL>" style="width:97%">
<input name="q" type="text" placeholder="Search" value="<Search ornull>" style="width:97%">
</form>
<a class="btn" href="new" style="width:5%">New</a>
</search>
 
templates/diff-new.html added: 288, removed: 211, total 77
@@ -9,7 +9,7 @@
<content>
<form class="pretty" action="create" method="POST">
<context>Suggest New Diff</context>
<input name="title" placeholder="Diff Title" value="<Title ORNULL>" />
<input name="title" placeholder="Diff Title" value="<Title ornull>" />
<With Network>
<div style="display:flex">
<select name="network">
@@ -25,7 +25,7 @@
</div>
</With>
<With PatchUri><div style="display:flex"><input name="patch_uri" placeholder="Patch URL" /><button name="from_network" value="true" formaction="new">Use Network</button></div></With>
<textarea name="desc" placeholder="Additional information about this patch suggestion"><Desc ORNULL></textarea>
<textarea name="desc" placeholder="Additional information about this patch suggestion"><Desc ornull></textarea>
<buttons>
<button name="submit">Submit</button>
<button name="preview">Preview (does nothing)</button>
 
templates/gist.html added: 288, removed: 211, total 77
@@ -9,9 +9,9 @@
<content>
<For GistFiles>
<blob>
<header><FileName ORNULL></header>
<header><FileName ornull></header>
<code>
<FileBlob ORNULL>
<FileBlob ornull>
</code>
</blob>
</For>
 
templates/gist_new.html added: 288, removed: 211, total 77
@@ -11,9 +11,9 @@
<For GistFiles>
<div class="block">
<label>File Name</label>
<input name="file_name" value="<Name ORNULL>"/>
<input name="file_name" value="<Name ornull>"/>
<br>
<textarea name="file_blob" cols="100" rows="<Count ORELSE 10>"><Blob ORNULL></textarea>
<textarea name="file_blob" cols="100" rows="<Count default='10'>"><Blob ornull></textarea>
</div>
 
</For>
 
templates/repo-tags.html added: 288, removed: 211, total 77
@@ -11,9 +11,9 @@
<With Upstream>
<a class="btn" href="<URI>">Go To Upstream</a>
</With>
<a class="btn" href="<Repo_name ORNULL>/commits">commits</a>
<a class="btn" href="<Repo_name ORNULL>/issues/new">New Issue</a>
<a class="btn" href="<Repo_name ORNULL>/diffs/new">Suggest Diff</a>
<a class="btn" href="<Repo_name ornull>/commits">commits</a>
<a class="btn" href="<Repo_name ornull>/issues/new">New Issue</a>
<a class="btn" href="<Repo_name ornull>/diffs/new">Suggest Diff</a>
</div>
 
<For Tags>
 
templates/repos.html added: 288, removed: 211, total 77
@@ -12,7 +12,7 @@
<For RepoList>
<repo>
<name><a href="<Uri>"><Name></a></name>
<desc><Desc ORNULL><p class="upstream"><Upstream ORNULL></p>
<desc><Desc ornull><p class="upstream"><Upstream ornull></p>
<div class="updated"><span><Updated></span><With Tag><a href="<Uri>" title="<Title>"><Tag></a></With></div>
</desc><last></last>
</repo>
 
templates/settings.html added: 288, removed: 211, total 77
@@ -13,7 +13,7 @@
<label>Block Name</label>
<input name="block_name" value="<ConfigName ORELSE default>"/>
<br>
<textarea name="block_text" cols="100" rows="<Count ORELSE 10>"><ConfigText ORNULL></textarea>
<textarea name="block_text" cols="100" rows="<Count ORELSE 10>"><ConfigText ornull></textarea>
</div>
 
</For>
 
templates/tree.html added: 288, removed: 211, total 77
@@ -16,7 +16,7 @@
<a class="btn" href="/repo/<RepoName>/diffs/new">Suggest Diff</a>
</div>
<Repo>
<Readme ORNULL>
<Readme ornull>
</content>
</body>
</html>
 
templates/user_commits.html added: 288, removed: 211, total 77
@@ -30,7 +30,7 @@
<intro>
<Group>
</intro>
<Lead ORNULL>
<Lead ornull>
<For JournalRows>
<journal>
<span><a href="/repo/<Repo>/commit/<Sha>"><Sha></a>: <Title></span>