markly 0.6.1 → 0.8.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 (52) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/conduct.md +133 -0
  4. data/ext/markly/arena.c +9 -8
  5. data/ext/markly/autolink.c +217 -134
  6. data/ext/markly/blocks.c +40 -4
  7. data/ext/markly/cmark-gfm-core-extensions.h +11 -11
  8. data/ext/markly/cmark-gfm-extension_api.h +1 -0
  9. data/ext/markly/cmark-gfm.h +18 -2
  10. data/ext/markly/cmark-gfm_version.h +2 -2
  11. data/ext/markly/cmark.c +3 -3
  12. data/ext/markly/commonmark.c +33 -38
  13. data/ext/markly/ext_scanners.c +360 -640
  14. data/ext/markly/extconf.rb +8 -1
  15. data/ext/markly/footnotes.c +23 -0
  16. data/ext/markly/footnotes.h +2 -0
  17. data/ext/markly/html.c +60 -23
  18. data/ext/markly/inlines.c +216 -61
  19. data/ext/markly/latex.c +6 -4
  20. data/ext/markly/man.c +7 -11
  21. data/ext/markly/map.c +11 -4
  22. data/ext/markly/map.h +5 -2
  23. data/ext/markly/markly.c +582 -586
  24. data/ext/markly/markly.h +1 -1
  25. data/ext/markly/node.c +76 -10
  26. data/ext/markly/node.h +49 -1
  27. data/ext/markly/parser.h +1 -0
  28. data/ext/markly/plaintext.c +12 -29
  29. data/ext/markly/references.c +1 -0
  30. data/ext/markly/render.c +15 -7
  31. data/ext/markly/scanners.c +13916 -20242
  32. data/ext/markly/scanners.h +8 -0
  33. data/ext/markly/scanners.re +47 -8
  34. data/ext/markly/strikethrough.c +1 -1
  35. data/ext/markly/table.c +143 -74
  36. data/ext/markly/xml.c +2 -1
  37. data/lib/markly/flags.rb +16 -0
  38. data/lib/markly/node/inspect.rb +59 -53
  39. data/lib/markly/node.rb +125 -58
  40. data/lib/markly/renderer/generic.rb +136 -0
  41. data/lib/markly/renderer/html.rb +301 -0
  42. data/lib/markly/version.rb +7 -1
  43. data/lib/markly.rb +38 -32
  44. data/license.md +39 -0
  45. data/readme.md +36 -0
  46. data.tar.gz.sig +0 -0
  47. metadata +63 -31
  48. metadata.gz.sig +0 -0
  49. data/bin/markly +0 -94
  50. data/lib/markly/markly.so +0 -0
  51. data/lib/markly/renderer/html_renderer.rb +0 -281
  52. data/lib/markly/renderer.rb +0 -133
data/ext/markly/markly.h CHANGED
@@ -11,6 +11,6 @@
11
11
 
12
12
  #define CSTR2SYM(s) (ID2SYM(rb_intern((s))))
13
13
 
14
- void Init_markly();
14
+ void Init_markly(void);
15
15
 
16
16
  #endif
data/ext/markly/node.c CHANGED
@@ -5,10 +5,42 @@
5
5
  #include "node.h"
6
6
  #include "syntax_extension.h"
7
7
 
8
+ /**
9
+ * Expensive safety checks are off by default, but can be enabled
10
+ * by calling cmark_enable_safety_checks().
11
+ */
12
+ static bool enable_safety_checks = false;
13
+
14
+ void cmark_enable_safety_checks(bool enable) {
15
+ enable_safety_checks = enable;
16
+ }
17
+
8
18
  static void S_node_unlink(cmark_node *node);
9
19
 
10
20
  #define NODE_MEM(node) cmark_node_mem(node)
11
21
 
22
+ void cmark_register_node_flag(cmark_node_internal_flags *flags) {
23
+ static cmark_node_internal_flags nextflag = CMARK_NODE__REGISTER_FIRST;
24
+
25
+ // flags should be a pointer to a global variable and this function
26
+ // should only be called once to initialize its value.
27
+ if (*flags) {
28
+ fprintf(stderr, "flag initialization error in cmark_register_node_flag\n");
29
+ abort();
30
+ }
31
+
32
+ // Check that we haven't run out of bits.
33
+ if (nextflag == 0) {
34
+ fprintf(stderr, "too many flags in cmark_register_node_flag\n");
35
+ abort();
36
+ }
37
+
38
+ *flags = nextflag;
39
+ nextflag <<= 1;
40
+ }
41
+
42
+ void cmark_init_standard_node_flags(void) {}
43
+
12
44
  bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type) {
13
45
  if (child_type == CMARK_NODE_DOCUMENT) {
14
46
  return false;
@@ -48,8 +80,6 @@ bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type) {
48
80
  }
49
81
 
50
82
  static bool S_can_contain(cmark_node *node, cmark_node *child) {
51
- cmark_node *cur;
52
-
53
83
  if (node == NULL || child == NULL) {
54
84
  return false;
55
85
  }
@@ -57,14 +87,16 @@ static bool S_can_contain(cmark_node *node, cmark_node *child) {
57
87
  return 0;
58
88
  }
59
89
 
60
- // Verify that child is not an ancestor of node or equal to node.
61
- cur = node;
62
- do {
63
- if (cur == child) {
64
- return false;
65
- }
66
- cur = cur->parent;
67
- } while (cur != NULL);
90
+ if (enable_safety_checks) {
91
+ // Verify that child is not an ancestor of node or equal to node.
92
+ cmark_node *cur = node;
93
+ do {
94
+ if (cur == child) {
95
+ return false;
96
+ }
97
+ cur = cur->parent;
98
+ } while (cur != NULL);
99
+ }
68
100
 
69
101
  return cmark_node_can_contain_type(node, (cmark_node_type) child->type);
70
102
  }
@@ -301,6 +333,14 @@ cmark_node *cmark_node_last_child(cmark_node *node) {
301
333
  }
302
334
  }
303
335
 
336
+ cmark_node *cmark_node_parent_footnote_def(cmark_node *node) {
337
+ if (node == NULL) {
338
+ return NULL;
339
+ } else {
340
+ return node->parent_footnote_def;
341
+ }
342
+ }
343
+
304
344
  void *cmark_node_get_user_data(cmark_node *node) {
305
345
  if (node == NULL) {
306
346
  return NULL;
@@ -337,6 +377,7 @@ const char *cmark_node_get_literal(cmark_node *node) {
337
377
  case CMARK_NODE_HTML_INLINE:
338
378
  case CMARK_NODE_CODE:
339
379
  case CMARK_NODE_FOOTNOTE_REFERENCE:
380
+ case CMARK_NODE_FOOTNOTE_DEFINITION:
340
381
  return cmark_chunk_to_cstr(NODE_MEM(node), &node->as.literal);
341
382
 
342
383
  case CMARK_NODE_CODE_BLOCK:
@@ -524,6 +565,31 @@ int cmark_node_set_list_tight(cmark_node *node, int tight) {
524
565
  }
525
566
  }
526
567
 
568
+ int cmark_node_get_item_index(cmark_node *node) {
569
+ if (node == NULL) {
570
+ return 0;
571
+ }
572
+
573
+ if (node->type == CMARK_NODE_ITEM) {
574
+ return node->as.list.start;
575
+ } else {
576
+ return 0;
577
+ }
578
+ }
579
+
580
+ int cmark_node_set_item_index(cmark_node *node, int idx) {
581
+ if (node == NULL || idx < 0) {
582
+ return 0;
583
+ }
584
+
585
+ if (node->type == CMARK_NODE_ITEM) {
586
+ node->as.list.start = idx;
587
+ return 1;
588
+ } else {
589
+ return 0;
590
+ }
591
+ }
592
+
527
593
  const char *cmark_node_get_fence_info(cmark_node *node) {
528
594
  if (node == NULL) {
529
595
  return NULL;
data/ext/markly/node.h CHANGED
@@ -52,8 +52,14 @@ enum cmark_node__internal_flags {
52
52
  CMARK_NODE__OPEN = (1 << 0),
53
53
  CMARK_NODE__LAST_LINE_BLANK = (1 << 1),
54
54
  CMARK_NODE__LAST_LINE_CHECKED = (1 << 2),
55
+
56
+ // Extensions can register custom flags by calling `cmark_register_node_flag`.
57
+ // This is the starting value for the custom flags.
58
+ CMARK_NODE__REGISTER_FIRST = (1 << 3),
55
59
  };
56
60
 
61
+ typedef uint16_t cmark_node_internal_flags;
62
+
57
63
  struct cmark_node {
58
64
  cmark_strbuf content;
59
65
 
@@ -72,10 +78,25 @@ struct cmark_node {
72
78
  int end_column;
73
79
  int internal_offset;
74
80
  uint16_t type;
75
- uint16_t flags;
81
+ cmark_node_internal_flags flags;
76
82
 
77
83
  cmark_syntax_extension *extension;
78
84
 
85
+ /**
86
+ * Used during cmark_render() to cache the most recent non-NULL
87
+ * extension, if you go up the parent chain like this:
88
+ *
89
+ * node->parent->...parent->extension
90
+ */
91
+ cmark_syntax_extension *ancestor_extension;
92
+
93
+ union {
94
+ int ref_ix;
95
+ int def_count;
96
+ } footnote;
97
+
98
+ cmark_node *parent_footnote_def;
99
+
79
100
  union {
80
101
  cmark_chunk literal;
81
102
  cmark_list list;
@@ -88,6 +109,26 @@ struct cmark_node {
88
109
  } as;
89
110
  };
90
111
 
112
+ /**
113
+ * Syntax extensions can use this function to register a custom node
114
+ * flag. The flags are stored in the `flags` field of the `cmark_node`
115
+ * struct. The `flags` parameter should be the address of a global variable
116
+ * which will store the flag value.
117
+ */
118
+ CMARK_GFM_EXPORT
119
+ void cmark_register_node_flag(cmark_node_internal_flags *flags);
120
+
121
+ /**
122
+ * DEPRECATED.
123
+ *
124
+ * This function was added in cmark-gfm version 0.29.0.gfm.7, and was
125
+ * required to be called at program start time, which caused
126
+ * backwards-compatibility issues in applications that use cmark-gfm as a
127
+ * library. It is now a no-op.
128
+ */
129
+ CMARK_GFM_EXPORT
130
+ void cmark_init_standard_node_flags(void);
131
+
91
132
  static CMARK_INLINE cmark_mem *cmark_node_mem(cmark_node *node) {
92
133
  return node->content.mem;
93
134
  }
@@ -111,6 +152,13 @@ static CMARK_INLINE bool CMARK_NODE_INLINE_P(cmark_node *node) {
111
152
 
112
153
  CMARK_GFM_EXPORT bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type);
113
154
 
155
+ /**
156
+ * Enable (or disable) extra safety checks. These extra checks cause
157
+ * extra performance overhead (in some cases quadratic), so they are only
158
+ * intended to be used during testing.
159
+ */
160
+ CMARK_GFM_EXPORT void cmark_enable_safety_checks(bool enable);
161
+
114
162
  #ifdef __cplusplus
115
163
  }
116
164
  #endif
data/ext/markly/parser.h CHANGED
@@ -46,6 +46,7 @@ struct cmark_parser {
46
46
  /* Options set by the user, see the Options section in cmark.h */
47
47
  int options;
48
48
  bool last_buffer_ended_with_cr;
49
+ size_t total_size;
49
50
  cmark_llist *syntax_extensions;
50
51
  cmark_llist *inline_syntax_extensions;
51
52
  cmark_ispunct_func backslash_ispunct;
@@ -16,23 +16,8 @@ static CMARK_INLINE void outc(cmark_renderer *renderer, cmark_node *node,
16
16
  cmark_render_code_point(renderer, c);
17
17
  }
18
18
 
19
- // if node is a block node, returns node.
20
- // otherwise returns first block-level node that is an ancestor of node.
21
- // if there is no block-level ancestor, returns NULL.
22
- static cmark_node *get_containing_block(cmark_node *node) {
23
- while (node) {
24
- if (CMARK_NODE_BLOCK_P(node)) {
25
- return node;
26
- } else {
27
- node = node->parent;
28
- }
29
- }
30
- return NULL;
31
- }
32
-
33
19
  static int S_render_node(cmark_renderer *renderer, cmark_node *node,
34
20
  cmark_event_type ev_type, int options) {
35
- cmark_node *tmp;
36
21
  int list_number;
37
22
  cmark_delim_type list_delim;
38
23
  int i;
@@ -46,14 +31,17 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
46
31
  // Don't adjust tight list status til we've started the list.
47
32
  // Otherwise we loose the blank line between a paragraph and
48
33
  // a following list.
49
- if (!(node->type == CMARK_NODE_ITEM && node->prev == NULL && entering)) {
50
- tmp = get_containing_block(node);
51
- renderer->in_tight_list_item =
52
- tmp && // tmp might be NULL if there is no containing block
53
- ((tmp->type == CMARK_NODE_ITEM &&
54
- cmark_node_get_list_tight(tmp->parent)) ||
55
- (tmp && tmp->parent && tmp->parent->type == CMARK_NODE_ITEM &&
56
- cmark_node_get_list_tight(tmp->parent->parent)));
34
+ if (entering) {
35
+ if (node->parent && node->parent->type == CMARK_NODE_ITEM) {
36
+ renderer->in_tight_list_item = node->parent->parent->as.list.tight;
37
+ }
38
+ } else {
39
+ if (node->type == CMARK_NODE_LIST) {
40
+ renderer->in_tight_list_item =
41
+ node->parent &&
42
+ node->parent->type == CMARK_NODE_ITEM &&
43
+ node->parent->parent->as.list.tight;
44
+ }
57
45
  }
58
46
 
59
47
  if (node->extension && node->extension->plaintext_render_func) {
@@ -79,13 +67,8 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
79
67
  if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
80
68
  marker_width = 4;
81
69
  } else {
82
- list_number = cmark_node_get_list_start(node->parent);
70
+ list_number = cmark_node_get_item_index(node);
83
71
  list_delim = cmark_node_get_list_delim(node->parent);
84
- tmp = node;
85
- while (tmp->prev) {
86
- tmp = tmp->prev;
87
- list_number += 1;
88
- }
89
72
  // we ensure a width of at least 4 so
90
73
  // we get nice transition from single digits
91
74
  // to double
@@ -32,6 +32,7 @@ void cmark_reference_create(cmark_map *map, cmark_chunk *label,
32
32
  ref->title = cmark_clean_title(map->mem, title);
33
33
  ref->entry.age = map->size;
34
34
  ref->entry.next = map->refs;
35
+ ref->entry.size = ref->url.len + ref->title.len;
35
36
 
36
37
  map->refs = (cmark_map_entry *)ref;
37
38
  map->size++;
data/ext/markly/render.c CHANGED
@@ -31,13 +31,7 @@ static void S_out(cmark_renderer *renderer, cmark_node *node,
31
31
  cmark_chunk remainder = cmark_chunk_literal("");
32
32
  int k = renderer->buffer->size - 1;
33
33
 
34
- cmark_syntax_extension *ext = NULL;
35
- cmark_node *n = node;
36
- while (n && !ext) {
37
- ext = n->extension;
38
- if (!ext)
39
- n = n->parent;
40
- }
34
+ cmark_syntax_extension *ext = node->ancestor_extension;
41
35
  if (ext && !ext->commonmark_escape_func)
42
36
  ext = NULL;
43
37
 
@@ -182,6 +176,20 @@ char *cmark_render(cmark_mem *mem, cmark_node *root, int options, int width,
182
176
 
183
177
  while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
184
178
  cur = cmark_iter_get_node(iter);
179
+ if (cur->extension) {
180
+ cur->ancestor_extension = cur->extension;
181
+ } else if (cur->parent) {
182
+ cur->ancestor_extension = cur->parent->ancestor_extension;
183
+ }
184
+ if (cur->type == CMARK_NODE_ITEM) {
185
+ // Calculate the list item's index, for the benefit of output formats
186
+ // like commonmark and plaintext.
187
+ if (cur->prev) {
188
+ cmark_node_set_item_index(cur, 1 + cmark_node_get_item_index(cur->prev));
189
+ } else {
190
+ cmark_node_set_item_index(cur, cmark_node_get_list_start(cur->parent));
191
+ }
192
+ }
185
193
  if (!render_node(&renderer, cur, ev_type, options)) {
186
194
  // a false value causes us to skip processing
187
195
  // the node's contents. this is used for