@@ -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