markly 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,1226 @@
1
+ #include "markly.h"
2
+ #include "cmark-gfm.h"
3
+ #include "houdini.h"
4
+ #include "node.h"
5
+ #include "registry.h"
6
+ #include "parser.h"
7
+ #include "syntax_extension.h"
8
+ #include "cmark-gfm-core-extensions.h"
9
+
10
+ static VALUE rb_Markly;
11
+ static VALUE rb_Markly_Error;
12
+ static VALUE rb_Markly_Node;
13
+ static VALUE rb_Markly_Parser;
14
+
15
+ static VALUE sym_document;
16
+ static VALUE sym_blockquote;
17
+ static VALUE sym_list;
18
+ static VALUE sym_list_item;
19
+ static VALUE sym_code_block;
20
+ static VALUE sym_html;
21
+ static VALUE sym_paragraph;
22
+ static VALUE sym_header;
23
+ static VALUE sym_hrule;
24
+ static VALUE sym_text;
25
+ static VALUE sym_softbreak;
26
+ static VALUE sym_linebreak;
27
+ static VALUE sym_code;
28
+ static VALUE sym_inline_html;
29
+ static VALUE sym_emph;
30
+ static VALUE sym_strong;
31
+ static VALUE sym_link;
32
+ static VALUE sym_image;
33
+ static VALUE sym_footnote_reference;
34
+ static VALUE sym_footnote_definition;
35
+
36
+ static VALUE sym_bullet_list;
37
+ static VALUE sym_ordered_list;
38
+
39
+ static VALUE sym_left;
40
+ static VALUE sym_right;
41
+ static VALUE sym_center;
42
+
43
+ static void rb_Markly_Node_free(void *data) {
44
+ // It's important that the `free` function does not inspect the node data, as it may be part of a tree that was already freed.
45
+ cmark_node *node = (cmark_node*)data;
46
+
47
+ if (cmark_node_parent(node) == NULL) {
48
+ cmark_node_free(node);
49
+ }
50
+ }
51
+
52
+ static void rb_Markly_Node_mark(void *data) {
53
+ cmark_node *node = data;
54
+
55
+ // Mark the parent to make sure that the tree won't be freed as long as a child node is referenced.
56
+ cmark_node *parent = cmark_node_parent(node);
57
+ if (parent) {
58
+ void *user_data = cmark_node_get_user_data(parent);
59
+ rb_gc_mark((VALUE)user_data);
60
+ }
61
+
62
+ // Mark all children to make sure their cached Ruby objects won't be freed.
63
+ for (cmark_node *child = cmark_node_first_child(node); child != NULL; child = cmark_node_next(child)) {
64
+ void *user_data = cmark_node_get_user_data(child);
65
+
66
+ if (user_data) {
67
+ rb_gc_mark((VALUE)user_data);
68
+ }
69
+ }
70
+ }
71
+
72
+ static const rb_data_type_t rb_Markly_Node_Type = {
73
+ .wrap_struct_name = "Markly::Node",
74
+ .function = {
75
+ .dmark = rb_Markly_Node_mark,
76
+ .dfree = rb_Markly_Node_free,
77
+ },
78
+ .data = NULL,
79
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
80
+ };
81
+
82
+ static VALUE rb_Markly_Node_wrap(cmark_node *node) {
83
+ if (node == NULL)
84
+ return Qnil;
85
+
86
+ void * user_data = cmark_node_get_user_data(node);
87
+
88
+ if (user_data) {
89
+ return (VALUE)user_data;
90
+ }
91
+
92
+ VALUE self = TypedData_Wrap_Struct(rb_Markly_Node, &rb_Markly_Node_Type, node);
93
+ cmark_node_set_user_data(node, (void *)self);
94
+
95
+ return self;
96
+ }
97
+
98
+ static void rb_Markly_Parser_free(void *data) {
99
+ cmark_parser_free(data);
100
+ }
101
+
102
+ static void rb_Markly_Parser_mark(void *data) {
103
+ cmark_parser *parser = data;
104
+
105
+ // Mark the parent to make sure that the tree won't be freed as long as a child node is referenced.
106
+ cmark_node *root = parser->root;
107
+
108
+ if (root) {
109
+ void *user_data = cmark_node_get_user_data(root);
110
+ rb_gc_mark((VALUE)user_data);
111
+ }
112
+ }
113
+
114
+ static const rb_data_type_t rb_Markly_Parser_Type = {
115
+ .wrap_struct_name = "Markly::Parser",
116
+ .function = {
117
+ .dmark = rb_Markly_Parser_mark,
118
+ .dfree = rb_Markly_Parser_free,
119
+ },
120
+ .data = NULL,
121
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY,
122
+ };
123
+
124
+ static VALUE rb_Markly_Parser_root(VALUE self) {
125
+ cmark_parser *parser = NULL;
126
+
127
+ TypedData_Get_Struct(self, cmark_parser, &rb_Markly_Parser_Type, parser);
128
+
129
+ assert(parser != NULL);
130
+
131
+ return rb_Markly_Node_wrap(parser->root);
132
+ }
133
+
134
+ static VALUE rb_Markly_Parser_alloc(VALUE self) {
135
+ return TypedData_Wrap_Struct(self, &rb_Markly_Parser_Type, NULL);
136
+ }
137
+
138
+ static VALUE rb_Markly_Parser_initialize(VALUE self, VALUE flags) {
139
+ Check_Type(flags, T_FIXNUM);
140
+
141
+ cmark_mem *mem = cmark_get_default_mem_allocator();
142
+ cmark_parser *parser = cmark_parser_new_with_mem(NUM2INT(flags), mem);
143
+
144
+ RTYPEDDATA_DATA(self) = parser;
145
+
146
+ return self;
147
+ }
148
+
149
+ static VALUE rb_Markly_Parser_enable(VALUE self, VALUE extension) {
150
+ cmark_parser *parser = NULL;
151
+
152
+ Check_Type(extension, T_SYMBOL);
153
+
154
+ VALUE extension_name = rb_sym2str(extension);
155
+
156
+ TypedData_Get_Struct(self, cmark_parser, &rb_Markly_Parser_Type, parser);
157
+
158
+ cmark_syntax_extension *syntax_extension =
159
+ cmark_find_syntax_extension(StringValueCStr(extension_name));
160
+
161
+ if (!syntax_extension) {
162
+ rb_raise(rb_eArgError, "extension %s not found", StringValueCStr(extension_name));
163
+ }
164
+
165
+ cmark_parser_attach_syntax_extension(parser, syntax_extension);
166
+
167
+ return Qnil;
168
+ }
169
+
170
+ static VALUE rb_Markly_Parser_parse(VALUE self, VALUE text) {
171
+ cmark_parser *parser = NULL;
172
+
173
+ StringValue(text);
174
+
175
+ TypedData_Get_Struct(self, cmark_parser, &rb_Markly_Parser_Type, parser);
176
+
177
+ cmark_parser_feed(parser, RSTRING_PTR(text), RSTRING_LEN(text));
178
+
179
+ cmark_node *root = cmark_parser_finish(parser);
180
+
181
+ return rb_Markly_Node_wrap(root);
182
+ }
183
+
184
+ /*
185
+ * Internal: Creates a node based on a node type.
186
+ *
187
+ * type - A {Symbol} representing the node to be created. Must be one of the
188
+ * following:
189
+ * - `:document`
190
+ * - `:blockquote`
191
+ * - `:list`
192
+ * - `:list_item`
193
+ * - `:code_block`
194
+ * - `:html`
195
+ * - `:paragraph`
196
+ * - `:header`
197
+ * - `:hrule`
198
+ * - `:text`
199
+ * - `:softbreak`
200
+ * - `:linebreak`
201
+ * - `:code`
202
+ * - `:inline_html`
203
+ * - `:emph`
204
+ * - `:strong`
205
+ * - `:link`
206
+ * - `:image`
207
+ */
208
+ static VALUE rb_node_new(VALUE self, VALUE type) {
209
+ cmark_node_type node_type = 0;
210
+ cmark_node *node;
211
+
212
+ Check_Type(type, T_SYMBOL);
213
+
214
+ if (type == sym_document)
215
+ node_type = CMARK_NODE_DOCUMENT;
216
+ else if (type == sym_blockquote)
217
+ node_type = CMARK_NODE_BLOCK_QUOTE;
218
+ else if (type == sym_list)
219
+ node_type = CMARK_NODE_LIST;
220
+ else if (type == sym_list_item)
221
+ node_type = CMARK_NODE_ITEM;
222
+ else if (type == sym_code_block)
223
+ node_type = CMARK_NODE_CODE_BLOCK;
224
+ else if (type == sym_html)
225
+ node_type = CMARK_NODE_HTML;
226
+ else if (type == sym_paragraph)
227
+ node_type = CMARK_NODE_PARAGRAPH;
228
+ else if (type == sym_header)
229
+ node_type = CMARK_NODE_HEADER;
230
+ else if (type == sym_hrule)
231
+ node_type = CMARK_NODE_HRULE;
232
+ else if (type == sym_text)
233
+ node_type = CMARK_NODE_TEXT;
234
+ else if (type == sym_softbreak)
235
+ node_type = CMARK_NODE_SOFTBREAK;
236
+ else if (type == sym_linebreak)
237
+ node_type = CMARK_NODE_LINEBREAK;
238
+ else if (type == sym_code)
239
+ node_type = CMARK_NODE_CODE;
240
+ else if (type == sym_inline_html)
241
+ node_type = CMARK_NODE_INLINE_HTML;
242
+ else if (type == sym_emph)
243
+ node_type = CMARK_NODE_EMPH;
244
+ else if (type == sym_strong)
245
+ node_type = CMARK_NODE_STRONG;
246
+ else if (type == sym_link)
247
+ node_type = CMARK_NODE_LINK;
248
+ else if (type == sym_image)
249
+ node_type = CMARK_NODE_IMAGE;
250
+ else if (type == sym_footnote_reference)
251
+ node_type = CMARK_NODE_FOOTNOTE_REFERENCE;
252
+ else if (type == sym_footnote_definition)
253
+ node_type = CMARK_NODE_FOOTNOTE_DEFINITION;
254
+ else
255
+ rb_raise(rb_Markly_Error, "invalid node of type %d", node_type);
256
+
257
+ node = cmark_node_new(node_type);
258
+ if (node == NULL) {
259
+ rb_raise(rb_Markly_Error, "could not create node of type %d", node_type);
260
+ }
261
+
262
+ return rb_Markly_Node_wrap(node);
263
+ }
264
+
265
+ static VALUE encode_utf8_string(const char *c_string) {
266
+ VALUE string = rb_str_new2(c_string);
267
+ int enc = rb_enc_find_index("UTF-8");
268
+ rb_enc_associate_index(string, enc);
269
+ return string;
270
+ }
271
+
272
+ /*
273
+ * Public: Fetch the string contents of the node.
274
+ *
275
+ * Returns a {String}.
276
+ */
277
+ static VALUE rb_node_get_string_content(VALUE self) {
278
+ const char *text;
279
+ cmark_node *node;
280
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
281
+
282
+ text = cmark_node_get_literal(node);
283
+ if (text == NULL) {
284
+ rb_raise(rb_Markly_Error, "could not get string content");
285
+ }
286
+
287
+ return encode_utf8_string(text);
288
+ }
289
+
290
+ /*
291
+ * Public: Sets the string content of the node.
292
+ *
293
+ * string - A {String} containing new content.
294
+ *
295
+ * Raises Error if the string content can't be set.
296
+ */
297
+ static VALUE rb_node_set_string_content(VALUE self, VALUE s) {
298
+ char *text;
299
+ cmark_node *node;
300
+ Check_Type(s, T_STRING);
301
+
302
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
303
+ text = StringValueCStr(s);
304
+
305
+ if (!cmark_node_set_literal(node, text)) {
306
+ rb_raise(rb_Markly_Error, "could not set string content");
307
+ }
308
+
309
+ return Qnil;
310
+ }
311
+
312
+ /*
313
+ * Public: Fetches the list type of the node.
314
+ *
315
+ * Returns a {Symbol} representing the node's type.
316
+ */
317
+ static VALUE rb_node_get_type(VALUE self) {
318
+ int node_type;
319
+ cmark_node *node;
320
+ VALUE symbol;
321
+ const char *s;
322
+
323
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
324
+
325
+ node_type = cmark_node_get_type(node);
326
+ symbol = Qnil;
327
+
328
+ switch (node_type) {
329
+ case CMARK_NODE_DOCUMENT:
330
+ symbol = sym_document;
331
+ break;
332
+ case CMARK_NODE_BLOCK_QUOTE:
333
+ symbol = sym_blockquote;
334
+ break;
335
+ case CMARK_NODE_LIST:
336
+ symbol = sym_list;
337
+ break;
338
+ case CMARK_NODE_ITEM:
339
+ symbol = sym_list_item;
340
+ break;
341
+ case CMARK_NODE_CODE_BLOCK:
342
+ symbol = sym_code_block;
343
+ break;
344
+ case CMARK_NODE_HTML:
345
+ symbol = sym_html;
346
+ break;
347
+ case CMARK_NODE_PARAGRAPH:
348
+ symbol = sym_paragraph;
349
+ break;
350
+ case CMARK_NODE_HEADER:
351
+ symbol = sym_header;
352
+ break;
353
+ case CMARK_NODE_HRULE:
354
+ symbol = sym_hrule;
355
+ break;
356
+ case CMARK_NODE_TEXT:
357
+ symbol = sym_text;
358
+ break;
359
+ case CMARK_NODE_SOFTBREAK:
360
+ symbol = sym_softbreak;
361
+ break;
362
+ case CMARK_NODE_LINEBREAK:
363
+ symbol = sym_linebreak;
364
+ break;
365
+ case CMARK_NODE_CODE:
366
+ symbol = sym_code;
367
+ break;
368
+ case CMARK_NODE_INLINE_HTML:
369
+ symbol = sym_inline_html;
370
+ break;
371
+ case CMARK_NODE_EMPH:
372
+ symbol = sym_emph;
373
+ break;
374
+ case CMARK_NODE_STRONG:
375
+ symbol = sym_strong;
376
+ break;
377
+ case CMARK_NODE_LINK:
378
+ symbol = sym_link;
379
+ break;
380
+ case CMARK_NODE_IMAGE:
381
+ symbol = sym_image;
382
+ break;
383
+ case CMARK_NODE_FOOTNOTE_REFERENCE:
384
+ symbol = sym_footnote_reference;
385
+ break;
386
+ case CMARK_NODE_FOOTNOTE_DEFINITION:
387
+ symbol = sym_footnote_definition;
388
+ break;
389
+ default:
390
+ if (node->extension) {
391
+ s = node->extension->get_type_string_func(node->extension, node);
392
+ return ID2SYM(rb_intern(s));
393
+ }
394
+ rb_raise(rb_Markly_Error, "invalid node type %d", node_type);
395
+ }
396
+
397
+ return symbol;
398
+ }
399
+
400
+ /*
401
+ * Public: Fetches the source_position of the node.
402
+ *
403
+ * Returns a {Hash} containing {Symbol} keys of the positions.
404
+ */
405
+ static VALUE rb_node_get_source_position(VALUE self) {
406
+ int start_line, start_column, end_line, end_column;
407
+ VALUE result;
408
+
409
+ cmark_node *node;
410
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
411
+
412
+ start_line = cmark_node_get_start_line(node);
413
+ start_column = cmark_node_get_start_column(node);
414
+ end_line = cmark_node_get_end_line(node);
415
+ end_column = cmark_node_get_end_column(node);
416
+
417
+ result = rb_hash_new();
418
+ rb_hash_aset(result, CSTR2SYM("start_line"), INT2NUM(start_line));
419
+ rb_hash_aset(result, CSTR2SYM("start_column"), INT2NUM(start_column));
420
+ rb_hash_aset(result, CSTR2SYM("end_line"), INT2NUM(end_line));
421
+ rb_hash_aset(result, CSTR2SYM("end_column"), INT2NUM(end_column));
422
+
423
+ return result;
424
+ }
425
+
426
+ /*
427
+ * Public: Returns the type of the current pointer as a string.
428
+ *
429
+ * Returns a {String}.
430
+ */
431
+ static VALUE rb_node_get_type_string(VALUE self) {
432
+ cmark_node *node;
433
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
434
+
435
+ return rb_str_new2(cmark_node_get_type_string(node));
436
+ }
437
+
438
+ /*
439
+ * Internal: Unlinks the node from the tree (fixing pointers in
440
+ * parents and siblings appropriately).
441
+ */
442
+ static VALUE rb_node_unlink(VALUE self) {
443
+ cmark_node *node;
444
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
445
+
446
+ cmark_node_unlink(node);
447
+
448
+ return Qnil;
449
+ }
450
+
451
+ /* Public: Fetches the first child of the node.
452
+ *
453
+ * Returns a {Node} if a child exists, `nil` otherise.
454
+ */
455
+ static VALUE rb_node_first_child(VALUE self) {
456
+ cmark_node *node, *child;
457
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
458
+
459
+ child = cmark_node_first_child(node);
460
+
461
+ return rb_Markly_Node_wrap(child);
462
+ }
463
+
464
+ /* Public: Fetches the next sibling of the node.
465
+ *
466
+ * Returns a {Node} if a sibling exists, `nil` otherwise.
467
+ */
468
+ static VALUE rb_node_next(VALUE self) {
469
+ cmark_node *node, *next;
470
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
471
+
472
+ next = cmark_node_next(node);
473
+
474
+ return rb_Markly_Node_wrap(next);
475
+ }
476
+
477
+ /*
478
+ * Public: Inserts a node as a sibling before the current node.
479
+ *
480
+ * sibling - A sibling {Node} to insert.
481
+ *
482
+ * Returns `true` if successful.
483
+ * Raises Error if the node can't be inserted.
484
+ */
485
+ static VALUE rb_node_insert_before(VALUE self, VALUE sibling) {
486
+ cmark_node *node1, *node2;
487
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node1);
488
+ TypedData_Get_Struct(sibling, cmark_node, &rb_Markly_Node_Type, node2);
489
+
490
+ if (!cmark_node_insert_before(node1, node2)) {
491
+ rb_raise(rb_Markly_Error, "could not insert before");
492
+ }
493
+
494
+ return Qtrue;
495
+ }
496
+
497
+ /* Internal: Convert the node to an HTML string.
498
+ *
499
+ * Returns a {String}.
500
+ */
501
+ static VALUE rb_render_html(VALUE self, VALUE rb_options, VALUE rb_extensions) {
502
+ int options, extensions_len;
503
+ VALUE rb_ext_name;
504
+ int i;
505
+ cmark_node *node;
506
+ cmark_llist *extensions = NULL;
507
+ cmark_mem *mem = cmark_get_default_mem_allocator();
508
+ Check_Type(rb_options, T_FIXNUM);
509
+ Check_Type(rb_extensions, T_ARRAY);
510
+
511
+ options = FIX2INT(rb_options);
512
+ extensions_len = RARRAY_LEN(rb_extensions);
513
+
514
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
515
+
516
+ for (i = 0; i < extensions_len; ++i) {
517
+ rb_ext_name = RARRAY_PTR(rb_extensions)[i];
518
+
519
+ if (!SYMBOL_P(rb_ext_name)) {
520
+ cmark_llist_free(mem, extensions);
521
+ rb_raise(rb_eTypeError, "extension names should be Symbols; got a %"PRIsVALUE"", rb_obj_class(rb_ext_name));
522
+ }
523
+
524
+ cmark_syntax_extension *syntax_extension =
525
+ cmark_find_syntax_extension(rb_id2name(SYM2ID(rb_ext_name)));
526
+
527
+ if (!syntax_extension) {
528
+ cmark_llist_free(mem, extensions);
529
+ rb_raise(rb_eArgError, "extension %s not found\n", rb_id2name(SYM2ID(rb_ext_name)));
530
+ }
531
+
532
+ extensions = cmark_llist_append(mem, extensions, syntax_extension);
533
+ }
534
+
535
+ char *html = cmark_render_html(node, options, extensions);
536
+ VALUE ruby_html = rb_str_new2(html);
537
+
538
+ cmark_llist_free(mem, extensions);
539
+ free(html);
540
+
541
+ return ruby_html;
542
+ }
543
+
544
+ /* Internal: Convert the node to a CommonMark string.
545
+ *
546
+ * Returns a {String}.
547
+ */
548
+ static VALUE rb_render_commonmark(int argc, VALUE *argv, VALUE self) {
549
+ VALUE rb_options, rb_width;
550
+ rb_scan_args(argc, argv, "11", &rb_options, &rb_width);
551
+
552
+ int width = 120;
553
+ if (!NIL_P(rb_width)) {
554
+ Check_Type(rb_width, T_FIXNUM);
555
+ width = FIX2INT(rb_width);
556
+ }
557
+
558
+ int options;
559
+ cmark_node *node;
560
+ Check_Type(rb_options, T_FIXNUM);
561
+
562
+ options = FIX2INT(rb_options);
563
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
564
+
565
+ char *cmark = cmark_render_commonmark(node, options, width);
566
+ VALUE ruby_cmark = rb_str_new2(cmark);
567
+ free(cmark);
568
+
569
+ return ruby_cmark;
570
+ }
571
+
572
+ /* Internal: Convert the node to a plain textstring.
573
+ *
574
+ * Returns a {String}.
575
+ */
576
+ static VALUE rb_render_plaintext(int argc, VALUE *argv, VALUE self) {
577
+ VALUE rb_options, rb_width;
578
+ rb_scan_args(argc, argv, "11", &rb_options, &rb_width);
579
+
580
+ int width = 120;
581
+ if (!NIL_P(rb_width)) {
582
+ Check_Type(rb_width, T_FIXNUM);
583
+ width = FIX2INT(rb_width);
584
+ }
585
+
586
+ int options;
587
+ cmark_node *node;
588
+ Check_Type(rb_options, T_FIXNUM);
589
+
590
+ options = FIX2INT(rb_options);
591
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
592
+
593
+ char *text = cmark_render_plaintext(node, options, width);
594
+ VALUE ruby_text = rb_str_new2(text);
595
+ free(text);
596
+
597
+ return ruby_text;
598
+ }
599
+
600
+ /*
601
+ * Public: Inserts a node as a sibling after the current node.
602
+ *
603
+ * sibling - A sibling {Node} to insert.
604
+ *
605
+ * Returns `true` if successful.
606
+ * Raises Error if the node can't be inserted.
607
+ */
608
+ static VALUE rb_node_insert_after(VALUE self, VALUE sibling) {
609
+ cmark_node *node1, *node2;
610
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node1);
611
+ TypedData_Get_Struct(sibling, cmark_node, &rb_Markly_Node_Type, node2);
612
+
613
+ if (!cmark_node_insert_after(node1, node2)) {
614
+ rb_raise(rb_Markly_Error, "could not insert after");
615
+ }
616
+
617
+ return Qtrue;
618
+ }
619
+
620
+ /*
621
+ * Public: Inserts a node as the first child of the current node.
622
+ *
623
+ * child - A child {Node} to insert.
624
+ *
625
+ * Returns `true` if successful.
626
+ * Raises Error if the node can't be inserted.
627
+ */
628
+ static VALUE rb_node_prepend_child(VALUE self, VALUE child) {
629
+ cmark_node *node1, *node2;
630
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node1);
631
+ TypedData_Get_Struct(child, cmark_node, &rb_Markly_Node_Type, node2);
632
+
633
+ if (!cmark_node_prepend_child(node1, node2)) {
634
+ rb_raise(rb_Markly_Error, "could not prepend child");
635
+ }
636
+
637
+ return Qtrue;
638
+ }
639
+
640
+ /*
641
+ * Public: Inserts a node as the last child of the current node.
642
+ *
643
+ * child - A child {Node} to insert.
644
+ *
645
+ * Returns `true` if successful.
646
+ * Raises Error if the node can't be inserted.
647
+ */
648
+ static VALUE rb_node_append_child(VALUE self, VALUE child) {
649
+ cmark_node *node1, *node2;
650
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node1);
651
+ TypedData_Get_Struct(child, cmark_node, &rb_Markly_Node_Type, node2);
652
+
653
+ if (!cmark_node_append_child(node1, node2)) {
654
+ rb_raise(rb_Markly_Error, "could not append child");
655
+ }
656
+
657
+ return Qtrue;
658
+ }
659
+
660
+ /* Public: Fetches the first child of the current node.
661
+ *
662
+ * Returns a {Node} if a child exists, `nil` otherise.
663
+ */
664
+ static VALUE rb_node_last_child(VALUE self) {
665
+ cmark_node *node, *child;
666
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
667
+
668
+ child = cmark_node_last_child(node);
669
+
670
+ return rb_Markly_Node_wrap(child);
671
+ }
672
+
673
+ /* Public: Fetches the parent of the current node.
674
+ *
675
+ * Returns a {Node} if a parent exists, `nil` otherise.
676
+ */
677
+ static VALUE rb_node_parent(VALUE self) {
678
+ cmark_node *node, *parent;
679
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
680
+
681
+ parent = cmark_node_parent(node);
682
+
683
+ return rb_Markly_Node_wrap(parent);
684
+ }
685
+
686
+ /* Public: Fetches the previous sibling of the current node.
687
+ *
688
+ * Returns a {Node} if a parent exists, `nil` otherise.
689
+ */
690
+ static VALUE rb_node_previous(VALUE self) {
691
+ cmark_node *node, *previous;
692
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
693
+
694
+ previous = cmark_node_previous(node);
695
+
696
+ return rb_Markly_Node_wrap(previous);
697
+ }
698
+
699
+ /*
700
+ * Public: Gets the URL of the current node (must be a `:link` or `:image`).
701
+ *
702
+ * Returns a {String}.
703
+ * Raises a Error if the URL can't be retrieved.
704
+ */
705
+ static VALUE rb_node_get_url(VALUE self) {
706
+ const char *text;
707
+ cmark_node *node;
708
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
709
+
710
+ text = cmark_node_get_url(node);
711
+ if (text == NULL) {
712
+ rb_raise(rb_Markly_Error, "could not get url");
713
+ }
714
+
715
+ return rb_str_new2(text);
716
+ }
717
+
718
+ /*
719
+ * Public: Sets the URL of the current node (must be a `:link` or `:image`).
720
+ *
721
+ * url - A {String} representing the new URL
722
+ *
723
+ * Raises a Error if the URL can't be set.
724
+ */
725
+ static VALUE rb_node_set_url(VALUE self, VALUE url) {
726
+ cmark_node *node;
727
+ char *text;
728
+ Check_Type(url, T_STRING);
729
+
730
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
731
+ text = StringValueCStr(url);
732
+
733
+ if (!cmark_node_set_url(node, text)) {
734
+ rb_raise(rb_Markly_Error, "could not set url");
735
+ }
736
+
737
+ return Qnil;
738
+ }
739
+
740
+ /*
741
+ * Public: Gets the title of the current node (must be a `:link` or `:image`).
742
+ *
743
+ * Returns a {String}.
744
+ * Raises a Error if the title can't be retrieved.
745
+ */
746
+ static VALUE rb_node_get_title(VALUE self) {
747
+ const char *text;
748
+ cmark_node *node;
749
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
750
+
751
+ text = cmark_node_get_title(node);
752
+ if (text == NULL) {
753
+ rb_raise(rb_Markly_Error, "could not get title");
754
+ }
755
+
756
+ return rb_str_new2(text);
757
+ }
758
+
759
+ /*
760
+ * Public: Sets the title of the current node (must be a `:link` or `:image`).
761
+ *
762
+ * title - A {String} representing the new title
763
+ *
764
+ * Raises a Error if the title can't be set.
765
+ */
766
+ static VALUE rb_node_set_title(VALUE self, VALUE title) {
767
+ char *text;
768
+ cmark_node *node;
769
+ Check_Type(title, T_STRING);
770
+
771
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
772
+ text = StringValueCStr(title);
773
+
774
+ if (!cmark_node_set_title(node, text)) {
775
+ rb_raise(rb_Markly_Error, "could not set title");
776
+ }
777
+
778
+ return Qnil;
779
+ }
780
+
781
+ /*
782
+ * Public: Gets the header level of the current node (must be a `:header`).
783
+ *
784
+ * Returns a {Number} representing the header level.
785
+ * Raises a Error if the header level can't be retrieved.
786
+ */
787
+ static VALUE rb_node_get_header_level(VALUE self) {
788
+ int header_level;
789
+ cmark_node *node;
790
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
791
+
792
+ header_level = cmark_node_get_header_level(node);
793
+
794
+ if (header_level == 0) {
795
+ rb_raise(rb_Markly_Error, "could not get header_level");
796
+ }
797
+
798
+ return INT2NUM(header_level);
799
+ }
800
+
801
+ /*
802
+ * Public: Sets the header level of the current node (must be a `:header`).
803
+ *
804
+ * level - A {Number} representing the new header level
805
+ *
806
+ * Raises a Error if the header level can't be set.
807
+ */
808
+ static VALUE rb_node_set_header_level(VALUE self, VALUE level) {
809
+ int l;
810
+ cmark_node *node;
811
+ Check_Type(level, T_FIXNUM);
812
+
813
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
814
+ l = FIX2INT(level);
815
+
816
+ if (!cmark_node_set_header_level(node, l)) {
817
+ rb_raise(rb_Markly_Error, "could not set header_level");
818
+ }
819
+
820
+ return Qnil;
821
+ }
822
+
823
+ /*
824
+ * Public: Gets the list type of the current node (must be a `:list`).
825
+ *
826
+ * Returns a {Symbol}.
827
+ * Raises a Error if the title can't be retrieved.
828
+ */
829
+ static VALUE rb_node_get_list_type(VALUE self) {
830
+ int list_type;
831
+ cmark_node *node;
832
+ VALUE symbol;
833
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
834
+
835
+ list_type = cmark_node_get_list_type(node);
836
+
837
+ if (list_type == CMARK_BULLET_LIST) {
838
+ symbol = sym_bullet_list;
839
+ } else if (list_type == CMARK_ORDERED_LIST) {
840
+ symbol = sym_ordered_list;
841
+ } else {
842
+ rb_raise(rb_Markly_Error, "could not get list_type");
843
+ }
844
+
845
+ return symbol;
846
+ }
847
+
848
+ /*
849
+ * Public: Sets the list type of the current node (must be a `:list`).
850
+ *
851
+ * level - A {Symbol} representing the new list type
852
+ *
853
+ * Raises a Error if the list type can't be set.
854
+ */
855
+ static VALUE rb_node_set_list_type(VALUE self, VALUE list_type) {
856
+ int type = 0;
857
+ cmark_node *node;
858
+ Check_Type(list_type, T_SYMBOL);
859
+
860
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
861
+
862
+ if (list_type == sym_bullet_list) {
863
+ type = CMARK_BULLET_LIST;
864
+ } else if (list_type == sym_ordered_list) {
865
+ type = CMARK_ORDERED_LIST;
866
+ } else {
867
+ rb_raise(rb_Markly_Error, "invalid list_type");
868
+ }
869
+
870
+ if (!cmark_node_set_list_type(node, type)) {
871
+ rb_raise(rb_Markly_Error, "could not set list_type");
872
+ }
873
+
874
+ return Qnil;
875
+ }
876
+
877
+ /*
878
+ * Public: Gets the starting number the current node (must be an
879
+ * `:ordered_list`).
880
+ *
881
+ * Returns a {Number} representing the starting number.
882
+ * Raises a Error if the starting number can't be retrieved.
883
+ */
884
+ static VALUE rb_node_get_list_start(VALUE self) {
885
+ cmark_node *node;
886
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
887
+
888
+ if (cmark_node_get_type(node) != CMARK_NODE_LIST ||
889
+ cmark_node_get_list_type(node) != CMARK_ORDERED_LIST) {
890
+ rb_raise(rb_Markly_Error, "can't get list_start for non-ordered list %d",
891
+ cmark_node_get_list_type(node));
892
+ }
893
+
894
+ return INT2NUM(cmark_node_get_list_start(node));
895
+ }
896
+
897
+ /*
898
+ * Public: Sets the starting number of the current node (must be an
899
+ * `:ordered_list`).
900
+ *
901
+ * level - A {Number} representing the new starting number
902
+ *
903
+ * Raises a Error if the starting number can't be set.
904
+ */
905
+ static VALUE rb_node_set_list_start(VALUE self, VALUE start) {
906
+ int s;
907
+ cmark_node *node;
908
+ Check_Type(start, T_FIXNUM);
909
+
910
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
911
+ s = FIX2INT(start);
912
+
913
+ if (!cmark_node_set_list_start(node, s)) {
914
+ rb_raise(rb_Markly_Error, "could not set list_start");
915
+ }
916
+
917
+ return Qnil;
918
+ }
919
+
920
+ /*
921
+ * Public: Gets the tight status the current node (must be a `:list`).
922
+ *
923
+ * Returns a `true` if the list is tight, `false` otherwise.
924
+ * Raises a Error if the starting number can't be retrieved.
925
+ */
926
+ static VALUE rb_node_get_list_tight(VALUE self) {
927
+ int flag;
928
+ cmark_node *node;
929
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
930
+
931
+ if (cmark_node_get_type(node) != CMARK_NODE_LIST) {
932
+ rb_raise(rb_Markly_Error, "can't get list_tight for non-list");
933
+ }
934
+
935
+ flag = cmark_node_get_list_tight(node);
936
+
937
+ return flag ? Qtrue : Qfalse;
938
+ }
939
+
940
+ /*
941
+ * Public: Sets the tight status of the current node (must be a `:list`).
942
+ *
943
+ * tight - A {Boolean} representing the new tightness
944
+ *
945
+ * Raises a Error if the tightness can't be set.
946
+ */
947
+ static VALUE rb_node_set_list_tight(VALUE self, VALUE tight) {
948
+ int t;
949
+ cmark_node *node;
950
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
951
+ t = RTEST(tight);
952
+
953
+ if (!cmark_node_set_list_tight(node, t)) {
954
+ rb_raise(rb_Markly_Error, "could not set list_tight");
955
+ }
956
+
957
+ return Qnil;
958
+ }
959
+
960
+ /*
961
+ * Public: Gets the fence info of the current node (must be a `:code_block`).
962
+ *
963
+ * Returns a {String} representing the fence info.
964
+ * Raises a Error if the fence info can't be retrieved.
965
+ */
966
+ static VALUE rb_node_get_fence_info(VALUE self) {
967
+ const char *fence_info;
968
+ cmark_node *node;
969
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
970
+
971
+ fence_info = cmark_node_get_fence_info(node);
972
+
973
+ if (fence_info == NULL) {
974
+ rb_raise(rb_Markly_Error, "could not get fence_info");
975
+ }
976
+
977
+ return rb_str_new2(fence_info);
978
+ }
979
+
980
+ /*
981
+ * Public: Sets the fence info of the current node (must be a `:code_block`).
982
+ *
983
+ * info - A {String} representing the new fence info
984
+ *
985
+ * Raises a Error if the fence info can't be set.
986
+ */
987
+ static VALUE rb_node_set_fence_info(VALUE self, VALUE info) {
988
+ char *text;
989
+ cmark_node *node;
990
+ Check_Type(info, T_STRING);
991
+
992
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
993
+ text = StringValueCStr(info);
994
+
995
+ if (!cmark_node_set_fence_info(node, text)) {
996
+ rb_raise(rb_Markly_Error, "could not set fence_info");
997
+ }
998
+
999
+ return Qnil;
1000
+ }
1001
+
1002
+ static VALUE rb_node_get_tasklist_item_checked(VALUE self) {
1003
+ int tasklist_state;
1004
+ cmark_node *node;
1005
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
1006
+
1007
+ tasklist_state = cmark_gfm_extensions_get_tasklist_item_checked(node);
1008
+
1009
+ if (tasklist_state == 1) {
1010
+ return Qtrue;
1011
+ } else {
1012
+ return Qfalse;
1013
+ }
1014
+ }
1015
+
1016
+ /*
1017
+ * Public: Sets the checkbox state of the current node (must be a `:tasklist`).
1018
+ *
1019
+ * item_checked - A {Boolean} representing the new checkbox state
1020
+ *
1021
+ * Returns a {Boolean} representing the new checkbox state.
1022
+ * Raises a Error if the checkbox state can't be set.
1023
+ */
1024
+ static VALUE rb_node_set_tasklist_item_checked(VALUE self, VALUE item_checked) {
1025
+ int tasklist_state;
1026
+ cmark_node *node;
1027
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
1028
+ tasklist_state = RTEST(item_checked);
1029
+
1030
+ if (!cmark_gfm_extensions_set_tasklist_item_checked(node, tasklist_state)) {
1031
+ rb_raise(rb_Markly_Error, "could not set tasklist_item_checked");
1032
+ };
1033
+
1034
+ if (tasklist_state) {
1035
+ return Qtrue;
1036
+ } else {
1037
+ return Qfalse;
1038
+ }
1039
+ }
1040
+
1041
+ // TODO: remove this, superseded by the above method
1042
+ static VALUE rb_node_get_tasklist_state(VALUE self) {
1043
+ int tasklist_state;
1044
+ cmark_node *node;
1045
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
1046
+
1047
+ tasklist_state = cmark_gfm_extensions_get_tasklist_item_checked(node);
1048
+
1049
+ if (tasklist_state == 1) {
1050
+ return rb_str_new2("checked");
1051
+ } else {
1052
+ return rb_str_new2("unchecked");
1053
+ }
1054
+ }
1055
+
1056
+ static VALUE rb_node_get_table_alignments(VALUE self) {
1057
+ uint16_t column_count, i;
1058
+ uint8_t *alignments;
1059
+ cmark_node *node;
1060
+ VALUE ary;
1061
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
1062
+
1063
+ column_count = cmark_gfm_extensions_get_table_columns(node);
1064
+ alignments = cmark_gfm_extensions_get_table_alignments(node);
1065
+
1066
+ if (!column_count || !alignments) {
1067
+ rb_raise(rb_Markly_Error, "could not get column_count or alignments");
1068
+ }
1069
+
1070
+ ary = rb_ary_new();
1071
+ for (i = 0; i < column_count; ++i) {
1072
+ if (alignments[i] == 'l')
1073
+ rb_ary_push(ary, sym_left);
1074
+ else if (alignments[i] == 'c')
1075
+ rb_ary_push(ary, sym_center);
1076
+ else if (alignments[i] == 'r')
1077
+ rb_ary_push(ary, sym_right);
1078
+ else
1079
+ rb_ary_push(ary, Qnil);
1080
+ }
1081
+ return ary;
1082
+ }
1083
+
1084
+ /* Internal: Escapes href URLs safely. */
1085
+ static VALUE rb_html_escape_href(VALUE self, VALUE rb_text) {
1086
+ char *result;
1087
+ cmark_node *node;
1088
+ Check_Type(rb_text, T_STRING);
1089
+
1090
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
1091
+
1092
+ cmark_mem *mem = cmark_node_mem(node);
1093
+ cmark_strbuf buf = CMARK_BUF_INIT(mem);
1094
+
1095
+ if (houdini_escape_href(&buf, (const uint8_t *)RSTRING_PTR(rb_text),
1096
+ RSTRING_LEN(rb_text))) {
1097
+ result = (char *)cmark_strbuf_detach(&buf);
1098
+ return rb_str_new2(result);
1099
+ }
1100
+
1101
+ return rb_text;
1102
+ }
1103
+
1104
+ /* Internal: Escapes HTML content safely. */
1105
+ static VALUE rb_html_escape_html(VALUE self, VALUE rb_text) {
1106
+ char *result;
1107
+ cmark_node *node;
1108
+ Check_Type(rb_text, T_STRING);
1109
+
1110
+ TypedData_Get_Struct(self, cmark_node, &rb_Markly_Node_Type, node);
1111
+
1112
+ cmark_mem *mem = cmark_node_mem(node);
1113
+ cmark_strbuf buf = CMARK_BUF_INIT(mem);
1114
+
1115
+ if (houdini_escape_html0(&buf, (const uint8_t *)RSTRING_PTR(rb_text),
1116
+ RSTRING_LEN(rb_text), 0)) {
1117
+ result = (char *)cmark_strbuf_detach(&buf);
1118
+ return rb_str_new2(result);
1119
+ }
1120
+
1121
+ return rb_text;
1122
+ }
1123
+
1124
+ VALUE rb_Markly_extensions(VALUE self) {
1125
+ cmark_llist *exts, *it;
1126
+ cmark_syntax_extension *ext;
1127
+ VALUE ary = rb_ary_new();
1128
+
1129
+ cmark_mem *mem = cmark_get_default_mem_allocator();
1130
+ exts = cmark_list_syntax_extensions(mem);
1131
+ for (it = exts; it; it = it->next) {
1132
+ ext = it->data;
1133
+ rb_ary_push(ary, rb_str_new2(ext->name));
1134
+ }
1135
+
1136
+ cmark_llist_free(mem, exts);
1137
+
1138
+ return ary;
1139
+ }
1140
+
1141
+ __attribute__((visibility("default"))) void Init_markly() {
1142
+ sym_document = ID2SYM(rb_intern("document"));
1143
+ sym_blockquote = ID2SYM(rb_intern("blockquote"));
1144
+ sym_list = ID2SYM(rb_intern("list"));
1145
+ sym_list_item = ID2SYM(rb_intern("list_item"));
1146
+ sym_code_block = ID2SYM(rb_intern("code_block"));
1147
+ sym_html = ID2SYM(rb_intern("html"));
1148
+ sym_paragraph = ID2SYM(rb_intern("paragraph"));
1149
+ sym_header = ID2SYM(rb_intern("header"));
1150
+ sym_hrule = ID2SYM(rb_intern("hrule"));
1151
+ sym_text = ID2SYM(rb_intern("text"));
1152
+ sym_softbreak = ID2SYM(rb_intern("softbreak"));
1153
+ sym_linebreak = ID2SYM(rb_intern("linebreak"));
1154
+ sym_code = ID2SYM(rb_intern("code"));
1155
+ sym_inline_html = ID2SYM(rb_intern("inline_html"));
1156
+ sym_emph = ID2SYM(rb_intern("emph"));
1157
+ sym_strong = ID2SYM(rb_intern("strong"));
1158
+ sym_link = ID2SYM(rb_intern("link"));
1159
+ sym_image = ID2SYM(rb_intern("image"));
1160
+ sym_footnote_reference = ID2SYM(rb_intern("footnote_reference"));
1161
+ sym_footnote_definition = ID2SYM(rb_intern("footnote_definition"));
1162
+
1163
+ sym_bullet_list = ID2SYM(rb_intern("bullet_list"));
1164
+ sym_ordered_list = ID2SYM(rb_intern("ordered_list"));
1165
+
1166
+ sym_left = ID2SYM(rb_intern("left"));
1167
+ sym_right = ID2SYM(rb_intern("right"));
1168
+ sym_center = ID2SYM(rb_intern("center"));
1169
+
1170
+ rb_Markly = rb_define_module("Markly");
1171
+ rb_define_singleton_method(rb_Markly, "extensions", rb_Markly_extensions, 0);
1172
+
1173
+ rb_Markly_Error = rb_define_class_under(rb_Markly, "Error", rb_eStandardError);
1174
+ rb_define_singleton_method(rb_Markly_Node, "parse", rb_Markly_Parser_parse, 1);
1175
+
1176
+ rb_Markly_Parser = rb_define_class_under(rb_Markly, "Parser", rb_cObject);
1177
+ rb_define_alloc_func(rb_Markly_Parser, rb_Markly_Parser_alloc);
1178
+ rb_define_method(rb_Markly_Parser, "initialize", rb_Markly_Parser_initialize, 1);
1179
+ rb_define_method(rb_Markly_Parser, "enable", rb_Markly_Parser_enable, 1);
1180
+ rb_define_method(rb_Markly_Parser, "parse", rb_Markly_Parser_parse, 1);
1181
+ rb_define_method(rb_Markly_Parser, "root", rb_Markly_Parser_root, 0);
1182
+
1183
+ rb_Markly_Node = rb_define_class_under(rb_Markly, "Node", rb_cObject);
1184
+ rb_define_singleton_method(rb_Markly_Node, "new", rb_node_new, 1);
1185
+ rb_define_method(rb_Markly_Node, "string_content", rb_node_get_string_content, 0);
1186
+ rb_define_method(rb_Markly_Node, "string_content=", rb_node_set_string_content, 1);
1187
+ rb_define_method(rb_Markly_Node, "type", rb_node_get_type, 0);
1188
+ rb_define_method(rb_Markly_Node, "type_string", rb_node_get_type_string, 0);
1189
+ rb_define_method(rb_Markly_Node, "source_position", rb_node_get_source_position, 0);
1190
+ rb_define_method(rb_Markly_Node, "delete", rb_node_unlink, 0);
1191
+ rb_define_method(rb_Markly_Node, "first_child", rb_node_first_child, 0);
1192
+ rb_define_method(rb_Markly_Node, "next", rb_node_next, 0);
1193
+ rb_define_method(rb_Markly_Node, "insert_before", rb_node_insert_before, 1);
1194
+ rb_define_method(rb_Markly_Node, "_render_html", rb_render_html, 2);
1195
+ rb_define_method(rb_Markly_Node, "_render_commonmark", rb_render_commonmark, -1);
1196
+ rb_define_method(rb_Markly_Node, "_render_plaintext", rb_render_plaintext, -1);
1197
+ rb_define_method(rb_Markly_Node, "insert_after", rb_node_insert_after, 1);
1198
+ rb_define_method(rb_Markly_Node, "prepend_child", rb_node_prepend_child, 1);
1199
+ rb_define_method(rb_Markly_Node, "append_child", rb_node_append_child, 1);
1200
+ rb_define_method(rb_Markly_Node, "last_child", rb_node_last_child, 0);
1201
+ rb_define_method(rb_Markly_Node, "parent", rb_node_parent, 0);
1202
+ rb_define_method(rb_Markly_Node, "previous", rb_node_previous, 0);
1203
+ rb_define_method(rb_Markly_Node, "url", rb_node_get_url, 0);
1204
+ rb_define_method(rb_Markly_Node, "url=", rb_node_set_url, 1);
1205
+ rb_define_method(rb_Markly_Node, "title", rb_node_get_title, 0);
1206
+ rb_define_method(rb_Markly_Node, "title=", rb_node_set_title, 1);
1207
+ rb_define_method(rb_Markly_Node, "header_level", rb_node_get_header_level, 0);
1208
+ rb_define_method(rb_Markly_Node, "header_level=", rb_node_set_header_level, 1);
1209
+ rb_define_method(rb_Markly_Node, "list_type", rb_node_get_list_type, 0);
1210
+ rb_define_method(rb_Markly_Node, "list_type=", rb_node_set_list_type, 1);
1211
+ rb_define_method(rb_Markly_Node, "list_start", rb_node_get_list_start, 0);
1212
+ rb_define_method(rb_Markly_Node, "list_start=", rb_node_set_list_start, 1);
1213
+ rb_define_method(rb_Markly_Node, "list_tight", rb_node_get_list_tight, 0);
1214
+ rb_define_method(rb_Markly_Node, "list_tight=", rb_node_set_list_tight, 1);
1215
+ rb_define_method(rb_Markly_Node, "fence_info", rb_node_get_fence_info, 0);
1216
+ rb_define_method(rb_Markly_Node, "fence_info=", rb_node_set_fence_info, 1);
1217
+ rb_define_method(rb_Markly_Node, "table_alignments", rb_node_get_table_alignments, 0);
1218
+ rb_define_method(rb_Markly_Node, "tasklist_state", rb_node_get_tasklist_state, 0);
1219
+ rb_define_method(rb_Markly_Node, "tasklist_item_checked?", rb_node_get_tasklist_item_checked, 0);
1220
+ rb_define_method(rb_Markly_Node, "tasklist_item_checked=", rb_node_set_tasklist_item_checked, 1);
1221
+
1222
+ rb_define_method(rb_Markly_Node, "html_escape_href", rb_html_escape_href, 1);
1223
+ rb_define_method(rb_Markly_Node, "html_escape_html", rb_html_escape_html, 1);
1224
+
1225
+ cmark_gfm_core_extensions_ensure_registered();
1226
+ }