markly 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/conduct.md +133 -0
- data/ext/markly/arena.c +9 -8
- data/ext/markly/autolink.c +217 -134
- data/ext/markly/blocks.c +27 -2
- data/ext/markly/cmark-gfm-core-extensions.h +11 -11
- data/ext/markly/cmark-gfm-extension_api.h +1 -0
- data/ext/markly/cmark-gfm.h +18 -2
- data/ext/markly/cmark.c +3 -3
- data/ext/markly/commonmark.c +19 -34
- data/ext/markly/extconf.rb +8 -1
- data/ext/markly/html.c +22 -6
- data/ext/markly/inlines.c +148 -51
- data/ext/markly/latex.c +6 -4
- data/ext/markly/man.c +7 -11
- data/ext/markly/map.c +11 -4
- data/ext/markly/map.h +5 -2
- data/ext/markly/markly.c +582 -586
- data/ext/markly/markly.h +1 -1
- data/ext/markly/node.c +76 -10
- data/ext/markly/node.h +42 -1
- data/ext/markly/parser.h +1 -0
- data/ext/markly/plaintext.c +12 -29
- data/ext/markly/references.c +1 -0
- data/ext/markly/render.c +15 -7
- data/ext/markly/scanners.c +13916 -10380
- data/ext/markly/scanners.h +8 -0
- data/ext/markly/scanners.re +47 -8
- data/ext/markly/strikethrough.c +1 -1
- data/ext/markly/table.c +81 -31
- data/ext/markly/xml.c +2 -1
- data/lib/markly/flags.rb +16 -0
- data/lib/markly/node/inspect.rb +59 -53
- data/lib/markly/node.rb +125 -58
- data/lib/markly/renderer/generic.rb +129 -124
- data/lib/markly/renderer/html.rb +294 -275
- data/lib/markly/version.rb +7 -1
- data/lib/markly.rb +36 -30
- data/license.md +39 -0
- data/readme.md +36 -0
- data.tar.gz.sig +0 -0
- metadata +61 -29
- metadata.gz.sig +0 -0
- data/bin/markly +0 -94
- data/lib/markly/markly.bundle +0 -0
data/ext/markly/markly.h
CHANGED
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
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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,18 @@ struct cmark_node {
|
|
72
78
|
int end_column;
|
73
79
|
int internal_offset;
|
74
80
|
uint16_t type;
|
75
|
-
|
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
|
+
|
79
93
|
union {
|
80
94
|
int ref_ix;
|
81
95
|
int def_count;
|
@@ -95,6 +109,26 @@ struct cmark_node {
|
|
95
109
|
} as;
|
96
110
|
};
|
97
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
|
+
|
98
132
|
static CMARK_INLINE cmark_mem *cmark_node_mem(cmark_node *node) {
|
99
133
|
return node->content.mem;
|
100
134
|
}
|
@@ -118,6 +152,13 @@ static CMARK_INLINE bool CMARK_NODE_INLINE_P(cmark_node *node) {
|
|
118
152
|
|
119
153
|
CMARK_GFM_EXPORT bool cmark_node_can_contain_type(cmark_node *node, cmark_node_type child_type);
|
120
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
|
+
|
121
162
|
#ifdef __cplusplus
|
122
163
|
}
|
123
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;
|
data/ext/markly/plaintext.c
CHANGED
@@ -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 (
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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 =
|
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
|
data/ext/markly/references.c
CHANGED
@@ -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 =
|
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
|