about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-04-23 11:37:51 -0400
committerJune McEnroe <june@causal.agency>2020-04-23 11:37:51 -0400
commita204deb1bc65a2d52f23bade4cdc4b319a62edf3 (patch)
tree29f6320861c95d619ac926648c2e0eb976109930
parentMake sure to close attachment <ul> at end of multipart (diff)
downloadbubger-a204deb1bc65a2d52f23bade4cdc4b319a62edf3.tar.gz
bubger-a204deb1bc65a2d52f23bade4cdc4b319a62edf3.zip
Add basic patch highlighting
-rw-r--r--html.c66
1 files changed, 60 insertions, 6 deletions
diff --git a/html.c b/html.c
index 5f7dc16..b883414 100644
--- a/html.c
+++ b/html.c
@@ -167,7 +167,7 @@ int htmlMessageOpen(FILE *file, const struct Envelope *envelope) {
 	return error;
 }
 
-int htmlInlineAttrs(FILE *file, const struct BodyPart *part) {
+static int htmlInlineAttrs(FILE *file, const struct BodyPart *part) {
 	const char *template = " [attr]=\"[value]\"";
 	if (part->id) {
 		struct Variable vars[] = {
@@ -204,14 +204,68 @@ int htmlInlineAttrs(FILE *file, const struct BodyPart *part) {
 	return 0;
 }
 
+static bool isPatch(const char *content) {
+	return !strncmp(content, "---\n", 4) || strstr(content, "\n---\n");
+}
+
+static int htmlPatch(FILE *file, const char *content) {
+	int error = 0;
+	size_t cap = 0;
+	char *buf = NULL;
+	bool patch = false;
+	for (const char *nl; (nl = strchr(content, '\n')); content = &nl[1]) {
+		size_t len = &nl[1] - content;
+		if (cap < len + 1) {
+			cap = len + 1;
+			buf = realloc(buf, cap);
+			if (!buf) err(EX_OSERR, "realloc");
+		}
+		memcpy(buf, content, len);
+		buf[len] = '\0';
+		struct Variable vars[] = {
+			{ "line", buf },
+			{0},
+		};
+
+		if (!strcmp(buf, "---\n")) {
+			patch = true;
+		} else if (patch && !strcmp(buf, "-- \n")) {
+			patch = false;
+		}
+
+		if (patch && !strncmp(buf, "@@", 2)) {
+			error = templateRender(
+				file, TEMPLATE(<b>[line]</b>), vars, escapeXML
+			);
+		} else if (patch && buf[0] == '-' && strncmp(buf, "---", 3)) {
+			error = templateRender(
+				file, TEMPLATE(<del>[line]</del>), vars, escapeXML
+			);
+		} else if (patch && buf[0] == '+' && strncmp(buf, "+++", 3)) {
+			error = templateRender(
+				file, TEMPLATE(<ins>[line]</ins>), vars, escapeXML
+			);
+		} else {
+			error = escapeXML(file, buf);
+		}
+		if (error) break;
+	}
+	free(buf);
+	return error;
+}
+
 int htmlInline(FILE *file, const struct BodyPart *part, const char *content) {
-	// TODO: Process diffs -> <ins>, <del>
-	return 0
+	int error = 0
 		|| templateRender(file, TEMPLATE(<pre), NULL, NULL)
 		|| htmlInlineAttrs(file, part)
-		|| templateRender(file, TEMPLATE(>), NULL, NULL)
-		|| escapeXML(file, content)
-		|| templateRender(file, TEMPLATE(</pre>), NULL, NULL);
+		|| templateRender(file, TEMPLATE(>), NULL, NULL);
+	if (error) return error;
+	if (isPatch(content)) {
+		error = htmlPatch(file, content);
+	} else {
+		error = escapeXML(file, content);
+	}
+	return error || templateRender(file, TEMPLATE(</pre>), NULL, NULL);
 }
 
 int htmlAttachmentOpen(FILE *file) {