33#include <parser.h>
44#include <render.h>
55
6+ static cmark_chunk * S_get_node_literal_chunk (cmark_node * node ) {
7+ if (node == NULL ) {
8+ return NULL ;
9+ }
10+
11+ switch (node -> type ) {
12+ case CMARK_NODE_HTML_BLOCK :
13+ case CMARK_NODE_TEXT :
14+ case CMARK_NODE_HTML_INLINE :
15+ case CMARK_NODE_CODE :
16+ case CMARK_NODE_FOOTNOTE_REFERENCE :
17+ return & node -> as .literal ;
18+
19+ case CMARK_NODE_CODE_BLOCK :
20+ return & node -> as .code .literal ;
21+
22+ default :
23+ break ;
24+ }
25+
26+ return NULL ;
27+ }
28+
29+ static bool S_node_contains_space (cmark_node * node ) {
30+ cmark_chunk * chunk = S_get_node_literal_chunk (node );
31+ if (chunk )
32+ return (cmark_chunk_strchr (chunk , ' ' , 0 ) != chunk -> len );
33+ else
34+ return false;
35+ }
36+
37+ static bool S_children_contain_space (cmark_node * parent ) {
38+ cmark_node * node = parent -> first_child ;
39+ while (node ) {
40+ if (S_node_contains_space (node )) {
41+ return true;
42+ }
43+ node = node -> next ;
44+ }
45+
46+ return false;
47+ }
48+
649cmark_node_type CMARK_NODE_SUPERSCRIPT ;
750
851static cmark_node * match (cmark_syntax_extension * self , cmark_parser * parser ,
952 cmark_node * parent , unsigned char character ,
1053 cmark_inline_parser * inline_parser ) {
1154 cmark_node * res = NULL ;
12- int startpos = cmark_inline_parser_get_offset (inline_parser ) + 1 ;
13- int endpos = startpos ;
14-
15- if (character != '^' )
16- return NULL ;
17-
18- // TODO: long-form parsing with parens
19- if (cmark_inline_parser_peek_at (inline_parser , endpos ) == '(' )
20- return NULL ;
55+ int initpos = cmark_inline_parser_get_offset (inline_parser );
56+
57+ if (character == '^' ) {
58+ if (cmark_inline_parser_peek_at (inline_parser , initpos + 1 ) == '(' ) {
59+ res = cmark_node_new_with_mem (CMARK_NODE_TEXT , parser -> mem );
60+ cmark_node_set_literal (res , "^(" );
61+ res -> start_line = res -> end_line = cmark_inline_parser_get_line (inline_parser );
62+ res -> start_column = cmark_inline_parser_get_column (inline_parser );
63+ res -> end_column = res -> start_column + 2 ;
64+
65+ cmark_inline_parser_set_offset (inline_parser , initpos + 2 );
66+ cmark_inline_parser_push_delimiter (inline_parser , '^' , true, false, res );
67+ } else {
68+ int startpos = initpos + 1 ;
69+ int endpos = startpos ;
70+
71+ cmark_chunk * chunk = cmark_inline_parser_get_chunk (inline_parser );
72+ bufsize_t len = chunk -> len ;
73+
74+ while (endpos < len ) {
75+ unsigned char seekchar = cmark_inline_parser_peek_at (inline_parser , endpos );
76+ if (cmark_isspace (seekchar ) || (cmark_ispunct (seekchar ) && seekchar != '^' ))
77+ break ;
78+ endpos ++ ;
79+ }
80+
81+ int nodelen = endpos - startpos ;
82+
83+ // don't emit an empty node
84+ if (nodelen == 0 )
85+ return NULL ;
86+
87+ cmark_inline_parser_set_offset (inline_parser , startpos );
88+
89+ res = cmark_node_new_with_mem_and_ext (CMARK_NODE_SUPERSCRIPT , parser -> mem , self );
90+ res -> as .literal = cmark_chunk_dup (chunk , startpos , nodelen );
91+ res -> start_line = cmark_inline_parser_get_line (inline_parser );
92+ res -> start_column = cmark_inline_parser_get_column (inline_parser );
93+
94+ cmark_inline_parser_set_offset (inline_parser , endpos );
95+
96+ res -> end_line = cmark_inline_parser_get_line (inline_parser );
97+ res -> end_column = cmark_inline_parser_get_column (inline_parser );
98+
99+ const char * text = cmark_chunk_to_cstr (parser -> mem , & res -> as .literal );
100+ cmark_node_set_string_content (res , text );
101+
102+ cmark_parse_inlines (parser , res , parser -> refmap , parser -> options );
103+ }
104+ } else if (character == ')' ) {
105+ res = cmark_node_new_with_mem (CMARK_NODE_TEXT , parser -> mem );
106+ cmark_node_set_literal (res , ")" );
107+ res -> start_line = res -> end_line = cmark_inline_parser_get_line (inline_parser );
108+ res -> start_column = cmark_inline_parser_get_column (inline_parser );
109+ res -> end_column = res -> start_column + 1 ;
110+
111+ cmark_inline_parser_set_offset (inline_parser , initpos + 1 );
112+ cmark_inline_parser_push_delimiter (inline_parser , '^' , false, true, res );
113+ }
21114
22- cmark_chunk * chunk = cmark_inline_parser_get_chunk ( inline_parser ) ;
23- bufsize_t len = chunk -> len ;
115+ return res ;
116+ }
24117
25- while (endpos < len && !cmark_isspace (cmark_inline_parser_peek_at (inline_parser , endpos )))
26- endpos ++ ;
118+ static delimiter * insert (cmark_syntax_extension * self , cmark_parser * parser ,
119+ cmark_inline_parser * inline_parser , delimiter * opener ,
120+ delimiter * closer ) {
121+ cmark_node * superscript ;
122+ cmark_node * tmp , * next ;
123+ delimiter * delim , * tmp_delim ;
124+ delimiter * res = closer -> next ;
27125
28- int nodelen = endpos - startpos ;
126+ superscript = opener -> inl_text ;
29127
30- // don't emit an empty node
31- if (nodelen == 0 )
32- return NULL ;
128+ if (!cmark_node_set_type (superscript , CMARK_NODE_SUPERSCRIPT ))
129+ return res ;
33130
34- cmark_inline_parser_set_offset ( inline_parser , startpos );
131+ cmark_node_set_syntax_extension ( superscript , self );
35132
36- res = cmark_node_new_with_mem_and_ext (CMARK_NODE_SUPERSCRIPT , parser -> mem , self );
37- res -> as .literal = cmark_chunk_dup (chunk , startpos , nodelen );
38- res -> start_line = cmark_inline_parser_get_line (inline_parser );
39- res -> start_column = cmark_inline_parser_get_column (inline_parser );
133+ tmp = cmark_node_next (opener -> inl_text );
40134
41- cmark_inline_parser_set_offset (inline_parser , endpos );
135+ while (tmp ) {
136+ if (tmp == closer -> inl_text )
137+ break ;
138+ next = cmark_node_next (tmp );
139+ cmark_node_append_child (superscript , tmp );
140+ tmp = next ;
141+ }
42142
43- res -> end_line = cmark_inline_parser_get_line ( inline_parser ) ;
44- res -> end_column = cmark_inline_parser_get_column ( inline_parser );
143+ superscript -> end_column = closer -> inl_text -> start_column + closer -> inl_text -> as . literal . len - 1 ;
144+ cmark_node_free ( closer -> inl_text );
45145
46- const char * text = cmark_chunk_to_cstr (parser -> mem , & res -> as .literal );
47- cmark_node_set_string_content (res , text );
146+ delim = closer ;
147+ while (delim != NULL && delim != opener ) {
148+ tmp_delim = delim -> previous ;
149+ cmark_inline_parser_remove_delimiter (inline_parser , delim );
150+ delim = tmp_delim ;
151+ }
48152
49- cmark_parse_inlines ( parser , res , parser -> refmap , parser -> options );
153+ cmark_inline_parser_remove_delimiter ( inline_parser , opener );
50154
51155 return res ;
52156}
@@ -67,7 +171,7 @@ static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
67171static void commonmark_render (cmark_syntax_extension * extension ,
68172 cmark_renderer * renderer , cmark_node * node ,
69173 cmark_event_type ev_type , int options ) {
70- bool should_wrap = ( cmark_strbuf_strchr ( & node -> content , ' ' , 0 ) != -1 );
174+ bool should_wrap = S_children_contain_space ( node );
71175 bool entering = (ev_type == CMARK_EVENT_ENTER );
72176 if (entering ) {
73177 if (should_wrap )
@@ -129,10 +233,11 @@ cmark_syntax_extension *create_superscript_extension(void) {
129233 CMARK_NODE_SUPERSCRIPT = cmark_syntax_extension_add_node (1 );
130234
131235 cmark_syntax_extension_set_match_inline_func (ext , match );
132- // cmark_syntax_extension_set_inline_from_delim_func(ext, insert);
236+ cmark_syntax_extension_set_inline_from_delim_func (ext , insert );
133237
134238 cmark_mem * mem = cmark_get_default_mem_allocator ();
135239 special_chars = cmark_llist_append (mem , special_chars , (void * )'^' );
240+ special_chars = cmark_llist_append (mem , special_chars , (void * )')' );
136241 cmark_syntax_extension_set_special_inline_chars (ext , special_chars );
137242
138243 cmark_syntax_extension_set_emphasis (ext , 1 );
0 commit comments