summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--main.c82
1 files changed, 56 insertions, 26 deletions
diff --git a/main.c b/main.c
index 0cddf91..caaee7c 100644
--- a/main.c
+++ b/main.c
@@ -13,10 +13,12 @@
 #include "args.h"
 
 typedef struct {
+	Str language;
 	int standalone;
 	int from_stdin;
 	Str stylesheet;
 	int inlinep;
+	int smartquot;
 	int csslink;
 	Str hvarv[1024];
 	Str title;
@@ -268,11 +270,15 @@ BlockList blk_gather(Str src, Arena *perm) {
 #define Otl(a, f, b) for (Line *l = blk->lines; l; l = l->next) Ot(a, f, b)
 
 typedef enum {
-	IM_NONE,
 	IM_ITAL,
-	IM_CODE
+	IM_CODE,
+	IM_DQUOT,
+	IM_NONE
 } InlineMarkup;
 
+Str im_str_op[IM_NONE] = { S( "<em>"), S( "<code>"), S("“") };
+Str im_str_cl[IM_NONE] = { S("</em>"), S("</code>"), S("”") };
+
 typedef struct {
 	int stkc;
 	InlineMarkup *stkv;
@@ -287,19 +293,11 @@ InlineMarkup im_last(InlineState *ms) {
 }
 
 void im_cat_op(Str *out, InlineMarkup mu, Arena *perm) {
-	switch (mu) {
-	case IM_ITAL: str_cat(out, S("<em>"), perm); break;
-	case IM_CODE: str_cat(out, S("<code>"), perm); break;
-	default: break;
-	}
+	str_cat(out, im_str_op[mu], perm);
 }
 
 void im_cat_cl(Str *out, InlineMarkup mu, Arena *perm) {
-	switch (mu) {
-	case IM_ITAL: str_cat(out, S("</em>"), perm); break;
-	case IM_CODE: str_cat(out, S("</code>"), perm); break;
-	default: break;
-	}
+	str_cat(out, im_str_cl[mu], perm);
 }
 
 InlineMarkup im_pop(InlineState *ms) {
@@ -325,6 +323,14 @@ void im_cl(InlineState *ms, Str *out, Arena *perm) {
 	im_cat_cl(out, im_pop(ms), perm);
 }
 
+void im_tog(InlineState *ms, Str *out, InlineMarkup mu, Arena *scratch, Arena *perm) {
+	if (im_last(ms) == mu) {
+		im_cl(ms, out, perm);
+	} else {
+		im_op(ms, out, mu, scratch, perm);
+	}
+}
+
 void markup_inline(InlineState *ms, Str *out, Str src, Arena *scratch, Arena *perm) {
 	if (!opts.inlinep) {
 		str_cat_html(out, src, perm);
@@ -339,15 +345,10 @@ void markup_inline(InlineState *ms, Str *out, Str src, Arena *scratch, Arena *pe
 				str_catc_html(out, src.s[i], perm);
 			}
 		} else {
-			if (c == '`') {
-				im_op(ms, out, IM_CODE, scratch, perm);
-			} else if (c == '*') {
-				if (im_last(ms) == IM_ITAL) {
-					im_cl(ms, out, perm);
-				} else {
-					im_op(ms, out, IM_ITAL, scratch, perm);
-				}
-			} else if (str_starts(str_skip(src, i), S("---"))) {
+			if (c == '`') im_op(ms, out, IM_CODE, scratch, perm);
+			else if (c == '*') im_tog(ms, out, IM_ITAL, scratch, perm);
+			else if (c == '"' && opts.smartquot) im_tog(ms, out, IM_DQUOT, scratch, perm);
+			else if (str_starts(str_skip(src, i), S("---"))) {
 				str_cat(out, S("&mdash;"), perm);
 				i += 2;
 			} else {
@@ -483,7 +484,7 @@ int hvar_calc(Str param, Str *name, Str *val, Str filename) {
 
 void usage(const char *cmd) {
 	fprintf(stderr, "usage: %s -?\n"
-			"       %s [-s] [-i] [[-l] -c FILE] [-t TITLE] [-h NAME:ARG1[,ARG2,ARG3...]] [FILES...]\n"
+			"       %s [-silq] [-L LANG] [-c FILE] [-t TITLE] [-h NAME:ARG1[,ARG2,ARG3...]] [FILES...]\n"
 			"\n"
 			" -? --help         show this help text\n"
 			" -s --standalone   prefix with html metadata\n"
@@ -493,14 +494,25 @@ void usage(const char *cmd) {
 			" -l --link         when combined with --css, link to an external stylehseet\n"
 			"                   instead of reading from a file locally\n"
 			" -i --inline       enable inline formatting (*italics*, `code`, ---dashes)\n"
-			" -t --title        set the document title (does nothing without --standalone)\n",
+			" -q --smartq       enable smart quotes\n"
+			" -t --title        set the document title (does nothing without --standalone)\n"
+			" -L --lang         set the document's language\n",
 			cmd, cmd);
 }
 
 Str html_head(Arena *m, Arena *l) {
-	Str h = S("<!DOCTYPE html>\n"
+	Str h = S("<!DOCTYPE html>\n");
+
+	if (opts.language.n) {
+		str_cat(&h, S("<html lang="), m);
+		str_cat_uri(&h, opts.language, m);
+		str_cat(&h, S(">\n"), m);
+	}
+
+	str_cat(&h, S(
 			"<meta charset=utf-8>\n"
-			"<meta name=viewport content='width=device-width,initial-scale=1'>\n");
+			"<meta name=viewport content='width=device-width,initial-scale=1'>\n"
+			), m);
 
 	if (opts.title.s) {
 		str_cat(&h, S("<title>"), m);
@@ -549,6 +561,14 @@ Str html_head(Arena *m, Arena *l) {
 			str_cat(&h, S("</style>"), m);
 		}
 	}
+
+	return h;
+}
+
+Str html_tail(Arena *m, Arena *l) {
+	(void)l;
+	Str h = S("");
+	if (opts.language.n) str_cat(&h, S("</html>"), m);
 	return h;
 }
 
@@ -566,13 +586,15 @@ int main(int argc, const char **argv) {
 	Str param = { 0 };
 	opts.from_stdin = 1;
 
-	while ((r = arg_get(&a, "?slic:h:t:", &param,
+	while ((r = arg_get(&a, "?sliqc:h:t:L:", &param,
 					"help", '?',
 					"standalone", 's',
+					"smartq", 'q',
 					"inline", 'i',
 					":title", 't',
 					":css", 'c',
 					"link", 'l',
+					"lang", 'L',
 					":hvar", 'h')) >= ARG_OK) {
 		Arena reset = scratch;
 		FILE *f;
@@ -586,12 +608,18 @@ int main(int argc, const char **argv) {
 		case 'i':
 			opts.inlinep = 1;
 			break;
+		case 'q':
+			opts.smartquot = 1;
+			break;
 		case 'c':
 			opts.stylesheet = param;
 			break;
 		case 'l':
 			opts.csslink = 1;
 			break;
+		case 'L':
+			opts.language = param;
+			break;
 		case 't':
 			opts.title = param;
 			break;
@@ -663,5 +691,7 @@ int main(int argc, const char **argv) {
 		doc = doc->next;
 	}
 
+	str_put(html_tail(&perm, &scratch));
+
 	return 0;
 }