summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-12-01 20:19:34 -0500
committerJune McEnroe <june@causal.agency>2020-12-01 20:19:34 -0500
commit0894022e6db9e119ad42f8e821d9e82d5d4fa4d0 (patch)
treec23b6650ab4ffc7b2f01e5c98d32cbb63e2f8355
parentAdd conditionals to templates (diff)
downloadbubger-0894022e6db9e119ad42f8e821d9e82d5d4fa4d0.tar.gz
bubger-0894022e6db9e119ad42f8e821d9e82d5d4fa4d0.zip
Be even less weird about HTML
-rw-r--r--default.html40
-rw-r--r--html.c236
2 files changed, 108 insertions, 168 deletions
diff --git a/default.html b/default.html
index f1503c4..8573ba6 100644
--- a/default.html
+++ b/default.html
@@ -9,12 +9,8 @@ body {
 	padding: 0 1ch;
 }
 
-nav ul {
-	padding: 0;
-	list-style-type: none;
-}
-nav ul li {
-	display: inline;
+header {
+	margin: 1em 0;
 }
 
 main.index ol {
@@ -46,39 +42,29 @@ article.message header h2 {
 	font-size: 1em;
 	margin: 0;
 }
-article.message header nav ul {
-	margin: 0;
-}
-
-ul.address {
-	padding: 0;
-	list-style-type: none;
-	display: inline;
-}
-ul.address li {
-	display: inline;
-}
 
 pre {
 	white-space: pre-wrap;
 }
-pre q::before, pre q::after {
-	content: none;
-}
-pre q {
+span.quote {
 	color: navy;
 }
-pre q q {
+span.quote.level2 {
 	color: teal;
 }
-pre q q q {
+span.quote.level3 {
 	color: purple;
 }
-pre del {
-	text-decoration: none;
+span.diff.head {
+	font-weight: bold;
+}
+span.diff.hunk {
+	color: navy;
+}
+span.diff.old {
 	color: red;
 }
-pre ins {
+span.diff.new {
 	text-decoration: none;
 	color: green;
 }
diff --git a/html.c b/html.c
index 95afe4d..1757fd9 100644
--- a/html.c
+++ b/html.c
@@ -46,29 +46,21 @@ static char *htmlMailto(struct Address addr) {
 	return templateString("mailto:[mailbox]@[host]", vars, escapeURL);
 }
 
-static int htmlAddress(FILE *file, struct Address addr, bool last) {
+static int htmlAddress(FILE *file, struct Address addr, bool comma) {
 	char *mailto = htmlMailto(addr);
 	const char *template;
 	if (addr.host) {
-		template = Q(
-			<li><a href="[mailto]">[name]</a>[,]</li>
-		);
+		template = Q([,]<a href="[mailto]">[name]</a>);
 	} else if (addr.mailbox) {
-		template = Q(
-			<li>[mailbox]:
-				<ul>
-		);
+		template = "[mailbox]: ";
 	} else {
-		template = Q(
-				</ul>;
-			</li>
-		);
+		template = ";";
 	}
 	struct Variable vars[] = {
 		{ "mailto", mailto },
 		{ "name", addressName(addr) },
 		{ "mailbox", addr.mailbox },
-		{ ",", (last ? "" : ", ") },
+		{ ",", (comma ? ", " : " ") },
 		{0},
 	};
 	int error = templateRender(file, template, vars, escapeXML);
@@ -82,7 +74,6 @@ htmlAddressList(FILE *file, const char *name, struct AddressList list) {
 	const char *template = Q(
 		<div class="[name]">
 			[name]:
-			<ul class="address">
 	);
 	struct Variable vars[] = {
 		{ "name", name },
@@ -91,31 +82,12 @@ htmlAddressList(FILE *file, const char *name, struct AddressList list) {
 	int error = templateRender(file, template, vars, escapeXML);
 	if (error) return error;
 	for (size_t i = 0; i < list.len; ++i) {
-		error = htmlAddress(file, list.addrs[i], i == list.len - 1);
+		error = htmlAddress(
+			file, list.addrs[i], i > 0 && list.addrs[i - 1].host
+		);
 		if (error) return error;
 	}
-	return templateRender(file, Q(</ul></div>), NULL, NULL);
-}
-
-static char *htmlReply(const struct Envelope *envelope) {
-	const char *template = {
-		"mailto:[mailbox]@[host]"
-		"?cc=[cc]"
-		"&subject=[re][subject]"
-		"&In-Reply-To=[<][messageID][>]"
-	};
-	struct Variable vars[] = {
-		{ "mailbox", envelope->replyTo.mailbox },
-		{ "host", envelope->replyTo.host },
-		{ "cc", baseMailto },
-		{ "re", (strncmp(envelope->subject, "Re: ", 4) ? "Re: " : "") },
-		{ "subject", envelope->subject },
-		{ "messageID", envelope->messageID },
-		{ "<", "<" },
-		{ ">", ">" },
-		{0},
-	};
-	return templateString(template, vars, escapeURL);
+	return templateRender(file, Q(</div>), NULL, NULL);
 }
 
 static char *htmlFragment(const char *messageID) {
@@ -135,35 +107,50 @@ static char *htmlMbox(const char *messageID) {
 	return templateString("../" PATH_MESSAGE, vars, escapeURL);
 }
 
-static int
-htmlNavItem(FILE *file, const char *name, const char *base, const char *url) {
-	const char *template = Q(<li><a href="[base][url]">[name]</a> </li>);
+static char *htmlReply(const struct Envelope *envelope) {
+	const char *template = {
+		"mailto:[mailbox]@[host]"
+		"?cc=[cc]"
+		"&subject=[re][subject]"
+		"&In-Reply-To=[<][messageID][>]"
+	};
 	struct Variable vars[] = {
-		{ "name", name },
-		{ "base", base },
-		{ "url", url },
+		{ "mailbox", envelope->replyTo.mailbox },
+		{ "host", envelope->replyTo.host },
+		{ "cc", baseMailto },
+		{ "re", (strncmp(envelope->subject, "Re: ", 4) ? "Re: " : "") },
+		{ "subject", envelope->subject },
+		{ "messageID", envelope->messageID },
+		{ "<", "<" },
+		{ ">", ">" },
 		{0},
 	};
-	return templateRender(file, template, vars, escapeXML);
-}
-
-static int htmlParent(FILE *file, const struct Envelope *envelope) {
-	if (!envelope->inReplyTo) return 0;
-	char *fragment = htmlFragment(envelope->inReplyTo);
-	int error = htmlNavItem(file, "parent", "", fragment);
-	free(fragment);
-	return error;
+	return templateString(template, vars, escapeURL);
 }
 
 int htmlMessageNav(FILE *file, const struct Envelope *envelope) {
+	char *parent = envelope->inReplyTo
+		? htmlFragment(envelope->inReplyTo)
+		: NULL;
 	char *mbox = htmlMbox(envelope->messageID);
 	char *reply = htmlReply(envelope);
-	int error = 0
-		|| templateRender(file, Q(<nav><ul>), NULL, NULL)
-		|| htmlParent(file, envelope)
-		|| htmlNavItem(file, "download", "", mbox)
-		|| htmlNavItem(file, "reply", "", reply)
-		|| templateRender(file, Q(</ul></nav>), NULL, NULL);
+	const char *template = Q(
+		<nav>
+			[+parent]
+			<a href="[parent]">parent</a>
+			[-]
+			<a href="[mbox]">download</a>
+			<a href="[reply]">reply</a>
+		</nav>
+	);
+	struct Variable vars[] = {
+		{ "parent", parent },
+		{ "mbox", mbox },
+		{ "reply", reply },
+		{0},
+	};
+	int error = templateRender(file, template, vars, escapeXML);
+	free(parent);
 	free(mbox);
 	free(reply);
 	return error;
@@ -202,43 +189,6 @@ int htmlMessageOpen(FILE *file, const struct Envelope *envelope) {
 	return error;
 }
 
-static int htmlInlineAttrs(FILE *file, const struct BodyPart *part) {
-	const char *template = " " Q([attr]="[value]");
-	if (part->contentID) {
-		struct Variable vars[] = {
-			{ "attr", "id" },
-			{ "value", part->contentID },
-			{0},
-		};
-		int error = templateRender(file, template, vars, escapeXML);
-		if (error) return error;
-	}
-	if (part->description) {
-		struct Variable vars[] = {
-			{ "attr", "title" },
-			{ "value", part->description },
-			{0},
-		};
-		int error = templateRender(file, template, vars, escapeXML);
-		if (error) return error;
-	}
-	const char *language = NULL;
-	if (part->language.type == String) language = part->language.string;
-	if (part->language.type == List && part->language.list.len == 1) {
-		language = dataCheck(part->language.list.ptr[0], String).string;
-	}
-	if (language) {
-		struct Variable vars[] = {
-			{ "attr", "lang" },
-			{ "value", language },
-			{0},
-		};
-		int error = templateRender(file, template, vars, escapeXML);
-		if (error) return error;
-	}
-	return 0;
-}
-
 static void swap(char *a, char *b) {
 	char ch = *a;
 	*a = *b;
@@ -278,20 +228,17 @@ static int htmlMarkupURLs(FILE *file, char *buf) {
 }
 
 static int htmlMarkupQuote(FILE *file, char *buf) {
-	int error;
-	size_t level = 0;
+	uint32_t level = 0;
 	for (char *ch = buf; *ch == '>' || *ch == ' '; level += (*ch++ == '>'));
-	for (size_t i = 0; i < level; ++i) {
-		error = templateRender(file, Q(<q>), NULL, NULL);
-		if (error) return error;
-	}
-	error = htmlMarkupURLs(file, buf);
-	if (error) return error;
-	for (size_t i = 0; i < level; ++i) {
-		error = templateRender(file, Q(</q>), NULL, NULL);
-		if (error) return error;
-	}
-	return 0;
+	const char *template = Q(<span class="quote level[level]">);
+	struct Variable vars[] = {
+		{ "level", u32(level).s },
+		{0},
+	};
+	return 0
+		|| templateRender(file, template, vars, escapeXML)
+		|| htmlMarkupURLs(file, buf)
+		|| templateRender(file, Q(</span>), NULL, NULL);
 }
 
 static int htmlMarkup(FILE *file, const char *content) {
@@ -319,7 +266,7 @@ static int htmlMarkup(FILE *file, const char *content) {
 			patch = false;
 		}
 
-		static const char *Pattern = "^(diff|index|---|[+]{3}|@@) ";
+		static const char *Pattern = "^(diff|index|---|[+]{3}) ";
 		static regex_t regex;
 		if (!regex.re_nsub) {
 			error = regcomp(&regex, Pattern, REG_EXTENDED);
@@ -327,15 +274,19 @@ static int htmlMarkup(FILE *file, const char *content) {
 		}
 		if (patch && !regexec(&regex, buf, 0, NULL, 0)) {
 			error = templateRender(
-				file, Q(<b>[line]</b>), vars, escapeXML
+				file, Q(<span class="diff head">[line]</span>), vars, escapeXML
+			);
+		} else if (patch && buf[0] == '@' && buf[1] == '@') {
+			error = templateRender(
+				file, Q(<span class="diff hunk">[line]</span>), vars, escapeXML
 			);
 		} else if (patch && buf[0] == '-' && strcmp(buf, "---")) {
 			error = templateRender(
-				file, Q(<del>[line]</del>), vars, escapeXML
+				file, Q(<span class="diff old">[line]</span>), vars, escapeXML
 			);
 		} else if (patch && buf[0] == '+') {
 			error = templateRender(
-				file, Q(<ins>[line]</ins>), vars, escapeXML
+				file, Q(<span class="diff new">[line]</span>), vars, escapeXML
 			);
 		} else if (patch) {
 			error = escapeXML(file, buf);
@@ -354,10 +305,25 @@ static int htmlMarkup(FILE *file, const char *content) {
 }
 
 int htmlInline(FILE *file, const struct BodyPart *part, const char *content) {
+	const char *template = Q(
+		<pre
+			[+contentID]id="[contentID]"[-]
+			[+description]title="[description]"[-]
+			[+language]lang="[language]"[-]>
+	);
+	const char *language = NULL;
+	if (part->language.type == String) language = part->language.string;
+	if (part->language.type == List && part->language.list.len == 1) {
+		language = dataCheck(part->language.list.ptr[0], String).string;
+	}
+	struct Variable vars[] = {
+		{ "contentID", part->contentID },
+		{ "description", part->description },
+		{ "language",  language },
+		{0},
+	};
 	return 0
-		|| templateRender(file, Q(<pre), NULL, NULL)
-		|| htmlInlineAttrs(file, part)
-		|| templateRender(file, Q(>), NULL, NULL)
+		|| templateRender(file, template, vars, escapeXML)
 		|| htmlMarkup(file, content)
 		|| templateRender(file, Q(</pre>), NULL, NULL);
 }
@@ -436,11 +402,9 @@ int htmlThreadOpen(FILE *file, const struct Envelope *envelope) {
 		<header class="thread">
 			<h1>[subject]</h1>
 			<nav>
-				<ul>
-					<li><a href="../index.html">index</a> </li>
-					<li><a href="[atom]">follow</a> </li>
-					<li><a href="[mbox]">download</a> </li>
-				</ul>
+				<a href="../index.html">index</a>
+				<a href="[atom]">follow</a>
+				<a href="[mbox]">download</a>
 			</nav>
 		</header>
 		<main class="thread">
@@ -533,38 +497,28 @@ int htmlIndexHead(FILE *file) {
 	return templateRender(file, template, vars, escapeXML);
 }
 
-static int htmlIndexNav(FILE *file) {
-	int error = 0
-		|| templateRender(file, Q(<nav><ul>), NULL, NULL)
-		|| htmlNavItem(file, "follow", "", "index.atom");
-	if (error) return error;
-	if (baseSubscribe) {
-		error = htmlNavItem(file, "subscribe", "", baseSubscribe);
-		if (error) return error;
-	}
-	return 0
-		|| htmlNavItem(file, "write", "mailto:", baseMailto)
-		|| templateRender(file, Q(</ul></nav>), NULL, NULL);
-}
-
 int htmlIndexOpen(FILE *file) {
-	const char *head = Q(
+	const char *template = Q(
 		<header class="index">
 			<h1>[title]</h1>
-	);
-	const char *tail = Q(
+			<nav>
+				<a href="index.atom">follow</a>
+				[+subscribe]
+				<a href="[subscribe]">subscribe</a>
+				[-]
+				<a href="mailto:[mailto]">write</a>
+			</nav>
 		</header>
 		<main class="index">
 			<ol>
 	);
 	struct Variable vars[] = {
 		{ "title", baseTitle },
+		{ "subscribe", baseSubscribe },
+		{ "mailto", baseMailto },
 		{0},
 	};
-	return 0
-		|| templateRender(file, head, vars, escapeXML)
-		|| htmlIndexNav(file)
-		|| templateRender(file, tail, vars, escapeXML);
+	return templateRender(file, template, vars, escapeXML);
 }
 
 static char *htmlIndexURL(const struct Envelope *envelope) {