summary refs log tree commit diff
path: root/bin/hilex/html.c
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-12-29 00:55:47 -0500
committerJune McEnroe <june@causal.agency>2020-12-29 00:55:47 -0500
commitcc1cb6c36ecb93e7b9b458f4ea24d1f00480503b (patch)
treea52adc39db865db26dba4d640723376b62ec0b83 /bin/hilex/html.c
parentAdd hilex manual page (diff)
downloadsrc-cc1cb6c36ecb93e7b9b458f4ea24d1f00480503b.tar.gz
src-cc1cb6c36ecb93e7b9b458f4ea24d1f00480503b.zip
Add hilex HTML output
Diffstat (limited to '')
-rw-r--r--bin/hilex/html.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/bin/hilex/html.c b/bin/hilex/html.c
new file mode 100644
index 00000000..2fcbcc57
--- /dev/null
+++ b/bin/hilex/html.c
@@ -0,0 +1,135 @@
+/* Copyright (C) 2020  June McEnroe <june@causal.agency>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hilex.h"
+
+static void htmlEscape(const char *text) {
+	while (*text) {
+		switch (*text) {
+			break; case '"': text++; printf("&quot;");
+			break; case '&': text++; printf("&amp;");
+			break; case '<': text++; printf("&lt;");
+		}
+		size_t len = strcspn(text, "\"&<");
+		if (len) fwrite(text, len, 1, stdout);
+		text += len;
+	}
+}
+
+static const char *Class[ClassCap] = {
+#define X(class) [class] = #class,
+	ENUM_CLASS
+#undef X
+};
+
+static const char *Style[ClassCap] = {
+	[Keyword]      = "color: dimgray;",
+	[Tag]          = "color: inherit;",
+	[Macro]        = "color: green;",
+	[Comment]      = "color: navy;",
+	[String]       = "color: teal;",
+	[StringFormat] = "color: teal; font-weight: bold;",
+};
+
+static void styleTabSize(const char *tab) {
+	printf("-moz-tab-size: ");
+	htmlEscape(tab);
+	printf("; tab-size: ");
+	htmlEscape(tab);
+	printf(";");
+}
+
+static void htmlHeader(const char *opts[]) {
+	if (!opts[Document]) goto body;
+
+	printf("<!DOCTYPE html>\n<title>");
+	if (opts[Title]) htmlEscape(opts[Title]);
+	printf("</title>\n");
+
+	if (opts[CSS]) {
+		printf("<link rel=\"stylesheet\" href=\"");
+		htmlEscape(opts[CSS]);
+		printf("\">\n");
+	} else if (!opts[Inline]) {
+		printf("<style>\n");
+		if (opts[Tab]) {
+			printf("pre.hi { ");
+			styleTabSize(opts[Tab]);
+			printf(" }\n");
+		}
+		for (enum Class class = 0; class < ClassCap; ++class) {
+			if (!Style[class]) continue;
+			printf(".hi.%s { %s }\n", Class[class], Style[class]);
+		}
+		if (opts[Anchor]) {
+			printf(
+				".hi.%s:target { color: goldenrod; outline: none; }\n",
+				Class[Tag]
+			);
+		}
+		printf("</style>\n");
+	}
+
+body:
+	if (opts[Inline] && opts[Tab]) {
+		printf("<pre class=\"hi\" style=\"");
+		styleTabSize(opts[Tab]);
+		printf("\">");
+	} else {
+		printf("<pre class=\"hi\">");
+	}
+}
+
+static void htmlFooter(const char *opts[]) {
+	printf("</pre>");
+	if (opts[Document]) printf("\n");
+}
+
+static void htmlAnchor(const char *opts[], const char *text) {
+	if (opts[Inline]) {
+		printf("<a style=\"%s\" id=\"", Style[Tag]);
+	} else {
+		printf("<a class=\"hi %s\" id=\"", Class[Tag]);
+	}
+	htmlEscape(text);
+	printf("\" href=\"#");
+	htmlEscape(text);
+	printf("\">");
+	htmlEscape(text);
+	printf("</a>");
+}
+
+static void htmlFormat(const char *opts[], enum Class class, const char *text) {
+	if (opts[Anchor] && class == Tag) {
+		htmlAnchor(opts, text);
+	} else if (class == Normal) {
+		htmlEscape(text);
+	} else {
+		if (opts[Inline]) {
+			printf("<span style=\"%s\">", Style[class] ? Style[class] : "");
+		} else {
+			printf("<span class=\"hi %s\">", Class[class]);
+		}
+		htmlEscape(text);
+		printf("</span>");
+	}
+}
+
+const struct Formatter FormatHTML = { htmlHeader, htmlFormat, htmlFooter };