commonmarker 0.17.13 → 0.23.4

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.

Potentially problematic release.


This version of commonmarker might be problematic. Click here for more details.

Files changed (74) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +94 -18
  3. data/Rakefile +24 -5
  4. data/bin/commonmarker +107 -47
  5. data/commonmarker.gemspec +18 -15
  6. data/ext/commonmarker/autolink.c +10 -6
  7. data/ext/commonmarker/blocks.c +102 -31
  8. data/ext/commonmarker/buffer.c +0 -1
  9. data/ext/commonmarker/chunk.h +0 -1
  10. data/ext/commonmarker/cmark-gfm-core-extensions.h +29 -0
  11. data/ext/commonmarker/cmark-gfm-extension_api.h +19 -2
  12. data/ext/commonmarker/cmark-gfm.h +19 -5
  13. data/ext/commonmarker/cmark-gfm_version.h +2 -2
  14. data/ext/commonmarker/commonmark.c +33 -12
  15. data/ext/commonmarker/commonmarker.c +209 -100
  16. data/ext/commonmarker/core-extensions.c +2 -0
  17. data/ext/commonmarker/ext_scanners.c +622 -684
  18. data/ext/commonmarker/ext_scanners.h +2 -0
  19. data/ext/commonmarker/extconf.rb +3 -1
  20. data/ext/commonmarker/footnotes.c +23 -0
  21. data/ext/commonmarker/footnotes.h +2 -0
  22. data/ext/commonmarker/houdini_href_e.c +1 -1
  23. data/ext/commonmarker/html.c +46 -25
  24. data/ext/commonmarker/inlines.c +127 -30
  25. data/ext/commonmarker/iterator.h +0 -1
  26. data/ext/commonmarker/map.h +0 -1
  27. data/ext/commonmarker/node.c +17 -3
  28. data/ext/commonmarker/node.h +9 -0
  29. data/ext/commonmarker/parser.h +2 -1
  30. data/ext/commonmarker/plaintext.c +22 -0
  31. data/ext/commonmarker/render.c +18 -15
  32. data/ext/commonmarker/render.h +0 -1
  33. data/ext/commonmarker/scanners.c +779 -953
  34. data/ext/commonmarker/scanners.h +0 -2
  35. data/ext/commonmarker/strikethrough.c +4 -1
  36. data/ext/commonmarker/syntax_extension.c +10 -0
  37. data/ext/commonmarker/syntax_extension.h +2 -0
  38. data/ext/commonmarker/table.c +178 -31
  39. data/ext/commonmarker/tasklist.c +156 -0
  40. data/ext/commonmarker/tasklist.h +8 -0
  41. data/ext/commonmarker/xml.c +9 -2
  42. data/lib/commonmarker/config.rb +41 -38
  43. data/lib/commonmarker/errors.rb +12 -0
  44. data/lib/commonmarker/node/inspect.rb +15 -17
  45. data/lib/commonmarker/node.rb +14 -2
  46. data/lib/commonmarker/renderer/html_renderer.rb +45 -36
  47. data/lib/commonmarker/renderer.rb +16 -10
  48. data/lib/commonmarker/version.rb +3 -1
  49. data/lib/commonmarker.rb +8 -7
  50. data/test/benchmark.rb +26 -21
  51. data/test/fixtures/strong.md +1 -0
  52. data/test/fixtures/table.md +10 -0
  53. data/test/test_attributes.rb +5 -3
  54. data/test/test_basics.rb +19 -0
  55. data/test/test_commands.rb +72 -0
  56. data/test/test_commonmark.rb +15 -13
  57. data/test/test_doc.rb +31 -29
  58. data/test/test_encoding.rb +9 -5
  59. data/test/test_extensions.rb +66 -73
  60. data/test/test_footnotes.rb +47 -12
  61. data/test/test_gc.rb +6 -2
  62. data/test/test_helper.rb +25 -15
  63. data/test/test_linebreaks.rb +2 -0
  64. data/test/test_maliciousness.rb +189 -190
  65. data/test/test_node.rb +12 -12
  66. data/test/test_options.rb +17 -15
  67. data/test/test_pathological_inputs.rb +14 -12
  68. data/test/test_plaintext.rb +23 -21
  69. data/test/test_renderer.rb +29 -10
  70. data/test/test_smartpunct.rb +7 -2
  71. data/test/test_spec.rb +7 -4
  72. data/test/test_tasklists.rb +43 -0
  73. data/test/test_xml.rb +107 -0
  74. metadata +74 -30
@@ -7,8 +7,8 @@
7
7
  #include "syntax_extension.h"
8
8
  #include "cmark-gfm-core-extensions.h"
9
9
 
10
- static VALUE rb_mNodeError;
11
- static VALUE rb_mNode;
10
+ static VALUE rb_eNodeError;
11
+ static VALUE rb_cNode;
12
12
 
13
13
  static VALUE sym_document;
14
14
  static VALUE sym_blockquote;
@@ -45,6 +45,13 @@ static VALUE encode_utf8_string(const char *c_string) {
45
45
  return string;
46
46
  }
47
47
 
48
+ /* Encode a C string using the encoding from Ruby string +source+. */
49
+ static VALUE encode_source_string(const char *c_string, VALUE source) {
50
+ VALUE string = rb_str_new2(c_string);
51
+ rb_enc_copy(string, source);
52
+ return string;
53
+ }
54
+
48
55
  static void rb_mark_c_struct(void *data) {
49
56
  cmark_node *node = data;
50
57
  cmark_node *child;
@@ -94,7 +101,7 @@ static VALUE rb_node_to_value(cmark_node *node) {
94
101
 
95
102
  /* Only free tree roots. */
96
103
  free_func = cmark_node_parent(node) ? NULL : rb_free_c_struct;
97
- val = Data_Wrap_Struct(rb_mNode, rb_mark_c_struct, free_func, node);
104
+ val = Data_Wrap_Struct(rb_cNode, rb_mark_c_struct, free_func, node);
98
105
  cmark_node_set_user_data(node, (void *)val);
99
106
 
100
107
  return val;
@@ -108,25 +115,23 @@ static void rb_parent_removed(VALUE val) {
108
115
  RDATA(val)->dfree = rb_free_c_struct;
109
116
  }
110
117
 
111
- static cmark_parser *prepare_parser(VALUE rb_options, VALUE rb_extensions, cmark_mem *mem) {
118
+ static cmark_parser *prepare_parser(VALUE rb_options, VALUE rb_extensions) {
112
119
  int options;
113
- int extensions_len;
114
120
  VALUE rb_ext_name;
115
121
  int i;
116
122
 
117
- Check_Type(rb_options, T_FIXNUM);
123
+ FIXNUM_P(rb_options);
124
+ options = FIX2INT(rb_options);
125
+
118
126
  Check_Type(rb_extensions, T_ARRAY);
119
127
 
120
- options = FIX2INT(rb_options);
121
- extensions_len = RARRAY_LEN(rb_extensions);
128
+ cmark_parser *parser = cmark_parser_new(options);
122
129
 
123
- cmark_parser *parser = cmark_parser_new_with_mem(options, mem);
124
- for (i = 0; i < extensions_len; ++i) {
125
- rb_ext_name = RARRAY_PTR(rb_extensions)[i];
130
+ for (i = 0; i < RARRAY_LEN(rb_extensions); ++i) {
131
+ rb_ext_name = rb_ary_entry(rb_extensions, i);
126
132
 
127
133
  if (!SYMBOL_P(rb_ext_name)) {
128
134
  cmark_parser_free(parser);
129
- cmark_arena_reset();
130
135
  rb_raise(rb_eTypeError, "extension names should be Symbols; got a %"PRIsVALUE"", rb_obj_class(rb_ext_name));
131
136
  }
132
137
 
@@ -135,7 +140,6 @@ static cmark_parser *prepare_parser(VALUE rb_options, VALUE rb_extensions, cmark
135
140
 
136
141
  if (!syntax_extension) {
137
142
  cmark_parser_free(parser);
138
- cmark_arena_reset();
139
143
  rb_raise(rb_eArgError, "extension %s not found", rb_id2name(SYM2ID(rb_ext_name)));
140
144
  }
141
145
 
@@ -150,33 +154,57 @@ static cmark_parser *prepare_parser(VALUE rb_options, VALUE rb_extensions, cmark
150
154
  *
151
155
  */
152
156
  static VALUE rb_markdown_to_html(VALUE self, VALUE rb_text, VALUE rb_options, VALUE rb_extensions) {
153
- char *str, *html;
154
- int len;
157
+ char *html;
155
158
  cmark_parser *parser;
156
159
  cmark_node *doc;
160
+
157
161
  Check_Type(rb_text, T_STRING);
158
- Check_Type(rb_options, T_FIXNUM);
159
162
 
160
- parser = prepare_parser(rb_options, rb_extensions, cmark_get_arena_mem_allocator());
163
+ parser = prepare_parser(rb_options, rb_extensions);
164
+
165
+ cmark_parser_feed(parser, StringValuePtr(rb_text), RSTRING_LEN(rb_text));
166
+ doc = cmark_parser_finish(parser);
167
+
168
+ if (doc == NULL) {
169
+ cmark_parser_free(parser);
170
+ rb_raise(rb_eNodeError, "error parsing document");
171
+ }
172
+
173
+ html = cmark_render_html(doc, parser->options, parser->syntax_extensions);
174
+
175
+ cmark_parser_free(parser);
176
+ cmark_node_free(doc);
177
+
178
+ return rb_utf8_str_new_cstr(html);
179
+ }
161
180
 
162
- str = (char *)RSTRING_PTR(rb_text);
163
- len = RSTRING_LEN(rb_text);
181
+ /*
182
+ * Internal: Parses a Markdown string into an HTML string.
183
+ *
184
+ */
185
+ static VALUE rb_markdown_to_xml(VALUE self, VALUE rb_text, VALUE rb_options, VALUE rb_extensions) {
186
+ char *xml;
187
+ cmark_parser *parser;
188
+ cmark_node *doc;
189
+
190
+ Check_Type(rb_text, T_STRING);
164
191
 
165
- cmark_parser_feed(parser, str, len);
192
+ parser = prepare_parser(rb_options, rb_extensions);
193
+
194
+ cmark_parser_feed(parser, StringValuePtr(rb_text), RSTRING_LEN(rb_text));
166
195
  doc = cmark_parser_finish(parser);
196
+
167
197
  if (doc == NULL) {
168
- cmark_arena_reset();
169
- rb_raise(rb_mNodeError, "error parsing document");
198
+ cmark_parser_free(parser);
199
+ rb_raise(rb_eNodeError, "error parsing document");
170
200
  }
171
201
 
172
- cmark_mem *default_mem = cmark_get_default_mem_allocator();
173
- html = cmark_render_html_with_mem(doc, FIX2INT(rb_options), parser->syntax_extensions, default_mem);
174
- cmark_arena_reset();
202
+ xml = cmark_render_xml(doc, parser->options);
175
203
 
176
- VALUE ruby_html = rb_str_new2(html);
177
- default_mem->free(html);
204
+ cmark_parser_free(parser);
205
+ cmark_node_free(doc);
178
206
 
179
- return ruby_html;
207
+ return rb_utf8_str_new_cstr(xml);
180
208
  }
181
209
 
182
210
  /*
@@ -250,11 +278,11 @@ static VALUE rb_node_new(VALUE self, VALUE type) {
250
278
  else if (type == sym_footnote_definition)
251
279
  node_type = CMARK_NODE_FOOTNOTE_DEFINITION;
252
280
  else
253
- rb_raise(rb_mNodeError, "invalid node of type %d", node_type);
281
+ rb_raise(rb_eNodeError, "invalid node of type %d", node_type);
254
282
 
255
283
  node = cmark_node_new(node_type);
256
284
  if (node == NULL) {
257
- rb_raise(rb_mNodeError, "could not create node of type %d", node_type);
285
+ rb_raise(rb_eNodeError, "could not create node of type %d", node_type);
258
286
  }
259
287
 
260
288
  return rb_node_to_value(node);
@@ -267,23 +295,22 @@ static VALUE rb_node_new(VALUE self, VALUE type) {
267
295
  static VALUE rb_parse_document(VALUE self, VALUE rb_text, VALUE rb_len,
268
296
  VALUE rb_options, VALUE rb_extensions) {
269
297
  char *text;
270
- int len, options;
298
+ int len;
271
299
  cmark_parser *parser;
272
300
  cmark_node *doc;
273
301
  Check_Type(rb_text, T_STRING);
274
302
  Check_Type(rb_len, T_FIXNUM);
275
303
  Check_Type(rb_options, T_FIXNUM);
276
304
 
277
- parser = prepare_parser(rb_options, rb_extensions, cmark_get_default_mem_allocator());
305
+ parser = prepare_parser(rb_options, rb_extensions);
278
306
 
279
307
  text = (char *)RSTRING_PTR(rb_text);
280
308
  len = FIX2INT(rb_len);
281
- options = FIX2INT(rb_options);
282
309
 
283
310
  cmark_parser_feed(parser, text, len);
284
311
  doc = cmark_parser_finish(parser);
285
312
  if (doc == NULL) {
286
- rb_raise(rb_mNodeError, "error parsing document");
313
+ rb_raise(rb_eNodeError, "error parsing document");
287
314
  }
288
315
  cmark_parser_free(parser);
289
316
 
@@ -302,7 +329,7 @@ static VALUE rb_node_get_string_content(VALUE self) {
302
329
 
303
330
  text = cmark_node_get_literal(node);
304
331
  if (text == NULL) {
305
- rb_raise(rb_mNodeError, "could not get string content");
332
+ rb_raise(rb_eNodeError, "could not get string content");
306
333
  }
307
334
 
308
335
  return encode_utf8_string(text);
@@ -324,7 +351,7 @@ static VALUE rb_node_set_string_content(VALUE self, VALUE s) {
324
351
  text = StringValueCStr(s);
325
352
 
326
353
  if (!cmark_node_set_literal(node, text)) {
327
- rb_raise(rb_mNodeError, "could not set string content");
354
+ rb_raise(rb_eNodeError, "could not set string content");
328
355
  }
329
356
 
330
357
  return Qnil;
@@ -412,7 +439,7 @@ static VALUE rb_node_get_type(VALUE self) {
412
439
  s = node->extension->get_type_string_func(node->extension, node);
413
440
  return ID2SYM(rb_intern(s));
414
441
  }
415
- rb_raise(rb_mNodeError, "invalid node type %d", node_type);
442
+ rb_raise(rb_eNodeError, "invalid node type %d", node_type);
416
443
  }
417
444
 
418
445
  return symbol;
@@ -512,7 +539,7 @@ static VALUE rb_node_insert_before(VALUE self, VALUE sibling) {
512
539
  Data_Get_Struct(sibling, cmark_node, node2);
513
540
 
514
541
  if (!cmark_node_insert_before(node1, node2)) {
515
- rb_raise(rb_mNodeError, "could not insert before");
542
+ rb_raise(rb_eNodeError, "could not insert before");
516
543
  }
517
544
 
518
545
  rb_parent_added(sibling);
@@ -567,6 +594,27 @@ static VALUE rb_render_html(VALUE self, VALUE rb_options, VALUE rb_extensions) {
567
594
  return ruby_html;
568
595
  }
569
596
 
597
+ /* Internal: Convert the node to an XML string.
598
+ *
599
+ * Returns a {String}.
600
+ */
601
+ static VALUE rb_render_xml(VALUE self, VALUE rb_options) {
602
+ int options;
603
+ cmark_node *node;
604
+ Check_Type(rb_options, T_FIXNUM);
605
+
606
+ options = FIX2INT(rb_options);
607
+
608
+ Data_Get_Struct(self, cmark_node, node);
609
+
610
+ char *xml = cmark_render_xml(node, options);
611
+ VALUE ruby_xml = rb_str_new2(xml);
612
+
613
+ free(xml);
614
+
615
+ return ruby_xml;
616
+ }
617
+
570
618
  /* Internal: Convert the node to a CommonMark string.
571
619
  *
572
620
  * Returns a {String}.
@@ -638,7 +686,7 @@ static VALUE rb_node_insert_after(VALUE self, VALUE sibling) {
638
686
  Data_Get_Struct(sibling, cmark_node, node2);
639
687
 
640
688
  if (!cmark_node_insert_after(node1, node2)) {
641
- rb_raise(rb_mNodeError, "could not insert after");
689
+ rb_raise(rb_eNodeError, "could not insert after");
642
690
  }
643
691
 
644
692
  rb_parent_added(sibling);
@@ -661,7 +709,7 @@ static VALUE rb_node_prepend_child(VALUE self, VALUE child) {
661
709
  Data_Get_Struct(child, cmark_node, node2);
662
710
 
663
711
  if (!cmark_node_prepend_child(node1, node2)) {
664
- rb_raise(rb_mNodeError, "could not prepend child");
712
+ rb_raise(rb_eNodeError, "could not prepend child");
665
713
  }
666
714
 
667
715
  rb_parent_added(child);
@@ -684,7 +732,7 @@ static VALUE rb_node_append_child(VALUE self, VALUE child) {
684
732
  Data_Get_Struct(child, cmark_node, node2);
685
733
 
686
734
  if (!cmark_node_append_child(node1, node2)) {
687
- rb_raise(rb_mNodeError, "could not append child");
735
+ rb_raise(rb_eNodeError, "could not append child");
688
736
  }
689
737
 
690
738
  rb_parent_added(child);
@@ -744,7 +792,7 @@ static VALUE rb_node_get_url(VALUE self) {
744
792
 
745
793
  text = cmark_node_get_url(node);
746
794
  if (text == NULL) {
747
- rb_raise(rb_mNodeError, "could not get url");
795
+ rb_raise(rb_eNodeError, "could not get url");
748
796
  }
749
797
 
750
798
  return rb_str_new2(text);
@@ -766,7 +814,7 @@ static VALUE rb_node_set_url(VALUE self, VALUE url) {
766
814
  text = StringValueCStr(url);
767
815
 
768
816
  if (!cmark_node_set_url(node, text)) {
769
- rb_raise(rb_mNodeError, "could not set url");
817
+ rb_raise(rb_eNodeError, "could not set url");
770
818
  }
771
819
 
772
820
  return Qnil;
@@ -785,7 +833,7 @@ static VALUE rb_node_get_title(VALUE self) {
785
833
 
786
834
  text = cmark_node_get_title(node);
787
835
  if (text == NULL) {
788
- rb_raise(rb_mNodeError, "could not get title");
836
+ rb_raise(rb_eNodeError, "could not get title");
789
837
  }
790
838
 
791
839
  return rb_str_new2(text);
@@ -807,7 +855,7 @@ static VALUE rb_node_set_title(VALUE self, VALUE title) {
807
855
  text = StringValueCStr(title);
808
856
 
809
857
  if (!cmark_node_set_title(node, text)) {
810
- rb_raise(rb_mNodeError, "could not set title");
858
+ rb_raise(rb_eNodeError, "could not set title");
811
859
  }
812
860
 
813
861
  return Qnil;
@@ -827,7 +875,7 @@ static VALUE rb_node_get_header_level(VALUE self) {
827
875
  header_level = cmark_node_get_header_level(node);
828
876
 
829
877
  if (header_level == 0) {
830
- rb_raise(rb_mNodeError, "could not get header_level");
878
+ rb_raise(rb_eNodeError, "could not get header_level");
831
879
  }
832
880
 
833
881
  return INT2NUM(header_level);
@@ -849,7 +897,7 @@ static VALUE rb_node_set_header_level(VALUE self, VALUE level) {
849
897
  l = FIX2INT(level);
850
898
 
851
899
  if (!cmark_node_set_header_level(node, l)) {
852
- rb_raise(rb_mNodeError, "could not set header_level");
900
+ rb_raise(rb_eNodeError, "could not set header_level");
853
901
  }
854
902
 
855
903
  return Qnil;
@@ -874,7 +922,7 @@ static VALUE rb_node_get_list_type(VALUE self) {
874
922
  } else if (list_type == CMARK_ORDERED_LIST) {
875
923
  symbol = sym_ordered_list;
876
924
  } else {
877
- rb_raise(rb_mNodeError, "could not get list_type");
925
+ rb_raise(rb_eNodeError, "could not get list_type");
878
926
  }
879
927
 
880
928
  return symbol;
@@ -899,11 +947,11 @@ static VALUE rb_node_set_list_type(VALUE self, VALUE list_type) {
899
947
  } else if (list_type == sym_ordered_list) {
900
948
  type = CMARK_ORDERED_LIST;
901
949
  } else {
902
- rb_raise(rb_mNodeError, "invalid list_type");
950
+ rb_raise(rb_eNodeError, "invalid list_type");
903
951
  }
904
952
 
905
953
  if (!cmark_node_set_list_type(node, type)) {
906
- rb_raise(rb_mNodeError, "could not set list_type");
954
+ rb_raise(rb_eNodeError, "could not set list_type");
907
955
  }
908
956
 
909
957
  return Qnil;
@@ -922,7 +970,7 @@ static VALUE rb_node_get_list_start(VALUE self) {
922
970
 
923
971
  if (cmark_node_get_type(node) != CMARK_NODE_LIST ||
924
972
  cmark_node_get_list_type(node) != CMARK_ORDERED_LIST) {
925
- rb_raise(rb_mNodeError, "can't get list_start for non-ordered list %d",
973
+ rb_raise(rb_eNodeError, "can't get list_start for non-ordered list %d",
926
974
  cmark_node_get_list_type(node));
927
975
  }
928
976
 
@@ -946,7 +994,7 @@ static VALUE rb_node_set_list_start(VALUE self, VALUE start) {
946
994
  s = FIX2INT(start);
947
995
 
948
996
  if (!cmark_node_set_list_start(node, s)) {
949
- rb_raise(rb_mNodeError, "could not set list_start");
997
+ rb_raise(rb_eNodeError, "could not set list_start");
950
998
  }
951
999
 
952
1000
  return Qnil;
@@ -964,7 +1012,7 @@ static VALUE rb_node_get_list_tight(VALUE self) {
964
1012
  Data_Get_Struct(self, cmark_node, node);
965
1013
 
966
1014
  if (cmark_node_get_type(node) != CMARK_NODE_LIST) {
967
- rb_raise(rb_mNodeError, "can't get list_tight for non-list");
1015
+ rb_raise(rb_eNodeError, "can't get list_tight for non-list");
968
1016
  }
969
1017
 
970
1018
  flag = cmark_node_get_list_tight(node);
@@ -986,7 +1034,7 @@ static VALUE rb_node_set_list_tight(VALUE self, VALUE tight) {
986
1034
  t = RTEST(tight);
987
1035
 
988
1036
  if (!cmark_node_set_list_tight(node, t)) {
989
- rb_raise(rb_mNodeError, "could not set list_tight");
1037
+ rb_raise(rb_eNodeError, "could not set list_tight");
990
1038
  }
991
1039
 
992
1040
  return Qnil;
@@ -1006,7 +1054,7 @@ static VALUE rb_node_get_fence_info(VALUE self) {
1006
1054
  fence_info = cmark_node_get_fence_info(node);
1007
1055
 
1008
1056
  if (fence_info == NULL) {
1009
- rb_raise(rb_mNodeError, "could not get fence_info");
1057
+ rb_raise(rb_eNodeError, "could not get fence_info");
1010
1058
  }
1011
1059
 
1012
1060
  return rb_str_new2(fence_info);
@@ -1028,12 +1076,66 @@ static VALUE rb_node_set_fence_info(VALUE self, VALUE info) {
1028
1076
  text = StringValueCStr(info);
1029
1077
 
1030
1078
  if (!cmark_node_set_fence_info(node, text)) {
1031
- rb_raise(rb_mNodeError, "could not set fence_info");
1079
+ rb_raise(rb_eNodeError, "could not set fence_info");
1032
1080
  }
1033
1081
 
1034
1082
  return Qnil;
1035
1083
  }
1036
1084
 
1085
+ static VALUE rb_node_get_tasklist_item_checked(VALUE self) {
1086
+ int tasklist_state;
1087
+ cmark_node *node;
1088
+ Data_Get_Struct(self, cmark_node, node);
1089
+
1090
+ tasklist_state = cmark_gfm_extensions_get_tasklist_item_checked(node);
1091
+
1092
+ if (tasklist_state == 1) {
1093
+ return Qtrue;
1094
+ } else {
1095
+ return Qfalse;
1096
+ }
1097
+ }
1098
+
1099
+ /*
1100
+ * Public: Sets the checkbox state of the current node (must be a `:tasklist`).
1101
+ *
1102
+ * item_checked - A {Boolean} representing the new checkbox state
1103
+ *
1104
+ * Returns a {Boolean} representing the new checkbox state.
1105
+ * Raises a NodeError if the checkbox state can't be set.
1106
+ */
1107
+ static VALUE rb_node_set_tasklist_item_checked(VALUE self, VALUE item_checked) {
1108
+ int tasklist_state;
1109
+ cmark_node *node;
1110
+ Data_Get_Struct(self, cmark_node, node);
1111
+ tasklist_state = RTEST(item_checked);
1112
+
1113
+ if (!cmark_gfm_extensions_set_tasklist_item_checked(node, tasklist_state)) {
1114
+ rb_raise(rb_eNodeError, "could not set tasklist_item_checked");
1115
+ };
1116
+
1117
+ if (tasklist_state) {
1118
+ return Qtrue;
1119
+ } else {
1120
+ return Qfalse;
1121
+ }
1122
+ }
1123
+
1124
+ // TODO: remove this, superseded by the above method
1125
+ static VALUE rb_node_get_tasklist_state(VALUE self) {
1126
+ int tasklist_state;
1127
+ cmark_node *node;
1128
+ Data_Get_Struct(self, cmark_node, node);
1129
+
1130
+ tasklist_state = cmark_gfm_extensions_get_tasklist_item_checked(node);
1131
+
1132
+ if (tasklist_state == 1) {
1133
+ return rb_str_new2("checked");
1134
+ } else {
1135
+ return rb_str_new2("unchecked");
1136
+ }
1137
+ }
1138
+
1037
1139
  static VALUE rb_node_get_table_alignments(VALUE self) {
1038
1140
  uint16_t column_count, i;
1039
1141
  uint8_t *alignments;
@@ -1045,7 +1147,7 @@ static VALUE rb_node_get_table_alignments(VALUE self) {
1045
1147
  alignments = cmark_gfm_extensions_get_table_alignments(node);
1046
1148
 
1047
1149
  if (!column_count || !alignments) {
1048
- rb_raise(rb_mNodeError, "could not get column_count or alignments");
1150
+ rb_raise(rb_eNodeError, "could not get column_count or alignments");
1049
1151
  }
1050
1152
 
1051
1153
  ary = rb_ary_new();
@@ -1076,7 +1178,8 @@ static VALUE rb_html_escape_href(VALUE self, VALUE rb_text) {
1076
1178
  if (houdini_escape_href(&buf, (const uint8_t *)RSTRING_PTR(rb_text),
1077
1179
  RSTRING_LEN(rb_text))) {
1078
1180
  result = (char *)cmark_strbuf_detach(&buf);
1079
- return rb_str_new2(result);
1181
+ return encode_source_string(result, rb_text);
1182
+
1080
1183
  }
1081
1184
 
1082
1185
  return rb_text;
@@ -1096,7 +1199,7 @@ static VALUE rb_html_escape_html(VALUE self, VALUE rb_text) {
1096
1199
  if (houdini_escape_html0(&buf, (const uint8_t *)RSTRING_PTR(rb_text),
1097
1200
  RSTRING_LEN(rb_text), 0)) {
1098
1201
  result = (char *)cmark_strbuf_detach(&buf);
1099
- return rb_str_new2(result);
1202
+ return encode_source_string(result, rb_text);
1100
1203
  }
1101
1204
 
1102
1205
  return rb_text;
@@ -1150,48 +1253,54 @@ __attribute__((visibility("default"))) void Init_commonmarker() {
1150
1253
 
1151
1254
  module = rb_define_module("CommonMarker");
1152
1255
  rb_define_singleton_method(module, "extensions", rb_extensions, 0);
1153
- rb_mNodeError = rb_define_class_under(module, "NodeError", rb_eStandardError);
1154
- rb_mNode = rb_define_class_under(module, "Node", rb_cObject);
1155
- rb_define_singleton_method(rb_mNode, "markdown_to_html", rb_markdown_to_html,
1256
+ rb_eNodeError = rb_define_class_under(module, "NodeError", rb_eStandardError);
1257
+ rb_cNode = rb_define_class_under(module, "Node", rb_cObject);
1258
+ rb_define_singleton_method(rb_cNode, "markdown_to_html", rb_markdown_to_html,
1259
+ 3);
1260
+ rb_define_singleton_method(rb_cNode, "markdown_to_xml", rb_markdown_to_xml,
1156
1261
  3);
1157
- rb_define_singleton_method(rb_mNode, "new", rb_node_new, 1);
1158
- rb_define_singleton_method(rb_mNode, "parse_document", rb_parse_document, 4);
1159
- rb_define_method(rb_mNode, "string_content", rb_node_get_string_content, 0);
1160
- rb_define_method(rb_mNode, "string_content=", rb_node_set_string_content, 1);
1161
- rb_define_method(rb_mNode, "type", rb_node_get_type, 0);
1162
- rb_define_method(rb_mNode, "type_string", rb_node_get_type_string, 0);
1163
- rb_define_method(rb_mNode, "sourcepos", rb_node_get_sourcepos, 0);
1164
- rb_define_method(rb_mNode, "delete", rb_node_unlink, 0);
1165
- rb_define_method(rb_mNode, "first_child", rb_node_first_child, 0);
1166
- rb_define_method(rb_mNode, "next", rb_node_next, 0);
1167
- rb_define_method(rb_mNode, "insert_before", rb_node_insert_before, 1);
1168
- rb_define_method(rb_mNode, "_render_html", rb_render_html, 2);
1169
- rb_define_method(rb_mNode, "_render_commonmark", rb_render_commonmark, -1);
1170
- rb_define_method(rb_mNode, "_render_plaintext", rb_render_plaintext, -1);
1171
- rb_define_method(rb_mNode, "insert_after", rb_node_insert_after, 1);
1172
- rb_define_method(rb_mNode, "prepend_child", rb_node_prepend_child, 1);
1173
- rb_define_method(rb_mNode, "append_child", rb_node_append_child, 1);
1174
- rb_define_method(rb_mNode, "last_child", rb_node_last_child, 0);
1175
- rb_define_method(rb_mNode, "parent", rb_node_parent, 0);
1176
- rb_define_method(rb_mNode, "previous", rb_node_previous, 0);
1177
- rb_define_method(rb_mNode, "url", rb_node_get_url, 0);
1178
- rb_define_method(rb_mNode, "url=", rb_node_set_url, 1);
1179
- rb_define_method(rb_mNode, "title", rb_node_get_title, 0);
1180
- rb_define_method(rb_mNode, "title=", rb_node_set_title, 1);
1181
- rb_define_method(rb_mNode, "header_level", rb_node_get_header_level, 0);
1182
- rb_define_method(rb_mNode, "header_level=", rb_node_set_header_level, 1);
1183
- rb_define_method(rb_mNode, "list_type", rb_node_get_list_type, 0);
1184
- rb_define_method(rb_mNode, "list_type=", rb_node_set_list_type, 1);
1185
- rb_define_method(rb_mNode, "list_start", rb_node_get_list_start, 0);
1186
- rb_define_method(rb_mNode, "list_start=", rb_node_set_list_start, 1);
1187
- rb_define_method(rb_mNode, "list_tight", rb_node_get_list_tight, 0);
1188
- rb_define_method(rb_mNode, "list_tight=", rb_node_set_list_tight, 1);
1189
- rb_define_method(rb_mNode, "fence_info", rb_node_get_fence_info, 0);
1190
- rb_define_method(rb_mNode, "fence_info=", rb_node_set_fence_info, 1);
1191
- rb_define_method(rb_mNode, "table_alignments", rb_node_get_table_alignments, 0);
1192
-
1193
- rb_define_method(rb_mNode, "html_escape_href", rb_html_escape_href, 1);
1194
- rb_define_method(rb_mNode, "html_escape_html", rb_html_escape_html, 1);
1262
+ rb_define_singleton_method(rb_cNode, "new", rb_node_new, 1);
1263
+ rb_define_singleton_method(rb_cNode, "parse_document", rb_parse_document, 4);
1264
+ rb_define_method(rb_cNode, "string_content", rb_node_get_string_content, 0);
1265
+ rb_define_method(rb_cNode, "string_content=", rb_node_set_string_content, 1);
1266
+ rb_define_method(rb_cNode, "type", rb_node_get_type, 0);
1267
+ rb_define_method(rb_cNode, "type_string", rb_node_get_type_string, 0);
1268
+ rb_define_method(rb_cNode, "sourcepos", rb_node_get_sourcepos, 0);
1269
+ rb_define_method(rb_cNode, "delete", rb_node_unlink, 0);
1270
+ rb_define_method(rb_cNode, "first_child", rb_node_first_child, 0);
1271
+ rb_define_method(rb_cNode, "next", rb_node_next, 0);
1272
+ rb_define_method(rb_cNode, "insert_before", rb_node_insert_before, 1);
1273
+ rb_define_method(rb_cNode, "_render_html", rb_render_html, 2);
1274
+ rb_define_method(rb_cNode, "_render_xml", rb_render_xml, 1);
1275
+ rb_define_method(rb_cNode, "_render_commonmark", rb_render_commonmark, -1);
1276
+ rb_define_method(rb_cNode, "_render_plaintext", rb_render_plaintext, -1);
1277
+ rb_define_method(rb_cNode, "insert_after", rb_node_insert_after, 1);
1278
+ rb_define_method(rb_cNode, "prepend_child", rb_node_prepend_child, 1);
1279
+ rb_define_method(rb_cNode, "append_child", rb_node_append_child, 1);
1280
+ rb_define_method(rb_cNode, "last_child", rb_node_last_child, 0);
1281
+ rb_define_method(rb_cNode, "parent", rb_node_parent, 0);
1282
+ rb_define_method(rb_cNode, "previous", rb_node_previous, 0);
1283
+ rb_define_method(rb_cNode, "url", rb_node_get_url, 0);
1284
+ rb_define_method(rb_cNode, "url=", rb_node_set_url, 1);
1285
+ rb_define_method(rb_cNode, "title", rb_node_get_title, 0);
1286
+ rb_define_method(rb_cNode, "title=", rb_node_set_title, 1);
1287
+ rb_define_method(rb_cNode, "header_level", rb_node_get_header_level, 0);
1288
+ rb_define_method(rb_cNode, "header_level=", rb_node_set_header_level, 1);
1289
+ rb_define_method(rb_cNode, "list_type", rb_node_get_list_type, 0);
1290
+ rb_define_method(rb_cNode, "list_type=", rb_node_set_list_type, 1);
1291
+ rb_define_method(rb_cNode, "list_start", rb_node_get_list_start, 0);
1292
+ rb_define_method(rb_cNode, "list_start=", rb_node_set_list_start, 1);
1293
+ rb_define_method(rb_cNode, "list_tight", rb_node_get_list_tight, 0);
1294
+ rb_define_method(rb_cNode, "list_tight=", rb_node_set_list_tight, 1);
1295
+ rb_define_method(rb_cNode, "fence_info", rb_node_get_fence_info, 0);
1296
+ rb_define_method(rb_cNode, "fence_info=", rb_node_set_fence_info, 1);
1297
+ rb_define_method(rb_cNode, "table_alignments", rb_node_get_table_alignments, 0);
1298
+ rb_define_method(rb_cNode, "tasklist_state", rb_node_get_tasklist_state, 0);
1299
+ rb_define_method(rb_cNode, "tasklist_item_checked?", rb_node_get_tasklist_item_checked, 0);
1300
+ rb_define_method(rb_cNode, "tasklist_item_checked=", rb_node_set_tasklist_item_checked, 1);
1301
+
1302
+ rb_define_method(rb_cNode, "html_escape_href", rb_html_escape_href, 1);
1303
+ rb_define_method(rb_cNode, "html_escape_html", rb_html_escape_html, 1);
1195
1304
 
1196
1305
  cmark_gfm_core_extensions_ensure_registered();
1197
1306
  }
@@ -3,6 +3,7 @@
3
3
  #include "strikethrough.h"
4
4
  #include "table.h"
5
5
  #include "tagfilter.h"
6
+ #include "tasklist.h"
6
7
  #include "registry.h"
7
8
  #include "plugin.h"
8
9
 
@@ -12,6 +13,7 @@ static int core_extensions_registration(cmark_plugin *plugin) {
12
13
  create_strikethrough_extension());
13
14
  cmark_plugin_register_syntax_extension(plugin, create_autolink_extension());
14
15
  cmark_plugin_register_syntax_extension(plugin, create_tagfilter_extension());
16
+ cmark_plugin_register_syntax_extension(plugin, create_tasklist_extension());
15
17
  return 1;
16
18
  }
17
19