@@ -11,25 +11,74 @@ static cmark_node *match(cmark_syntax_extension *self, cmark_parser *parser,
1111 int left_flanking , right_flanking , punct_before , punct_after , delims ;
1212 char buffer [101 ];
1313
14- if (character != '|' )
15- return NULL ;
16-
17- delims = cmark_inline_parser_scan_delimiters (
18- inline_parser , sizeof (buffer ) - 1 , '|' ,
19- & left_flanking ,
20- & right_flanking , & punct_before , & punct_after );
21-
22- memset (buffer , '|' , delims );
23- buffer [delims ] = 0 ;
24-
25- res = cmark_node_new_with_mem (CMARK_NODE_TEXT , parser -> mem );
26- cmark_node_set_literal (res , buffer );
27- res -> start_line = res -> end_line = cmark_inline_parser_get_line (inline_parser );
28- res -> start_column = cmark_inline_parser_get_column (inline_parser ) - delims ;
29-
30- if ((left_flanking || right_flanking ) && (delims == 2 )) {
31- cmark_inline_parser_push_delimiter (inline_parser , character , left_flanking ,
32- right_flanking , res );
14+ if ((parser -> options & CMARK_OPT_SPOILER_REDDIT_STYLE )) {
15+ // Reddit-style spoilers - flanked by angle brackets and exclamation marks,
16+ // e.g. >!this is a spoiler!<
17+ int pos = cmark_inline_parser_get_offset (inline_parser );
18+ char * txt = NULL ;
19+ bool opener = false;
20+ bool closer = false;
21+ if (cmark_inline_parser_peek_at (inline_parser , pos ) == '>' &&
22+ cmark_inline_parser_peek_at (inline_parser , pos + 1 ) == '!' ) {
23+ txt = ">!" ;
24+ opener = true;
25+ } else if (cmark_inline_parser_peek_at (inline_parser , pos ) == '!' &&
26+ cmark_inline_parser_peek_at (inline_parser , pos + 1 ) == '<' ) {
27+ txt = "!<" ;
28+ closer = true;
29+ }
30+
31+ if (opener && pos > 0 && !cmark_isspace (cmark_inline_parser_peek_at (inline_parser , pos - 1 ))) {
32+ opener = false;
33+ }
34+
35+ if (closer ) {
36+ cmark_chunk * chunk = cmark_inline_parser_get_chunk (inline_parser );
37+ bufsize_t len = chunk -> len ;
38+ if (pos + 2 < len && !cmark_isspace (cmark_inline_parser_peek_at (inline_parser , pos + 2 ))) {
39+ closer = false;
40+ }
41+ }
42+
43+ if ((!opener && !closer ) || !txt )
44+ return NULL ;
45+
46+ res = cmark_node_new_with_mem (CMARK_NODE_TEXT , parser -> mem );
47+ cmark_node_set_literal (res , txt );
48+ res -> start_line = cmark_inline_parser_get_line (inline_parser );
49+ res -> start_column = cmark_inline_parser_get_column (inline_parser );
50+
51+ cmark_inline_parser_set_offset (inline_parser , pos + 2 );
52+
53+ res -> end_line = cmark_inline_parser_get_line (inline_parser );
54+ res -> end_column = cmark_inline_parser_get_column (inline_parser );
55+
56+ // Set the character for this delimiter to `!`, since it's a heterogenous
57+ // delimiter and the delimiter API assumes single repeated characters.
58+ cmark_inline_parser_push_delimiter (inline_parser , '!' , opener , closer , res );
59+ } else {
60+ // Discord-style spoilers - flanked on both sides by two pipes,
61+ // e.g. ||this is a spoiler||
62+ if (character != '|' )
63+ return NULL ;
64+
65+ delims = cmark_inline_parser_scan_delimiters (
66+ inline_parser , sizeof (buffer ) - 1 , '|' ,
67+ & left_flanking ,
68+ & right_flanking , & punct_before , & punct_after );
69+
70+ memset (buffer , '|' , delims );
71+ buffer [delims ] = 0 ;
72+
73+ res = cmark_node_new_with_mem (CMARK_NODE_TEXT , parser -> mem );
74+ cmark_node_set_literal (res , buffer );
75+ res -> start_line = res -> end_line = cmark_inline_parser_get_line (inline_parser );
76+ res -> start_column = cmark_inline_parser_get_column (inline_parser ) - delims ;
77+
78+ if ((left_flanking || right_flanking ) && (delims == 2 )) {
79+ cmark_inline_parser_push_delimiter (inline_parser , character , left_flanking ,
80+ right_flanking , res );
81+ }
3382 }
3483
3584 return res ;
@@ -95,7 +144,16 @@ static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
95144static void commonmark_render (cmark_syntax_extension * extension ,
96145 cmark_renderer * renderer , cmark_node * node ,
97146 cmark_event_type ev_type , int options ) {
98- renderer -> out (renderer , node , "||" , false, LITERAL );
147+ if (options & CMARK_OPT_SPOILER_REDDIT_STYLE ) {
148+ bool entering = (ev_type == CMARK_EVENT_ENTER );
149+ if (entering ) {
150+ renderer -> out (renderer , node , ">!" , false, LITERAL );
151+ } else {
152+ renderer -> out (renderer , node , "!<" , false, LITERAL );
153+ }
154+ } else {
155+ renderer -> out (renderer , node , "||" , false, LITERAL );
156+ }
99157}
100158
101159static void html_render (cmark_syntax_extension * extension ,
@@ -109,12 +167,6 @@ static void html_render(cmark_syntax_extension *extension,
109167 }
110168}
111169
112- static void plaintext_render (cmark_syntax_extension * extension ,
113- cmark_renderer * renderer , cmark_node * node ,
114- cmark_event_type ev_type , int options ) {
115- renderer -> out (renderer , node , "~" , false, LITERAL );
116- }
117-
118170cmark_syntax_extension * create_spoiler_extension (void ) {
119171 cmark_syntax_extension * ext = cmark_syntax_extension_new ("spoiler" );
120172 cmark_llist * special_chars = NULL ;
@@ -123,14 +175,17 @@ cmark_syntax_extension *create_spoiler_extension(void) {
123175 cmark_syntax_extension_set_can_contain_func (ext , can_contain );
124176 cmark_syntax_extension_set_commonmark_render_func (ext , commonmark_render );
125177 cmark_syntax_extension_set_html_render_func (ext , html_render );
126- cmark_syntax_extension_set_plaintext_render_func (ext , plaintext_render );
178+ cmark_syntax_extension_set_plaintext_render_func (ext , commonmark_render );
127179 CMARK_NODE_SPOILER = cmark_syntax_extension_add_node (1 );
128180
129181 cmark_syntax_extension_set_match_inline_func (ext , match );
130182 cmark_syntax_extension_set_inline_from_delim_func (ext , insert );
131183
132184 cmark_mem * mem = cmark_get_default_mem_allocator ();
133185 special_chars = cmark_llist_append (mem , special_chars , (void * )'|' );
186+ special_chars = cmark_llist_append (mem , special_chars , (void * )'>' );
187+ special_chars = cmark_llist_append (mem , special_chars , (void * )'<' );
188+ special_chars = cmark_llist_append (mem , special_chars , (void * )'!' );
134189 cmark_syntax_extension_set_special_inline_chars (ext , special_chars );
135190
136191 cmark_syntax_extension_set_emphasis (ext , 1 );
0 commit comments