Skip to content

Commit f150d07

Browse files
committed
[vnotex] support mark
1 parent 6e85436 commit f150d07

File tree

8 files changed

+141
-117
lines changed

8 files changed

+141
-117
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,6 @@ cmark
3737
# Visual Studio CMake support
3838
/.vs/
3939
/out/
40+
41+
# Clangd
42+
.cache/*

parser_test/CMakeLists.txt

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
add_executable(heading_tests
2-
heading_tests.c
3-
test_utils.c)
4-
target_link_libraries(heading_tests cmark)
5-
target_include_directories(heading_tests PRIVATE
6-
${CMAKE_SOURCE_DIR}/src
7-
${CMAKE_BINARY_DIR}/src)
1+
set(TEST_TARGETS
2+
heading_tests
3+
strikethrough_tests
4+
mark_tests)
85

9-
add_executable(strikethrough_tests strikethrough_tests.c test_utils.c)
10-
target_link_libraries(strikethrough_tests cmark)
11-
target_include_directories(heading_tests PRIVATE
12-
${CMAKE_SOURCE_DIR}/src
13-
${CMAKE_BINARY_DIR}/src)
6+
foreach(TARGET ${TEST_TARGETS})
7+
add_executable(${TARGET} ${TARGET}.c test_utils.c)
8+
target_link_libraries(${TARGET} cmark)
9+
add_test(NAME ${TARGET} COMMAND ${TARGET})
1410

15-
add_test(NAME heading_tests COMMAND heading_tests)
16-
add_test(NAME strikethrough_tests COMMAND strikethrough_tests)
11+
if(WIN32 AND BUILD_SHARED_LIBS)
12+
set_tests_properties(${TARGET} PROPERTIES
13+
ENVIRONMENT "PATH=$<TARGET_FILE_DIR:cmark>$<SEMICOLON>$ENV{PATH}")
14+
endif()
15+
endforeach()

parser_test/mark_tests.c

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#include <cmark.h>
2+
3+
#include "test_utils.h"
4+
5+
int test_mark_simple() {
6+
return test_xml("==mark==",
7+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
8+
"<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
9+
"<document sourcepos=\"1:1-1:8\" xmlns=\"http://commonmark.org/xml/1.0\">\n"
10+
" <paragraph sourcepos=\"1:1-1:8\">\n"
11+
" <mark sourcepos=\"1:1-1:8\">\n"
12+
" <text sourcepos=\"1:3-1:6\" xml:space=\"preserve\">mark</text>\n"
13+
" </mark>\n"
14+
" </paragraph>\n"
15+
"</document>\n",
16+
CMARK_OPT_SOURCEPOS);
17+
}
18+
19+
int test_mark_multiple() {
20+
return test_xml("==mark== and ==another==",
21+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
22+
"<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
23+
"<document xmlns=\"http://commonmark.org/xml/1.0\">\n"
24+
" <paragraph>\n"
25+
" <mark>\n"
26+
" <text xml:space=\"preserve\">mark</text>\n"
27+
" </mark>\n"
28+
" <text xml:space=\"preserve\"> and </text>\n"
29+
" <mark>\n"
30+
" <text xml:space=\"preserve\">another</text>\n"
31+
" </mark>\n"
32+
" </paragraph>\n"
33+
"</document>\n",
34+
CMARK_OPT_DEFAULT);
35+
}
36+
37+
int test_mark_nested() {
38+
return test_xml("==mark *with emphasis*==",
39+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
40+
"<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
41+
"<document xmlns=\"http://commonmark.org/xml/1.0\">\n"
42+
" <paragraph>\n"
43+
" <mark>\n"
44+
" <text xml:space=\"preserve\">mark </text>\n"
45+
" <emph>\n"
46+
" <text xml:space=\"preserve\">with emphasis</text>\n"
47+
" </emph>\n"
48+
" </mark>\n"
49+
" </paragraph>\n"
50+
"</document>\n",
51+
CMARK_OPT_DEFAULT);
52+
}
53+
54+
int test_mark_incomplete() {
55+
return test_xml("~mark~",
56+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
57+
"<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
58+
"<document xmlns=\"http://commonmark.org/xml/1.0\">\n"
59+
" <paragraph>\n"
60+
" <text xml:space=\"preserve\">~mark~</text>\n"
61+
" </paragraph>\n"
62+
"</document>\n",
63+
CMARK_OPT_DEFAULT);
64+
}
65+
66+
int test_mark_not_closed() {
67+
return test_xml("==mark",
68+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
69+
"<!DOCTYPE document SYSTEM \"CommonMark.dtd\">\n"
70+
"<document xmlns=\"http://commonmark.org/xml/1.0\">\n"
71+
" <paragraph>\n"
72+
" <text xml:space=\"preserve\">==mark</text>\n"
73+
" </paragraph>\n"
74+
"</document>\n",
75+
CMARK_OPT_DEFAULT);
76+
}
77+
78+
int main() {
79+
CASE(test_mark_simple);
80+
CASE(test_mark_multiple);
81+
CASE(test_mark_nested);
82+
CASE(test_mark_incomplete);
83+
CASE(test_mark_not_closed);
84+
return 0;
85+
}

src/cmark.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ typedef enum {
6060
CMARK_NODE_EMPH,
6161
CMARK_NODE_STRONG,
6262
CMARK_NODE_STRIKETHROUGH,
63+
CMARK_NODE_MARK,
6364
CMARK_NODE_LINK,
6465
CMARK_NODE_IMAGE,
6566

src/html.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,14 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
277277
}
278278
break;
279279

280+
case CMARK_NODE_MARK:
281+
if (entering) {
282+
cmark_strbuf_puts(html, "<mark>");
283+
} else {
284+
cmark_strbuf_puts(html, "</mark>");
285+
}
286+
break;
287+
280288
case CMARK_NODE_EMPH:
281289
if (entering) {
282290
cmark_strbuf_puts(html, "<em>");

src/inlines.c

Lines changed: 28 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,8 @@ static inline bool S_is_line_end_char(char c) {
7474
return (c == '\n' || c == '\r');
7575
}
7676

77-
static delimiter *S_insert_emph(subject *subj, delimiter *opener,
78-
delimiter *closer);
79-
80-
static delimiter *S_insert_strikethrough(subject *subj, delimiter *opener,
81-
delimiter *closer);
77+
static delimiter *S_insert_emph_like_inline(subject *subj, delimiter *opener,
78+
delimiter *closer);
8279

8380
static int parse_inline(subject *subj, cmark_node *parent, int options);
8481

@@ -658,7 +655,8 @@ static void process_emphasis(subject *subj, bufsize_t stack_bottom) {
658655
delimiter *old_closer;
659656
bool opener_found;
660657
int openers_bottom_index = 0;
661-
bufsize_t openers_bottom[18] = {stack_bottom, stack_bottom, stack_bottom,
658+
bufsize_t openers_bottom[21] = {stack_bottom, stack_bottom, stack_bottom,
659+
stack_bottom, stack_bottom, stack_bottom,
662660
stack_bottom, stack_bottom, stack_bottom,
663661
stack_bottom, stack_bottom, stack_bottom,
664662
stack_bottom, stack_bottom, stack_bottom,
@@ -694,6 +692,10 @@ static void process_emphasis(subject *subj, bufsize_t stack_bottom) {
694692
openers_bottom_index = 14 +
695693
(closer->can_open ? 2 : 0) + (closer->length % 2);
696694
break;
695+
case '=':
696+
openers_bottom_index = 17 +
697+
(closer->can_open ? 2 : 0) + (closer->length % 2);
698+
break;
697699
default:
698700
assert(false);
699701
}
@@ -718,13 +720,13 @@ static void process_emphasis(subject *subj, bufsize_t stack_bottom) {
718720
old_closer = closer;
719721
if (closer->delim_char == '*' || closer->delim_char == '_') {
720722
if (opener_found) {
721-
closer = S_insert_emph(subj, opener, closer);
723+
closer = S_insert_emph_like_inline(subj, opener, closer);
722724
} else {
723725
closer = closer->next;
724726
}
725-
} else if (closer->delim_char == '~') {
727+
} else if (closer->delim_char == '~' || closer->delim_char == '=') {
726728
if (opener_found && opener->length >= 2 && closer->length >= 2) {
727-
closer = S_insert_strikethrough(subj, opener, closer);
729+
closer = S_insert_emph_like_inline(subj, opener, closer);
728730
} else {
729731
closer = closer->next;
730732
}
@@ -766,15 +768,16 @@ static void process_emphasis(subject *subj, bufsize_t stack_bottom) {
766768
}
767769
}
768770

769-
static delimiter *S_insert_emph(subject *subj, delimiter *opener,
770-
delimiter *closer) {
771+
static delimiter *S_insert_emph_like_inline(subject *subj, delimiter *opener,
772+
delimiter *closer) {
771773
delimiter *delim, *tmp_delim;
772774
bufsize_t use_delims;
773775
cmark_node *opener_inl = opener->inl_text;
774776
cmark_node *closer_inl = closer->inl_text;
775777
bufsize_t opener_num_chars = opener_inl->len;
776778
bufsize_t closer_num_chars = closer_inl->len;
777779
cmark_node *tmp, *tmpnext, *emph;
780+
const char delim_char = closer->delim_char;
778781

779782
// calculate the actual number of characters used from this closer
780783
use_delims = (closer_num_chars >= 2 && opener_num_chars >= 2) ? 2 : 1;
@@ -799,7 +802,17 @@ static delimiter *S_insert_emph(subject *subj, delimiter *opener,
799802

800803
// create new emph or strong, and splice it in to our inlines
801804
// between the opener and closer
802-
emph = use_delims == 1 ? make_emph(subj->mem) : make_strong(subj->mem);
805+
switch (delim_char) {
806+
case '~':
807+
emph = make_simple(subj->mem, CMARK_NODE_STRIKETHROUGH);
808+
break;
809+
case '=':
810+
emph = make_simple(subj->mem, CMARK_NODE_MARK);
811+
break;
812+
default:
813+
emph = use_delims == 1 ? make_emph(subj->mem) : make_strong(subj->mem);
814+
break;
815+
}
803816

804817
tmp = opener_inl->next;
805818
if (tmp && tmp != closer_inl) {
@@ -847,86 +860,6 @@ static delimiter *S_insert_emph(subject *subj, delimiter *opener,
847860
return closer;
848861
}
849862

850-
static delimiter *S_insert_strikethrough(subject *subj, delimiter *opener,
851-
delimiter *closer) {
852-
delimiter *delim, *tmp_delim;
853-
bufsize_t use_delims;
854-
cmark_node *opener_inl = opener->inl_text;
855-
cmark_node *closer_inl = closer->inl_text;
856-
bufsize_t opener_num_chars = opener_inl->len;
857-
bufsize_t closer_num_chars = closer_inl->len;
858-
cmark_node *tmp, *tmpnext, *strike;
859-
860-
// calculate the actual number of characters used from this closer
861-
use_delims = 2;
862-
863-
// remove used characters from associated inlines.
864-
opener_num_chars -= use_delims;
865-
closer_num_chars -= use_delims;
866-
opener_inl->len = opener_num_chars;
867-
opener_inl->data[opener_num_chars] = 0;
868-
opener_inl->end_column -= use_delims;
869-
closer_inl->len = closer_num_chars;
870-
closer_inl->data[closer_num_chars] = 0;
871-
closer_inl->start_column += use_delims;
872-
873-
// free delimiters between opener and closer
874-
delim = closer->previous;
875-
while (delim != NULL && delim != opener) {
876-
tmp_delim = delim->previous;
877-
remove_delimiter(subj, delim);
878-
delim = tmp_delim;
879-
}
880-
881-
// create new strike node
882-
strike = make_simple(subj->mem, CMARK_NODE_STRIKETHROUGH);
883-
884-
tmp = opener_inl->next;
885-
if (tmp && tmp != closer_inl) {
886-
strike->first_child = tmp;
887-
tmp->prev = NULL;
888-
889-
while (tmp && tmp != closer_inl) {
890-
tmpnext = tmp->next;
891-
tmp->parent = strike;
892-
if (tmpnext == closer_inl) {
893-
strike->last_child = tmp;
894-
tmp->next = NULL;
895-
}
896-
tmp = tmpnext;
897-
}
898-
}
899-
900-
opener_inl->next = strike;
901-
closer_inl->prev = strike;
902-
strike->prev = opener_inl;
903-
strike->next = closer_inl;
904-
strike->parent = opener_inl->parent;
905-
906-
strike->start_line = opener_inl->start_line;
907-
strike->end_line = closer_inl->end_line;
908-
strike->start_column = opener_inl->start_column + opener_inl->len;
909-
strike->end_column = closer_inl->end_column - closer_inl->len;
910-
911-
// if opener has 0 characters, remove it and its associated inline
912-
if (opener_num_chars == 0) {
913-
cmark_node_free(opener_inl);
914-
remove_delimiter(subj, opener);
915-
}
916-
917-
// if closer has 0 characters, remove it and its associated inline
918-
if (closer_num_chars == 0) {
919-
// remove empty closer inline
920-
cmark_node_free(closer_inl);
921-
// remove closer from list
922-
tmp_delim = closer->next;
923-
remove_delimiter(subj, closer);
924-
closer = tmp_delim;
925-
}
926-
927-
return closer;
928-
}
929-
930863
// Parse backslash-escape or just a backslash, returning an inline.
931864
static cmark_node *handle_backslash(subject *subj) {
932865
advance(subj);
@@ -1380,11 +1313,11 @@ static cmark_node *handle_newline(subject *subj) {
13801313

13811314
static bufsize_t subject_find_special_char(subject *subj, int options) {
13821315
// "\r\n\\`&_*[]<!"
1383-
// + "~"
1316+
// Add '~', '='.
13841317
static const int8_t SPECIAL_CHARS[256] = {
13851318
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
13861319
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0,
1387-
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1320+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
13881321
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,
13891322
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
13901323
0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -1455,6 +1388,7 @@ static int parse_inline(subject *subj, cmark_node *parent, int options) {
14551388
case '\'':
14561389
case '"':
14571390
case '~':
1391+
case '=':
14581392
new_inl = handle_delim(subj, c, (options & CMARK_OPT_SMART) != 0);
14591393
break;
14601394
case '-':

src/node.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ const char *cmark_node_get_type_string(cmark_node *node) {
217217
return "strong";
218218
case CMARK_NODE_STRIKETHROUGH:
219219
return "strikethrough";
220+
case CMARK_NODE_MARK:
221+
return "mark";
220222
case CMARK_NODE_LINK:
221223
return "link";
222224
case CMARK_NODE_IMAGE:

src/xml.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -177,17 +177,9 @@ static int S_render_node(cmark_node *node, cmark_event_type ev_type,
177177
case CMARK_NODE_STRONG:
178178
case CMARK_NODE_EMPH:
179179
case CMARK_NODE_STRIKETHROUGH:
180+
case CMARK_NODE_MARK:
180181
break;
181182
case CMARK_NODE_LINK:
182-
cmark_strbuf_puts(xml, " destination=\"");
183-
escape_xml_str(xml, node->as.link.url);
184-
cmark_strbuf_putc(xml, '"');
185-
if (node->as.link.title) {
186-
cmark_strbuf_puts(xml, " title=\"");
187-
escape_xml_str(xml, node->as.link.title);
188-
cmark_strbuf_putc(xml, '"');
189-
}
190-
break;
191183
case CMARK_NODE_IMAGE:
192184
cmark_strbuf_puts(xml, " destination=\"");
193185
escape_xml_str(xml, node->as.link.url);

0 commit comments

Comments
 (0)