From: Olaf Wintermann Date: Fri, 14 Mar 2025 11:09:08 +0000 (+0100) Subject: fix markdown syntax tree generation X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=f0bc50e8ce4c7d49be00057d121d49586f05849d;p=note.git fix markdown syntax tree generation --- diff --git a/application/editor.c b/application/editor.c index 93289af..c369412 100644 --- a/application/editor.c +++ b/application/editor.c @@ -120,6 +120,7 @@ static void textstack_update_last_element(CxList *stack_list, MDNode *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 @@ -138,6 +139,7 @@ static MDNode* md_node_create(MDParserData *data) { } else { md_node_add_child(current, node); } + } else { data->p_current->content = node; } @@ -164,7 +166,17 @@ static int md_enter_span(MD_SPANTYPE type, void* detail, void* userdata) { static int md_leave_span(MD_SPANTYPE type, void* detail, void* userdata) { MDParserData *data = userdata; size_t len = cxListSize(data->text_stack); + MDNode *current = get_current_textnode(data); MDNode *elm = NULL; + + if(current->text.ptr) { + // last node was a text node + // there is no leave event for text nodes, so we have to handle it here + // and remove it from the stack + cxListRemove(data->text_stack, len-1); + len--; // len is always > 1 here + } + if(len > 1) { cxListRemoveAndGet(data->text_stack, len-1, &elm); } else { @@ -211,15 +223,18 @@ static int md_text(MD_TEXTTYPE type, const MD_CHAR* text, MD_SIZE size, void* us if(current->parent) { current->parent->children_end = textnode; } + textstack_update_last_element(data->text_stack, textnode); } else { md_node_add_child(current, textnode); + cxListAdd(data->text_stack, textnode); } + } else { // root node data->p_current->content = textnode; cxListAdd(data->text_stack, textnode); } - + return 0; } @@ -317,6 +332,7 @@ static const char* paragraph_style(MDPara *p) { case 6: return EDITOR_STYLE_HEADING6; } } + case MD_BLOCK_QUOTE: return EDITOR_STYLE_QUOTE; case MD_BLOCK_CODE: return EDITOR_STYLE_CODE_BLOCK; default: return EDITOR_STYLE_PARAGRAPH; } diff --git a/application/tests/test-editor.c b/application/tests/test-editor.c index c9e2a63..6d275ec 100644 --- a/application/tests/test-editor.c +++ b/application/tests/test-editor.c @@ -89,6 +89,7 @@ CX_TEST(test_parse_markdown_formatting_simple) { MDNode *t0; MDNode *t1; MDNode *t2; + MDNode *t3; CX_TEST_DO { doc = parse_markdown(CX_STR("test **bold** end")); @@ -142,6 +143,58 @@ CX_TEST(test_parse_markdown_formatting_simple) { CX_TEST_ASSERT(t1->type == MD_SPAN_STRONG); CX_TEST_ASSERT(!cx_strcmp(mdnode_get_text(t1), CX_STR("bold end"))); mddoc_free(doc); + + doc = parse_markdown(CX_STR("hello `code` hello *emphasis*")); + CX_TEST_ASSERT(doc); + CX_TEST_ASSERT(doc->content); + p0 = doc->content; + CX_TEST_ASSERT(p0->type == MD_BLOCK_P); + t0 = p0->content; + CX_TEST_ASSERT(t0->text.ptr); + CX_TEST_ASSERT(!cx_strcmp(cx_strcast(t0->text), CX_STR("hello "))); + t1 = t0->next; + CX_TEST_ASSERT(t1); + CX_TEST_ASSERT(t1->type == MD_SPAN_CODE); + CX_TEST_ASSERT(!cx_strcmp(mdnode_get_text(t1), CX_STR("code"))); + t2 = t1->next; + CX_TEST_ASSERT(t2); + CX_TEST_ASSERT(t2->text.ptr); + CX_TEST_ASSERT(!cx_strcmp(cx_strcast(t2->text), CX_STR(" hello "))); + t3 = t2->next; + CX_TEST_ASSERT(t3); + CX_TEST_ASSERT(t3->type == MD_SPAN_EM); + CX_TEST_ASSERT(!cx_strcmp(mdnode_get_text(t3), CX_STR("emphasis"))); + + doc = parse_markdown(CX_STR("test *begin __bold__ text* end")); + CX_TEST_ASSERT(doc); + CX_TEST_ASSERT(doc->content); + p0 = doc->content; + CX_TEST_ASSERT(p0->type == MD_BLOCK_P); + t0 = p0->content; + CX_TEST_ASSERT(t0); + CX_TEST_ASSERT(t0->text.ptr); + CX_TEST_ASSERT(!cx_strcmp(cx_strcast(t0->text), CX_STR("test "))); + t1 = t0->next; + CX_TEST_ASSERT(t1); + CX_TEST_ASSERT(!t1->text.ptr); + CX_TEST_ASSERT(t1->type == MD_SPAN_EM); + t2 = t1->next; + CX_TEST_ASSERT(t2); + CX_TEST_ASSERT(t2->text.ptr); + CX_TEST_ASSERT(!cx_strcmp(cx_strcast(t2->text), CX_STR(" end"))); + MDNode *em_t0 = t1->children_begin; + CX_TEST_ASSERT(em_t0); + CX_TEST_ASSERT(em_t0->text.ptr); + CX_TEST_ASSERT(!cx_strcmp(cx_strcast(em_t0->text), CX_STR("begin "))); + MDNode *em_t1 = em_t0->next; + CX_TEST_ASSERT(em_t1); + CX_TEST_ASSERT(em_t1->type == MD_SPAN_STRONG); + CX_TEST_ASSERT(!cx_strcmp(mdnode_get_text(em_t1), CX_STR("bold"))); + MDNode *em_t2 = em_t1->next; + CX_TEST_ASSERT(em_t2); + CX_TEST_ASSERT(!em_t2->next); + CX_TEST_ASSERT(em_t2->text.ptr); + CX_TEST_ASSERT(!cx_strcmp(cx_strcast(em_t2->text), CX_STR(" text"))); } }