markly 0.17.0 → 0.18.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b86cb2d3095458e69fe2d6fc2b9d6eb7dbee37b15edf5cc7064104ef12b5cb98
4
- data.tar.gz: 1ddb2cac9ff79ee9fd2012e67949ddd5886930f6c5ecb28b54edf2eeffbbf110
3
+ metadata.gz: a6df3d157ca441e13f840de336bf04408669aae72ff791d35be091ee008da87c
4
+ data.tar.gz: 682356cc37b69d2a486624ffd0e0c02f75a717b07f32c0a41d838e2032730223
5
5
  SHA512:
6
- metadata.gz: fbc478782839f1c5d20abd6f9697da6e870f4620873d1b1450b96e7f8e21c31f345d0461fbc6536da9f3a0b33b19ef7dd69a70c5f1edd40bc7e08b42cab66ac1
7
- data.tar.gz: ef38f140dd12fbd5788e17f124f280fe25cb1a3af67963d0b8e1780b851adf75609f9da6f38e682ca4ff2a6f59d7d756dc5a7469ffaf76e99c9ea6a9f03b115f
6
+ metadata.gz: 70315346cac721d22cbc67c0efaee8bd6a035198fec894388a827136c3710d60844c24e29a26a4374a899af01212618412d929acfd840db03ce887f79e2b80ef
7
+ data.tar.gz: 895682bb5cd75d95306c2e60b9bb446b4459ade9800d8a29e5ecd13b4fb9f8e1caa33518ac1d3f6779143af9f213d50a0c17460ded2fc94eea57872e7aba9c26
checksums.yaml.gz.sig CHANGED
@@ -1,6 +1,5 @@
1
- (����3����}�'�t�����ՇSi�ݶ�=��7y�] vh��m(c�[��n�:�3��XTl��@)���)���
2
- 5^XS��0|���������'H}�+�J�����!܊0���~C
3
- ߖ��l��S+�5Yӏ^�z1C�f����>hOv��hdJ�Wi�
4
- B"�پ �����Y���j��O�����?�$�u���b��*�qfR��0�=/�l�Lf��N�I���B�Vt�������
5
- M�ov��OM�*��٤-e�Σ�S��D#�9�6ש"�^�hw�+�J��w%;����Jjk
6
- �DƢ��� :k�"x�B���Z׭
1
+ ^��WE�M���KH�\���3}6���ѳ:�v�™Z���[A21������v.��گ�yg..z�������)sbC�**_HS0/P�X����3���-<���Pq��4h
2
+ w�M���6r.�c*Ҹ־}�1��p韻��̬&�v?�a���↞��7Di���̫�-�>��\Mi�2h��:�0�T ��
3
+ B{�.;
4
+ �W�\b�qub����'��a�݉藣�䩋��GYJe��oH(�@�E��pJ�><��ڿ�}��P���A;��i
5
+ ��{kgg���l��`�z��)��$hc���� ���s ����6Ug�ݟ|�^a��`ӟ�\#:�NXD�h�^�}מi
@@ -264,6 +264,10 @@ typedef void (*cmark_opaque_free_func) (cmark_syntax_extension *extension,
264
264
  cmark_mem *mem,
265
265
  cmark_node *node);
266
266
 
267
+ typedef void (*cmark_opaque_copy_func)(cmark_syntax_extension *extension,
268
+ cmark_mem *mem, cmark_node *node,
269
+ cmark_node *source);
270
+
267
271
  /** Free a cmark_syntax_extension.
268
272
  */
269
273
  CMARK_GFM_EXPORT
@@ -406,6 +410,12 @@ CMARK_GFM_EXPORT
406
410
  void cmark_syntax_extension_set_opaque_free_func(cmark_syntax_extension *extension,
407
411
  cmark_opaque_free_func func);
408
412
 
413
+ /** See the documentation for 'cmark_syntax_extension'
414
+ */
415
+ CMARK_GFM_EXPORT
416
+ void cmark_syntax_extension_set_opaque_copy_func(
417
+ cmark_syntax_extension *extension, cmark_opaque_copy_func func);
418
+
409
419
  /** See the documentation for 'cmark_syntax_extension'
410
420
  */
411
421
  CMARK_GFM_EXPORT
@@ -196,6 +196,12 @@ CMARK_GFM_EXPORT cmark_node *cmark_node_new_with_mem_and_ext(cmark_node_type typ
196
196
  cmark_mem *mem,
197
197
  cmark_syntax_extension *extension);
198
198
 
199
+ /** Creates an independent deep copy of 'node' and all its children.
200
+ * User data is not copied. Returns NULL when extension-specific node data
201
+ * cannot be copied.
202
+ */
203
+ CMARK_GFM_EXPORT cmark_node *cmark_node_clone(cmark_node *node);
204
+
199
205
  /** Frees the memory allocated for a node and any children.
200
206
  */
201
207
  CMARK_GFM_EXPORT void cmark_node_free(cmark_node *node);
@@ -842,6 +842,29 @@ static void opaque_free(cmark_syntax_extension *self, cmark_mem *mem, cmark_node
842
842
  }
843
843
  }
844
844
 
845
+ static void opaque_copy(cmark_syntax_extension *self, cmark_mem *mem,
846
+ cmark_node *node, cmark_node *source) {
847
+ if (node->type == CMARK_NODE_TABLE) {
848
+ node_table *table = (node_table *)node->as.opaque;
849
+ node_table *source_table = (node_table *)source->as.opaque;
850
+
851
+ table->n_columns = source_table->n_columns;
852
+ table->n_rows = source_table->n_rows;
853
+ table->n_nonempty_cells = source_table->n_nonempty_cells;
854
+
855
+ if (source_table->alignments) {
856
+ table->alignments = mem->calloc(source_table->n_columns, sizeof(uint8_t));
857
+ memcpy(table->alignments, source_table->alignments,
858
+ source_table->n_columns * sizeof(uint8_t));
859
+ }
860
+ } else if (node->type == CMARK_NODE_TABLE_ROW) {
861
+ *(node_table_row *)node->as.opaque = *(node_table_row *)source->as.opaque;
862
+ } else if (node->type == CMARK_NODE_TABLE_CELL) {
863
+ mem->free(node->as.opaque);
864
+ node->as.cell_index = source->as.cell_index;
865
+ }
866
+ }
867
+
845
868
  static int escape(cmark_syntax_extension *self, cmark_node *node, int c) {
846
869
  return
847
870
  node->type != CMARK_NODE_TABLE &&
@@ -867,6 +890,7 @@ cmark_syntax_extension *create_table_extension(void) {
867
890
  cmark_syntax_extension_set_html_render_func(self, html_render);
868
891
  cmark_syntax_extension_set_opaque_alloc_func(self, opaque_alloc);
869
892
  cmark_syntax_extension_set_opaque_free_func(self, opaque_free);
893
+ cmark_syntax_extension_set_opaque_copy_func(self, opaque_copy);
870
894
  cmark_syntax_extension_set_commonmark_escape_func(self, escape);
871
895
  CMARK_NODE_TABLE = cmark_syntax_extension_add_node(0);
872
896
  CMARK_NODE_TABLE_ROW = cmark_syntax_extension_add_node(0);
data/ext/markly/html.c CHANGED
@@ -303,7 +303,7 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
303
303
 
304
304
  case CMARK_NODE_PARAGRAPH:
305
305
  parent = cmark_node_parent(node);
306
- grandparent = cmark_node_parent(parent);
306
+ grandparent = parent ? cmark_node_parent(parent) : NULL;
307
307
  if (grandparent != NULL && grandparent->type == CMARK_NODE_LIST) {
308
308
  tight = grandparent->as.list.tight;
309
309
  } else {
@@ -316,7 +316,8 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
316
316
  cmark_html_render_sourcepos(node, html, options);
317
317
  cmark_strbuf_putc(html, '>');
318
318
  } else {
319
- if (parent->type == CMARK_NODE_FOOTNOTE_DEFINITION && node->next == NULL) {
319
+ if (parent && parent->type == CMARK_NODE_FOOTNOTE_DEFINITION &&
320
+ node->next == NULL) {
320
321
  cmark_strbuf_putc(html, ' ');
321
322
  S_put_footnote_backref(renderer, html, parent);
322
323
  }
data/ext/markly/markly.c CHANGED
@@ -271,6 +271,21 @@ static VALUE Markly_Node_new(VALUE self, VALUE type) {
271
271
  return Markly_Node_wrap(node);
272
272
  }
273
273
 
274
+ /*
275
+ * Duplicate the current node and all its children.
276
+ */
277
+ static VALUE Markly_Node_duplicate(VALUE self) {
278
+ cmark_node *node;
279
+ TypedData_Get_Struct(self, cmark_node, &Markly_Node_Type, node);
280
+
281
+ cmark_node *copy = cmark_node_clone(node);
282
+ if (copy == NULL) {
283
+ rb_raise(Markly_Error, "could not duplicate node");
284
+ }
285
+
286
+ return Markly_Node_wrap(copy);
287
+ }
288
+
274
289
  static VALUE Markly_Node_replace(VALUE self, VALUE other) {
275
290
  cmark_node *current_node = NULL, *replacement_node = NULL;
276
291
 
@@ -1273,6 +1288,7 @@ static void Init_Markly_Node(VALUE Markly) {
1273
1288
  rb_undef_alloc_func(Markly_Node);
1274
1289
  rb_define_singleton_method(Markly_Node, "new", Markly_Node_new, 1);
1275
1290
  Markly_Node_Fence = rb_struct_define_under(Markly_Node, "Fence", "character", "length", "indent", NULL);
1291
+ rb_define_method(Markly_Node, "_dup", Markly_Node_duplicate, 0);
1276
1292
 
1277
1293
  rb_define_method(Markly_Node, "replace", Markly_Node_replace, 1);
1278
1294
 
data/ext/markly/node.c CHANGED
@@ -145,6 +145,144 @@ cmark_node *cmark_node_new(cmark_node_type type) {
145
145
  return cmark_node_new_with_ext(type, NULL);
146
146
  }
147
147
 
148
+ static cmark_chunk S_clone_chunk(cmark_mem *mem, const cmark_chunk *source) {
149
+ cmark_chunk clone = {NULL, source->len, 1};
150
+ clone.data = (unsigned char *)mem->calloc(source->len + 1, 1);
151
+ if (source->len > 0) {
152
+ memcpy(clone.data, source->data, source->len);
153
+ }
154
+ return clone;
155
+ }
156
+
157
+ static cmark_node *S_clone_node(cmark_node *node) {
158
+ cmark_mem *mem = NODE_MEM(node);
159
+ cmark_node *clone = cmark_node_new_with_mem_and_ext(
160
+ (cmark_node_type)node->type, mem, node->extension);
161
+
162
+ if (!clone) {
163
+ return NULL;
164
+ }
165
+
166
+ cmark_strbuf_set(&clone->content, node->content.ptr, node->content.size);
167
+ clone->start_line = node->start_line;
168
+ clone->start_column = node->start_column;
169
+ clone->end_line = node->end_line;
170
+ clone->end_column = node->end_column;
171
+ clone->internal_offset = node->internal_offset;
172
+ clone->flags = node->flags;
173
+ clone->footnote = node->footnote;
174
+
175
+ switch (node->type) {
176
+ case CMARK_NODE_HEADING:
177
+ clone->as.heading = node->as.heading;
178
+ break;
179
+ case CMARK_NODE_LIST:
180
+ case CMARK_NODE_ITEM:
181
+ clone->as.list = node->as.list;
182
+ break;
183
+ case CMARK_NODE_CODE_BLOCK:
184
+ case CMARK_NODE_FRONT_MATTER:
185
+ case CMARK_NODE_CODE:
186
+ clone->as.code = node->as.code;
187
+ clone->as.code.info = S_clone_chunk(mem, &node->as.code.info);
188
+ clone->as.code.literal = S_clone_chunk(mem, &node->as.code.literal);
189
+ break;
190
+ case CMARK_NODE_TEXT:
191
+ case CMARK_NODE_HTML_INLINE:
192
+ case CMARK_NODE_HTML_BLOCK:
193
+ case CMARK_NODE_FOOTNOTE_REFERENCE:
194
+ case CMARK_NODE_FOOTNOTE_DEFINITION:
195
+ clone->as.literal = S_clone_chunk(mem, &node->as.literal);
196
+ break;
197
+ case CMARK_NODE_LINK:
198
+ case CMARK_NODE_IMAGE:
199
+ clone->as.link.url = S_clone_chunk(mem, &node->as.link.url);
200
+ clone->as.link.title = S_clone_chunk(mem, &node->as.link.title);
201
+ break;
202
+ case CMARK_NODE_CUSTOM_BLOCK:
203
+ case CMARK_NODE_CUSTOM_INLINE:
204
+ clone->as.custom.on_enter = S_clone_chunk(mem, &node->as.custom.on_enter);
205
+ clone->as.custom.on_exit = S_clone_chunk(mem, &node->as.custom.on_exit);
206
+ break;
207
+ default:
208
+ break;
209
+ }
210
+
211
+ if (node->extension && node->extension->opaque_alloc_func) {
212
+ if (!node->extension->opaque_copy_func) {
213
+ cmark_node_free(clone);
214
+ return NULL;
215
+ }
216
+
217
+ node->extension->opaque_copy_func(node->extension, mem, clone, node);
218
+ }
219
+
220
+ for (cmark_node *child = node->first_child; child; child = child->next) {
221
+ cmark_node *child_clone = S_clone_node(child);
222
+ if (!child_clone) {
223
+ cmark_node_free(clone);
224
+ return NULL;
225
+ }
226
+
227
+ if (!cmark_node_append_child(clone, child_clone)) {
228
+ cmark_node_free(child_clone);
229
+ cmark_node_free(clone);
230
+ return NULL;
231
+ }
232
+ }
233
+
234
+ return clone;
235
+ }
236
+
237
+ static cmark_node *S_find_clone(cmark_node *source, cmark_node *clone,
238
+ cmark_node *target) {
239
+ if (source == target) {
240
+ return clone;
241
+ }
242
+
243
+ cmark_node *source_child = source->first_child;
244
+ cmark_node *clone_child = clone->first_child;
245
+ while (source_child && clone_child) {
246
+ cmark_node *result = S_find_clone(source_child, clone_child, target);
247
+ if (result) {
248
+ return result;
249
+ }
250
+ source_child = source_child->next;
251
+ clone_child = clone_child->next;
252
+ }
253
+
254
+ return NULL;
255
+ }
256
+
257
+ static void S_clone_footnote_links(cmark_node *source, cmark_node *clone,
258
+ cmark_node *source_root,
259
+ cmark_node *clone_root) {
260
+ if (source->parent_footnote_def) {
261
+ clone->parent_footnote_def =
262
+ S_find_clone(source_root, clone_root, source->parent_footnote_def);
263
+ }
264
+
265
+ cmark_node *source_child = source->first_child;
266
+ cmark_node *clone_child = clone->first_child;
267
+ while (source_child && clone_child) {
268
+ S_clone_footnote_links(source_child, clone_child, source_root, clone_root);
269
+ source_child = source_child->next;
270
+ clone_child = clone_child->next;
271
+ }
272
+ }
273
+
274
+ cmark_node *cmark_node_clone(cmark_node *node) {
275
+ if (!node) {
276
+ return NULL;
277
+ }
278
+
279
+ cmark_node *clone = S_clone_node(node);
280
+ if (clone) {
281
+ S_clone_footnote_links(node, clone, node, clone);
282
+ }
283
+ return clone;
284
+ }
285
+
148
286
  static void free_node_as(cmark_node *node) {
149
287
  switch (node->type) {
150
288
  case CMARK_NODE_CODE_BLOCK:
@@ -143,6 +143,11 @@ void cmark_syntax_extension_set_opaque_free_func(cmark_syntax_extension *extensi
143
143
  extension->opaque_free_func = func;
144
144
  }
145
145
 
146
+ void cmark_syntax_extension_set_opaque_copy_func(
147
+ cmark_syntax_extension *extension, cmark_opaque_copy_func func) {
148
+ extension->opaque_copy_func = func;
149
+ }
150
+
146
151
  void cmark_syntax_extension_set_commonmark_escape_func(cmark_syntax_extension *extension,
147
152
  cmark_commonmark_escape_func func) {
148
153
  extension->commonmark_escape_func = func;
@@ -28,6 +28,7 @@ struct cmark_syntax_extension {
28
28
  cmark_postprocess_func postprocess_func;
29
29
  cmark_opaque_alloc_func opaque_alloc_func;
30
30
  cmark_opaque_free_func opaque_free_func;
31
+ cmark_opaque_copy_func opaque_copy_func;
31
32
  cmark_commonmark_escape_func commonmark_escape_func;
32
33
  };
33
34
 
data/lib/markly/node.rb CHANGED
@@ -20,15 +20,7 @@ module Markly
20
20
  #
21
21
  # @returns [Markly::Node] The duplicated node tree.
22
22
  def dup
23
- # This is a bit crazy, but it's the best I can come up with right now:
24
- node = Markly.parse(self.to_markdown)
25
-
26
- # If we aren't duplicating a document, we return `first_child` as the root will be a document node:
27
- if self.type == :document
28
- return node
29
- else
30
- return node.first_child
31
- end
23
+ _dup
32
24
  end
33
25
 
34
26
  # Walk the node tree recursively.
@@ -9,5 +9,5 @@
9
9
  # @namespace
10
10
  module Markly
11
11
  # @constant [String] The version of the Markly gem.
12
- VERSION = "0.17.0"
12
+ VERSION = "0.18.0"
13
13
  end
data/readme.md CHANGED
@@ -24,6 +24,10 @@ Please see the [project documentation](https://socketry.github.io/markly/) for m
24
24
 
25
25
  Please see the [project releases](https://socketry.github.io/markly/releases/index) for all releases.
26
26
 
27
+ ### v0.18.0
28
+
29
+ - Preserve complete node and extension metadata when duplicating node trees.
30
+
27
31
  ### v0.17.0
28
32
 
29
33
  - Add opt-in language prefixes for inline code spans with `Markly::INLINE_CODE_INFO`, expose code metadata through `Node#code_info`, and provide `Node#code_language` as a convenient language accessor.
data/releases.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Releases
2
2
 
3
+ ## v0.18.0
4
+
5
+ - Preserve complete node and extension metadata when duplicating node trees.
6
+
3
7
  ## v0.17.0
4
8
 
5
9
  - Add opt-in language prefixes for inline code spans with `Markly::INLINE_CODE_INFO`, expose code metadata through `Node#code_info`, and provide `Node#code_language` as a convenient language accessor.
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: markly
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen Torikian
metadata.gz.sig CHANGED
Binary file