3
3
#include <parser.h>
4
4
#include <render.h>
5
5
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
+
6
49
cmark_node_type CMARK_NODE_SUPERSCRIPT ;
7
50
8
51
static cmark_node * match (cmark_syntax_extension * self , cmark_parser * parser ,
9
52
cmark_node * parent , unsigned char character ,
10
53
cmark_inline_parser * inline_parser ) {
11
54
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
+ }
21
114
22
- cmark_chunk * chunk = cmark_inline_parser_get_chunk ( inline_parser ) ;
23
- bufsize_t len = chunk -> len ;
115
+ return res ;
116
+ }
24
117
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 ;
27
125
28
- int nodelen = endpos - startpos ;
126
+ superscript = opener -> inl_text ;
29
127
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 ;
33
130
34
- cmark_inline_parser_set_offset ( inline_parser , startpos );
131
+ cmark_node_set_syntax_extension ( superscript , self );
35
132
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 );
40
134
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
+ }
42
142
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 );
45
145
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
+ }
48
152
49
- cmark_parse_inlines ( parser , res , parser -> refmap , parser -> options );
153
+ cmark_inline_parser_remove_delimiter ( inline_parser , opener );
50
154
51
155
return res ;
52
156
}
@@ -67,7 +171,7 @@ static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
67
171
static void commonmark_render (cmark_syntax_extension * extension ,
68
172
cmark_renderer * renderer , cmark_node * node ,
69
173
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 );
71
175
bool entering = (ev_type == CMARK_EVENT_ENTER );
72
176
if (entering ) {
73
177
if (should_wrap )
@@ -129,10 +233,11 @@ cmark_syntax_extension *create_superscript_extension(void) {
129
233
CMARK_NODE_SUPERSCRIPT = cmark_syntax_extension_add_node (1 );
130
234
131
235
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 );
133
237
134
238
cmark_mem * mem = cmark_get_default_mem_allocator ();
135
239
special_chars = cmark_llist_append (mem , special_chars , (void * )'^' );
240
+ special_chars = cmark_llist_append (mem , special_chars , (void * )')' );
136
241
cmark_syntax_extension_set_special_inline_chars (ext , special_chars );
137
242
138
243
cmark_syntax_extension_set_emphasis (ext , 1 );
0 commit comments