author | Olivier Brunel
<jjk@jjacky.com> 2022-12-24 17:21:24 UTC |
committer | Olivier Brunel
<jjk@jjacky.com> 2022-12-24 17:21:24 UTC |
parent | a5c8f4189bac527ec9e3993a2263d2410f741445 |
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);