Welcome to little lamb

Code » qmdoc » commit b2c06ef

Refactor how titles (<hX>) & page title work

author Olivier Brunel
2022-12-28 08:46:02 UTC
committer Olivier Brunel
2022-12-28 08:46:05 UTC
parent 04eefb2681026187c8603c500ffb1bbd5509f930

Refactor how titles (<hX>) & page title work

Titles will now also be buffered at first, that way we can put the
opening <section> *before* the <hX> tag, which is better.
Also put the entire section into a <scetion> block.

main.c +49 -25

diff --git a/main.c b/main.c
index 7dfe740..8a32d45 100644
--- a/main.c
+++ b/main.c
@@ -55,6 +55,10 @@ struct page {
     size_t size;
 };
 
+enum {
+    DOC_HAS_TITLE   = (1 << 0),
+};
+
 enum {
     BUF_OFF = 0,
     BUF_WAITING,
@@ -65,23 +69,30 @@ struct ctx {
     int options;
     stralloc sa;
     size_t otoc;
-    size_t otitle;
     stralloc sa_out;
     int toc_lvl;
     struct css *css;
     struct page *pages;
     int nb_pages;
     int cur_page;
-    const char *title;
     struct {
+        const char *title;
         int flags;
-        int from;
-    } code;
+    } doc;
     struct {
         stralloc sa;
         size_t salen;
         int state;
     } buf;
+    union {
+        struct {
+            int level;
+        } title;
+        struct {
+            int flags;
+            int from;
+        } code;
+    };
 };
 
 enum {
@@ -282,7 +293,7 @@ enter_block(MD_BLOCKTYPE type, void *details, void *ctx_)
                     }
                 }
                 if (!raw_str(ctx, "</head><body><header><section><h1>")
-                        || !escape_text(ctx, ctx->title, strlen(ctx->title))
+                        || !escape_text(ctx, ctx->doc.title, strlen(ctx->doc.title))
                         || !raw_str(ctx, "</h1></section><nav><ul>"))
                     return ERR_PARSER_ENTER_BLOCK;
 
@@ -345,13 +356,15 @@ enter_block(MD_BLOCKTYPE type, void *details, void *ctx_)
         case MD_BLOCK_H:
             {
                 MD_BLOCK_H_DETAIL *d = details;
-                char buf[UINT32_FMT];
-                buf[uint32_fmt(buf, (uint32) d->level)] = '\0';
-                if (!raw_str(ctx, "<h") || !raw_str(ctx, buf) || !raw_str(ctx, ">"))
+                ctx->title.level = d->level;
+
+                if ((ctx->doc.flags & DOC_HAS_TITLE) && !raw_str(ctx, "</section>"))
                     return ERR_PARSER_ENTER_BLOCK;
+                ctx->doc.flags |= DOC_HAS_TITLE;
 
-                /* TOC */
                 ctx->buf.state = BUF_ON;
+
+                /* TOC */
                 for ( ; ctx->toc_lvl < d->level; ++ctx->toc_lvl) {
                     if (!raw_str(ctx, "<ul>"))
                         return ERR_PARSER_TOC;
@@ -360,8 +373,7 @@ enter_block(MD_BLOCKTYPE type, void *details, void *ctx_)
                     if (!raw_str(ctx, "</ul>"))
                         return ERR_PARSER_TOC;
                 }
-                ctx->buf.state = BUF_OFF;
-                ctx->otitle = ctx->sa_out.len;
+                ctx->buf.salen = ctx->buf.sa.len;
             }
             break;
 
@@ -369,8 +381,7 @@ enter_block(MD_BLOCKTYPE type, void *details, void *ctx_)
             {
                 MD_BLOCK_CODE_DETAIL *d = details;
 
-                if (ctx->code.flags)
-                    return ERR_INVALID;
+                ctx->code.flags = 0;
 
                 if (!d->info.text || !strncmp(d->info.text, "pre\n", 4)) {
                     return (raw_str(ctx, "<pre>")) ? 0 : ERR_PARSER_ENTER_BLOCK;
@@ -451,7 +462,8 @@ leave_block(MD_BLOCKTYPE type, void *details, void *ctx_)
 
     switch (type) {
         case MD_BLOCK_DOC:
-            if (!raw_str(ctx, "</body></html>"))
+            if (((ctx->doc.flags & DOC_HAS_TITLE) && !raw_str(ctx, "</section>"))
+                    || !raw_str(ctx, "</body></html>"))
                 return ERR_PARSER_LEAVE_BLOCK;
             break;
 
@@ -480,28 +492,40 @@ leave_block(MD_BLOCKTYPE type, void *details, void *ctx_)
 
         case MD_BLOCK_H:
             {
-                /* TOC */
-                const char *s = ctx->sa_out.s + ctx->otitle;
-                size_t l = ctx->sa_out.len - ctx->otitle;
-
                 MD_BLOCK_H_DETAIL *d = details;
+                if (d->level != ctx->title.level)
+                    return ERR_INVALID;
+
+                const char *s = ctx->buf.sa.s + ctx->buf.salen;
+                size_t l = ctx->buf.sa.len - ctx->buf.salen;
+                ctx->buf.sa.len = ctx->buf.salen;
+                ctx->buf.state = BUF_OFF;
+
                 char buf[UINT32_FMT];
-                buf[uint32_fmt(buf, (uint32) d->level)] = '\0';
-                if (!raw_str(ctx, "<span id=\"")
+                buf[uint32_fmt(buf, (uint32) ctx->title.level)] = '\0';
+
+                if (!raw_str(ctx, "<section id=\"")
                         || !anchor(ctx, s, l)
-                        || !raw_str(ctx, "\"><a href=\"#")
+                        || !raw_str(ctx, "\">")
+                        || !raw_str(ctx, "<h")
+                        || !raw_str(ctx, buf)
+                        || !raw_str(ctx, ">")
+                        || !raw_text(ctx, s, l)
+                        || !raw_str(ctx, "<a href=\"#")
                         || !anchor(ctx, s, l)
-                        || !raw_str(ctx, "\"></a></span></h")
+                        || !raw_str(ctx, "\"></a></h")
                         || !raw_str(ctx, buf)
                         || !raw_str(ctx, ">"))
                     return ERR_PARSER_LEAVE_BLOCK;
 
                 /* TOC */
+                char toc[l];
+                memcpy(toc, s, l);
                 ctx->buf.state = BUF_ON;
                 if (!raw_str(ctx, "<li><a href=\"#")
-                        || !anchor(ctx, s, l)
+                        || !anchor(ctx, toc, l)
                         || !raw_str(ctx, "\">")
-                        || !strip_tags(ctx, s, l)
+                        || !strip_tags(ctx, toc, l)
                         || !raw_str(ctx, "</a></li>"))
                     return ERR_PARSER_TOC;
                 ctx->buf.state = BUF_OFF;
@@ -977,7 +1001,7 @@ main (int argc, char *argv[])
         .css = css,
         .pages = pages,
         .nb_pages = sizeof(pages) / sizeof(*pages),
-        .title = title,
+        .doc.title = title,
         .buf.sa = STRALLOC_ZERO,
     };