nihdoc

WIP markup parser (txt -> html)
git clone git://git.alexkarle.com.com/blag
Log | Files | Refs | README | LICENSE

commit 0d53d6e8b4ed96eb0f686f9dd41ee0e74201f939 (patch)
parent a18a54a3ae97e1e6ff5aae196449587a8492b4ff
Author: Alex Karle <alex@alexkarle.com>
Date:   Sat, 18 Dec 2021 01:12:30 -0500

Add support for nested lists

Wooee it's getting complicated up in here! I'm not sure the feature is
worth the complexity (might revert), but it's a fun problem to solve!
There were multiple bumps--needing to store the previndent of the last
list item (not the last line), needing to add while-loops to closeblock
to support "dangling" nested lists, etc.

Diffstat:
Mblag.c | 81+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 65 insertions(+), 16 deletions(-)

diff --git a/blag.c b/blag.c @@ -10,9 +10,9 @@ * * <p> tags around paragraphs * - * - bullets (non-nested), breaks allowed if indented + * - bullets, breaks allowed if indented * - * 1. numerical lists (non-nested), breaks allowed if indented + * 1. numerical lists, breaks allowed if indented * * > quotes * @@ -86,9 +86,13 @@ typedef struct State { int escape; char lnkbuf[2048]; int lnkidx; + int indent; + int previndent; + int listdepth; } state; void closeblock(state *s) { + s->indent = 0; if (s->in == HEADER) { s->in = NONE; printf("</h%d>", s->hlvl); @@ -111,12 +115,20 @@ void closeblock(state *s) { s->in = ULIST_BREAK; } else if (s->in == ULIST_BREAK) { s->in = NONE; - printf("\n</li>\n</ul>\n"); + s->previndent = 0; + while (s->listdepth > 0) { + printf("\n</li>\n</ul>\n"); + s->listdepth--; + } } else if (s->in == OLIST) { s->in = OLIST_BREAK; } else if (s->in == OLIST_BREAK) { s->in = NONE; - printf("\n</li>\n</ol>\n"); + s->previndent = 0; + while (s->listdepth > 0) { + printf("\n</li>\n</ol>\n"); + s->listdepth--; + } } else { /* keep in as is */ } @@ -143,7 +155,10 @@ int parse() { .in_bold = 0, .escape = 0, .lnkbuf = {0}, - .lnkidx = 0 + .lnkidx = 0, + .indent = 0, + .previndent = 0, + .listdepth = 0, }; while ((c = getchar()) != EOF) { @@ -162,6 +177,14 @@ int parse() { if (s.in_link == LINK_URL_PARSE && c != ']') { s.lnkbuf[s.lnkidx++] = c; } + + /* first non-space char in a list continuation breaks break */ + if (s.in == ULIST_BREAK && c != ' ' && c != '-' && c != '\n') { + s.in = ULIST; + } + if (s.in == OLIST_BREAK && c != ' ' && (c < 48 || c > 58) && c != '\n') { + s.in = OLIST; + } /* Handle unique state changes by char */ switch (c) { @@ -184,25 +207,29 @@ int parse() { printf("<h%d>", s.hlvl); s.in = HEADER; } else if (s.in == ULIST_START) { - printf("<ul>\n<li>\n"); + s.previndent = s.indent; + printf("\n<ul>\n<li>\n"); s.in = ULIST; + s.listdepth++; } else if (s.in == ULIST_PARSE) { printf("\n</li>\n<li>\n"); s.in = ULIST; } else if (s.in == OLIST_START) { - printf("<ol>\n<li>\n"); + s.previndent = s.indent; + printf("\n<ol>\n<li>\n"); s.in = OLIST; + s.listdepth++; } else if (s.in == OLIST_PARSE) { printf("\n</li>\n<li>\n"); s.in = OLIST; } else if (s.in == NONE) { - /* no op */ + s.indent++; } else if (s.in == ULIST_BREAK) { - /* assume it's a continuation! */ - s.in = ULIST; + s.indent++; + putesc(c); } else if (s.in == OLIST_BREAK) { - /* assume it's a continuation! */ - s.in = OLIST; + s.indent++; + putesc(c); } else if (s.in_link == LINK_URL_PARSE) { s.in_link = LINK_DESC_PARSE; printf("\">"); @@ -300,8 +327,20 @@ int parse() { } else if (s.in == ULIST_START || s.in == ULIST_PARSE) { /* no op */ } else if (s.in == ULIST_BREAK) { - /* next list item */ - s.in = ULIST_PARSE; + /* printf("\n>> %d | %d \n", s.previndent, s.indent); */ + if (s.previndent < s.indent) { + /* new sublist */ + s.in = ULIST_START; + } else if (s.previndent > s.indent) { + /* end of a sublist */ + printf("\n</li>\n</ul>\n"); + s.previndent = s.indent; + s.listdepth--; + s.in = ULIST_PARSE; + } else { + /* next list item */ + s.in = ULIST_PARSE; + } } else { putesc(c); } @@ -321,8 +360,18 @@ int parse() { } else if (s.in == OLIST_START || s.in == OLIST_PARSE) { /* no op */ } else if (s.in == OLIST_BREAK) { - /* next list item */ - s.in = OLIST_PARSE; + if (s.previndent < s.indent) { + /* new sublist */ + s.in = OLIST_START; + } else if (s.previndent > s.indent) { + /* end of a sublist */ + printf("\n</li>\n</ol>\n"); + s.listdepth--; + s.in = OLIST_PARSE; + } else { + /* next list item */ + s.in = OLIST_PARSE; + } } else { putesc(c); }