redcarpet 3.4.0 → 3.6.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 +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,
|