redcarpet 3.2.3 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of redcarpet might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/COPYING +0 -0
- data/README.markdown +37 -0
- data/bin/redcarpet +4 -40
- data/ext/redcarpet/buffer.c +6 -6
- data/ext/redcarpet/buffer.h +1 -1
- data/ext/redcarpet/html.c +92 -27
- data/ext/redcarpet/html.h +7 -1
- data/ext/redcarpet/markdown.c +17 -8
- data/ext/redcarpet/markdown.h +0 -3
- data/ext/redcarpet/rc_markdown.c +3 -7
- data/ext/redcarpet/rc_render.c +13 -8
- data/lib/redcarpet.rb +1 -1
- data/lib/redcarpet/compat.rb +0 -3
- data/redcarpet.gemspec +5 -4
- data/test/custom_render_test.rb +1 -1
- data/test/fixtures/benchmark.md +232 -0
- data/test/html_render_test.rb +77 -76
- data/test/html_toc_render_test.rb +35 -9
- data/test/markdown_test.rb +62 -26
- data/test/redcarpet_bin_test.rb +80 -0
- data/test/redcarpet_compat_test.rb +6 -6
- data/test/test_helper.rb +15 -11
- metadata +15 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1ec4be4477178cfdbddb7bef23823f45b62fa49
|
4
|
+
data.tar.gz: 8d444aba2d98347c039435dadc795d642d92c7c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f7de4add3ffb9325b0feb63d5353cc8d946704fbd9835a7e549d8adcab9509ac78c832089fce6fb869d40b836a6db79c7050a3f469946bb33d740104f4c3164
|
7
|
+
data.tar.gz: 8cf876f963adce44ba5513028e1a01b0a79beb649233f7e7f2355b26e4148d28991c9216d32c711caa96e344713ef51886a4e85e784ce8af95f1c34fc55b3bfc
|
data/COPYING
CHANGED
File without changes
|
data/README.markdown
CHANGED
@@ -332,6 +332,43 @@ SmartyPants works on top of already-rendered HTML, and will ignore replacements
|
|
332
332
|
inside the content of HTML tags and inside specific HTML blocks such as
|
333
333
|
`<code>` or `<pre>`.
|
334
334
|
|
335
|
+
What? You really want to mix Markdown renderers?
|
336
|
+
------------------------------------------------
|
337
|
+
|
338
|
+
Redcarpet used to be a drop-in replacement for Redcloth. This is no longer the
|
339
|
+
case since version 2 -- it now has its own API, but retains the old name. Yes,
|
340
|
+
that does mean that Redcarpet is not backwards-compatible with the 1.X
|
341
|
+
versions.
|
342
|
+
|
343
|
+
Each renderer has its own API and its own set of extensions: you should choose one
|
344
|
+
(it doesn't have to be Redcarpet, though that would be great!), write your
|
345
|
+
software accordingly, and force your users to install it. That's the
|
346
|
+
only way to have reliable and predictable Markdown output on your program.
|
347
|
+
|
348
|
+
Markdown is already ill-specified enough; if you create software that is
|
349
|
+
renderer-independent, the results will be completely unreliable!
|
350
|
+
|
351
|
+
Still, if major forces (let's say, tornadoes or other natural disasters) force you
|
352
|
+
to keep a Markdown-compatibility layer, Redcarpet also supports this:
|
353
|
+
|
354
|
+
~~~~~ ruby
|
355
|
+
require 'redcarpet/compat'
|
356
|
+
~~~~~
|
357
|
+
|
358
|
+
Requiring the compatibility library will declare a `Markdown` class with the
|
359
|
+
classical RedCloth API, e.g.
|
360
|
+
|
361
|
+
~~~~~ ruby
|
362
|
+
Markdown.new('this is my text').to_html
|
363
|
+
~~~~~
|
364
|
+
|
365
|
+
This class renders 100% standards compliant Markdown with 0 extensions. Nada.
|
366
|
+
Don't even try to enable extensions with a compatibility layer, because
|
367
|
+
that's a maintenance nightmare and won't work.
|
368
|
+
|
369
|
+
On a related topic: if your Markdown gem has a `lib/markdown.rb` file that
|
370
|
+
monkeypatches the Markdown class, you're a terrible human being. Just saying.
|
371
|
+
|
335
372
|
Boring legal stuff
|
336
373
|
------------------
|
337
374
|
|
data/bin/redcarpet
CHANGED
@@ -1,43 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
|
4
|
-
# no <file> or when <file> is '-', read Markdown source text from standard input.
|
5
|
-
# With <extension>s, perform additional Markdown processing before writing output.
|
6
|
-
# With --smarty, use the SmartyHTML renderer
|
7
|
-
if ARGV.include?('--help') or ARGV.include?('-h')
|
8
|
-
File.read(__FILE__).split("\n").grep(/^# /).each do |line|
|
9
|
-
puts line[2..-1]
|
10
|
-
end
|
11
|
-
exit 0
|
12
|
-
end
|
2
|
+
lib_path = File.expand_path('../../lib', __FILE__)
|
3
|
+
$:.unshift(lib_path)
|
13
4
|
|
14
|
-
require 'redcarpet'
|
5
|
+
require 'redcarpet/cli'
|
15
6
|
|
16
|
-
|
17
|
-
puts "Redcarpet #{Redcarpet::VERSION}"
|
18
|
-
exit 0
|
19
|
-
end
|
20
|
-
|
21
|
-
root = File.expand_path('../../', __FILE__)
|
22
|
-
$:.unshift File.expand_path('lib', root)
|
23
|
-
|
24
|
-
render_extensions = {}
|
25
|
-
parse_extensions = {}
|
26
|
-
renderer = Redcarpet::Render::HTML
|
27
|
-
|
28
|
-
ARGV.delete_if do |arg|
|
29
|
-
if arg =~ /^--render-([\w-]+)$/
|
30
|
-
arg = $1.gsub('-', '_')
|
31
|
-
render_extensions[arg.to_sym] = true
|
32
|
-
elsif arg =~ /^--parse-([\w-]+)$/
|
33
|
-
arg = $1.gsub('-', '_')
|
34
|
-
parse_extensions[arg.to_sym] = true
|
35
|
-
elsif arg == '--smarty'
|
36
|
-
renderer = Redcarpet::Render::SmartyHTML
|
37
|
-
else
|
38
|
-
false
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
render = renderer.new(render_extensions)
|
43
|
-
STDOUT.write(Redcarpet::Markdown.new(render, parse_extensions).render(ARGF.read))
|
7
|
+
Redcarpet::CLI.process(ARGV)
|
data/ext/redcarpet/buffer.c
CHANGED
@@ -94,14 +94,14 @@ bufnew(size_t unit)
|
|
94
94
|
|
95
95
|
/* bufnullterm: NULL-termination of the string array */
|
96
96
|
const char *
|
97
|
-
bufcstr(struct buf *buf)
|
97
|
+
bufcstr(const struct buf *buf)
|
98
98
|
{
|
99
99
|
assert(buf && buf->unit);
|
100
100
|
|
101
101
|
if (buf->size < buf->asize && buf->data[buf->size] == 0)
|
102
102
|
return (char *)buf->data;
|
103
103
|
|
104
|
-
if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1) ==
|
104
|
+
if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1) == BUF_OK) {
|
105
105
|
buf->data[buf->size] = 0;
|
106
106
|
return (char *)buf->data;
|
107
107
|
}
|
@@ -118,7 +118,7 @@ bufprintf(struct buf *buf, const char *fmt, ...)
|
|
118
118
|
|
119
119
|
assert(buf && buf->unit);
|
120
120
|
|
121
|
-
if (buf->size >= buf->asize && bufgrow(buf, buf->size + 1) <
|
121
|
+
if (buf->size >= buf->asize && bufgrow(buf, buf->size + 1) < BUF_OK)
|
122
122
|
return;
|
123
123
|
|
124
124
|
va_start(ap, fmt);
|
@@ -136,7 +136,7 @@ bufprintf(struct buf *buf, const char *fmt, ...)
|
|
136
136
|
}
|
137
137
|
|
138
138
|
if ((size_t)n >= buf->asize - buf->size) {
|
139
|
-
if (bufgrow(buf, buf->size + n + 1) <
|
139
|
+
if (bufgrow(buf, buf->size + n + 1) < BUF_OK)
|
140
140
|
return;
|
141
141
|
|
142
142
|
va_start(ap, fmt);
|
@@ -156,7 +156,7 @@ bufput(struct buf *buf, const void *data, size_t len)
|
|
156
156
|
{
|
157
157
|
assert(buf && buf->unit);
|
158
158
|
|
159
|
-
if (buf->size + len > buf->asize && bufgrow(buf, buf->size + len) <
|
159
|
+
if (buf->size + len > buf->asize && bufgrow(buf, buf->size + len) < BUF_OK)
|
160
160
|
return;
|
161
161
|
|
162
162
|
memcpy(buf->data + buf->size, data, len);
|
@@ -177,7 +177,7 @@ bufputc(struct buf *buf, int c)
|
|
177
177
|
{
|
178
178
|
assert(buf && buf->unit);
|
179
179
|
|
180
|
-
if (buf->size + 1 > buf->asize && bufgrow(buf, buf->size + 1) <
|
180
|
+
if (buf->size + 1 > buf->asize && bufgrow(buf, buf->size + 1) < BUF_OK)
|
181
181
|
return;
|
182
182
|
|
183
183
|
buf->data[buf->size] = c;
|
data/ext/redcarpet/buffer.h
CHANGED
@@ -55,7 +55,7 @@ int bufgrow(struct buf *, size_t);
|
|
55
55
|
struct buf *bufnew(size_t) __attribute__ ((malloc));
|
56
56
|
|
57
57
|
/* bufnullterm: NUL-termination of the string array (making a C-string) */
|
58
|
-
const char *bufcstr(struct buf *);
|
58
|
+
const char *bufcstr(const struct buf *);
|
59
59
|
|
60
60
|
/* bufprefix: compare the beginning of a buffer with a string */
|
61
61
|
int bufprefix(const struct buf *buf, const char *prefix);
|
data/ext/redcarpet/html.c
CHANGED
@@ -17,7 +17,6 @@
|
|
17
17
|
|
18
18
|
#include "markdown.h"
|
19
19
|
#include "html.h"
|
20
|
-
#include "ruby.h"
|
21
20
|
#include <string.h>
|
22
21
|
#include <stdlib.h>
|
23
22
|
#include <stdio.h>
|
@@ -125,7 +124,7 @@ rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, v
|
|
125
124
|
if (lang && lang->size) {
|
126
125
|
size_t i, cls;
|
127
126
|
if (options->flags & HTML_PRETTIFY) {
|
128
|
-
BUFPUTSL(ob, "<pre><code class=\"prettyprint ");
|
127
|
+
BUFPUTSL(ob, "<pre><code class=\"prettyprint lang-");
|
129
128
|
cls++;
|
130
129
|
} else {
|
131
130
|
BUFPUTSL(ob, "<pre><code class=\"");
|
@@ -265,17 +264,56 @@ rndr_linebreak(struct buf *ob, void *opaque)
|
|
265
264
|
return 1;
|
266
265
|
}
|
267
266
|
|
268
|
-
char *header_anchor(struct buf *
|
267
|
+
char *header_anchor(const struct buf *buffer)
|
269
268
|
{
|
270
|
-
|
271
|
-
VALUE space_regex = rb_reg_new(" +", 2 /* length */, 0);
|
272
|
-
VALUE tags_regex = rb_reg_new("<\\/?[^>]*>", 10, 0);
|
269
|
+
size_t i = 0, j, k, size = buffer->size;
|
273
270
|
|
274
|
-
|
275
|
-
|
276
|
-
heading = rb_funcall(heading, rb_intern("downcase"), 0);
|
271
|
+
char text[size];
|
272
|
+
strcpy(text, bufcstr(buffer));
|
277
273
|
|
278
|
-
|
274
|
+
char raw_string[size];
|
275
|
+
|
276
|
+
/* Strip down the inline HTML markup if needed */
|
277
|
+
if (strchr(text, '<') < strchr(text, '>')) {
|
278
|
+
char* part = strtok(text, "<>");
|
279
|
+
|
280
|
+
/* Once every two times, the yielded token is the
|
281
|
+
content of a HTML tag so we don't need to copy it */
|
282
|
+
for (k = 0; part != NULL; k++) {
|
283
|
+
if (k == 0)
|
284
|
+
strcpy(raw_string, part);
|
285
|
+
else if (k % 2 == 0)
|
286
|
+
strcat(raw_string, part);
|
287
|
+
|
288
|
+
part = strtok(NULL, "<>");
|
289
|
+
}
|
290
|
+
|
291
|
+
size = strlen(raw_string);
|
292
|
+
} else {
|
293
|
+
strcpy(raw_string, text);
|
294
|
+
}
|
295
|
+
|
296
|
+
char* heading = malloc(size * sizeof(char));
|
297
|
+
|
298
|
+
/* Remove leading stripped chars */
|
299
|
+
while (STRIPPED_CHAR(raw_string[i])) i++;
|
300
|
+
|
301
|
+
/* Dasherize the string removing extra white spaces
|
302
|
+
and stripped chars */
|
303
|
+
for (j = 0; i < size; i++, j++) {
|
304
|
+
while ((i+1) < size && STRIPPED_CHAR(raw_string[i]) && STRIPPED_CHAR(raw_string[i+1]))
|
305
|
+
i++;
|
306
|
+
|
307
|
+
if (STRIPPED_CHAR(raw_string[i]) && i == size - 1)
|
308
|
+
break;
|
309
|
+
else if (STRIPPED_CHAR(raw_string[i]))
|
310
|
+
heading[j] = '-';
|
311
|
+
else
|
312
|
+
heading[j] = tolower(raw_string[i]);
|
313
|
+
}
|
314
|
+
|
315
|
+
heading[j++] = '\0';
|
316
|
+
return heading;
|
279
317
|
}
|
280
318
|
|
281
319
|
static void
|
@@ -395,15 +433,30 @@ rndr_paragraph(struct buf *ob, const struct buf *text, void *opaque)
|
|
395
433
|
static void
|
396
434
|
rndr_raw_block(struct buf *ob, const struct buf *text, void *opaque)
|
397
435
|
{
|
398
|
-
size_t org,
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
436
|
+
size_t org, size;
|
437
|
+
struct html_renderopt *options = opaque;
|
438
|
+
|
439
|
+
if (!text)
|
440
|
+
return;
|
441
|
+
|
442
|
+
size = text->size;
|
443
|
+
while (size > 0 && text->data[size - 1] == '\n')
|
444
|
+
size--;
|
445
|
+
|
446
|
+
for (org = 0; org < size && text->data[org] == '\n'; ++org)
|
447
|
+
|
448
|
+
if (org >= size)
|
449
|
+
return;
|
450
|
+
|
451
|
+
/* Remove style tags if the `:no_styles` option is enabled */
|
452
|
+
if ((options->flags & HTML_SKIP_STYLE) != 0 &&
|
453
|
+
sdhtml_is_tag(text->data, size, "style"))
|
454
|
+
return;
|
455
|
+
|
456
|
+
if (ob->size)
|
457
|
+
bufputc(ob, '\n');
|
458
|
+
|
459
|
+
bufput(ob, text->data + org, size - org);
|
407
460
|
bufputc(ob, '\n');
|
408
461
|
}
|
409
462
|
|
@@ -429,10 +482,15 @@ static int
|
|
429
482
|
rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque)
|
430
483
|
{
|
431
484
|
struct html_renderopt *options = opaque;
|
432
|
-
|
485
|
+
|
486
|
+
if (link != NULL && (options->flags & HTML_SAFELINK) != 0 && !sd_autolink_issafe(link->data, link->size))
|
487
|
+
return 0;
|
433
488
|
|
434
489
|
BUFPUTSL(ob, "<img src=\"");
|
435
|
-
|
490
|
+
|
491
|
+
if (link && link->size)
|
492
|
+
escape_href(ob, link->data, link->size);
|
493
|
+
|
436
494
|
BUFPUTSL(ob, "\" alt=\"");
|
437
495
|
|
438
496
|
if (alt && alt->size)
|
@@ -440,7 +498,8 @@ rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, cons
|
|
440
498
|
|
441
499
|
if (title && title->size) {
|
442
500
|
BUFPUTSL(ob, "\" title=\"");
|
443
|
-
escape_html(ob, title->data, title->size);
|
501
|
+
escape_html(ob, title->data, title->size);
|
502
|
+
}
|
444
503
|
|
445
504
|
bufputs(ob, USE_XHTML(options) ? "\"/>" : "\">");
|
446
505
|
return 1;
|
@@ -452,7 +511,7 @@ rndr_raw_html(struct buf *ob, const struct buf *text, void *opaque)
|
|
452
511
|
struct html_renderopt *options = opaque;
|
453
512
|
|
454
513
|
/* HTML_ESCAPE overrides SKIP_HTML, SKIP_STYLE, SKIP_LINKS and SKIP_IMAGES
|
455
|
-
|
514
|
+
It doesn't see if there are any valid tags, just escape all of them. */
|
456
515
|
if((options->flags & HTML_ESCAPE) != 0) {
|
457
516
|
escape_html(ob, text->data, text->size);
|
458
517
|
return 1;
|
@@ -636,7 +695,14 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
|
|
636
695
|
}
|
637
696
|
|
638
697
|
bufprintf(ob, "<a href=\"#%s\">", header_anchor(text));
|
639
|
-
|
698
|
+
|
699
|
+
if (text) {
|
700
|
+
if (options->flags & HTML_ESCAPE)
|
701
|
+
escape_html(ob, text->data, text->size);
|
702
|
+
else
|
703
|
+
bufput(ob, text->data, text->size);
|
704
|
+
}
|
705
|
+
|
640
706
|
BUFPUTSL(ob, "</a>\n");
|
641
707
|
}
|
642
708
|
}
|
@@ -661,7 +727,7 @@ toc_finalize(struct buf *ob, void *opaque)
|
|
661
727
|
}
|
662
728
|
|
663
729
|
void
|
664
|
-
sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options, int
|
730
|
+
sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options, unsigned int render_flags)
|
665
731
|
{
|
666
732
|
static const struct sd_callbacks cb_default = {
|
667
733
|
NULL,
|
@@ -702,8 +768,7 @@ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *optio
|
|
702
768
|
};
|
703
769
|
|
704
770
|
memset(options, 0x0, sizeof(struct html_renderopt));
|
705
|
-
options->flags =
|
706
|
-
options->toc_data.nesting_level = nesting_level;
|
771
|
+
options->flags = render_flags;
|
707
772
|
|
708
773
|
memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks));
|
709
774
|
}
|
data/ext/redcarpet/html.h
CHANGED
@@ -65,11 +65,17 @@ extern void
|
|
65
65
|
sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, unsigned int render_flags);
|
66
66
|
|
67
67
|
extern void
|
68
|
-
sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, int
|
68
|
+
sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, unsigned int render_flags);
|
69
69
|
|
70
70
|
extern void
|
71
71
|
sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size);
|
72
72
|
|
73
|
+
/* header method used internally in Redcarpet */
|
74
|
+
char *header_anchor(const struct buf *buffer);
|
75
|
+
|
76
|
+
#define STRIPPED_CHARS " -&+$,/:;=?@\"#{}|^~[]`\\*()%.!'"
|
77
|
+
#define STRIPPED_CHAR(x) (strchr(STRIPPED_CHARS, x) != NULL)
|
78
|
+
|
73
79
|
#ifdef __cplusplus
|
74
80
|
}
|
75
81
|
#endif
|
data/ext/redcarpet/markdown.c
CHANGED
@@ -1119,7 +1119,7 @@ char_link(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t offset
|
|
1119
1119
|
title_e--;
|
1120
1120
|
|
1121
1121
|
/* checking for closing quote presence */
|
1122
|
-
if (data[title_e] != '\'' &&
|
1122
|
+
if (data[title_e] != '\'' && data[title_e] != '"') {
|
1123
1123
|
title_b = title_e = 0;
|
1124
1124
|
link_e = i;
|
1125
1125
|
}
|
@@ -1548,7 +1548,7 @@ prefix_oli(uint8_t *data, size_t size)
|
|
1548
1548
|
return i + 2;
|
1549
1549
|
}
|
1550
1550
|
|
1551
|
-
/* prefix_uli • returns
|
1551
|
+
/* prefix_uli • returns unordered list item prefix */
|
1552
1552
|
static size_t
|
1553
1553
|
prefix_uli(uint8_t *data, size_t size)
|
1554
1554
|
{
|
@@ -1620,7 +1620,7 @@ parse_blockquote(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t
|
|
1620
1620
|
static size_t
|
1621
1621
|
parse_htmlblock(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size, int do_render);
|
1622
1622
|
|
1623
|
-
/*
|
1623
|
+
/* parse_paragraph • handles parsing of a regular paragraph */
|
1624
1624
|
static size_t
|
1625
1625
|
parse_paragraph(struct buf *ob, struct sd_markdown *rndr, uint8_t *data, size_t size)
|
1626
1626
|
{
|
@@ -2801,6 +2801,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2801
2801
|
|
2802
2802
|
struct buf *text;
|
2803
2803
|
size_t beg, end;
|
2804
|
+
int in_fence = 0;
|
2804
2805
|
|
2805
2806
|
text = bufnew(64);
|
2806
2807
|
if (!text)
|
@@ -2812,7 +2813,8 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2812
2813
|
/* reset the references table */
|
2813
2814
|
memset(&md->refs, 0x0, REF_TABLE_SIZE * sizeof(void *));
|
2814
2815
|
|
2815
|
-
int footnotes_enabled
|
2816
|
+
int footnotes_enabled = md->ext_flags & MKDEXT_FOOTNOTES;
|
2817
|
+
int codefences_enabled = md->ext_flags & MKDEXT_FENCED_CODE;
|
2816
2818
|
|
2817
2819
|
/* reset the footnotes lists */
|
2818
2820
|
if (footnotes_enabled) {
|
@@ -2828,10 +2830,13 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2828
2830
|
if (doc_size >= 3 && memcmp(document, UTF8_BOM, 3) == 0)
|
2829
2831
|
beg += 3;
|
2830
2832
|
|
2831
|
-
while (beg < doc_size) /* iterating over lines */
|
2832
|
-
if (
|
2833
|
+
while (beg < doc_size) { /* iterating over lines */
|
2834
|
+
if (codefences_enabled && (is_codefence(document + beg, doc_size - beg, NULL) != 0))
|
2835
|
+
in_fence = !in_fence;
|
2836
|
+
|
2837
|
+
if (!in_fence && footnotes_enabled && is_footnote(document, beg, doc_size, &end, &md->footnotes_found))
|
2833
2838
|
beg = end;
|
2834
|
-
else if (is_ref(document, beg, doc_size, &end, md->refs))
|
2839
|
+
else if (!in_fence && is_ref(document, beg, doc_size, &end, md->refs))
|
2835
2840
|
beg = end;
|
2836
2841
|
else { /* skipping to the next line */
|
2837
2842
|
end = beg;
|
@@ -2851,6 +2856,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2851
2856
|
|
2852
2857
|
beg = end;
|
2853
2858
|
}
|
2859
|
+
}
|
2854
2860
|
|
2855
2861
|
/* pre-grow the output buffer to minimize allocations */
|
2856
2862
|
bufgrow(ob, MARKDOWN_GROW(text->size));
|
@@ -2861,7 +2867,7 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2861
2867
|
|
2862
2868
|
if (text->size) {
|
2863
2869
|
/* adding a final newline if not already present */
|
2864
|
-
if (text->data[text->size - 1] != '\n' &&
|
2870
|
+
if (text->data[text->size - 1] != '\n' && text->data[text->size - 1] != '\r')
|
2865
2871
|
bufputc(text, '\n');
|
2866
2872
|
|
2867
2873
|
parse_block(ob, md, text->data, text->size);
|
@@ -2874,6 +2880,9 @@ sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, str
|
|
2874
2880
|
if (md->cb.doc_footer)
|
2875
2881
|
md->cb.doc_footer(ob, md->opaque);
|
2876
2882
|
|
2883
|
+
/* Null-terminate the buffer */
|
2884
|
+
bufcstr(ob);
|
2885
|
+
|
2877
2886
|
/* clean-up */
|
2878
2887
|
bufrelease(text);
|
2879
2888
|
free_link_refs(md->refs);
|