Welcome to little lamb

Code » qmdoc » commit 2d20a70

Change how code blocks are printed..

author Olivier Brunel
2022-12-24 17:21:24 UTC
committer Olivier Brunel
2022-12-24 17:21:24 UTC
parent a5c8f4189bac527ec9e3993a2263d2410f741445

Change how code blocks are printed..

Indented code blocks are simple pre-s with highlighting enabled. Only
fenced blocks are actual <code> blocks, i.e. with line numbering

Also one can enable the highlighting inside a <code> block by specyfing
"hl" on the info string.

Finally, using "pre" as language (first word on info string) means no
<code> block (i.e. no line numbers), just a plain old <pre> block, but
without highlighting by default.

main.c +99 -20

diff --git a/main.c b/main.c
index eed24c1..21f9755 100644
--- a/main.c
+++ b/main.c
@@ -10,14 +10,26 @@
 #include "md4c.h"
 
 enum {
-    ERR_USAGE   = -1,
-    ERR_IO      = -5,
-    ERR_PARSER  = -6,
-    ERR_MEM     = -7,
-    ERR_NOTSUPP = -8,
+    ERR_USAGE       = -1,
+    ERR_IO          = -5,
+    ERR_PARSER      = -6,
+    ERR_MEM         = -7,
+    ERR_NOTSUPP     = -8,
+    ERR_INVALID     = -9,
+};
+
+enum {
+    CODE_OPEN       = 1 << 0,
+    CODE_PRINT      = 1 << 1,
+    CODE_LINES      = 1 << 2,
+    CODE_HIGHLIGHT  = 1 << 3,
 };
 
 struct ctx {
+    struct {
+        int flags;
+        int from;
+    } code;
 };
 
 static int enter_block(MD_BLOCKTYPE type, void *details, void *ctx_)
@@ -56,15 +68,51 @@ static int enter_block(MD_BLOCKTYPE type, void *details, void *ctx_)
 
         case MD_BLOCK_CODE:
             {
+                struct ctx *ctx = ctx_;
                 MD_BLOCK_CODE_DETAIL *d = details;
-                int from = 1;
-                if (d->fence_char) {
-                    if (d->info.text && !strncmp(d->info.text, "from=", 5))
-                        from = strtol(d->info.text + 5, NULL, 10);
-                    printf("<pre class=\"lineno\">%d...</pre>", from);
-                    printf("<code>");
+
+                ctx->code.flags = CODE_OPEN;
+                if (!d->info.text) {
+                    ctx->code.flags |= CODE_HIGHLIGHT;
                 } else {
-                    printf("<pre>");
+                    const char *t = d->info.text;
+                    size_t l = d->info.size;
+                    if (strncmp(t, "pre", 3) || (t[4] != ' ' && t[4] != '\n')) {
+                        ctx->code.flags |= CODE_LINES;
+                        ctx->code.from = 1;
+
+                        const char *s;
+                        s = memchr(t, ' ', l);
+                        if (!s) break;
+
+                        ++s;
+                        l -= s - t;
+                        t = s;
+                        while (l > 0) {
+                            if (l > 5 && !strncmp(t, "from=", 5)) {
+                                char *end = NULL;
+                                ctx->code.from = strtol(t + 5, &end, 10);
+                                if (!end || (*end != ' ' && *end != '\n'))
+                                    return ERR_INVALID;
+                                l -= end - t;
+                                t = end;
+                            } else if (l >= 2 && !strncmp(t, "hl", 2)
+                                    && (s[2] == ' ' || s[2] == '\n')) {
+                                ctx->code.flags |= CODE_HIGHLIGHT;
+                                l -= 2;
+                                t += 2;
+                            } else {
+                                s = memchr(t, ' ', l);
+                                if (!s) break;
+                                l -= s - t;
+                                t = s;
+                            }
+                            while (*t == ' ' && l > 0) {
+                                ++t;
+                                --l;
+                            }
+                        }
+                    }
                 }
             }
             break;
@@ -123,11 +171,17 @@ static int leave_block(MD_BLOCKTYPE type, void *details, void *ctx_)
 
         case MD_BLOCK_CODE:
             {
-                MD_BLOCK_CODE_DETAIL *d = details;
-                if (d->fence_char)
-                    printf("</code>");
-                else
-                    printf("</pre>");
+                struct ctx *ctx = ctx_;
+
+                if (!(ctx->code.flags & CODE_OPEN))
+                    return ERR_INVALID;
+                if (ctx->code.flags & CODE_PRINT) {
+                    if (ctx->code.flags & CODE_LINES)
+                        printf("</code>");
+                    else
+                        printf("</pre>");
+                }
+                ctx->code.flags = 0;
             }
             break;
 
@@ -305,9 +359,10 @@ static int escape_text(const char *text, size_t size)
     return 0;
 }
 
-static int code_text(const char *text, size_t size, void *ctx_)
+static int highlight_code_text(const char *text, size_t size, void *ctx_)
 {
     const char *end = text + size;
+
     for ( ; text < end; ) {
         const char *open, *close;
         open = memmem(text, size, "<hl>", 4);
@@ -348,7 +403,31 @@ static int text(MD_TEXTTYPE type, const MD_CHAR *text, MD_SIZE size, void *ctx_)
             break;
 
         case MD_TEXT_CODE:
-            return code_text(text, size, ctx_);
+            {
+                struct ctx *ctx = ctx_;
+
+                if (!(ctx->code.flags & CODE_OPEN)) {
+                    /* inline code */
+                    printf("%.*s", size, text);
+                    break;
+                }
+
+                if (!(ctx->code.flags & CODE_PRINT)) {
+                    if (ctx->code.flags & CODE_LINES) {
+                        printf("<pre class=\"lineno\">%d...</pre>", ctx->code.from);
+                        printf("<code>");
+                    } else {
+                        printf("<pre>");
+                    }
+                    ctx->code.flags |= CODE_PRINT;
+                }
+
+                if (ctx->code.flags & CODE_HIGHLIGHT)
+                    return highlight_code_text(text, size, ctx_);
+                else
+                    printf("%.*s", size, text);
+                break;
+            }
 
         case MD_TEXT_HTML:
             if (size == 4 && !strncmp(text, "<hl>", 4))
@@ -414,7 +493,7 @@ int main (int argc, char *argv[])
         .leave_span = leave_span,
         .text = text,
     };
-    struct ctx ctx;
+    struct ctx ctx = { 0 };
     int r = md_parse(buf, done, &parser, &ctx);
     if (r < 0) errx(-ERR_PARSER, "parser internal error %d", -r);
     else if (r > 0) errx(-r, "parser error %d", r);