summary refs log tree commit diff
diff options
context:
space:
mode:
authorWormHeamer2025-03-10 15:40:01 -0400
committerWormHeamer2025-03-10 15:40:01 -0400
commit913c7e3bc4a8ba2b9ec46e4cd33286c713968f0b (patch)
treee82192a7e2d870f7a810a2908a3dde12c464f15f
parent9ab6a07efd2b89b01020470c17b3b9341f391faf (diff)
add figure support
-rw-r--r--main.c124
1 files changed, 89 insertions, 35 deletions
diff --git a/main.c b/main.c
index 553ed06..267c56f 100644
--- a/main.c
+++ b/main.c
@@ -88,6 +88,7 @@ typedef enum {
 	LN_PAR,
 	LN_CODE,
 	LN_LINK,
+	LN_IMG,
 	LN_BQUOT,
 	LN_ULIST,
 	LN_OLIST,
@@ -99,7 +100,7 @@ typedef enum {
 
 typedef struct Line Line;
 struct Line {
-	Str txt;
+	Str txt, url;
 	Line *next;
 };
 
@@ -148,6 +149,64 @@ LineType classify_line(Str line, LineType prev) {
 	}
 }
 
+int has_image_ext(Str url) {
+	return str_ends(url, S(".png"))
+		|| str_ends(url, S(".jpg"))
+		|| str_ends(url, S(".jpeg"))
+		|| str_ends(url, S(".webp"));
+}
+
+/* can change the line type based on parsing */
+LineType line_init(Line *l, Str txt, LineType t) {
+	Cut c;
+	switch (t) {
+	case LN_LINK:
+		c = str_cut(str_trim(str_skip(txt, 2)), ' ');
+		c.tail = str_trim(c.tail);
+		l->url = c.head;
+		l->txt = c.tail.n > 0 ? c.tail : c.head;
+		return has_image_ext(l->url) ? LN_IMG : LN_LINK;
+	case LN_HDR1:
+		l->txt = str_trim(str_skip(txt, 1));
+		break;
+	case LN_HDR2:
+		l->txt = str_trim(str_skip(txt, 2));
+		break;
+	case LN_HDR3:
+		l->txt = str_trim(str_skip(txt, 3));
+		break;
+	case LN_ULIST:
+		l->txt = str_skip(txt, 2);
+		break;
+	case LN_OLIST:
+		l->txt = str_trim(str_cut(l->txt, '.').tail);
+		break;
+	case LN_BQUOT:
+		l->txt = str_trim(str_skip(txt, 1));
+		break;
+	default:
+		l->txt = txt;
+		break;
+	}
+	return t;
+}
+
+Block *blk_push(BlockList *blk, Line **lptr, LineType t, Arena *perm) {
+	if (blk->cap <= blk->len) {
+		size_t c = blk->cap;
+		if (!c) c = 16;
+		while (c <= blk->len) c <<= 1;
+		blk->data = resize(perm, blk->data,
+				blk->cap, c);
+		blk->cap = c;
+	}
+	Block *b = &blk->data[blk->len++];
+	b->type = t;
+	b->lines = NULL;
+	*lptr = NULL;
+	return b;
+}
+
 BlockList blk_gather(Str src, Arena *perm) {
 	Str line;
 	LineType last = LN_NONE;
@@ -160,25 +219,18 @@ BlockList blk_gather(Str src, Arena *perm) {
 		} else if (t == LN_CODE) {
 			last = LN_CODE;
 		} else {
-			if (blk.len < 1 || t != blk.data[blk.len-1].type) {
-				if (blk.cap <= blk.len) {
-					size_t c = blk.cap;
-					if (!c) c = 16;
-					while (c <= blk.len) c <<= 1;
-					blk.data = resize(perm, blk.data,
-							blk.cap, c);
-					blk.cap = c;
-				}
-				Block *b = &blk.data[blk.len++];
-				b->type = t;
-				b->lines = NULL;
-				lptr = NULL;
+			Block *b = blk.len > 0 ? &blk.data[blk.len-1] : NULL;
+			if (!b || t != b->type) {
+				b = blk_push(&blk, &lptr, t, perm);
 			}
 			Line *l = new(perm, Line);
-			l->txt = line;
+			LineType nt = line_init(l, line, t);
+			if (b->type != nt) {
+				if (b->lines) b = blk_push(&blk, &lptr, nt, perm);
+				else b->type = nt;
+			}
 			if (lptr) lptr->next = l;
 			lptr = l;
-			Block *b = &blk.data[blk.len-1];
 			if (!b->lines) b->lines = lptr;
 		}
 		last = t;
@@ -212,42 +264,51 @@ void str_cat_blk(Str *out, Block *blk, Arena *perm, Arena *scratch) {
 	case LN_LINK:
 		Os("<ul>\n");
 		for (Line *l = blk->lines; l; l = l->next) {
-			Cut c = str_cut(str_trim(str_skip(l->txt, 2)), ' ');
-			Str url = c.head, txt = c.tail.n > 0 ? c.tail : c.head;
 			Os("<li><a href=");
-			str_cat_uri(out, str_contains(url, S("://")) ? url :
-					str_replace_end(url, S(".gmi"),
-						S(".html"), scratch), perm);
-			Ot(">", txt, "</a></li>\n");
+			str_cat_uri(out, str_contains(l->url, S("://"))
+					? l->url
+					: str_replace_end(l->url,
+						S(".gmi"), S(".html"),
+						scratch), perm);
+			Ot(">", l->txt, "</a></li>\n");
 		}
 		Os("</ul>");
 		break;
+	case LN_IMG:
+		for (Line *l = blk->lines; l; l = l->next) {
+			Os("<figure>\n");
+			Ot("<figcaption>", l->txt, "</figcaption>\n<img src=");
+			str_cat_uri(out, l->url, perm);
+			Os(">\n</figcaption>");
+			if (l->next) Os("\n");
+		}
+		break;
 	case LN_BQUOT:
 		Os("<blockquote>");
 		for (Line *l = blk->lines; l; l = l->next) {
-			O(str_trim(str_skip(l->txt, 1)));
+			O(l->txt);
 			if (l->next) Os("<br>\n");
 		}
 		Os("<blockquote>");
 		break;
 	case LN_ULIST:
 		Os("<ul>\n");
-		Otl("<li>", str_skip(l->txt, 2), "</li>\n");
+		Otl("<li>", l->txt, "</li>\n");
 		Os("<ul>");
 		break;
 	case LN_OLIST:
 		Os("<ol>\n");
-		Otl("<li>", str_trim(str_cut(l->txt, '.').tail), "</li>\n");
+		Otl("<li>", l->txt, "</li>\n");
 		Os("<ol>");
 		break;
 	case LN_HDR1:
-		Otl("<h1>", str_trim(str_skip(l->txt,1)), "</h1>");
+		Otl("<h1>", l->txt, "</h1>");
 		break;
 	case LN_HDR2:
-		Otl("<h2>", str_trim(str_skip(l->txt,2)), "</h2>");
+		Otl("<h2>", l->txt, "</h2>");
 		break;
 	case LN_HDR3:
-		Otl("<h3>", str_trim(str_skip(l->txt,3)), "</h3>");
+		Otl("<h3>", l->txt, "</h3>");
 		break;
 	default:
 	case LN_PAR:
@@ -262,13 +323,6 @@ void str_cat_blk(Str *out, Block *blk, Arena *perm, Arena *scratch) {
 	Os("\n");
 }
 
-int has_image_ext(Str url) {
-	return str_ends(url, S(".png"))
-		|| str_ends(url, S(".jpg"))
-		|| str_ends(url, S(".jpeg"))
-		|| str_ends(url, S(".webp"));
-}
-
 int wdoc(FILE *f, Doc **dp, Arena *perm, Arena *scratch) {
 	Str buf;
 	if (read_all(f, &buf, scratch)) return -1;