Commit 72173b3f8aae2602af7f4233e0a2126f3106f6bc

Martin Mitas 2016-12-21T19:17:07

Propagate to renderer more info about lists (issue #13). Make MD_BLOCK_OL_DETAIL and MD_BLOCK_UL_DETAIL (new structure) expose more info about the lists. In particular flag whether the list is tight or loose, and info about the fundamental chartacter making the list item marks.

diff --git a/md4c/md4c.c b/md4c/md4c.c
index bae422e..965532e 100644
--- a/md4c/md4c.c
+++ b/md4c/md4c.c
@@ -3733,6 +3733,9 @@ struct MD_BLOCK_tag {
      */
     unsigned data      : 16;
 
+    /* Leaf blocks:     Count of lines (MD_LINE or MD_VERBATIMLINE) on the block.
+     * MD_BLOCK_OL:     Start item number.
+     */
     unsigned n_lines;
 };
 
@@ -3953,24 +3956,38 @@ md_process_all_blocks(MD_CTX* ctx)
 
     while(byte_off < ctx->n_block_bytes) {
         MD_BLOCK* block = (MD_BLOCK*)((char*)ctx->block_bytes + byte_off);
-        MD_BLOCK_OL_DETAIL ol_det;
-        void* det = NULL;
+        union {
+            MD_BLOCK_UL_DETAIL ul;
+            MD_BLOCK_OL_DETAIL ol;
+        } det;
+
+        switch(block->type) {
+            case MD_BLOCK_UL:
+                det.ul.is_tight = (block->flags & MD_BLOCK_LOOSE_LIST) ? FALSE : TRUE;
+                det.ul.mark = (CHAR) block->data;
+                break;
+
+            case MD_BLOCK_OL:
+                det.ol.start = block->n_lines;
+                det.ol.is_tight =  (block->flags & MD_BLOCK_LOOSE_LIST) ? FALSE : TRUE;
+                det.ol.mark_delimiter = (CHAR) block->data;
+                break;
 
-        if(block->type == MD_BLOCK_OL) {
-            ol_det.start = block->n_lines;
-            det = &ol_det;
+            default:
+                /* noop */
+                break;
         }
 
         if(block->flags & MD_BLOCK_CONTAINER) {
             if(block->flags & MD_BLOCK_CONTAINER_CLOSER) {
-                MD_LEAVE_BLOCK(block->type, det);
+                MD_LEAVE_BLOCK(block->type, &det);
 
                 if(block->type == MD_BLOCK_UL || block->type == MD_BLOCK_OL || block->type == MD_BLOCK_QUOTE)
                     ctx->n_containers--;
             }
 
             if(block->flags & MD_BLOCK_CONTAINER_OPENER) {
-                MD_ENTER_BLOCK(block->type, det);
+                MD_ENTER_BLOCK(block->type, &det);
 
                 if(block->type == MD_BLOCK_UL || block->type == MD_BLOCK_OL) {
                     ctx->containers[ctx->n_containers].is_loose = (block->flags & MD_BLOCK_LOOSE_LIST);
@@ -4190,7 +4207,8 @@ md_add_line_into_current_block(MD_CTX* ctx, const MD_LINE_ANALYSIS* analysis)
 }
 
 static int
-md_push_container_bytes(MD_CTX* ctx, MD_BLOCKTYPE type, unsigned start, unsigned flags)
+md_push_container_bytes(MD_CTX* ctx, MD_BLOCKTYPE type, unsigned start,
+                        unsigned data, unsigned flags)
 {
     MD_BLOCK* block;
     int ret = 0;
@@ -4203,7 +4221,7 @@ md_push_container_bytes(MD_CTX* ctx, MD_BLOCKTYPE type, unsigned start, unsigned
 
     block->type = type;
     block->flags = flags;
-    block->data = 0;
+    block->data = data;
     block->n_lines = start;
 
 abort:
@@ -4662,7 +4680,7 @@ md_push_container(MD_CTX* ctx, const MD_CONTAINER* container)
 }
 
 static int
-md_enter_child_containers(MD_CTX* ctx, int n_children)
+md_enter_child_containers(MD_CTX* ctx, int n_children, unsigned data)
 {
     int i;
     int ret = 0;
@@ -4687,12 +4705,12 @@ md_enter_child_containers(MD_CTX* ctx, int n_children)
 
                 MD_CHECK(md_push_container_bytes(ctx,
                                 (is_ordered_list ? MD_BLOCK_OL : MD_BLOCK_UL),
-                                c->start, MD_BLOCK_CONTAINER_OPENER));
-                MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, 0, MD_BLOCK_CONTAINER_OPENER));
+                                c->start, data, MD_BLOCK_CONTAINER_OPENER));
+                MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, 0, data, MD_BLOCK_CONTAINER_OPENER));
                 break;
 
             case _T('>'):
-                MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_QUOTE, 0, MD_BLOCK_CONTAINER_OPENER));
+                MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_QUOTE, 0, data, MD_BLOCK_CONTAINER_OPENER));
                 break;
 
             default:
@@ -4723,14 +4741,16 @@ md_leave_child_containers(MD_CTX* ctx, int n_keep)
             case _T('-'):
             case _T('+'):
             case _T('*'):
-                MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, 0, MD_BLOCK_CONTAINER_CLOSER));
+                MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, 0,
+                                0, MD_BLOCK_CONTAINER_CLOSER));
                 MD_CHECK(md_push_container_bytes(ctx,
                                 (is_ordered_list ? MD_BLOCK_OL : MD_BLOCK_UL), 0,
-                                MD_BLOCK_CONTAINER_CLOSER));
+                                c->ch, MD_BLOCK_CONTAINER_CLOSER));
                 break;
 
             case _T('>'):
-                MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_QUOTE, 0, MD_BLOCK_CONTAINER_CLOSER));
+                MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_QUOTE, 0,
+                                0, MD_BLOCK_CONTAINER_CLOSER));
                 break;
 
             default:
@@ -5082,6 +5102,7 @@ redo:
             total_indent += line->indent;
 
             line->beg = off;
+            line->data = container.ch;
 
             /* Some of the following whitespace actually still belongs to the mark. */
             if(off >= ctx->size || ISNEWLINE(off)) {
@@ -5203,7 +5224,7 @@ done:
 
     *p_end = off;
 
-    /* If we belong to a list after seeing a blank line, the enclosing is loose. */
+    /* If we belong to a list after seeing a blank line, the list is loose. */
     if(prev_line_has_list_loosening_effect  &&  line->type != MD_LINE_BLANK  &&  n_parents + n_brothers > 0) {
         MD_CONTAINER* c = &ctx->containers[n_parents + n_brothers - 1];
         if(c->ch != _T('>')) {
@@ -5219,12 +5240,12 @@ done:
     /* Enter any container we found a mark for. */
     if(n_brothers > 0) {
         MD_ASSERT(n_brothers == 1);
-        MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, 0,
+        MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI, 0, 0,
                 MD_BLOCK_CONTAINER_CLOSER | MD_BLOCK_CONTAINER_OPENER));
     }
 
     if(n_children > 0)
-        MD_CHECK(md_enter_child_containers(ctx, n_children));
+        MD_CHECK(md_enter_child_containers(ctx, n_children, line->data));
 
 abort:
     return ret;
diff --git a/md4c/md4c.h b/md4c/md4c.h
index 1e78647..d2fc60d 100644
--- a/md4c/md4c.h
+++ b/md4c/md4c.h
@@ -62,7 +62,8 @@ enum MD_BLOCKTYPE_tag {
     /* <blockquote>...</blockquote> */
     MD_BLOCK_QUOTE,
 
-    /* <ul>...</ul> */
+    /* <ul>...</ul>
+     * Detail: Structure MD_BLOCK_UL_DETAIL. */
     MD_BLOCK_UL,
 
     /* <ol>...</ol>
@@ -210,10 +211,19 @@ struct MD_ATTRIBUTE_tag {
 };
 
 
+/* Detailed info for MD_BLOCK_UL_DETAIL. */
+typedef struct MD_BLOCK_UL_DETAIL_tag MD_BLOCK_UL_DETAIL;
+struct MD_BLOCK_UL_DETAIL_tag {
+    int is_tight;           /* Non-zero if tight list, zero of loose. */
+    MD_CHAR mark;           /* Item bullet character in MarkDown source of the list, e.g. '-', '+', '*'. */
+};
+
 /* Detailed info for MD_BLOCK_OL_DETAIL. */
 typedef struct MD_BLOCK_OL_DETAIL_tag MD_BLOCK_OL_DETAIL;
 struct MD_BLOCK_OL_DETAIL_tag {
     unsigned start;         /* Start index of the ordered list. */
+    int is_tight;           /* Non-zero if tight list, zero of loose. */
+    MD_CHAR mark_delimiter; /* Character delimiting the item marks in MarkDown source, e.g. '.' or ')' */
 };
 
 /* Detailed info for MD_BLOCK_H. */