markly 0.7.0 → 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.
- 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/blocks.c
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
#include <stdlib.h>
|
9
9
|
#include <assert.h>
|
10
10
|
#include <stdio.h>
|
11
|
+
#include <limits.h>
|
11
12
|
|
12
13
|
#include "cmark_ctype.h"
|
13
14
|
#include "syntax_extension.h"
|
@@ -26,6 +27,14 @@
|
|
26
27
|
#define CODE_INDENT 4
|
27
28
|
#define TAB_STOP 4
|
28
29
|
|
30
|
+
/**
|
31
|
+
* Very deeply nested lists can cause quadratic performance issues.
|
32
|
+
* This constant is used in open_new_blocks() to limit the nesting
|
33
|
+
* depth. It is unlikely that a non-contrived markdown document will
|
34
|
+
* be nested this deeply.
|
35
|
+
*/
|
36
|
+
#define MAX_LIST_DEPTH 100
|
37
|
+
|
29
38
|
#ifndef MIN
|
30
39
|
#define MIN(x, y) ((x < y) ? x : y)
|
31
40
|
#endif
|
@@ -639,6 +648,14 @@ static cmark_node *finalize_document(cmark_parser *parser) {
|
|
639
648
|
}
|
640
649
|
|
641
650
|
finalize(parser, parser->root);
|
651
|
+
|
652
|
+
// Limit total size of extra content created from reference links to
|
653
|
+
// document size to avoid superlinear growth. Always allow 100KB.
|
654
|
+
if (parser->total_size > 100000)
|
655
|
+
parser->refmap->max_ref_size = parser->total_size;
|
656
|
+
else
|
657
|
+
parser->refmap->max_ref_size = 100000;
|
658
|
+
|
642
659
|
process_inlines(parser, parser->refmap, parser->options);
|
643
660
|
if (parser->options & CMARK_OPT_FOOTNOTES)
|
644
661
|
process_footnotes(parser);
|
@@ -698,6 +715,11 @@ static void S_parser_feed(cmark_parser *parser, const unsigned char *buffer,
|
|
698
715
|
const unsigned char *end = buffer + len;
|
699
716
|
static const uint8_t repl[] = {239, 191, 189};
|
700
717
|
|
718
|
+
if (len > UINT_MAX - parser->total_size)
|
719
|
+
parser->total_size = UINT_MAX;
|
720
|
+
else
|
721
|
+
parser->total_size += len;
|
722
|
+
|
701
723
|
if (parser->last_buffer_ended_with_cr && *buffer == '\n') {
|
702
724
|
// skip NL if last buffer ended with CR ; see #117
|
703
725
|
buffer++;
|
@@ -1105,10 +1127,11 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
|
|
1105
1127
|
bool has_content;
|
1106
1128
|
int save_offset;
|
1107
1129
|
int save_column;
|
1130
|
+
size_t depth = 0;
|
1108
1131
|
|
1109
1132
|
while (cont_type != CMARK_NODE_CODE_BLOCK &&
|
1110
1133
|
cont_type != CMARK_NODE_HTML_BLOCK) {
|
1111
|
-
|
1134
|
+
depth++;
|
1112
1135
|
S_find_first_nonspace(parser, input);
|
1113
1136
|
indented = parser->indent >= CODE_INDENT;
|
1114
1137
|
|
@@ -1197,12 +1220,13 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
|
|
1197
1220
|
parser->options & CMARK_OPT_FOOTNOTES &&
|
1198
1221
|
(matched = scan_footnote_definition(input, parser->first_nonspace))) {
|
1199
1222
|
cmark_chunk c = cmark_chunk_dup(input, parser->first_nonspace + 2, matched - 2);
|
1200
|
-
cmark_chunk_to_cstr(parser->mem, &c);
|
1201
1223
|
|
1202
1224
|
while (c.data[c.len - 1] != ']')
|
1203
1225
|
--c.len;
|
1204
1226
|
--c.len;
|
1205
1227
|
|
1228
|
+
cmark_chunk_to_cstr(parser->mem, &c);
|
1229
|
+
|
1206
1230
|
S_advance_offset(parser, input, parser->first_nonspace + matched - parser->offset, false);
|
1207
1231
|
*container = add_child(parser, *container, CMARK_NODE_FOOTNOTE_DEFINITION, parser->first_nonspace + matched + 1);
|
1208
1232
|
(*container)->as.literal = c;
|
@@ -1210,6 +1234,7 @@ static void open_new_blocks(cmark_parser *parser, cmark_node **container,
|
|
1210
1234
|
(*container)->internal_offset = matched;
|
1211
1235
|
} else if ((!indented || cont_type == CMARK_NODE_LIST) &&
|
1212
1236
|
parser->indent < 4 &&
|
1237
|
+
depth < MAX_LIST_DEPTH &&
|
1213
1238
|
(matched = parse_list_marker(
|
1214
1239
|
parser->mem, input, parser->first_nonspace,
|
1215
1240
|
(*container)->type == CMARK_NODE_PARAGRAPH, &data))) {
|
@@ -6,45 +6,45 @@ extern "C" {
|
|
6
6
|
#endif
|
7
7
|
|
8
8
|
#include "cmark-gfm-extension_api.h"
|
9
|
-
#include "cmark-
|
10
|
-
#include
|
9
|
+
#include "cmark-gfm_export.h"
|
10
|
+
#include <stdbool.h>
|
11
11
|
#include <stdint.h>
|
12
12
|
|
13
|
-
|
13
|
+
CMARK_GFM_EXPORT
|
14
14
|
void cmark_gfm_core_extensions_ensure_registered(void);
|
15
15
|
|
16
|
-
|
16
|
+
CMARK_GFM_EXPORT
|
17
17
|
uint16_t cmark_gfm_extensions_get_table_columns(cmark_node *node);
|
18
18
|
|
19
19
|
/** Sets the number of columns for the table, returning 1 on success and 0 on error.
|
20
20
|
*/
|
21
|
-
|
21
|
+
CMARK_GFM_EXPORT
|
22
22
|
int cmark_gfm_extensions_set_table_columns(cmark_node *node, uint16_t n_columns);
|
23
23
|
|
24
|
-
|
24
|
+
CMARK_GFM_EXPORT
|
25
25
|
uint8_t *cmark_gfm_extensions_get_table_alignments(cmark_node *node);
|
26
26
|
|
27
27
|
/** Sets the alignments for the table, returning 1 on success and 0 on error.
|
28
28
|
*/
|
29
|
-
|
29
|
+
CMARK_GFM_EXPORT
|
30
30
|
int cmark_gfm_extensions_set_table_alignments(cmark_node *node, uint16_t ncols, uint8_t *alignments);
|
31
31
|
|
32
|
-
|
32
|
+
CMARK_GFM_EXPORT
|
33
33
|
int cmark_gfm_extensions_get_table_row_is_header(cmark_node *node);
|
34
34
|
|
35
35
|
/** Sets whether the node is a table header row, returning 1 on success and 0 on error.
|
36
36
|
*/
|
37
|
-
|
37
|
+
CMARK_GFM_EXPORT
|
38
38
|
int cmark_gfm_extensions_set_table_row_is_header(cmark_node *node, int is_header);
|
39
39
|
|
40
|
-
|
40
|
+
CMARK_GFM_EXPORT
|
41
41
|
bool cmark_gfm_extensions_get_tasklist_item_checked(cmark_node *node);
|
42
42
|
/* For backwards compatibility */
|
43
43
|
#define cmark_gfm_extensions_tasklist_is_checked cmark_gfm_extensions_get_tasklist_item_checked
|
44
44
|
|
45
45
|
/** Sets whether a tasklist item is "checked" (completed), returning 1 on success and 0 on error.
|
46
46
|
*/
|
47
|
-
|
47
|
+
CMARK_GFM_EXPORT
|
48
48
|
int cmark_gfm_extensions_set_tasklist_item_checked(cmark_node *node, bool is_checked);
|
49
49
|
|
50
50
|
#ifdef __cplusplus
|
data/ext/markly/cmark-gfm.h
CHANGED
@@ -111,13 +111,13 @@ typedef struct cmark_mem {
|
|
111
111
|
* realloc and free.
|
112
112
|
*/
|
113
113
|
CMARK_GFM_EXPORT
|
114
|
-
cmark_mem *cmark_get_default_mem_allocator();
|
114
|
+
cmark_mem *cmark_get_default_mem_allocator(void);
|
115
115
|
|
116
116
|
/** An arena allocator; uses system calloc to allocate large
|
117
117
|
* slabs of memory. Memory in these slabs is not reused at all.
|
118
118
|
*/
|
119
119
|
CMARK_GFM_EXPORT
|
120
|
-
cmark_mem *cmark_get_arena_mem_allocator();
|
120
|
+
cmark_mem *cmark_get_arena_mem_allocator(void);
|
121
121
|
|
122
122
|
/** Resets the arena allocator, quickly returning all used memory
|
123
123
|
* to the operating system.
|
@@ -225,6 +225,11 @@ CMARK_GFM_EXPORT cmark_node *cmark_node_first_child(cmark_node *node);
|
|
225
225
|
*/
|
226
226
|
CMARK_GFM_EXPORT cmark_node *cmark_node_last_child(cmark_node *node);
|
227
227
|
|
228
|
+
/** Returns the footnote reference of 'node', or NULL if 'node' doesn't have a
|
229
|
+
* footnote reference.
|
230
|
+
*/
|
231
|
+
CMARK_GFM_EXPORT cmark_node *cmark_node_parent_footnote_def(cmark_node *node);
|
232
|
+
|
228
233
|
/**
|
229
234
|
* ## Iterator
|
230
235
|
*
|
@@ -408,6 +413,17 @@ CMARK_GFM_EXPORT int cmark_node_get_list_tight(cmark_node *node);
|
|
408
413
|
*/
|
409
414
|
CMARK_GFM_EXPORT int cmark_node_set_list_tight(cmark_node *node, int tight);
|
410
415
|
|
416
|
+
/**
|
417
|
+
* Returns item index of 'node'. This is only used when rendering output
|
418
|
+
* formats such as commonmark, which need to output the index. It is not
|
419
|
+
* required for formats such as html or latex.
|
420
|
+
*/
|
421
|
+
CMARK_GFM_EXPORT int cmark_node_get_item_index(cmark_node *node);
|
422
|
+
|
423
|
+
/** Sets item index of 'node'. Returns 1 on success, 0 on failure.
|
424
|
+
*/
|
425
|
+
CMARK_GFM_EXPORT int cmark_node_set_item_index(cmark_node *node, int idx);
|
426
|
+
|
411
427
|
/** Returns the info string from a fenced code block.
|
412
428
|
*/
|
413
429
|
CMARK_GFM_EXPORT const char *cmark_node_get_fence_info(cmark_node *node);
|
data/ext/markly/cmark.c
CHANGED
@@ -10,9 +10,9 @@
|
|
10
10
|
cmark_node_type CMARK_NODE_LAST_BLOCK = CMARK_NODE_FOOTNOTE_DEFINITION;
|
11
11
|
cmark_node_type CMARK_NODE_LAST_INLINE = CMARK_NODE_FOOTNOTE_REFERENCE;
|
12
12
|
|
13
|
-
int cmark_version() { return CMARK_GFM_VERSION; }
|
13
|
+
int cmark_version(void) { return CMARK_GFM_VERSION; }
|
14
14
|
|
15
|
-
const char *cmark_version_string() { return CMARK_GFM_VERSION_STRING; }
|
15
|
+
const char *cmark_version_string(void) { return CMARK_GFM_VERSION_STRING; }
|
16
16
|
|
17
17
|
static void *xcalloc(size_t nmem, size_t size) {
|
18
18
|
void *ptr = calloc(nmem, size);
|
@@ -38,7 +38,7 @@ static void xfree(void *ptr) {
|
|
38
38
|
|
39
39
|
cmark_mem CMARK_DEFAULT_MEM_ALLOCATOR = {xcalloc, xrealloc, xfree};
|
40
40
|
|
41
|
-
cmark_mem *cmark_get_default_mem_allocator() {
|
41
|
+
cmark_mem *cmark_get_default_mem_allocator(void) {
|
42
42
|
return &CMARK_DEFAULT_MEM_ALLOCATOR;
|
43
43
|
}
|
44
44
|
|
data/ext/markly/commonmark.c
CHANGED
@@ -153,23 +153,8 @@ static bool is_autolink(cmark_node *node) {
|
|
153
153
|
link_text->as.literal.len) == 0);
|
154
154
|
}
|
155
155
|
|
156
|
-
// if node is a block node, returns node.
|
157
|
-
// otherwise returns first block-level node that is an ancestor of node.
|
158
|
-
// if there is no block-level ancestor, returns NULL.
|
159
|
-
static cmark_node *get_containing_block(cmark_node *node) {
|
160
|
-
while (node) {
|
161
|
-
if (CMARK_NODE_BLOCK_P(node)) {
|
162
|
-
return node;
|
163
|
-
} else {
|
164
|
-
node = node->parent;
|
165
|
-
}
|
166
|
-
}
|
167
|
-
return NULL;
|
168
|
-
}
|
169
|
-
|
170
156
|
static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
171
157
|
cmark_event_type ev_type, int options) {
|
172
|
-
cmark_node *tmp;
|
173
158
|
int list_number;
|
174
159
|
cmark_delim_type list_delim;
|
175
160
|
int numticks;
|
@@ -180,7 +165,7 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
|
180
165
|
char fencechar[2] = {'\0', '\0'};
|
181
166
|
size_t info_len, code_len;
|
182
167
|
char listmarker[LISTMARKER_SIZE];
|
183
|
-
char *emph_delim;
|
168
|
+
const char *emph_delim;
|
184
169
|
bool first_in_list_item;
|
185
170
|
bufsize_t marker_width;
|
186
171
|
bool allow_wrap = renderer->width > 0 && !(CMARK_OPT_NOBREAKS & options) &&
|
@@ -189,14 +174,17 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
|
189
174
|
// Don't adjust tight list status til we've started the list.
|
190
175
|
// Otherwise we loose the blank line between a paragraph and
|
191
176
|
// a following list.
|
192
|
-
if (
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
177
|
+
if (entering) {
|
178
|
+
if (node->parent && node->parent->type == CMARK_NODE_ITEM) {
|
179
|
+
renderer->in_tight_list_item = node->parent->parent->as.list.tight;
|
180
|
+
}
|
181
|
+
} else {
|
182
|
+
if (node->type == CMARK_NODE_LIST) {
|
183
|
+
renderer->in_tight_list_item =
|
184
|
+
node->parent &&
|
185
|
+
node->parent->type == CMARK_NODE_ITEM &&
|
186
|
+
node->parent->parent->as.list.tight;
|
187
|
+
}
|
200
188
|
}
|
201
189
|
|
202
190
|
if (node->extension && node->extension->commonmark_render_func) {
|
@@ -234,13 +222,8 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
|
234
222
|
if (cmark_node_get_list_type(node->parent) == CMARK_BULLET_LIST) {
|
235
223
|
marker_width = 4;
|
236
224
|
} else {
|
237
|
-
list_number =
|
225
|
+
list_number = cmark_node_get_item_index(node);
|
238
226
|
list_delim = cmark_node_get_list_delim(node->parent);
|
239
|
-
tmp = node;
|
240
|
-
while (tmp->prev) {
|
241
|
-
tmp = tmp->prev;
|
242
|
-
list_number += 1;
|
243
|
-
}
|
244
227
|
// we ensure a width of at least 4 so
|
245
228
|
// we get nice transition from single digits
|
246
229
|
// to double
|
@@ -405,10 +388,12 @@ static int S_render_node(cmark_renderer *renderer, cmark_node *node,
|
|
405
388
|
break;
|
406
389
|
|
407
390
|
case CMARK_NODE_STRONG:
|
408
|
-
if (
|
409
|
-
|
410
|
-
|
411
|
-
|
391
|
+
if (node->parent == NULL || node->parent->type != CMARK_NODE_STRONG) {
|
392
|
+
if (entering) {
|
393
|
+
LIT("**");
|
394
|
+
} else {
|
395
|
+
LIT("**");
|
396
|
+
}
|
412
397
|
}
|
413
398
|
break;
|
414
399
|
|
data/ext/markly/extconf.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
1
2
|
# frozen_string_literal: true
|
2
3
|
|
3
|
-
#
|
4
|
+
# Released under the MIT License.
|
5
|
+
# Copyright, 2014, by John MacFarlane.
|
6
|
+
# Copyright, 2015-2019, by Garen Torikian.
|
7
|
+
# Copyright, 2016-2017, by Yuki Izumi.
|
8
|
+
# Copyright, 2017, by Ashe Connor.
|
9
|
+
# Copyright, 2020-2023, by Samuel Williams.
|
10
|
+
|
4
11
|
require 'mkmf'
|
5
12
|
|
6
13
|
$CFLAGS << " -O3 -std=c99"
|
data/ext/markly/html.c
CHANGED
@@ -63,10 +63,16 @@ static bool S_put_footnote_backref(cmark_html_renderer *renderer, cmark_strbuf *
|
|
63
63
|
if (renderer->written_footnote_ix >= renderer->footnote_ix)
|
64
64
|
return false;
|
65
65
|
renderer->written_footnote_ix = renderer->footnote_ix;
|
66
|
+
char m[32];
|
67
|
+
snprintf(m, sizeof(m), "%d", renderer->written_footnote_ix);
|
66
68
|
|
67
69
|
cmark_strbuf_puts(html, "<a href=\"#fnref-");
|
68
70
|
houdini_escape_href(html, node->as.literal.data, node->as.literal.len);
|
69
|
-
cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref
|
71
|
+
cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"");
|
72
|
+
cmark_strbuf_puts(html, m);
|
73
|
+
cmark_strbuf_puts(html, "\" aria-label=\"Back to reference ");
|
74
|
+
cmark_strbuf_puts(html, m);
|
75
|
+
cmark_strbuf_puts(html, "\">↩</a>");
|
70
76
|
|
71
77
|
if (node->footnote.def_count > 1)
|
72
78
|
{
|
@@ -78,7 +84,15 @@ static bool S_put_footnote_backref(cmark_html_renderer *renderer, cmark_strbuf *
|
|
78
84
|
houdini_escape_href(html, node->as.literal.data, node->as.literal.len);
|
79
85
|
cmark_strbuf_puts(html, "-");
|
80
86
|
cmark_strbuf_puts(html, n);
|
81
|
-
cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref
|
87
|
+
cmark_strbuf_puts(html, "\" class=\"footnote-backref\" data-footnote-backref data-footnote-backref-idx=\"");
|
88
|
+
cmark_strbuf_puts(html, m);
|
89
|
+
cmark_strbuf_puts(html, "-");
|
90
|
+
cmark_strbuf_puts(html, n);
|
91
|
+
cmark_strbuf_puts(html, "\" aria-label=\"Back to reference ");
|
92
|
+
cmark_strbuf_puts(html, m);
|
93
|
+
cmark_strbuf_puts(html, "-");
|
94
|
+
cmark_strbuf_puts(html, n);
|
95
|
+
cmark_strbuf_puts(html, "\">↩<sup class=\"footnote-ref\">");
|
82
96
|
cmark_strbuf_puts(html, n);
|
83
97
|
cmark_strbuf_puts(html, "</sup></a>");
|
84
98
|
}
|
@@ -350,10 +364,12 @@ static int S_render_node(cmark_html_renderer *renderer, cmark_node *node,
|
|
350
364
|
break;
|
351
365
|
|
352
366
|
case CMARK_NODE_STRONG:
|
353
|
-
if (
|
354
|
-
|
355
|
-
|
356
|
-
|
367
|
+
if (node->parent == NULL || node->parent->type != CMARK_NODE_STRONG) {
|
368
|
+
if (entering) {
|
369
|
+
cmark_strbuf_puts(html, "<strong>");
|
370
|
+
} else {
|
371
|
+
cmark_strbuf_puts(html, "</strong>");
|
372
|
+
}
|
357
373
|
}
|
358
374
|
break;
|
359
375
|
|