From f30af4d2a2e313a53a447b6dd6918b43635caf3d Mon Sep 17 00:00:00 2001 From: WormHeamer Date: Sun, 9 Mar 2025 18:11:05 -0400 Subject: construct list of blocks and lines first, instead of a single pass --- main.c | 309 +++++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 176 insertions(+), 133 deletions(-) diff --git a/main.c b/main.c index fa12a70..70029f8 100644 --- a/main.c +++ b/main.c @@ -79,6 +79,42 @@ void str_cat_html(Str *s, Str uri, Arena *a) { } } +typedef struct Doc Doc; +struct Doc { + Str html; + Str title; + Doc *prev, *next; +}; + +typedef enum { + LN_PAR, + LN_CODE, + LN_LINK, + LN_BQUOT, + LN_ULIST, + LN_OLIST, + LN_HDR1, + LN_HDR2, + LN_HDR3, + LN_NONE +} LineType; + +typedef struct Line Line; +struct Line { + Str txt; + Line *next; +}; + +typedef struct { + LineType type; + Line *lines; +} Block; + +typedef struct { + Block *data; + size_t len, cap; +} BlockList; + int is_ol_item(Str s) { Str h = str_cut(s, '.').head; if (h.n < 1) return 0; @@ -88,74 +124,142 @@ int is_ol_item(Str s) { return 1; } -typedef enum { - LINE_BLANK, LINE_PARA, - LINE_LINK, LINE_FIGURE, - LINE_UL, LINE_OL, - LINE_HDR1, LINE_HDR2, LINE_HDR3, LINE_CODE, - LINE_BQUOT, -} LineMode; - -LineMode lm_chg(LineMode from, LineMode to, Str *out, Arena *a) { -#undef S -#define S(s) {s,sizeof(s)-1} - static Str op[] = { - [LINE_BLANK] = S(""), - [LINE_PARA] = S("
"), - [LINE_LINK] = S("
"),
- [LINE_BQUOT] = S(""),
- };
- static Str cl[] = {
- [LINE_BLANK] = S(""),
- [LINE_PARA] = S(""),
- [LINE_LINK] = S("
");
+ for (Line *l = blk->lines; l; l = l->next) {
+ O(l->txt);
+ Os("\n");
+ }
+ Os("
");
+ break;
+ case LN_LINK:
+ Os(""); + for (Line *l = blk->lines; l; l = l->next) { + O(str_trim(str_skip(l->txt, 1))); + if (l->next) Os("
\n"); + } + Os(""); + break; + case LN_ULIST: + Os("\n"); + Otl("
- ", str_skip(l->txt, 2), "
\n"); + Os(""); + break; + case LN_OLIST: + Os("
\n"); + Otl("
- ", str_trim(str_cut(l->txt, '.').tail), "
\n"); + Os(""); + break; + case LN_HDR1: + Otl("
", str_trim(str_skip(l->txt,1)), "
"); + break; + case LN_HDR2: + Otl("", str_trim(str_skip(l->txt,2)), "
"); + break; + case LN_HDR3: + Otl("", str_trim(str_skip(l->txt,3)), "
"); + break; + default: + case LN_PAR: + Os(""); + for (Line *l = blk->lines; l; l = l->next) { + O(l->txt); + if (l->next) Os("
"); + break; + } + Os("\n"); +} int has_image_ext(Str url) { return str_ends(url, S(".png")) @@ -172,78 +276,17 @@ Str str_replace_end(Str s, Str a, Str b, Arena *m) { return (Str) { p, s.n + b.n - a.n }; } -int wdoc(FILE *f, Doc **dp, Arena *a, Arena *scratch) { - Str buf, line, out = {0}, title = {0}; +int wdoc(FILE *f, Doc **dp, Arena *perm, Arena *scratch) { + Str buf; if (read_all(f, &buf, scratch)) return -1; - LineMode lm = LINE_BLANK; - while (next_line(&buf, &line)) { - if (str_starts(line, S("```"))) { - lm = lm_chg(lm, lm == LINE_CODE ? LINE_BLANK : LINE_CODE, &out, a); - continue; - } else if (lm == LINE_CODE) { - lm = lm_chg(lm, LINE_CODE, &out, a); - str_cat(&out, line, a); - continue; - } else if (line.n == 0) { - lm = lm_chg(lm, LINE_BLANK, &out, a); - } else if (str_starts(line, S("=>"))) { - line = str_trim(str_skip(line, 2)); - isize i = 0; - while (i < line.n && !is_space(line.s[i])) i++; - Str url = { line.s, i }; - line = str_trim(str_skip(line, i)); - if (!str_starts(url, S("gemini://"))) { - url = str_replace_end(url, S(".gmi"), S(".html"), scratch); - } - if (has_image_ext(url)) { - lm = lm_chg(lm, LINE_FIGURE, &out, a); - str_cat(&out, S("
\n"); + } + Os(""), a); - str_cat_html(&out, line, a); - str_cat(&out, S(""), a); - } - } else { - Str display = line.n > 0 ? line : url; - lm = lm_chg(lm, LINE_LINK, &out, a); - str_cat(&out, S(""), a); - } - } else if (str_starts(line, S("*"))) { - lm = lm_chg(lm, LINE_UL, &out, a); - str_cat_html(&out, str_trim(str_skip(line, 1)), a); - } else if (is_ol_item(line)) { - lm = lm_chg(lm, LINE_OL, &out, a); - str_cat_html(&out, str_trim(str_cut(line, '.').tail), a); - } else if (str_starts(line, S("###"))) { - lm = lm_chg(lm, LINE_HDR3, &out, a); - str_cat_html(&out, str_trim(str_skip(line, 3)), a); - } else if (str_starts(line, S("##"))) { - lm = lm_chg(lm, LINE_HDR2, &out, a); - str_cat_html(&out, str_trim(str_skip(line, 2)), a); - } else if (str_starts(line, S("#"))) { - lm = lm_chg(lm, LINE_HDR1, &out, a); - title = str_trim(str_skip(line, 1)); - str_cat_html(&out, title, a); - } else if (str_starts(line, S(">"))) { - lm = lm_chg(lm, LINE_BQUOT, &out, a); - str_cat_html(&out, str_trim(str_skip(line, 1)), a); - } else { - lm = lm_chg(lm, LINE_PARA, &out, a); - str_cat_html(&out, line, a); + Doc *d = new(perm, Doc); + BlockList blk = blk_gather(buf, scratch); + for (size_t i = 0; i < blk.len; i++) { + if (blk.data[i].type == LN_HDR1 && !d->title.s) { + d->title = str_trim(str_skip(blk.data[i].lines->txt, 1)); } + str_cat_blk(&d->html, &blk.data[i], perm); } - lm = lm_chg(lm, LINE_BLANK, &out, a); - Doc *d = new(a, Doc); - if (title.s) d->title = str_dup(title, a); - d->html = out; - d->prev = (*dp); - if (*dp) (*dp)->next = d; *dp = d; return 0; } -- cgit 1.4.1-2-gfad0