MDDoc *doc;
MDPara *p_current;
CxList *text_stack;
+ int list_depth;
const CxAllocator *a;
} MDParserData;
return NULL;
}
+static void md_node_add_child(MDNode *node, MDNode *child) {
+ cx_linked_list_add((void**)&node->children_begin, (void**)&node->children_end, -1, offsetof(MDNode, next), child);
+ child->parent = node;
+}
+
+static void textstack_update_last_element(CxList *stack_list, MDNode *t) {
+ size_t len = cxListSize(stack_list);
+ if(len > 0) {
+ // replace this, when something like cxListSet is available
+ cxListRemove(stack_list, len-1);
+ cxListAdd(stack_list, t);
+ }
+}
+
+// create a node and add it to the current paragraph node tree
+static MDNode* md_node_create(MDParserData *data) {
+ MDNode *current = get_current_textnode(data);
+ size_t len = cxListSize(data->text_stack);
+
+ MDNode *node = cxCalloc(data->a, 1, sizeof(MDNode));
+ if(current) {
+ if(current->closed) {
+ current->next = node;
+ if(current->parent) {
+ current->parent->children_end = node;
+ }
+ textstack_update_last_element(data->text_stack, node);
+ } else {
+ md_node_add_child(current, node);
+ }
+
+ } else {
+ data->p_current->content = node;
+ }
+ cxListAdd(data->text_stack, node);
+ return node;
+}
+
static int md_enter_block(MD_BLOCKTYPE type, void* detail, void* userdata) {
MDParserData *data = userdata;
return 0;
}
- // TODO: li
+ if(type == MD_BLOCK_UL || type == MD_BLOCK_OL) {
+ // UL can be inserted as paragraph (toplevel list) or as
+ // MDNode (nested list)
+ if(++data->list_depth > 1) {
+ // TODO
+ //MDNode *node = cxCalloc(data->a, 1, sizeof(MDNode));
+ //node->type0 = MD_BLOCK_UL;
+ return 0;
+ }
+ } else if(type == MD_BLOCK_LI) {
+ // LI list elements are always added as MDNode*
+ MDNode *node = md_node_create(data);
+ node->type0 = type;
+ return 0;
+ }
// create empty paragraph node and add it to the document
MDPara *p = cxMalloc(data->a, sizeof(MDPara));
return 0;
}
-static int md_leave_block(MD_BLOCKTYPE type, void* detail, void* userdata) {
- return 0;
-}
+static int md_leave_span(MD_SPANTYPE type, void* detail, void* userdata);
-static void textstack_update_last_element(CxList *stack_list, MDNode *t) {
- size_t len = cxListSize(stack_list);
- if(len > 0) {
- // replace this, when something like cxListSet is available
- cxListRemove(stack_list, len-1);
- cxListAdd(stack_list, t);
- }
-}
-
-static void md_node_add_child(MDNode *node, MDNode *child) {
- cx_linked_list_add((void**)&node->children_begin, (void**)&node->children_end, -1, offsetof(MDNode, next), child);
- child->parent = node;
-}
-
-// create a node and add it to the current paragraph node tree
-static MDNode* md_node_create(MDParserData *data) {
- MDNode *current = get_current_textnode(data);
- size_t len = cxListSize(data->text_stack);
-
- MDNode *node = cxCalloc(data->a, 1, sizeof(MDNode));
- if(current) {
- if(current->closed) {
- current->next = node;
- if(current->parent) {
- current->parent->children_end = node;
- }
- textstack_update_last_element(data->text_stack, node);
- } else {
- md_node_add_child(current, node);
- }
-
- } else {
- data->p_current->content = node;
+static int md_leave_block(MD_BLOCKTYPE type, void* detail, void* userdata) {
+ MDParserData *data = userdata;
+ if(type == MD_BLOCK_UL || type == MD_BLOCK_OL) {
+ data->list_depth--;
+ } else if(type == MD_BLOCK_LI) {
+ md_leave_span(0, NULL, data);
}
- cxListAdd(data->text_stack, node);
- return node;
+ return 0;
}
static int md_enter_span(MD_SPANTYPE type, void* detail, void* userdata) {
data.doc = doc;
data.p_current = NULL;
data.text_stack = cxArrayListCreateSimple(CX_STORE_POINTERS, 16);
+ data.list_depth = 0;
data.a = a;
MD_PARSER parser = {0};
}
case MD_BLOCK_QUOTE: return EDITOR_STYLE_QUOTE;
case MD_BLOCK_CODE: return EDITOR_STYLE_CODE_BLOCK;
+ case MD_BLOCK_UL: return EDITOR_STYLE_LIST0;
default: return EDITOR_STYLE_PARAGRAPH;
}
}
}
}
+CX_TEST(test_parse_markdown_list) {
+ MDDoc *doc;
+ MDPara *p0; // Test Paragraph
+ MDPara *p1; // List
+ MDPara *p2; // end
+ MDNode *li0;
+ MDNode *li1;
+ MDNode *li0text;
+ MDNode *li1text;
+ MDNode *li1text_bold;
+
+ CX_TEST_DO {
+ doc = parse_markdown(CX_STR("Test Paragraph\n\n - List1\n - List2 __bold__\n\nend"));
+ CX_TEST_ASSERT(doc);
+
+ // paragraph structure
+ CX_TEST_ASSERT(doc->content);
+ p0 = doc->content;
+ CX_TEST_ASSERT(p0->type == MD_BLOCK_P);
+
+ CX_TEST_ASSERT(p0->next);
+ p1 = p0->next;
+ CX_TEST_ASSERT(p1->type = MD_BLOCK_UL);
+
+ CX_TEST_ASSERT(p1->next);
+ p2 = p1->next;
+ CX_TEST_ASSERT(p2->type == MD_BLOCK_P);
+
+ // check list
+ li0 = p1->content;
+ CX_TEST_ASSERT(li0);
+ li1 = li0->next;
+ CX_TEST_ASSERT(li1);
+
+ li0text = li0->children_begin;
+ CX_TEST_ASSERT(li0text);
+ CX_TEST_ASSERT(li0text->text.ptr != NULL);
+ CX_TEST_ASSERT(!cx_strcmp(mdnode_get_text(li0text), CX_STR("List1")));
+
+ li1text = li1->children_begin;
+ CX_TEST_ASSERT(li1text);
+ CX_TEST_ASSERT(li1text->text.ptr != NULL);
+ CX_TEST_ASSERT(!cx_strcmp(mdnode_get_text(li1text), CX_STR("List2 ")));
+ li1text_bold = li1text->next;
+ CX_TEST_ASSERT(li1text_bold);
+ CX_TEST_ASSERT(li1text_bold->type == MD_SPAN_STRONG);
+ CX_TEST_ASSERT(!cx_strcmp(mdnode_get_text(li1text_bold), CX_STR("bold")));
+
+ // check end paragraph
+ CX_TEST_ASSERT(p2->content != NULL);
+ CX_TEST_ASSERT(!cx_strcmp(mdnode_get_text(p2->content), CX_STR("end")));
+ }
+}
+
static int str_eq(const char *s1, const char *s2) {
if(!s1) {
return s1 == s2;