redcarpet 3.4.0 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +479 -0
- data/CONTRIBUTING.md +33 -0
- data/Gemfile +2 -2
- data/README.markdown +26 -25
- data/ext/redcarpet/autolink.c +0 -1
- data/ext/redcarpet/buffer.h +0 -1
- data/ext/redcarpet/houdini_html_e.c +0 -1
- data/ext/redcarpet/html.c +34 -7
- data/ext/redcarpet/html.h +1 -2
- data/ext/redcarpet/html_block_names.txt +44 -0
- data/ext/redcarpet/html_blocks.h +30 -35
- data/ext/redcarpet/html_smartypants.c +17 -2
- data/ext/redcarpet/markdown.c +51 -20
- data/ext/redcarpet/rc_markdown.c +13 -3
- data/ext/redcarpet/rc_render.c +42 -9
- data/lib/redcarpet/compat.rb +0 -2
- data/lib/redcarpet/render_strip.rb +1 -1
- data/lib/redcarpet.rb +1 -1
- data/redcarpet.gemspec +9 -21
- metadata +17 -45
- data/test/benchmark.rb +0 -24
- data/test/custom_render_test.rb +0 -57
- data/test/fixtures/benchmark.md +0 -232
- data/test/html5_test.rb +0 -82
- data/test/html_render_test.rb +0 -268
- data/test/html_toc_render_test.rb +0 -82
- data/test/markdown_test.rb +0 -406
- data/test/pathological_inputs_test.rb +0 -34
- data/test/redcarpet_bin_test.rb +0 -80
- data/test/redcarpet_compat_test.rb +0 -38
- data/test/safe_render_test.rb +0 -35
- data/test/smarty_html_test.rb +0 -45
- data/test/smarty_pants_test.rb +0 -58
- data/test/stripdown_render_test.rb +0 -61
- data/test/test_helper.rb +0 -47
data/ext/redcarpet/html.c
CHANGED
@@ -255,8 +255,15 @@ rndr_quote(struct buf *ob, const struct buf *text, void *opaque)
|
|
255
255
|
if (!text || !text->size)
|
256
256
|
return 0;
|
257
257
|
|
258
|
+
struct html_renderopt *options = opaque;
|
259
|
+
|
258
260
|
BUFPUTSL(ob, "<q>");
|
259
|
-
|
261
|
+
|
262
|
+
if (options->flags & HTML_ESCAPE)
|
263
|
+
escape_html(ob, text->data, text->size);
|
264
|
+
else
|
265
|
+
bufput(ob, text->data, text->size);
|
266
|
+
|
260
267
|
BUFPUTSL(ob, "</q>");
|
261
268
|
|
262
269
|
return 1;
|
@@ -270,6 +277,22 @@ rndr_linebreak(struct buf *ob, void *opaque)
|
|
270
277
|
return 1;
|
271
278
|
}
|
272
279
|
|
280
|
+
static int html_entity_ahead(const uint8_t *text, size_t start, size_t size) {
|
281
|
+
size_t i = start;
|
282
|
+
|
283
|
+
if (text[i] != '&')
|
284
|
+
return 0;
|
285
|
+
|
286
|
+
for (; i < size; ++i) {
|
287
|
+
if (text[i] == ' ')
|
288
|
+
return 0;
|
289
|
+
else if (text[i] == ';')
|
290
|
+
return 1;
|
291
|
+
}
|
292
|
+
|
293
|
+
return 0;
|
294
|
+
}
|
295
|
+
|
273
296
|
static void
|
274
297
|
rndr_header_anchor(struct buf *out, const struct buf *anchor)
|
275
298
|
{
|
@@ -286,10 +309,11 @@ rndr_header_anchor(struct buf *out, const struct buf *anchor)
|
|
286
309
|
while (i < size && a[i] != '>')
|
287
310
|
i++;
|
288
311
|
// skip html entities
|
289
|
-
} else if (a[i] == '&') {
|
312
|
+
} else if (a[i] == '&' && html_entity_ahead(a, i, size)) {
|
290
313
|
while (i < size && a[i] != ';')
|
291
314
|
i++;
|
292
315
|
}
|
316
|
+
|
293
317
|
// replace non-ascii or invalid characters with dashes
|
294
318
|
else if (!isascii(a[i]) || strchr(STRIPPED, a[i])) {
|
295
319
|
if (inserted && !stripped)
|
@@ -326,7 +350,8 @@ rndr_header(struct buf *ob, const struct buf *text, int level, void *opaque)
|
|
326
350
|
if (ob->size)
|
327
351
|
bufputc(ob, '\n');
|
328
352
|
|
329
|
-
if ((options->flags & HTML_TOC) &&
|
353
|
+
if ((options->flags & HTML_TOC) && level >= options->toc_data.nesting_bounds[0] &&
|
354
|
+
level <= options->toc_data.nesting_bounds[1]) {
|
330
355
|
bufprintf(ob, "<h%d id=\"", level);
|
331
356
|
rndr_header_anchor(ob, text);
|
332
357
|
BUFPUTSL(ob, "\">");
|
@@ -655,7 +680,7 @@ rndr_footnote_def(struct buf *ob, const struct buf *text, unsigned int num, void
|
|
655
680
|
bufprintf(ob, "\n<li id=\"fn%d\">\n", num);
|
656
681
|
if (pfound) {
|
657
682
|
bufput(ob, text->data, i);
|
658
|
-
bufprintf(ob, " <a href=\"#fnref%d\"
|
683
|
+
bufprintf(ob, " <a href=\"#fnref%d\">↩</a>", num);
|
659
684
|
bufput(ob, text->data + i, text->size - i);
|
660
685
|
} else if (text) {
|
661
686
|
bufput(ob, text->data, text->size);
|
@@ -666,7 +691,7 @@ rndr_footnote_def(struct buf *ob, const struct buf *text, unsigned int num, void
|
|
666
691
|
static int
|
667
692
|
rndr_footnote_ref(struct buf *ob, unsigned int num, void *opaque)
|
668
693
|
{
|
669
|
-
bufprintf(ob, "<sup id=\"fnref%d\"><a href=\"#fn%d\"
|
694
|
+
bufprintf(ob, "<sup id=\"fnref%d\"><a href=\"#fn%d\">%d</a></sup>", num, num, num);
|
670
695
|
return 1;
|
671
696
|
}
|
672
697
|
|
@@ -675,7 +700,8 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
|
|
675
700
|
{
|
676
701
|
struct html_renderopt *options = opaque;
|
677
702
|
|
678
|
-
if (level
|
703
|
+
if (level >= options->toc_data.nesting_bounds[0] &&
|
704
|
+
level <= options->toc_data.nesting_bounds[1]) {
|
679
705
|
/* set the level offset if this is the first header
|
680
706
|
* we're parsing for the document */
|
681
707
|
if (options->toc_data.current_level == 0)
|
@@ -824,7 +850,8 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options,
|
|
824
850
|
/* Prepare the options pointer */
|
825
851
|
memset(options, 0x0, sizeof(struct html_renderopt));
|
826
852
|
options->flags = render_flags;
|
827
|
-
options->toc_data.
|
853
|
+
options->toc_data.nesting_bounds[0] = 1;
|
854
|
+
options->toc_data.nesting_bounds[1] = 6;
|
828
855
|
|
829
856
|
/* Prepare the callbacks */
|
830
857
|
memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks));
|
data/ext/redcarpet/html.h
CHANGED
@@ -35,7 +35,7 @@ struct html_renderopt {
|
|
35
35
|
struct {
|
36
36
|
int current_level;
|
37
37
|
int level_offset;
|
38
|
-
int
|
38
|
+
int nesting_bounds[2];
|
39
39
|
} toc_data;
|
40
40
|
|
41
41
|
unsigned int flags;
|
@@ -81,4 +81,3 @@ sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size);
|
|
81
81
|
#endif
|
82
82
|
|
83
83
|
#endif
|
84
|
-
|
@@ -0,0 +1,44 @@
|
|
1
|
+
abbr
|
2
|
+
address
|
3
|
+
article
|
4
|
+
aside
|
5
|
+
audio
|
6
|
+
blockquote
|
7
|
+
canvas
|
8
|
+
center
|
9
|
+
dd
|
10
|
+
del
|
11
|
+
details
|
12
|
+
div
|
13
|
+
dl
|
14
|
+
fieldset
|
15
|
+
figcaption
|
16
|
+
figure
|
17
|
+
footer
|
18
|
+
form
|
19
|
+
h1
|
20
|
+
h2
|
21
|
+
h3
|
22
|
+
h4
|
23
|
+
h5
|
24
|
+
h6
|
25
|
+
header
|
26
|
+
hgroup
|
27
|
+
hr
|
28
|
+
iframe
|
29
|
+
ins
|
30
|
+
math
|
31
|
+
nav
|
32
|
+
noscript
|
33
|
+
ol
|
34
|
+
output
|
35
|
+
p
|
36
|
+
pre
|
37
|
+
script
|
38
|
+
section
|
39
|
+
style
|
40
|
+
summary
|
41
|
+
table
|
42
|
+
tfoot
|
43
|
+
ul
|
44
|
+
video
|
data/ext/redcarpet/html_blocks.h
CHANGED
@@ -1,6 +1,5 @@
|
|
1
|
-
/* C code produced by gperf version 3.
|
1
|
+
/* ANSI-C code produced by gperf version 3.1 */
|
2
2
|
/* Command-line: gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case html_block_names.txt */
|
3
|
-
/* See https://git.io/vPLqa for the list of recognized elements */
|
4
3
|
/* Computed positions: -k'1-2' */
|
5
4
|
|
6
5
|
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
@@ -27,7 +26,7 @@
|
|
27
26
|
&& ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
|
28
27
|
&& ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
|
29
28
|
/* The character set is not based on ISO-646. */
|
30
|
-
error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-
|
29
|
+
#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
|
31
30
|
#endif
|
32
31
|
|
33
32
|
/* maximum key range = 72, duplicates = 0 */
|
@@ -60,10 +59,7 @@ static unsigned char gperf_downcase[256] =
|
|
60
59
|
#ifndef GPERF_CASE_STRNCMP
|
61
60
|
#define GPERF_CASE_STRNCMP 1
|
62
61
|
static int
|
63
|
-
gperf_case_strncmp (s1, s2, n)
|
64
|
-
register const char *s1;
|
65
|
-
register const char *s2;
|
66
|
-
register unsigned int n;
|
62
|
+
gperf_case_strncmp (register const char *s1, register const char *s2, register size_t n)
|
67
63
|
{
|
68
64
|
for (; n > 0;)
|
69
65
|
{
|
@@ -88,9 +84,7 @@ inline
|
|
88
84
|
#endif
|
89
85
|
#endif
|
90
86
|
static unsigned int
|
91
|
-
hash_block_tag (str, len)
|
92
|
-
register const char *str;
|
93
|
-
register unsigned int len;
|
87
|
+
hash_block_tag (register const char *str, register size_t len)
|
94
88
|
{
|
95
89
|
static const unsigned char asso_values[] =
|
96
90
|
{
|
@@ -99,13 +93,13 @@ hash_block_tag (str, len)
|
|
99
93
|
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
100
94
|
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
101
95
|
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
102
|
-
|
103
|
-
73, 73, 73, 73, 73, 20, 15,
|
104
|
-
0,
|
96
|
+
16, 55, 50, 45, 40, 5, 73, 73, 73, 73,
|
97
|
+
73, 73, 73, 73, 73, 20, 15, 25, 0, 45,
|
98
|
+
0, 30, 10, 0, 5, 73, 73, 0, 15, 35,
|
105
99
|
0, 73, 73, 15, 20, 10, 10, 73, 73, 73,
|
106
|
-
73, 73, 73, 73, 73, 73, 73, 20, 15,
|
107
|
-
0,
|
108
|
-
15,
|
100
|
+
73, 73, 73, 73, 73, 73, 73, 20, 15, 25,
|
101
|
+
0, 45, 0, 30, 10, 0, 5, 73, 73, 0,
|
102
|
+
15, 35, 0, 73, 73, 15, 20, 10, 10, 73,
|
109
103
|
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
110
104
|
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
111
105
|
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
@@ -136,13 +130,11 @@ hash_block_tag (str, len)
|
|
136
130
|
}
|
137
131
|
|
138
132
|
const char *
|
139
|
-
find_block_tag (str, len)
|
140
|
-
register const char *str;
|
141
|
-
register unsigned int len;
|
133
|
+
find_block_tag (register const char *str, register size_t len)
|
142
134
|
{
|
143
135
|
enum
|
144
136
|
{
|
145
|
-
TOTAL_KEYWORDS =
|
137
|
+
TOTAL_KEYWORDS = 44,
|
146
138
|
MIN_WORD_LENGTH = 1,
|
147
139
|
MAX_WORD_LENGTH = 10,
|
148
140
|
MIN_HASH_VALUE = 1,
|
@@ -167,7 +159,7 @@ find_block_tag (str, len)
|
|
167
159
|
"",
|
168
160
|
"figcaption",
|
169
161
|
"header",
|
170
|
-
"
|
162
|
+
"h6",
|
171
163
|
"pre",
|
172
164
|
"math",
|
173
165
|
"video",
|
@@ -178,42 +170,45 @@ find_block_tag (str, len)
|
|
178
170
|
"blockquote",
|
179
171
|
"hgroup",
|
180
172
|
"hr",
|
181
|
-
"
|
173
|
+
"h1",
|
182
174
|
"",
|
183
175
|
"style",
|
184
|
-
"
|
176
|
+
"center",
|
185
177
|
"summary",
|
186
178
|
"nav",
|
187
179
|
"",
|
188
180
|
"audio",
|
189
|
-
"canvas",
|
190
|
-
"dd",
|
191
|
-
"h1",
|
192
|
-
"abbr",
|
193
|
-
"table",
|
194
181
|
"iframe",
|
182
|
+
"ol",
|
183
|
+
"ins",
|
184
|
+
"",
|
185
|
+
"table",
|
186
|
+
"",
|
195
187
|
"article",
|
196
188
|
"", "",
|
197
189
|
"aside",
|
190
|
+
"canvas",
|
191
|
+
"dd",
|
198
192
|
"",
|
199
|
-
"
|
193
|
+
"abbr",
|
194
|
+
"",
|
195
|
+
"output",
|
196
|
+
"h5",
|
200
197
|
"", "",
|
201
198
|
"tfoot",
|
202
199
|
"",
|
203
|
-
"h5",
|
204
|
-
"", "", "", "",
|
205
200
|
"h4",
|
206
201
|
"", "", "", "",
|
207
|
-
"address",
|
208
|
-
"", "", "", "",
|
209
202
|
"h3",
|
210
203
|
"", "", "", "",
|
211
|
-
"h2"
|
204
|
+
"h2",
|
205
|
+
"", "", "", "",
|
206
|
+
"address"
|
212
207
|
};
|
213
208
|
|
214
209
|
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
215
210
|
{
|
216
|
-
unsigned int key = hash_block_tag (str, len);
|
211
|
+
register unsigned int key = hash_block_tag (str, len);
|
217
212
|
|
218
213
|
if (key <= MAX_HASH_VALUE)
|
219
214
|
{
|
@@ -341,6 +341,7 @@ smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t prev
|
|
341
341
|
};
|
342
342
|
static const size_t skip_tags_count = 8;
|
343
343
|
|
344
|
+
size_t next_to_closing_a = 0;
|
344
345
|
size_t tag, i = 0;
|
345
346
|
|
346
347
|
while (i < size && text[i] != '>')
|
@@ -369,7 +370,23 @@ smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t prev
|
|
369
370
|
i++;
|
370
371
|
}
|
371
372
|
|
373
|
+
if (sdhtml_is_tag(text, size, "a") == HTML_TAG_CLOSE) {
|
374
|
+
while (i < size && text[i] != '>')
|
375
|
+
i++;
|
376
|
+
|
377
|
+
next_to_closing_a = 1;
|
378
|
+
}
|
379
|
+
|
372
380
|
bufput(ob, text, i + 1);
|
381
|
+
|
382
|
+
// Pretty tricky: since people may refer to something or someone
|
383
|
+
// with a link but use the possessive form right after it, we need
|
384
|
+
// to check whether a single quote is next to a closing "</a"> tag.
|
385
|
+
if (next_to_closing_a && strncmp("'", text+(i+1), 5) == 0) {
|
386
|
+
bufput(ob, "’", 7);
|
387
|
+
i += 5;
|
388
|
+
}
|
389
|
+
|
373
390
|
return i;
|
374
391
|
}
|
375
392
|
|
@@ -453,5 +470,3 @@ sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size)
|
|
453
470
|
}
|
454
471
|
}
|
455
472
|
}
|
456
|
-
|
457
|
-
|
data/ext/redcarpet/markdown.c
CHANGED
@@ -1353,13 +1353,13 @@ is_hrule(uint8_t *data, size_t size)
|
|
1353
1353
|
return n >= 3;
|
1354
1354
|
}
|
1355
1355
|
|
1356
|
-
/* check if a line begins with a code fence
|
1357
|
-
|
1356
|
+
/* check if a line begins with a code fence matching optional opendelim;
|
1357
|
+
return the width of the code fence and store the delimiter string */
|
1358
1358
|
static size_t
|
1359
|
-
prefix_codefence(uint8_t *data, size_t size)
|
1359
|
+
prefix_codefence(uint8_t *data, size_t size, struct buf *delim, struct buf *opendelim)
|
1360
1360
|
{
|
1361
|
-
size_t i = 0, n = 0;
|
1362
|
-
uint8_t c;
|
1361
|
+
size_t i = 0, n = 0, min_n = 3;
|
1362
|
+
uint8_t c, *delim_start;
|
1363
1363
|
|
1364
1364
|
/* skipping initial spaces */
|
1365
1365
|
if (size < 3) return 0;
|
@@ -1367,31 +1367,46 @@ prefix_codefence(uint8_t *data, size_t size)
|
|
1367
1367
|
if (data[1] == ' ') { i++;
|
1368
1368
|
if (data[2] == ' ') { i++; } } }
|
1369
1369
|
|
1370
|
+
delim_start = data + i;
|
1371
|
+
|
1370
1372
|
/* looking at the hrule uint8_t */
|
1371
1373
|
if (i + 2 >= size || !(data[i] == '~' || data[i] == '`'))
|
1372
1374
|
return 0;
|
1373
1375
|
|
1374
|
-
|
1376
|
+
if (opendelim && opendelim->size) {
|
1377
|
+
c = opendelim->data[0];
|
1378
|
+
min_n = opendelim->size;
|
1379
|
+
} else {
|
1380
|
+
c = data[i];
|
1381
|
+
}
|
1375
1382
|
|
1376
1383
|
/* the whole line must be the uint8_t or whitespace */
|
1377
1384
|
while (i < size && data[i] == c) {
|
1378
1385
|
n++; i++;
|
1379
1386
|
}
|
1380
1387
|
|
1381
|
-
if (n <
|
1388
|
+
if (n < min_n)
|
1382
1389
|
return 0;
|
1383
1390
|
|
1391
|
+
if (delim) {
|
1392
|
+
delim->data = delim_start;
|
1393
|
+
delim->size = n;
|
1394
|
+
}
|
1395
|
+
|
1384
1396
|
return i;
|
1385
1397
|
}
|
1386
1398
|
|
1387
1399
|
/* check if a line is a code fence; return its size if it is */
|
1400
|
+
/* checking is done in fence-pair matching mode if curdelim is provided */
|
1388
1401
|
static size_t
|
1389
|
-
is_codefence(uint8_t *data, size_t size, struct buf *syntax)
|
1402
|
+
is_codefence(uint8_t *data, size_t size, struct buf *curdelim, struct buf *syntax)
|
1390
1403
|
{
|
1391
1404
|
size_t i = 0, syn_len = 0;
|
1392
1405
|
uint8_t *syn_start;
|
1406
|
+
struct buf delim = { 0, 0, 0, 0 };
|
1407
|
+
|
1408
|
+
i = prefix_codefence(data, size, &delim, curdelim);
|
1393
1409
|
|
1394
|
-
i = prefix_codefence(data, size);
|
1395
1410
|
if (i == 0)
|
1396
1411
|
return 0;
|
1397
1412
|
|
@@ -1426,10 +1441,9 @@ is_codefence(uint8_t *data, size_t size, struct buf *syntax)
|
|
1426
1441
|
}
|
1427
1442
|
}
|
1428
1443
|
|
1429
|
-
|
1430
|
-
|
1431
|
-
|
1432
|
-
}
|
1444
|
+
/* info string must not be present at the closing fence */
|
1445
|
+
if (curdelim && curdelim->size && syn_len)
|
1446
|
+
return 0;
|
1433
1447
|
|
1434
1448
|
while (i < size && data[i] != '\n') {
|
1435
1449
|
if (!_isspace(data[i]))
|
@@ -1438,6 +1452,21 @@ is_codefence(uint8_t *data, size_t size, struct buf *syntax)
|
|
1438
1452
|
i++;
|
1439
1453
|
}
|
1440
1454
|
|
1455
|
+
if (curdelim) {
|
1456
|
+
if (curdelim->size) {
|
1457
|
+
curdelim->data = NULL;
|
1458
|
+
curdelim->size = 0;
|
1459
|
+
} else {
|
1460
|
+
curdelim->data = delim.data;
|
1461
|
+
curdelim->size = delim.size;
|
1462
|
+
}
|
1463
|
+
}
|
1464
|
+
|
1465
|
+
if (syntax) {
|
1466
|
+
syntax->data = syn_start;
|
1467
|
+
syntax->size = syn_len;
|
1468
|
+
}
|
1469
|
+
|
1441
1470
|
return i + 1;
|
1442
1471
|
}
|
1443
1472
|
|
@@ -1673,7 +1702,7 @@ parse_paragraph(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
|
|
1673
1702
|
|
1674
1703
|
/* see if a code fence starts here */
|
1675
1704
|
if ((rndr->ext_flags & MKDEXT_FENCED_CODE) != 0 &&
|
1676
|
-
is_codefence(data + i, size - i, NULL) != 0) {
|
1705
|
+
is_codefence(data + i, size - i, NULL, NULL) != 0) {
|
1677
1706
|
end = i;
|
1678
1707
|
break;
|
1679
1708
|
}
|
@@ -1739,19 +1768,19 @@ parse_fencedcode(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
|
|
1739
1768
|
{
|
1740
1769
|
size_t beg, end;
|
1741
1770
|
struct buf *work = 0;
|
1771
|
+
struct buf delim = { 0, 0, 0, 0 };
|
1742
1772
|
struct buf lang = { 0, 0, 0, 0 };
|
1743
1773
|
|
1744
|
-
beg = is_codefence(data, size, &lang);
|
1774
|
+
beg = is_codefence(data, size, &delim, &lang);
|
1745
1775
|
if (beg == 0) return 0;
|
1746
1776
|
|
1747
1777
|
work = rndr_newbuf(rndr, BUFFER_BLOCK);
|
1748
1778
|
|
1749
1779
|
while (beg < size) {
|
1750
1780
|
size_t fence_end;
|
1751
|
-
struct buf fence_trail = { 0, 0, 0, 0 };
|
1752
1781
|
|
1753
|
-
fence_end = is_codefence(data + beg, size - beg, &
|
1754
|
-
if (fence_end != 0
|
1782
|
+
fence_end = is_codefence(data + beg, size - beg, &delim, NULL);
|
1783
|
+
if (fence_end != 0) {
|
1755
1784
|
beg += fence_end;
|
1756
1785
|
break;
|
1757
1786
|
}
|
@@ -1827,6 +1856,7 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
|
|
1827
1856
|
struct buf *work = 0, *inter = 0;
|
1828
1857
|
size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;
|
1829
1858
|
int in_empty = 0, has_inside_empty = 0, in_fence = 0;
|
1859
|
+
struct buf fence_delim = { 0, 0, 0, 0 };
|
1830
1860
|
|
1831
1861
|
/* keeping track of the first indentation prefix */
|
1832
1862
|
while (orgpre < 3 && orgpre < size && data[orgpre] == ' ')
|
@@ -1876,7 +1906,7 @@ parse_listitem(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t s
|
|
1876
1906
|
pre = i;
|
1877
1907
|
|
1878
1908
|
if (rndr->ext_flags & MKDEXT_FENCED_CODE) {
|
1879
|
-
if (is_codefence(data + beg + i, end - beg - i, NULL) != 0)
|
1909
|
+
if (is_codefence(data + beg + i, end - beg - i, &fence_delim, NULL) != 0)
|
1880
1910
|
in_fence = !in_fence;
|
1881
1911
|
}
|
1882
1912
|
|
@@ -2804,6 +2834,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2804
2834
|
struct buf *text;
|
2805
2835
|
size_t beg, end;
|
2806
2836
|
int in_fence = 0;
|
2837
|
+
struct buf fence_delim = { 0, 0, 0, 0 };
|
2807
2838
|
|
2808
2839
|
text = bufnew(64);
|
2809
2840
|
if (!text)
|
@@ -2833,7 +2864,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2833
2864
|
beg += 3;
|
2834
2865
|
|
2835
2866
|
while (beg < doc_size) { /* iterating over lines */
|
2836
|
-
if (codefences_enabled && (is_codefence(document + beg, doc_size - beg, NULL) != 0))
|
2867
|
+
if (codefences_enabled && (is_codefence(document + beg, doc_size - beg, &fence_delim, NULL) != 0))
|
2837
2868
|
in_fence = !in_fence;
|
2838
2869
|
|
2839
2870
|
if (!in_fence && footnotes_enabled && is_footnote(document, beg, doc_size, &end, &md->footnotes_found))
|
data/ext/redcarpet/rc_markdown.c
CHANGED
@@ -24,6 +24,7 @@
|
|
24
24
|
|
25
25
|
VALUE rb_mRedcarpet;
|
26
26
|
VALUE rb_cMarkdown;
|
27
|
+
VALUE rb_cRenderHTML_TOC;
|
27
28
|
|
28
29
|
extern VALUE rb_cRenderBase;
|
29
30
|
|
@@ -101,12 +102,21 @@ static VALUE rb_redcarpet_md__new(int argc, VALUE *argv, VALUE klass)
|
|
101
102
|
if (!rb_obj_is_kind_of(rb_rndr, rb_cRenderBase))
|
102
103
|
rb_raise(rb_eTypeError, "Invalid Renderer instance given");
|
103
104
|
|
105
|
+
/**
|
106
|
+
* Automatically enable the `fenced_code_blocks` option if
|
107
|
+
* given a kind of `HTML_TOC` object since many languages
|
108
|
+
* like Ruby use the sharp to comment code so these comments
|
109
|
+
* would be processed as titles.
|
110
|
+
*/
|
111
|
+
if (rb_obj_is_kind_of(rb_rndr, rb_cRenderHTML_TOC))
|
112
|
+
extensions |= MKDEXT_FENCED_CODE;
|
113
|
+
|
104
114
|
Data_Get_Struct(rb_rndr, struct rb_redcarpet_rndr, rndr);
|
105
115
|
|
106
116
|
/* Merge the current options in the @options hash */
|
107
117
|
if (hash != Qnil) {
|
108
|
-
rndr_options = rb_iv_get(rb_rndr, "@options");
|
109
|
-
|
118
|
+
rndr_options = rb_funcall(rb_iv_get(rb_rndr, "@options"), rb_intern("merge"), 1, hash);
|
119
|
+
rb_iv_set(rb_rndr, "@options", rndr_options);
|
110
120
|
}
|
111
121
|
|
112
122
|
markdown = sd_markdown_new(extensions, 16, &rndr->callbacks, &rndr->options);
|
@@ -166,9 +176,9 @@ void Init_redcarpet()
|
|
166
176
|
rb_mRedcarpet = rb_define_module("Redcarpet");
|
167
177
|
|
168
178
|
rb_cMarkdown = rb_define_class_under(rb_mRedcarpet, "Markdown", rb_cObject);
|
179
|
+
rb_undef_alloc_func(rb_cMarkdown);
|
169
180
|
rb_define_singleton_method(rb_cMarkdown, "new", rb_redcarpet_md__new, -1);
|
170
181
|
rb_define_method(rb_cMarkdown, "render", rb_redcarpet_md_render, 1);
|
171
182
|
|
172
183
|
Init_redcarpet_rndr();
|
173
184
|
}
|
174
|
-
|
data/ext/redcarpet/rc_render.c
CHANGED
@@ -40,10 +40,10 @@
|
|
40
40
|
}
|
41
41
|
|
42
42
|
extern VALUE rb_mRedcarpet;
|
43
|
+
extern VALUE rb_cRenderHTML_TOC;
|
43
44
|
VALUE rb_mRender;
|
44
45
|
VALUE rb_cRenderBase;
|
45
46
|
VALUE rb_cRenderHTML;
|
46
|
-
VALUE rb_cRenderHTML_TOC;
|
47
47
|
VALUE rb_mSmartyPants;
|
48
48
|
|
49
49
|
#define buf2str(t) ((t) ? rb_enc_str_new((const char*)(t)->data, (t)->size, opt->active_enc) : Qnil)
|
@@ -113,9 +113,10 @@ rndr_tablerow(struct buf *ob, const struct buf *text, void *opaque)
|
|
113
113
|
static void
|
114
114
|
rndr_tablecell(struct buf *ob, const struct buf *text, int align, void *opaque)
|
115
115
|
{
|
116
|
-
VALUE rb_align;
|
116
|
+
VALUE rb_align, rb_header;
|
117
|
+
VALUE rb_callback, rb_callback_arity;
|
117
118
|
|
118
|
-
switch (align) {
|
119
|
+
switch (align & MKD_TABLE_ALIGNMASK) {
|
119
120
|
case MKD_TABLE_ALIGN_L:
|
120
121
|
rb_align = CSTR2SYM("left");
|
121
122
|
break;
|
@@ -133,7 +134,25 @@ rndr_tablecell(struct buf *ob, const struct buf *text, int align, void *opaque)
|
|
133
134
|
break;
|
134
135
|
}
|
135
136
|
|
136
|
-
|
137
|
+
if (align & MKD_TABLE_HEADER) {
|
138
|
+
rb_header = Qtrue;
|
139
|
+
} else {
|
140
|
+
rb_header = Qfalse;
|
141
|
+
}
|
142
|
+
|
143
|
+
struct redcarpet_renderopt *opt = opaque;
|
144
|
+
|
145
|
+
rb_callback = rb_funcall(opt->self, rb_intern("method"), 1, CSTR2SYM("table_cell"));
|
146
|
+
|
147
|
+
rb_callback_arity = rb_funcall(rb_callback, rb_intern("arity"), 0);
|
148
|
+
|
149
|
+
/* For backward compatibility, let's ensure that the erasure with
|
150
|
+
only two parameters is still supported. */
|
151
|
+
if (FIX2INT(rb_callback_arity) == 3) {
|
152
|
+
BLOCK_CALLBACK("table_cell", 3, buf2str(text), rb_align, rb_header);
|
153
|
+
} else {
|
154
|
+
BLOCK_CALLBACK("table_cell", 2, buf2str(text), rb_align);
|
155
|
+
}
|
137
156
|
}
|
138
157
|
|
139
158
|
static void
|
@@ -390,6 +409,7 @@ static VALUE rb_redcarpet_rbase_alloc(VALUE klass)
|
|
390
409
|
static void rb_redcarpet__overload(VALUE self, VALUE base_class)
|
391
410
|
{
|
392
411
|
struct rb_redcarpet_rndr *rndr;
|
412
|
+
VALUE options_ivar;
|
393
413
|
|
394
414
|
Data_Get_Struct(self, struct rb_redcarpet_rndr, rndr);
|
395
415
|
rndr->options.self = self;
|
@@ -411,7 +431,8 @@ static void rb_redcarpet__overload(VALUE self, VALUE base_class)
|
|
411
431
|
}
|
412
432
|
}
|
413
433
|
|
414
|
-
|
434
|
+
options_ivar = rb_attr_get(self, rb_intern("@options"));
|
435
|
+
if (options_ivar == Qundef || options_ivar == Qnil)
|
415
436
|
rb_iv_set(self, "@options", rb_hash_new());
|
416
437
|
}
|
417
438
|
|
@@ -511,10 +532,22 @@ static VALUE rb_redcarpet_htmltoc_init(int argc, VALUE *argv, VALUE self)
|
|
511
532
|
sdhtml_toc_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, render_flags);
|
512
533
|
rb_redcarpet__overload(self, rb_cRenderHTML_TOC);
|
513
534
|
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
535
|
+
/* Check whether we are dealing with a Range object by
|
536
|
+
checking whether the object responds to min and max */
|
537
|
+
if (rb_respond_to(nesting_level, rb_intern("min")) &&
|
538
|
+
rb_respond_to(nesting_level, rb_intern("max"))) {
|
539
|
+
int min = NUM2INT(rb_funcall(nesting_level, rb_intern("min"), 0));
|
540
|
+
int max = NUM2INT(rb_funcall(nesting_level, rb_intern("max"), 0));
|
541
|
+
|
542
|
+
rndr->options.html.toc_data.nesting_bounds[0] = min;
|
543
|
+
rndr->options.html.toc_data.nesting_bounds[1] = max;
|
544
|
+
} else if (FIXNUM_P(nesting_level)) {
|
545
|
+
rndr->options.html.toc_data.nesting_bounds[0] = 1;
|
546
|
+
rndr->options.html.toc_data.nesting_bounds[1] = NUM2INT(nesting_level);
|
547
|
+
} else {
|
548
|
+
rndr->options.html.toc_data.nesting_bounds[0] = 1;
|
549
|
+
rndr->options.html.toc_data.nesting_bounds[1] = 6;
|
550
|
+
}
|
518
551
|
|
519
552
|
return Qnil;
|
520
553
|
}
|
data/lib/redcarpet/compat.rb
CHANGED
@@ -13,7 +13,7 @@ module Redcarpet
|
|
13
13
|
:autolink, :codespan, :double_emphasis,
|
14
14
|
:emphasis, :underline, :raw_html,
|
15
15
|
:triple_emphasis, :strikethrough,
|
16
|
-
:superscript, :highlight,
|
16
|
+
:superscript, :highlight, :quote,
|
17
17
|
|
18
18
|
# footnotes
|
19
19
|
:footnotes, :footnote_def, :footnote_ref,
|