markly 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/bin/markly +94 -0
  3. data/ext/markly/arena.c +103 -0
  4. data/ext/markly/autolink.c +425 -0
  5. data/ext/markly/autolink.h +8 -0
  6. data/ext/markly/blocks.c +1585 -0
  7. data/ext/markly/buffer.c +278 -0
  8. data/ext/markly/buffer.h +116 -0
  9. data/ext/markly/case_fold_switch.inc +4327 -0
  10. data/ext/markly/chunk.h +135 -0
  11. data/ext/markly/cmark-gfm-core-extensions.h +54 -0
  12. data/ext/markly/cmark-gfm-extension_api.h +736 -0
  13. data/ext/markly/cmark-gfm-extensions_export.h +42 -0
  14. data/ext/markly/cmark-gfm.h +817 -0
  15. data/ext/markly/cmark-gfm_export.h +42 -0
  16. data/ext/markly/cmark-gfm_version.h +7 -0
  17. data/ext/markly/cmark.c +55 -0
  18. data/ext/markly/cmark_ctype.c +44 -0
  19. data/ext/markly/cmark_ctype.h +33 -0
  20. data/ext/markly/commonmark.c +519 -0
  21. data/ext/markly/config.h +76 -0
  22. data/ext/markly/core-extensions.c +27 -0
  23. data/ext/markly/entities.inc +2138 -0
  24. data/ext/markly/ext_scanners.c +1159 -0
  25. data/ext/markly/ext_scanners.h +24 -0
  26. data/ext/markly/extconf.rb +7 -0
  27. data/ext/markly/footnotes.c +40 -0
  28. data/ext/markly/footnotes.h +25 -0
  29. data/ext/markly/houdini.h +57 -0
  30. data/ext/markly/houdini_href_e.c +100 -0
  31. data/ext/markly/houdini_html_e.c +66 -0
  32. data/ext/markly/houdini_html_u.c +149 -0
  33. data/ext/markly/html.c +465 -0
  34. data/ext/markly/html.h +27 -0
  35. data/ext/markly/inlines.c +1633 -0
  36. data/ext/markly/inlines.h +29 -0
  37. data/ext/markly/iterator.c +159 -0
  38. data/ext/markly/iterator.h +26 -0
  39. data/ext/markly/latex.c +466 -0
  40. data/ext/markly/linked_list.c +37 -0
  41. data/ext/markly/man.c +278 -0
  42. data/ext/markly/map.c +122 -0
  43. data/ext/markly/map.h +41 -0
  44. data/ext/markly/markly.c +1226 -0
  45. data/ext/markly/markly.h +16 -0
  46. data/ext/markly/node.c +979 -0
  47. data/ext/markly/node.h +118 -0
  48. data/ext/markly/parser.h +58 -0
  49. data/ext/markly/plaintext.c +235 -0
  50. data/ext/markly/plugin.c +36 -0
  51. data/ext/markly/plugin.h +34 -0
  52. data/ext/markly/references.c +42 -0
  53. data/ext/markly/references.h +26 -0
  54. data/ext/markly/registry.c +63 -0
  55. data/ext/markly/registry.h +24 -0
  56. data/ext/markly/render.c +205 -0
  57. data/ext/markly/render.h +62 -0
  58. data/ext/markly/scanners.c +20382 -0
  59. data/ext/markly/scanners.h +62 -0
  60. data/ext/markly/scanners.re +326 -0
  61. data/ext/markly/strikethrough.c +167 -0
  62. data/ext/markly/strikethrough.h +9 -0
  63. data/ext/markly/syntax_extension.c +149 -0
  64. data/ext/markly/syntax_extension.h +34 -0
  65. data/ext/markly/table.c +803 -0
  66. data/ext/markly/table.h +12 -0
  67. data/ext/markly/tagfilter.c +60 -0
  68. data/ext/markly/tagfilter.h +8 -0
  69. data/ext/markly/tasklist.c +156 -0
  70. data/ext/markly/tasklist.h +8 -0
  71. data/ext/markly/utf8.c +317 -0
  72. data/ext/markly/utf8.h +35 -0
  73. data/ext/markly/xml.c +181 -0
  74. data/lib/markly.rb +43 -0
  75. data/lib/markly/flags.rb +37 -0
  76. data/lib/markly/markly.so +0 -0
  77. data/lib/markly/node.rb +70 -0
  78. data/lib/markly/node/inspect.rb +59 -0
  79. data/lib/markly/renderer.rb +133 -0
  80. data/lib/markly/renderer/html_renderer.rb +252 -0
  81. data/lib/markly/version.rb +5 -0
  82. metadata +211 -0
@@ -0,0 +1,62 @@
1
+ #ifndef CMARK_SCANNERS_H
2
+ #define CMARK_SCANNERS_H
3
+
4
+ #include "cmark-gfm.h"
5
+ #include "chunk.h"
6
+
7
+ #ifdef __cplusplus
8
+ extern "C" {
9
+ #endif
10
+
11
+ bufsize_t _scan_at(bufsize_t (*scanner)(const unsigned char *), cmark_chunk *c,
12
+ bufsize_t offset);
13
+ bufsize_t _scan_scheme(const unsigned char *p);
14
+ bufsize_t _scan_autolink_uri(const unsigned char *p);
15
+ bufsize_t _scan_autolink_email(const unsigned char *p);
16
+ bufsize_t _scan_html_tag(const unsigned char *p);
17
+ bufsize_t _scan_liberal_html_tag(const unsigned char *p);
18
+ bufsize_t _scan_html_block_start(const unsigned char *p);
19
+ bufsize_t _scan_html_block_start_7(const unsigned char *p);
20
+ bufsize_t _scan_html_block_end_1(const unsigned char *p);
21
+ bufsize_t _scan_html_block_end_2(const unsigned char *p);
22
+ bufsize_t _scan_html_block_end_3(const unsigned char *p);
23
+ bufsize_t _scan_html_block_end_4(const unsigned char *p);
24
+ bufsize_t _scan_html_block_end_5(const unsigned char *p);
25
+ bufsize_t _scan_link_title(const unsigned char *p);
26
+ bufsize_t _scan_spacechars(const unsigned char *p);
27
+ bufsize_t _scan_atx_heading_start(const unsigned char *p);
28
+ bufsize_t _scan_setext_heading_line(const unsigned char *p);
29
+ bufsize_t _scan_open_code_fence(const unsigned char *p);
30
+ bufsize_t _scan_close_code_fence(const unsigned char *p);
31
+ bufsize_t _scan_entity(const unsigned char *p);
32
+ bufsize_t _scan_dangerous_url(const unsigned char *p);
33
+ bufsize_t _scan_footnote_definition(const unsigned char *p);
34
+
35
+ #define scan_scheme(c, n) _scan_at(&_scan_scheme, c, n)
36
+ #define scan_autolink_uri(c, n) _scan_at(&_scan_autolink_uri, c, n)
37
+ #define scan_autolink_email(c, n) _scan_at(&_scan_autolink_email, c, n)
38
+ #define scan_html_tag(c, n) _scan_at(&_scan_html_tag, c, n)
39
+ #define scan_liberal_html_tag(c, n) _scan_at(&_scan_liberal_html_tag, c, n)
40
+ #define scan_html_block_start(c, n) _scan_at(&_scan_html_block_start, c, n)
41
+ #define scan_html_block_start_7(c, n) _scan_at(&_scan_html_block_start_7, c, n)
42
+ #define scan_html_block_end_1(c, n) _scan_at(&_scan_html_block_end_1, c, n)
43
+ #define scan_html_block_end_2(c, n) _scan_at(&_scan_html_block_end_2, c, n)
44
+ #define scan_html_block_end_3(c, n) _scan_at(&_scan_html_block_end_3, c, n)
45
+ #define scan_html_block_end_4(c, n) _scan_at(&_scan_html_block_end_4, c, n)
46
+ #define scan_html_block_end_5(c, n) _scan_at(&_scan_html_block_end_5, c, n)
47
+ #define scan_link_title(c, n) _scan_at(&_scan_link_title, c, n)
48
+ #define scan_spacechars(c, n) _scan_at(&_scan_spacechars, c, n)
49
+ #define scan_atx_heading_start(c, n) _scan_at(&_scan_atx_heading_start, c, n)
50
+ #define scan_setext_heading_line(c, n) \
51
+ _scan_at(&_scan_setext_heading_line, c, n)
52
+ #define scan_open_code_fence(c, n) _scan_at(&_scan_open_code_fence, c, n)
53
+ #define scan_close_code_fence(c, n) _scan_at(&_scan_close_code_fence, c, n)
54
+ #define scan_entity(c, n) _scan_at(&_scan_entity, c, n)
55
+ #define scan_dangerous_url(c, n) _scan_at(&_scan_dangerous_url, c, n)
56
+ #define scan_footnote_definition(c, n) _scan_at(&_scan_footnote_definition, c, n)
57
+
58
+ #ifdef __cplusplus
59
+ }
60
+ #endif
61
+
62
+ #endif
@@ -0,0 +1,326 @@
1
+ #include <stdlib.h>
2
+ #include "chunk.h"
3
+ #include "scanners.h"
4
+
5
+ bufsize_t _scan_at(bufsize_t (*scanner)(const unsigned char *), cmark_chunk *c, bufsize_t offset)
6
+ {
7
+ bufsize_t res;
8
+ unsigned char *ptr = (unsigned char *)c->data;
9
+
10
+ if (ptr == NULL || offset > c->len) {
11
+ return 0;
12
+ } else {
13
+ unsigned char lim = ptr[c->len];
14
+
15
+ ptr[c->len] = '\0';
16
+ res = scanner(ptr + offset);
17
+ ptr[c->len] = lim;
18
+ }
19
+
20
+ return res;
21
+ }
22
+
23
+ /*!re2c
24
+ re2c:define:YYCTYPE = "unsigned char";
25
+ re2c:define:YYCURSOR = p;
26
+ re2c:define:YYMARKER = marker;
27
+ re2c:define:YYCTXMARKER = marker;
28
+ re2c:yyfill:enable = 0;
29
+
30
+ wordchar = [^\x00-\x20];
31
+
32
+ spacechar = [ \t\v\f\r\n];
33
+
34
+ reg_char = [^\\()\x00-\x20];
35
+
36
+ escaped_char = [\\][!"#$%&'()*+,./:;<=>?@[\\\]^_`{|}~-];
37
+
38
+ tagname = [A-Za-z][A-Za-z0-9-:]*;
39
+
40
+ blocktagname = 'address'|'article'|'aside'|'base'|'basefont'|'blockquote'|'body'|'caption'|'center'|'col'|'colgroup'|'dd'|'details'|'dialog'|'dir'|'div'|'dl'|'dt'|'fieldset'|'figcaption'|'figure'|'footer'|'form'|'frame'|'frameset'|'h1'|'h2'|'h3'|'h4'|'h5'|'h6'|'head'|'header'|'hr'|'html'|'iframe'|'legend'|'li'|'link'|'main'|'menu'|'menuitem'|'nav'|'noframes'|'ol'|'optgroup'|'option'|'p'|'param'|'section'|'source'|'title'|'summary'|'table'|'tbody'|'td'|'tfoot'|'th'|'thead'|'title'|'tr'|'track'|'ul';
41
+
42
+ attributename = [a-zA-Z_:][a-zA-Z0-9:._-]*;
43
+
44
+ unquotedvalue = [^ \t\r\n\v\f"'=<>`\x00]+;
45
+ singlequotedvalue = ['][^'\x00]*['];
46
+ doublequotedvalue = ["][^"\x00]*["];
47
+
48
+ attributevalue = unquotedvalue | singlequotedvalue | doublequotedvalue;
49
+
50
+ attributevaluespec = spacechar* [=] spacechar* attributevalue;
51
+
52
+ attribute = spacechar+ attributename attributevaluespec?;
53
+
54
+ opentag = tagname attribute* spacechar* [/]? [>];
55
+ closetag = [/] tagname spacechar* [>];
56
+
57
+ htmlcomment = "!---->" | ("!--" ([-]? [^\x00>-]) ([-]? [^\x00-])* "-->");
58
+
59
+ processinginstruction = "?" ([^?>\x00]+ | [?][^>\x00] | [>])* "?>";
60
+
61
+ declaration = "!" [A-Z]+ spacechar+ [^>\x00]* ">";
62
+
63
+ cdata = "![CDATA[" ([^\]\x00]+ | "]" [^\]\x00] | "]]" [^>\x00])* "]]>";
64
+
65
+ htmltag = opentag | closetag | htmlcomment | processinginstruction |
66
+ declaration | cdata;
67
+
68
+ in_parens_nosp = [(] (reg_char|escaped_char|[\\])* [)];
69
+
70
+ in_double_quotes = ["] (escaped_char|[^"\x00])* ["];
71
+ in_single_quotes = ['] (escaped_char|[^'\x00])* ['];
72
+ in_parens = [(] (escaped_char|[^)\x00])* [)];
73
+
74
+ scheme = [A-Za-z][A-Za-z0-9.+-]{1,31};
75
+ */
76
+
77
+ // Try to match a scheme including colon.
78
+ bufsize_t _scan_scheme(const unsigned char *p)
79
+ {
80
+ const unsigned char *marker = NULL;
81
+ const unsigned char *start = p;
82
+ /*!re2c
83
+ scheme [:] { return (bufsize_t)(p - start); }
84
+ * { return 0; }
85
+ */
86
+ }
87
+
88
+ // Try to match URI autolink after first <, returning number of chars matched.
89
+ bufsize_t _scan_autolink_uri(const unsigned char *p)
90
+ {
91
+ const unsigned char *marker = NULL;
92
+ const unsigned char *start = p;
93
+ /*!re2c
94
+ scheme [:][^\x00-\x20<>]*[>] { return (bufsize_t)(p - start); }
95
+ * { return 0; }
96
+ */
97
+ }
98
+
99
+ // Try to match email autolink after first <, returning num of chars matched.
100
+ bufsize_t _scan_autolink_email(const unsigned char *p)
101
+ {
102
+ const unsigned char *marker = NULL;
103
+ const unsigned char *start = p;
104
+ /*!re2c
105
+ [a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+
106
+ [@]
107
+ [a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?
108
+ ([.][a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*
109
+ [>] { return (bufsize_t)(p - start); }
110
+ * { return 0; }
111
+ */
112
+ }
113
+
114
+ // Try to match an HTML tag after first <, returning num of chars matched.
115
+ bufsize_t _scan_html_tag(const unsigned char *p)
116
+ {
117
+ const unsigned char *marker = NULL;
118
+ const unsigned char *start = p;
119
+ /*!re2c
120
+ htmltag { return (bufsize_t)(p - start); }
121
+ * { return 0; }
122
+ */
123
+ }
124
+
125
+ // Try to (liberally) match an HTML tag after first <, returning num of chars matched.
126
+ bufsize_t _scan_liberal_html_tag(const unsigned char *p)
127
+ {
128
+ const unsigned char *marker = NULL;
129
+ const unsigned char *start = p;
130
+ /*!re2c
131
+ [^\n\x00]+ [>] { return (bufsize_t)(p - start); }
132
+ * { return 0; }
133
+ */
134
+ }
135
+
136
+ // Try to match an HTML block tag start line, returning
137
+ // an integer code for the type of block (1-6, matching the spec).
138
+ // #7 is handled by a separate function, below.
139
+ bufsize_t _scan_html_block_start(const unsigned char *p)
140
+ {
141
+ const unsigned char *marker = NULL;
142
+ /*!re2c
143
+ [<] ('script'|'pre'|'style') (spacechar | [>]) { return 1; }
144
+ '<!--' { return 2; }
145
+ '<?' { return 3; }
146
+ '<!' [A-Z] { return 4; }
147
+ '<![CDATA[' { return 5; }
148
+ [<] [/]? blocktagname (spacechar | [/]? [>]) { return 6; }
149
+ * { return 0; }
150
+ */
151
+ }
152
+
153
+ // Try to match an HTML block tag start line of type 7, returning
154
+ // 7 if successful, 0 if not.
155
+ bufsize_t _scan_html_block_start_7(const unsigned char *p)
156
+ {
157
+ const unsigned char *marker = NULL;
158
+ /*!re2c
159
+ [<] (opentag | closetag) [\t\n\f ]* [\r\n] { return 7; }
160
+ * { return 0; }
161
+ */
162
+ }
163
+
164
+ // Try to match an HTML block end line of type 1
165
+ bufsize_t _scan_html_block_end_1(const unsigned char *p)
166
+ {
167
+ const unsigned char *marker = NULL;
168
+ const unsigned char *start = p;
169
+ /*!re2c
170
+ [^\n\x00]* [<] [/] ('script'|'pre'|'style') [>] { return (bufsize_t)(p - start); }
171
+ * { return 0; }
172
+ */
173
+ }
174
+
175
+ // Try to match an HTML block end line of type 2
176
+ bufsize_t _scan_html_block_end_2(const unsigned char *p)
177
+ {
178
+ const unsigned char *marker = NULL;
179
+ const unsigned char *start = p;
180
+ /*!re2c
181
+ [^\n\x00]* '-->' { return (bufsize_t)(p - start); }
182
+ * { return 0; }
183
+ */
184
+ }
185
+
186
+ // Try to match an HTML block end line of type 3
187
+ bufsize_t _scan_html_block_end_3(const unsigned char *p)
188
+ {
189
+ const unsigned char *marker = NULL;
190
+ const unsigned char *start = p;
191
+ /*!re2c
192
+ [^\n\x00]* '?>' { return (bufsize_t)(p - start); }
193
+ * { return 0; }
194
+ */
195
+ }
196
+
197
+ // Try to match an HTML block end line of type 4
198
+ bufsize_t _scan_html_block_end_4(const unsigned char *p)
199
+ {
200
+ const unsigned char *marker = NULL;
201
+ const unsigned char *start = p;
202
+ /*!re2c
203
+ [^\n\x00]* '>' { return (bufsize_t)(p - start); }
204
+ * { return 0; }
205
+ */
206
+ }
207
+
208
+ // Try to match an HTML block end line of type 5
209
+ bufsize_t _scan_html_block_end_5(const unsigned char *p)
210
+ {
211
+ const unsigned char *marker = NULL;
212
+ const unsigned char *start = p;
213
+ /*!re2c
214
+ [^\n\x00]* ']]>' { return (bufsize_t)(p - start); }
215
+ * { return 0; }
216
+ */
217
+ }
218
+
219
+ // Try to match a link title (in single quotes, in double quotes, or
220
+ // in parentheses), returning number of chars matched. Allow one
221
+ // level of internal nesting (quotes within quotes).
222
+ bufsize_t _scan_link_title(const unsigned char *p)
223
+ {
224
+ const unsigned char *marker = NULL;
225
+ const unsigned char *start = p;
226
+ /*!re2c
227
+ ["] (escaped_char|[^"\x00])* ["] { return (bufsize_t)(p - start); }
228
+ ['] (escaped_char|[^'\x00])* ['] { return (bufsize_t)(p - start); }
229
+ [(] (escaped_char|[^()\x00])* [)] { return (bufsize_t)(p - start); }
230
+ * { return 0; }
231
+ */
232
+ }
233
+
234
+ // Match space characters, including newlines.
235
+ bufsize_t _scan_spacechars(const unsigned char *p)
236
+ {
237
+ const unsigned char *start = p; \
238
+ /*!re2c
239
+ [ \t\v\f\r\n]+ { return (bufsize_t)(p - start); }
240
+ * { return 0; }
241
+ */
242
+ }
243
+
244
+ // Match ATX heading start.
245
+ bufsize_t _scan_atx_heading_start(const unsigned char *p)
246
+ {
247
+ const unsigned char *marker = NULL;
248
+ const unsigned char *start = p;
249
+ /*!re2c
250
+ [#]{1,6} ([ \t]+|[\r\n]) { return (bufsize_t)(p - start); }
251
+ * { return 0; }
252
+ */
253
+ }
254
+
255
+ // Match setext heading line. Return 1 for level-1 heading,
256
+ // 2 for level-2, 0 for no match.
257
+ bufsize_t _scan_setext_heading_line(const unsigned char *p)
258
+ {
259
+ const unsigned char *marker = NULL;
260
+ /*!re2c
261
+ [=]+ [ \t]* [\r\n] { return 1; }
262
+ [-]+ [ \t]* [\r\n] { return 2; }
263
+ * { return 0; }
264
+ */
265
+ }
266
+
267
+ // Scan an opening code fence.
268
+ bufsize_t _scan_open_code_fence(const unsigned char *p)
269
+ {
270
+ const unsigned char *marker = NULL;
271
+ const unsigned char *start = p;
272
+ /*!re2c
273
+ [`]{3,} / [^`\r\n\x00]*[\r\n] { return (bufsize_t)(p - start); }
274
+ [~]{3,} / [^\r\n\x00]*[\r\n] { return (bufsize_t)(p - start); }
275
+ * { return 0; }
276
+ */
277
+ }
278
+
279
+ // Scan a closing code fence with length at least len.
280
+ bufsize_t _scan_close_code_fence(const unsigned char *p)
281
+ {
282
+ const unsigned char *marker = NULL;
283
+ const unsigned char *start = p;
284
+ /*!re2c
285
+ [`]{3,} / [ \t]*[\r\n] { return (bufsize_t)(p - start); }
286
+ [~]{3,} / [ \t]*[\r\n] { return (bufsize_t)(p - start); }
287
+ * { return 0; }
288
+ */
289
+ }
290
+
291
+ // Scans an entity.
292
+ // Returns number of chars matched.
293
+ bufsize_t _scan_entity(const unsigned char *p)
294
+ {
295
+ const unsigned char *marker = NULL;
296
+ const unsigned char *start = p;
297
+ /*!re2c
298
+ [&] ([#] ([Xx][A-Fa-f0-9]{1,6}|[0-9]{1,7}) |[A-Za-z][A-Za-z0-9]{1,31} ) [;]
299
+ { return (bufsize_t)(p - start); }
300
+ * { return 0; }
301
+ */
302
+ }
303
+
304
+ // Returns positive value if a URL begins in a way that is potentially
305
+ // dangerous, with javascript:, vbscript:, file:, or data:, otherwise 0.
306
+ bufsize_t _scan_dangerous_url(const unsigned char *p)
307
+ {
308
+ const unsigned char *marker = NULL;
309
+ const unsigned char *start = p;
310
+ /*!re2c
311
+ 'data:image/' ('png'|'gif'|'jpeg'|'webp') { return 0; }
312
+ 'javascript:' | 'vbscript:' | 'file:' | 'data:' { return (bufsize_t)(p - start); }
313
+ * { return 0; }
314
+ */
315
+ }
316
+
317
+ // Scans a footnote definition opening.
318
+ bufsize_t _scan_footnote_definition(const unsigned char *p)
319
+ {
320
+ const unsigned char *marker = NULL;
321
+ const unsigned char *start = p;
322
+ /*!re2c
323
+ '[^' ([^\] \r\n\x00\t]+) ']:' [ \t]* { return (bufsize_t)(p - start); }
324
+ * { return 0; }
325
+ */
326
+ }
@@ -0,0 +1,167 @@
1
+ #include "strikethrough.h"
2
+ #include <parser.h>
3
+ #include <render.h>
4
+
5
+ cmark_node_type CMARK_NODE_STRIKETHROUGH;
6
+
7
+ static cmark_node *match(cmark_syntax_extension *self, cmark_parser *parser,
8
+ cmark_node *parent, unsigned char character,
9
+ cmark_inline_parser *inline_parser) {
10
+ cmark_node *res = NULL;
11
+ int left_flanking, right_flanking, punct_before, punct_after, delims;
12
+ char buffer[101];
13
+
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) &&
31
+ (delims == 2 || (!(parser->options & CMARK_OPT_STRIKETHROUGH_DOUBLE_TILDE) && delims == 1))) {
32
+ cmark_inline_parser_push_delimiter(inline_parser, character, left_flanking,
33
+ right_flanking, res);
34
+ }
35
+
36
+ return res;
37
+ }
38
+
39
+ static delimiter *insert(cmark_syntax_extension *self, cmark_parser *parser,
40
+ cmark_inline_parser *inline_parser, delimiter *opener,
41
+ delimiter *closer) {
42
+ cmark_node *strikethrough;
43
+ cmark_node *tmp, *next;
44
+ delimiter *delim, *tmp_delim;
45
+ delimiter *res = closer->next;
46
+
47
+ strikethrough = opener->inl_text;
48
+
49
+ if (opener->inl_text->as.literal.len != closer->inl_text->as.literal.len)
50
+ goto done;
51
+
52
+ if (!cmark_node_set_type(strikethrough, CMARK_NODE_STRIKETHROUGH))
53
+ goto done;
54
+
55
+ cmark_node_set_syntax_extension(strikethrough, self);
56
+
57
+ tmp = cmark_node_next(opener->inl_text);
58
+
59
+ while (tmp) {
60
+ if (tmp == closer->inl_text)
61
+ break;
62
+ next = cmark_node_next(tmp);
63
+ cmark_node_append_child(strikethrough, tmp);
64
+ tmp = next;
65
+ }
66
+
67
+ strikethrough->end_column = closer->inl_text->start_column + closer->inl_text->as.literal.len - 1;
68
+ cmark_node_free(closer->inl_text);
69
+
70
+ delim = closer;
71
+ while (delim != NULL && delim != opener) {
72
+ tmp_delim = delim->previous;
73
+ cmark_inline_parser_remove_delimiter(inline_parser, delim);
74
+ delim = tmp_delim;
75
+ }
76
+
77
+ cmark_inline_parser_remove_delimiter(inline_parser, opener);
78
+
79
+ done:
80
+ return res;
81
+ }
82
+
83
+ static const char *get_type_string(cmark_syntax_extension *extension,
84
+ cmark_node *node) {
85
+ return node->type == CMARK_NODE_STRIKETHROUGH ? "strikethrough" : "<unknown>";
86
+ }
87
+
88
+ static int can_contain(cmark_syntax_extension *extension, cmark_node *node,
89
+ cmark_node_type child_type) {
90
+ if (node->type != CMARK_NODE_STRIKETHROUGH)
91
+ return false;
92
+
93
+ return CMARK_NODE_TYPE_INLINE_P(child_type);
94
+ }
95
+
96
+ static void commonmark_render(cmark_syntax_extension *extension,
97
+ cmark_renderer *renderer, cmark_node *node,
98
+ cmark_event_type ev_type, int options) {
99
+ renderer->out(renderer, node, "~~", false, LITERAL);
100
+ }
101
+
102
+ static void latex_render(cmark_syntax_extension *extension,
103
+ cmark_renderer *renderer, cmark_node *node,
104
+ cmark_event_type ev_type, int options) {
105
+ // requires \usepackage{ulem}
106
+ bool entering = (ev_type == CMARK_EVENT_ENTER);
107
+ if (entering) {
108
+ renderer->out(renderer, node, "\\sout{", false, LITERAL);
109
+ } else {
110
+ renderer->out(renderer, node, "}", false, LITERAL);
111
+ }
112
+ }
113
+
114
+ static void man_render(cmark_syntax_extension *extension,
115
+ cmark_renderer *renderer, cmark_node *node,
116
+ cmark_event_type ev_type, int options) {
117
+ bool entering = (ev_type == CMARK_EVENT_ENTER);
118
+ if (entering) {
119
+ renderer->cr(renderer);
120
+ renderer->out(renderer, node, ".ST \"", false, LITERAL);
121
+ } else {
122
+ renderer->out(renderer, node, "\"", false, LITERAL);
123
+ renderer->cr(renderer);
124
+ }
125
+ }
126
+
127
+ static void html_render(cmark_syntax_extension *extension,
128
+ cmark_html_renderer *renderer, cmark_node *node,
129
+ cmark_event_type ev_type, int options) {
130
+ bool entering = (ev_type == CMARK_EVENT_ENTER);
131
+ if (entering) {
132
+ cmark_strbuf_puts(renderer->html, "<del>");
133
+ } else {
134
+ cmark_strbuf_puts(renderer->html, "</del>");
135
+ }
136
+ }
137
+
138
+ static void plaintext_render(cmark_syntax_extension *extension,
139
+ cmark_renderer *renderer, cmark_node *node,
140
+ cmark_event_type ev_type, int options) {
141
+ renderer->out(renderer, node, "~", false, LITERAL);
142
+ }
143
+
144
+ cmark_syntax_extension *create_strikethrough_extension(void) {
145
+ cmark_syntax_extension *ext = cmark_syntax_extension_new("strikethrough");
146
+ cmark_llist *special_chars = NULL;
147
+
148
+ cmark_syntax_extension_set_get_type_string_func(ext, get_type_string);
149
+ cmark_syntax_extension_set_can_contain_func(ext, can_contain);
150
+ cmark_syntax_extension_set_commonmark_render_func(ext, commonmark_render);
151
+ cmark_syntax_extension_set_latex_render_func(ext, latex_render);
152
+ cmark_syntax_extension_set_man_render_func(ext, man_render);
153
+ cmark_syntax_extension_set_html_render_func(ext, html_render);
154
+ cmark_syntax_extension_set_plaintext_render_func(ext, plaintext_render);
155
+ CMARK_NODE_STRIKETHROUGH = cmark_syntax_extension_add_node(1);
156
+
157
+ cmark_syntax_extension_set_match_inline_func(ext, match);
158
+ cmark_syntax_extension_set_inline_from_delim_func(ext, insert);
159
+
160
+ cmark_mem *mem = cmark_get_default_mem_allocator();
161
+ special_chars = cmark_llist_append(mem, special_chars, (void *)'~');
162
+ cmark_syntax_extension_set_special_inline_chars(ext, special_chars);
163
+
164
+ cmark_syntax_extension_set_emphasis(ext, 1);
165
+
166
+ return ext;
167
+ }