greenmat 3.2.2.2 → 3.5.1.2
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/.travis.yml +21 -8
- data/CHANGELOG.md +24 -0
- data/COPYING +17 -11
- data/Gemfile +2 -2
- data/README.md +19 -13
- data/Rakefile +1 -0
- data/bin/greenmat +4 -40
- data/ext/greenmat/autolink.c +24 -12
- data/ext/greenmat/buffer.c +24 -17
- data/ext/greenmat/buffer.h +18 -13
- data/ext/greenmat/gm_markdown.c +41 -14
- data/ext/greenmat/gm_render.c +68 -21
- data/ext/greenmat/greenmat.h +22 -0
- data/ext/greenmat/houdini.h +22 -0
- data/ext/greenmat/houdini_href_e.c +27 -11
- data/ext/greenmat/houdini_html_e.c +22 -1
- data/ext/greenmat/html.c +177 -47
- data/ext/greenmat/html.h +19 -14
- data/ext/greenmat/html_smartypants.c +47 -20
- data/ext/greenmat/markdown.c +181 -30
- data/ext/greenmat/markdown.h +20 -16
- data/ext/greenmat/stack.c +22 -0
- data/ext/greenmat/stack.h +22 -0
- data/greenmat.gemspec +4 -3
- data/lib/greenmat.rb +1 -1
- data/lib/greenmat/cli.rb +86 -0
- data/lib/greenmat/compat.rb +0 -5
- data/lib/greenmat/render_strip.rb +13 -1
- data/lib/greenmat/version.rb +1 -1
- data/spec/greenmat/markdown_spec.rb +166 -0
- data/test/custom_render_test.rb +41 -2
- data/test/greenmat_bin_test.rb +80 -0
- data/test/greenmat_compat_test.rb +6 -6
- data/test/html5_test.rb +60 -38
- data/test/html_render_test.rb +162 -128
- data/test/html_toc_render_test.rb +74 -11
- data/test/markdown_test.rb +258 -182
- data/test/safe_render_test.rb +5 -6
- data/test/smarty_html_test.rb +19 -13
- data/test/smarty_pants_test.rb +10 -0
- data/test/stripdown_render_test.rb +38 -9
- data/test/test_helper.rb +30 -9
- metadata +29 -13
data/ext/greenmat/html.h
CHANGED
@@ -1,17 +1,23 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c)
|
2
|
+
* Copyright (c) 2015, Vicent Marti
|
3
3
|
*
|
4
|
-
* Permission
|
5
|
-
*
|
6
|
-
*
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
9
|
+
* furnished to do so, subject to the following conditions:
|
7
10
|
*
|
8
|
-
*
|
9
|
-
*
|
10
|
-
*
|
11
|
-
*
|
12
|
-
*
|
13
|
-
*
|
14
|
-
* OR
|
11
|
+
* The above copyright notice and this permission notice shall be included in
|
12
|
+
* all copies or substantial portions of the Software.
|
13
|
+
*
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
* THE SOFTWARE.
|
15
21
|
*/
|
16
22
|
|
17
23
|
#ifndef HTML_H__
|
@@ -29,7 +35,7 @@ struct html_renderopt {
|
|
29
35
|
struct {
|
30
36
|
int current_level;
|
31
37
|
int level_offset;
|
32
|
-
int
|
38
|
+
int nesting_bounds[2];
|
33
39
|
} toc_data;
|
34
40
|
|
35
41
|
unsigned int flags;
|
@@ -65,7 +71,7 @@ extern void
|
|
65
71
|
sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, unsigned int render_flags);
|
66
72
|
|
67
73
|
extern void
|
68
|
-
sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, int
|
74
|
+
sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, unsigned int render_flags);
|
69
75
|
|
70
76
|
extern void
|
71
77
|
sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size);
|
@@ -75,4 +81,3 @@ sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size);
|
|
75
81
|
#endif
|
76
82
|
|
77
83
|
#endif
|
78
|
-
|
@@ -1,17 +1,23 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c)
|
2
|
+
* Copyright (c) 2015, Vicent Marti
|
3
3
|
*
|
4
|
-
* Permission
|
5
|
-
*
|
6
|
-
*
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
9
|
+
* furnished to do so, subject to the following conditions:
|
7
10
|
*
|
8
|
-
*
|
9
|
-
*
|
10
|
-
*
|
11
|
-
*
|
12
|
-
*
|
13
|
-
*
|
14
|
-
* OR
|
11
|
+
* The above copyright notice and this permission notice shall be included in
|
12
|
+
* all copies or substantial portions of the Software.
|
13
|
+
*
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
* THE SOFTWARE.
|
15
21
|
*/
|
16
22
|
|
17
23
|
#include "buffer.h"
|
@@ -83,6 +89,12 @@ word_boundary(uint8_t c)
|
|
83
89
|
return c == 0 || isspace(c) || ispunct(c);
|
84
90
|
}
|
85
91
|
|
92
|
+
static inline int
|
93
|
+
fraction_boundary(uint8_t c)
|
94
|
+
{
|
95
|
+
return c == 0 || isspace(c) || (c != '/' && ispunct(c));
|
96
|
+
}
|
97
|
+
|
86
98
|
// If 'text' begins with any kind of single quote (e.g. "'" or "'" etc.),
|
87
99
|
// returns the length of the sequence of characters that makes up the single-
|
88
100
|
// quote. Otherwise, returns zero.
|
@@ -139,6 +151,9 @@ smartypants_squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previo
|
|
139
151
|
return next_squote_len;
|
140
152
|
}
|
141
153
|
|
154
|
+
if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote))
|
155
|
+
return 0;
|
156
|
+
|
142
157
|
// trailing single quotes: students', tryin'
|
143
158
|
if (word_boundary(t1)) {
|
144
159
|
BUFPUTSL(ob, "’");
|
@@ -166,9 +181,6 @@ smartypants_squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previo
|
|
166
181
|
}
|
167
182
|
}
|
168
183
|
|
169
|
-
if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote))
|
170
|
-
return 0;
|
171
|
-
|
172
184
|
bufput(ob, squote_text, squote_size);
|
173
185
|
return 0;
|
174
186
|
}
|
@@ -282,16 +294,16 @@ smartypants_cb__backtick(struct buf *ob, struct smartypants_data *smrt, uint8_t
|
|
282
294
|
static size_t
|
283
295
|
smartypants_cb__number(struct buf *ob, struct smartypants_data *smrt, uint8_t previous_char, const uint8_t *text, size_t size)
|
284
296
|
{
|
285
|
-
if (
|
297
|
+
if (fraction_boundary(previous_char) && size >= 3) {
|
286
298
|
if (text[0] == '1' && text[1] == '/' && text[2] == '2') {
|
287
|
-
if (size == 3 ||
|
299
|
+
if (size == 3 || fraction_boundary(text[3])) {
|
288
300
|
BUFPUTSL(ob, "½");
|
289
301
|
return 2;
|
290
302
|
}
|
291
303
|
}
|
292
304
|
|
293
305
|
if (text[0] == '1' && text[1] == '/' && text[2] == '4') {
|
294
|
-
if (size == 3 ||
|
306
|
+
if (size == 3 || fraction_boundary(text[3]) ||
|
295
307
|
(size >= 5 && tolower(text[3]) == 't' && tolower(text[4]) == 'h')) {
|
296
308
|
BUFPUTSL(ob, "¼");
|
297
309
|
return 2;
|
@@ -299,7 +311,7 @@ smartypants_cb__number(struct buf *ob, struct smartypants_data *smrt, uint8_t pr
|
|
299
311
|
}
|
300
312
|
|
301
313
|
if (text[0] == '3' && text[1] == '/' && text[2] == '4') {
|
302
|
-
if (size == 3 ||
|
314
|
+
if (size == 3 || fraction_boundary(text[3]) ||
|
303
315
|
(size >= 6 && tolower(text[3]) == 't' && tolower(text[4]) == 'h' && tolower(text[5]) == 's')) {
|
304
316
|
BUFPUTSL(ob, "¾");
|
305
317
|
return 2;
|
@@ -329,6 +341,7 @@ smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t prev
|
|
329
341
|
};
|
330
342
|
static const size_t skip_tags_count = 8;
|
331
343
|
|
344
|
+
size_t next_to_closing_a = 0;
|
332
345
|
size_t tag, i = 0;
|
333
346
|
|
334
347
|
while (i < size && text[i] != '>')
|
@@ -357,7 +370,23 @@ smartypants_cb__ltag(struct buf *ob, struct smartypants_data *smrt, uint8_t prev
|
|
357
370
|
i++;
|
358
371
|
}
|
359
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
|
+
|
360
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
|
+
|
361
390
|
return i;
|
362
391
|
}
|
363
392
|
|
@@ -441,5 +470,3 @@ sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size)
|
|
441
470
|
}
|
442
471
|
}
|
443
472
|
}
|
444
|
-
|
445
|
-
|
data/ext/greenmat/markdown.c
CHANGED
@@ -1,20 +1,24 @@
|
|
1
|
-
/* markdown.c - generic markdown parser */
|
2
|
-
|
3
1
|
/*
|
4
2
|
* Copyright (c) 2009, Natacha Porté
|
5
|
-
* Copyright (c)
|
3
|
+
* Copyright (c) 2015, Vicent Marti
|
4
|
+
*
|
5
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
* of this software and associated documentation files (the "Software"), to deal
|
7
|
+
* in the Software without restriction, including without limitation the rights
|
8
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
* copies of the Software, and to permit persons to whom the Software is
|
10
|
+
* furnished to do so, subject to the following conditions:
|
6
11
|
*
|
7
|
-
*
|
8
|
-
*
|
9
|
-
* copyright notice and this permission notice appear in all copies.
|
12
|
+
* The above copyright notice and this permission notice shall be included in
|
13
|
+
* all copies or substantial portions of the Software.
|
10
14
|
*
|
11
|
-
* THE SOFTWARE IS PROVIDED "AS IS"
|
12
|
-
*
|
13
|
-
*
|
14
|
-
*
|
15
|
-
*
|
16
|
-
*
|
17
|
-
*
|
15
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
* THE SOFTWARE.
|
18
22
|
*/
|
19
23
|
|
20
24
|
#include "markdown.h"
|
@@ -88,7 +92,6 @@ typedef size_t
|
|
88
92
|
|
89
93
|
static size_t char_emphasis(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
90
94
|
static size_t char_underline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
91
|
-
static size_t char_highlight(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
92
95
|
static size_t char_quote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
93
96
|
static size_t char_linebreak(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
94
97
|
static size_t char_codespan(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size);
|
@@ -467,7 +470,7 @@ tag_length(uint8_t *data, size_t size, enum mkd_autolink *autolink)
|
|
467
470
|
static void
|
468
471
|
parse_inline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size)
|
469
472
|
{
|
470
|
-
size_t i = 0, end = 0;
|
473
|
+
size_t i = 0, end = 0, consumed = 0;
|
471
474
|
uint8_t action = 0;
|
472
475
|
struct buf work = { 0, 0, 0, 0 };
|
473
476
|
|
@@ -492,12 +495,13 @@ parse_inline(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t siz
|
|
492
495
|
if (end >= size) break;
|
493
496
|
i = end;
|
494
497
|
|
495
|
-
end = markdown_char_ptrs[(int)action](ob, rndr, data + i, i, size - i);
|
498
|
+
end = markdown_char_ptrs[(int)action](ob, rndr, data + i, i - consumed, size - i);
|
496
499
|
if (!end) /* no action from the callback */
|
497
500
|
end = i + 1;
|
498
501
|
else {
|
499
502
|
i += end;
|
500
503
|
end = i;
|
504
|
+
consumed = i;
|
501
505
|
}
|
502
506
|
}
|
503
507
|
}
|
@@ -646,7 +650,7 @@ parse_emph1(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
|
|
646
650
|
if (data[i] == c && !_isspace(data[i - 1])) {
|
647
651
|
|
648
652
|
if (rndr->ext_flags & MKDEXT_NO_INTRA_EMPHASIS) {
|
649
|
-
if (i +
|
653
|
+
if (i + 1 < size && _isalnum(data[i + 1]))
|
650
654
|
continue;
|
651
655
|
}
|
652
656
|
|
@@ -898,7 +902,6 @@ char_quote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offse
|
|
898
902
|
return end;
|
899
903
|
}
|
900
904
|
|
901
|
-
|
902
905
|
/* char_escape • '\\' backslash escape */
|
903
906
|
static size_t
|
904
907
|
char_escape(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset, size_t size)
|
@@ -1176,7 +1179,7 @@ char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset
|
|
1176
1179
|
title_e--;
|
1177
1180
|
|
1178
1181
|
/* checking for closing quote presence */
|
1179
|
-
if (data[title_e] != '\'' &&
|
1182
|
+
if (data[title_e] != '\'' && data[title_e] != '"') {
|
1180
1183
|
title_b = title_e = 0;
|
1181
1184
|
link_e = i;
|
1182
1185
|
}
|
@@ -1439,6 +1442,37 @@ prefix_codefence(uint8_t *data, size_t size)
|
|
1439
1442
|
return i;
|
1440
1443
|
}
|
1441
1444
|
|
1445
|
+
/* check if a line begins with a custom fence; return the
|
1446
|
+
* width of the custom fence */
|
1447
|
+
static size_t
|
1448
|
+
prefix_customfence(uint8_t *data, size_t size)
|
1449
|
+
{
|
1450
|
+
size_t i = 0, n = 0;
|
1451
|
+
uint8_t c;
|
1452
|
+
|
1453
|
+
/* skipping initial spaces */
|
1454
|
+
if (size < 3) return 0;
|
1455
|
+
if (data[0] == ' ') { i++;
|
1456
|
+
if (data[1] == ' ') { i++;
|
1457
|
+
if (data[2] == ' ') { i++; } } }
|
1458
|
+
|
1459
|
+
/* looking at the hrule uint8_t */
|
1460
|
+
if (i + 2 >= size || !(data[i] == ':'))
|
1461
|
+
return 0;
|
1462
|
+
|
1463
|
+
c = data[i];
|
1464
|
+
|
1465
|
+
/* the whole line must be the uint8_t or whitespace */
|
1466
|
+
while (i < size && data[i] == c) {
|
1467
|
+
n++; i++;
|
1468
|
+
}
|
1469
|
+
|
1470
|
+
if (n < 3)
|
1471
|
+
return 0;
|
1472
|
+
|
1473
|
+
return i;
|
1474
|
+
}
|
1475
|
+
|
1442
1476
|
/* check if a line is a code fence; return its size if it is */
|
1443
1477
|
static size_t
|
1444
1478
|
is_codefence(uint8_t *data, size_t size, struct buf *syntax)
|
@@ -1496,6 +1530,63 @@ is_codefence(uint8_t *data, size_t size, struct buf *syntax)
|
|
1496
1530
|
return i + 1;
|
1497
1531
|
}
|
1498
1532
|
|
1533
|
+
/* check if a line is a custom fence; return its size if it is */
|
1534
|
+
static size_t
|
1535
|
+
is_customfence(uint8_t *data, size_t size, struct buf *syntax)
|
1536
|
+
{
|
1537
|
+
size_t i = 0, syn_len = 0;
|
1538
|
+
uint8_t *syn_start;
|
1539
|
+
|
1540
|
+
i = prefix_customfence(data, size);
|
1541
|
+
if (i == 0)
|
1542
|
+
return 0;
|
1543
|
+
|
1544
|
+
while (i < size && data[i] == ' ')
|
1545
|
+
i++;
|
1546
|
+
|
1547
|
+
syn_start = data + i;
|
1548
|
+
|
1549
|
+
if (i < size && data[i] == '{') {
|
1550
|
+
i++; syn_start++;
|
1551
|
+
|
1552
|
+
while (i < size && data[i] != '}' && data[i] != '\n') {
|
1553
|
+
syn_len++; i++;
|
1554
|
+
}
|
1555
|
+
|
1556
|
+
if (i == size || data[i] != '}')
|
1557
|
+
return 0;
|
1558
|
+
|
1559
|
+
/* strip all whitespace at the beginning and the end
|
1560
|
+
* of the {} block */
|
1561
|
+
while (syn_len > 0 && _isspace(syn_start[0])) {
|
1562
|
+
syn_start++; syn_len--;
|
1563
|
+
}
|
1564
|
+
|
1565
|
+
while (syn_len > 0 && _isspace(syn_start[syn_len - 1]))
|
1566
|
+
syn_len--;
|
1567
|
+
|
1568
|
+
i++;
|
1569
|
+
} else {
|
1570
|
+
while (i < size && data[i] != '\n') {
|
1571
|
+
syn_len++; i++;
|
1572
|
+
}
|
1573
|
+
}
|
1574
|
+
|
1575
|
+
if (syntax) {
|
1576
|
+
syntax->data = syn_start;
|
1577
|
+
syntax->size = syn_len;
|
1578
|
+
}
|
1579
|
+
|
1580
|
+
while (i < size && data[i] != '\n') {
|
1581
|
+
if (!_isspace(data[i]))
|
1582
|
+
return 0;
|
1583
|
+
|
1584
|
+
i++;
|
1585
|
+
}
|
1586
|
+
|
1587
|
+
return i + 1;
|
1588
|
+
}
|
1589
|
+
|
1499
1590
|
/* is_atxheader • returns whether the line is a hash-prefixed header */
|
1500
1591
|
static int
|
1501
1592
|
is_atxheader(struct sd_markdown *rndr, uint8_t *data, size_t size)
|
@@ -1605,7 +1696,7 @@ prefix_oli(uint8_t *data, size_t size)
|
|
1605
1696
|
return i + 2;
|
1606
1697
|
}
|
1607
1698
|
|
1608
|
-
/* prefix_uli • returns
|
1699
|
+
/* prefix_uli • returns unordered list item prefix */
|
1609
1700
|
static size_t
|
1610
1701
|
prefix_uli(uint8_t *data, size_t size)
|
1611
1702
|
{
|
@@ -1677,7 +1768,7 @@ parse_blockquote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
|
|
1677
1768
|
static size_t
|
1678
1769
|
parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render);
|
1679
1770
|
|
1680
|
-
/*
|
1771
|
+
/* parse_paragraph • handles parsing of a regular paragraph */
|
1681
1772
|
static size_t
|
1682
1773
|
parse_paragraph(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size)
|
1683
1774
|
{
|
@@ -1874,6 +1965,53 @@ parse_blockcode(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
|
|
1874
1965
|
return beg;
|
1875
1966
|
}
|
1876
1967
|
|
1968
|
+
|
1969
|
+
|
1970
|
+
/* parse_fencedcustom • handles parsing of a block-level custom fragment */
|
1971
|
+
static size_t
|
1972
|
+
parse_fencedcustom(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size)
|
1973
|
+
{
|
1974
|
+
size_t beg, end;
|
1975
|
+
struct buf *work = 0;
|
1976
|
+
struct buf type = { 0, 0, 0, 0 };
|
1977
|
+
|
1978
|
+
beg = is_customfence(data, size, &type);
|
1979
|
+
if (beg == 0) return 0;
|
1980
|
+
|
1981
|
+
work = rndr_newbuf(rndr, BUFFER_BLOCK);
|
1982
|
+
|
1983
|
+
while (beg < size) {
|
1984
|
+
size_t fence_end;
|
1985
|
+
struct buf fence_trail = { 0, 0, 0, 0 };
|
1986
|
+
|
1987
|
+
fence_end = is_customfence(data + beg, size - beg, &fence_trail);
|
1988
|
+
if (fence_end != 0 && fence_trail.size == 0) {
|
1989
|
+
beg += fence_end;
|
1990
|
+
break;
|
1991
|
+
}
|
1992
|
+
|
1993
|
+
for (end = beg + 1; end < size && data[end - 1] != '\n'; end++);
|
1994
|
+
|
1995
|
+
if (beg < end) {
|
1996
|
+
/* verbatim copy to the working buffer,
|
1997
|
+
escaping entities */
|
1998
|
+
if (is_empty(data + beg, end - beg))
|
1999
|
+
bufputc(work, '\n');
|
2000
|
+
else bufput(work, data + beg, end - beg);
|
2001
|
+
}
|
2002
|
+
beg = end;
|
2003
|
+
}
|
2004
|
+
|
2005
|
+
if (work->size && work->data[work->size - 1] != '\n')
|
2006
|
+
bufputc(work, '\n');
|
2007
|
+
|
2008
|
+
if (rndr->cb.blockcustom)
|
2009
|
+
rndr->cb.blockcustom(ob, work, type.size ? &type : NULL, rndr->opaque);
|
2010
|
+
|
2011
|
+
rndr_popbuf(rndr, BUFFER_BLOCK);
|
2012
|
+
return beg;
|
2013
|
+
}
|
2014
|
+
|
1877
2015
|
/* parse_listitem • parsing of a single list item */
|
1878
2016
|
/* assuming initial prefix is already removed */
|
1879
2017
|
static size_t
|
@@ -2392,7 +2530,7 @@ parse_table_header(
|
|
2392
2530
|
if (i < under_end && data[i] != '|' && data[i] != '+')
|
2393
2531
|
break;
|
2394
2532
|
|
2395
|
-
if (dashes <
|
2533
|
+
if (dashes < 1)
|
2396
2534
|
break;
|
2397
2535
|
|
2398
2536
|
i++;
|
@@ -2510,6 +2648,10 @@ parse_block(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size
|
|
2510
2648
|
(i = parse_fencedcode(ob, rndr, txt_data, end)) != 0)
|
2511
2649
|
beg += i;
|
2512
2650
|
|
2651
|
+
else if ((rndr->ext_flags & MKDEXT_FENCED_CUSTOM) != 0 &&
|
2652
|
+
(i = parse_fencedcustom(ob, rndr, txt_data, end)) != 0)
|
2653
|
+
beg += i;
|
2654
|
+
|
2513
2655
|
else if ((rndr->ext_flags & MKDEXT_TABLES) != 0 &&
|
2514
2656
|
(i = parse_table(ob, rndr, txt_data, end)) != 0)
|
2515
2657
|
beg += i;
|
@@ -2810,10 +2952,13 @@ sd_markdown_new(
|
|
2810
2952
|
if (md->cb.emphasis || md->cb.double_emphasis || md->cb.triple_emphasis) {
|
2811
2953
|
md->active_char['*'] = MD_CHAR_EMPHASIS;
|
2812
2954
|
md->active_char['_'] = MD_CHAR_EMPHASIS;
|
2955
|
+
|
2813
2956
|
if (extensions & MKDEXT_STRIKETHROUGH)
|
2814
2957
|
md->active_char['~'] = MD_CHAR_EMPHASIS;
|
2815
2958
|
if (extensions & MKDEXT_HIGHLIGHT)
|
2816
2959
|
md->active_char['='] = MD_CHAR_EMPHASIS;
|
2960
|
+
if (extensions & MKDEXT_QUOTE)
|
2961
|
+
md->active_char['"'] = MD_CHAR_QUOTE;
|
2817
2962
|
}
|
2818
2963
|
|
2819
2964
|
if (md->cb.codespan)
|
@@ -2838,9 +2983,6 @@ sd_markdown_new(
|
|
2838
2983
|
if (extensions & MKDEXT_SUPERSCRIPT)
|
2839
2984
|
md->active_char['^'] = MD_CHAR_SUPERSCRIPT;
|
2840
2985
|
|
2841
|
-
if (extensions & MKDEXT_QUOTE)
|
2842
|
-
md->active_char['"'] = MD_CHAR_QUOTE;
|
2843
|
-
|
2844
2986
|
/* Extension data */
|
2845
2987
|
md->ext_flags = extensions;
|
2846
2988
|
md->opaque = opaque;
|
@@ -2858,6 +3000,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2858
3000
|
|
2859
3001
|
struct buf *text;
|
2860
3002
|
size_t beg, end;
|
3003
|
+
int in_fence = 0;
|
2861
3004
|
|
2862
3005
|
text = bufnew(64);
|
2863
3006
|
if (!text)
|
@@ -2869,7 +3012,8 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2869
3012
|
/* reset the references table */
|
2870
3013
|
memset(&md->refs, 0x0, REF_TABLE_SIZE * sizeof(void *));
|
2871
3014
|
|
2872
|
-
int footnotes_enabled
|
3015
|
+
int footnotes_enabled = md->ext_flags & MKDEXT_FOOTNOTES;
|
3016
|
+
int codefences_enabled = md->ext_flags & MKDEXT_FENCED_CODE;
|
2873
3017
|
|
2874
3018
|
/* reset the footnotes lists */
|
2875
3019
|
if (footnotes_enabled) {
|
@@ -2885,10 +3029,13 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2885
3029
|
if (doc_size >= 3 && memcmp(document, UTF8_BOM, 3) == 0)
|
2886
3030
|
beg += 3;
|
2887
3031
|
|
2888
|
-
while (beg < doc_size) /* iterating over lines */
|
2889
|
-
if (
|
3032
|
+
while (beg < doc_size) { /* iterating over lines */
|
3033
|
+
if (codefences_enabled && (is_codefence(document + beg, doc_size - beg, NULL) != 0))
|
3034
|
+
in_fence = !in_fence;
|
3035
|
+
|
3036
|
+
if (!in_fence && footnotes_enabled && is_footnote(document, beg, doc_size, &end, &md->footnotes_found))
|
2890
3037
|
beg = end;
|
2891
|
-
else if (is_ref(document, beg, doc_size, &end, md->refs))
|
3038
|
+
else if (!in_fence && is_ref(document, beg, doc_size, &end, md->refs))
|
2892
3039
|
beg = end;
|
2893
3040
|
else { /* skipping to the next line */
|
2894
3041
|
end = beg;
|
@@ -2908,6 +3055,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2908
3055
|
|
2909
3056
|
beg = end;
|
2910
3057
|
}
|
3058
|
+
}
|
2911
3059
|
|
2912
3060
|
/* pre-grow the output buffer to minimize allocations */
|
2913
3061
|
bufgrow(ob, MARKDOWN_GROW(text->size));
|
@@ -2918,7 +3066,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2918
3066
|
|
2919
3067
|
if (text->size) {
|
2920
3068
|
/* adding a final newline if not already present */
|
2921
|
-
if (text->data[text->size - 1] != '\n' &&
|
3069
|
+
if (text->data[text->size - 1] != '\n' && text->data[text->size - 1] != '\r')
|
2922
3070
|
bufputc(text, '\n');
|
2923
3071
|
|
2924
3072
|
parse_block(ob, md, text->data, text->size);
|
@@ -2931,6 +3079,9 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2931
3079
|
if (md->cb.doc_footer)
|
2932
3080
|
md->cb.doc_footer(ob, md->opaque);
|
2933
3081
|
|
3082
|
+
/* Null-terminate the buffer */
|
3083
|
+
bufcstr(ob);
|
3084
|
+
|
2934
3085
|
/* clean-up */
|
2935
3086
|
bufrelease(text);
|
2936
3087
|
free_link_refs(md->refs);
|