redcarpet 1.1.1 → 1.2.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.
- data/ext/markdown.c +139 -111
- data/ext/markdown.h +14 -4
- data/ext/redcarpet.c +41 -7
- data/ext/render.c +12 -9
- data/ext/toc.c +101 -0
- data/lib/redcarpet.rb +4 -5
- data/redcarpet.gemspec +2 -1
- data/test/redcarpet_test.rb +13 -0
- metadata +5 -4
data/ext/markdown.c
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
/*
|
4
4
|
* Copyright (c) 2009, Natacha Porté
|
5
|
+
* Copyright (c) 2011, Vicent Marti
|
5
6
|
*
|
6
7
|
* Permission to use, copy, modify, and distribute this software for any
|
7
8
|
* purpose with or without fee is hereby granted, provided that the above
|
@@ -35,10 +36,10 @@
|
|
35
36
|
|
36
37
|
/* link_ref • reference to a link */
|
37
38
|
struct link_ref {
|
38
|
-
struct buf *
|
39
|
-
struct buf *
|
40
|
-
struct buf *
|
41
|
-
|
39
|
+
struct buf *id;
|
40
|
+
struct buf *link;
|
41
|
+
struct buf *title;
|
42
|
+
};
|
42
43
|
|
43
44
|
/* char_trigger • function pointer to render active chars */
|
44
45
|
/* returns the number of chars taken care of */
|
@@ -46,27 +47,24 @@ struct link_ref {
|
|
46
47
|
/* offset is the number of valid chars before data */
|
47
48
|
struct render;
|
48
49
|
typedef size_t
|
49
|
-
(*char_trigger)(struct buf *ob, struct render *rndr,
|
50
|
-
char *data, size_t offset, size_t size);
|
50
|
+
(*char_trigger)(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size);
|
51
51
|
|
52
52
|
|
53
53
|
/* render • structure containing one particular render */
|
54
54
|
struct render {
|
55
55
|
struct mkd_renderer make;
|
56
|
-
struct array
|
57
|
-
char_trigger
|
58
|
-
struct parray
|
56
|
+
struct array refs;
|
57
|
+
char_trigger active_char[256];
|
58
|
+
struct parray work;
|
59
|
+
int header_count;
|
59
60
|
};
|
60
61
|
|
61
|
-
|
62
62
|
/* html_tag • structure for quick HTML tag search (inspired from discount) */
|
63
63
|
struct html_tag {
|
64
64
|
const char *text;
|
65
65
|
size_t size;
|
66
66
|
};
|
67
67
|
|
68
|
-
|
69
|
-
|
70
68
|
/********************
|
71
69
|
* GLOBAL VARIABLES *
|
72
70
|
********************/
|
@@ -94,44 +92,48 @@ static struct html_tag block_tags[] = {
|
|
94
92
|
{ "script", 6 },
|
95
93
|
{ "fieldset", 8 },
|
96
94
|
{ "noscript", 8 },
|
97
|
-
{ "blockquote", 10 }
|
95
|
+
{ "blockquote", 10 }
|
96
|
+
};
|
98
97
|
|
99
98
|
#define INS_TAG (block_tags + 12)
|
100
99
|
#define DEL_TAG (block_tags + 10)
|
101
100
|
|
102
|
-
|
103
|
-
|
104
101
|
/***************************
|
105
102
|
* STATIC HELPER FUNCTIONS *
|
106
103
|
***************************/
|
107
104
|
|
108
105
|
/* cmp_link_ref • comparison function for link_ref sorted arrays */
|
109
106
|
static int
|
110
|
-
cmp_link_ref(void *key, void *array_entry)
|
107
|
+
cmp_link_ref(void *key, void *array_entry)
|
108
|
+
{
|
111
109
|
struct link_ref *lr = array_entry;
|
112
|
-
return bufcasecmp(key, lr->id);
|
113
|
-
|
110
|
+
return bufcasecmp(key, lr->id);
|
111
|
+
}
|
114
112
|
|
115
113
|
/* cmp_link_ref_sort • comparison function for link_ref qsort */
|
116
114
|
static int
|
117
|
-
cmp_link_ref_sort(const void *a, const void *b)
|
115
|
+
cmp_link_ref_sort(const void *a, const void *b)
|
116
|
+
{
|
118
117
|
const struct link_ref *lra = a;
|
119
118
|
const struct link_ref *lrb = b;
|
120
|
-
return bufcasecmp(lra->id, lrb->id);
|
121
|
-
|
119
|
+
return bufcasecmp(lra->id, lrb->id);
|
120
|
+
}
|
122
121
|
|
123
122
|
/* cmp_html_tag • comparison function for bsearch() (stolen from discount) */
|
124
123
|
static int
|
125
|
-
cmp_html_tag(const void *a, const void *b)
|
124
|
+
cmp_html_tag(const void *a, const void *b)
|
125
|
+
{
|
126
126
|
const struct html_tag *hta = a;
|
127
127
|
const struct html_tag *htb = b;
|
128
128
|
if (hta->size != htb->size) return (int)((ssize_t)hta->size - (ssize_t)htb->size);
|
129
|
-
return strncasecmp(hta->text, htb->text, hta->size);
|
129
|
+
return strncasecmp(hta->text, htb->text, hta->size);
|
130
|
+
}
|
130
131
|
|
131
132
|
|
132
133
|
/* find_block_tag • returns the current block tag */
|
133
134
|
static struct html_tag *
|
134
|
-
find_block_tag(char *data, size_t size)
|
135
|
+
find_block_tag(char *data, size_t size)
|
136
|
+
{
|
135
137
|
size_t i = 0;
|
136
138
|
struct html_tag key;
|
137
139
|
|
@@ -147,9 +149,8 @@ find_block_tag(char *data, size_t size) {
|
|
147
149
|
key.size = i;
|
148
150
|
return bsearch(&key, block_tags,
|
149
151
|
sizeof block_tags / sizeof block_tags[0],
|
150
|
-
sizeof block_tags[0], cmp_html_tag);
|
151
|
-
|
152
|
-
|
152
|
+
sizeof block_tags[0], cmp_html_tag);
|
153
|
+
}
|
153
154
|
|
154
155
|
/****************************
|
155
156
|
* INLINE PARSING FUNCTIONS *
|
@@ -158,7 +159,8 @@ find_block_tag(char *data, size_t size) {
|
|
158
159
|
/* is_mail_autolink • looks for the address part of a mail autolink and '>' */
|
159
160
|
/* this is less strict than the original markdown e-mail address matching */
|
160
161
|
static size_t
|
161
|
-
is_mail_autolink(char *data, size_t size)
|
162
|
+
is_mail_autolink(char *data, size_t size)
|
163
|
+
{
|
162
164
|
size_t i = 0, nb = 0;
|
163
165
|
/* address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' */
|
164
166
|
while (i < size && (data[i] == '-' || data[i] == '.'
|
@@ -169,12 +171,13 @@ is_mail_autolink(char *data, size_t size) {
|
|
169
171
|
if (data[i] == '@') nb += 1;
|
170
172
|
i += 1; }
|
171
173
|
if (i >= size || data[i] != '>' || nb != 1) return 0;
|
172
|
-
return i + 1;
|
173
|
-
|
174
|
+
return i + 1;
|
175
|
+
}
|
174
176
|
|
175
177
|
/* tag_length • returns the length of the given tag, or 0 is it's not valid */
|
176
178
|
static size_t
|
177
|
-
tag_length(char *data, size_t size, enum mkd_autolink *autolink)
|
179
|
+
tag_length(char *data, size_t size, enum mkd_autolink *autolink)
|
180
|
+
{
|
178
181
|
size_t i, j;
|
179
182
|
|
180
183
|
/* a valid tag can't be shorter than 3 chars */
|
@@ -225,12 +228,13 @@ tag_length(char *data, size_t size, enum mkd_autolink *autolink) {
|
|
225
228
|
/* looking for sometinhg looking like a tag end */
|
226
229
|
while (i < size && data[i] != '>') i += 1;
|
227
230
|
if (i >= size) return 0;
|
228
|
-
return i + 1;
|
229
|
-
|
231
|
+
return i + 1;
|
232
|
+
}
|
230
233
|
|
231
234
|
/* parse_inline • parses inline markdown elements */
|
232
235
|
static void
|
233
|
-
parse_inline(struct buf *ob, struct render *rndr, char *data, size_t size)
|
236
|
+
parse_inline(struct buf *ob, struct render *rndr, char *data, size_t size)
|
237
|
+
{
|
234
238
|
size_t i = 0, end = 0;
|
235
239
|
char_trigger action = 0;
|
236
240
|
struct buf work = { 0, 0, 0, 0, 0 };
|
@@ -256,12 +260,13 @@ parse_inline(struct buf *ob, struct render *rndr, char *data, size_t size) {
|
|
256
260
|
end = i + 1;
|
257
261
|
else {
|
258
262
|
i += end;
|
259
|
-
end = i; } }
|
260
|
-
|
263
|
+
end = i; } }
|
264
|
+
}
|
261
265
|
|
262
266
|
/* find_emph_char • looks for the next emph char, skipping other constructs */
|
263
267
|
static size_t
|
264
|
-
find_emph_char(char *data, size_t size, char c)
|
268
|
+
find_emph_char(char *data, size_t size, char c)
|
269
|
+
{
|
265
270
|
size_t i = 1;
|
266
271
|
|
267
272
|
while (i < size) {
|
@@ -306,14 +311,14 @@ find_emph_char(char *data, size_t size, char c) {
|
|
306
311
|
i += 1; }
|
307
312
|
if (i >= size) return tmp_i;
|
308
313
|
i += 1; } }
|
309
|
-
return 0;
|
310
|
-
|
314
|
+
return 0;
|
315
|
+
}
|
311
316
|
|
312
317
|
/* parse_emph1 • parsing single emphase */
|
313
318
|
/* closed by a symbol not preceded by whitespace and not followed by symbol */
|
314
319
|
static size_t
|
315
|
-
parse_emph1(struct buf *ob, struct render *rndr,
|
316
|
-
|
320
|
+
parse_emph1(struct buf *ob, struct render *rndr, char *data, size_t size, char c)
|
321
|
+
{
|
317
322
|
size_t i = 0, len;
|
318
323
|
struct buf *work = 0;
|
319
324
|
int r;
|
@@ -359,11 +364,10 @@ parse_emph1(struct buf *ob, struct render *rndr,
|
|
359
364
|
return 0;
|
360
365
|
}
|
361
366
|
|
362
|
-
|
363
367
|
/* parse_emph2 • parsing single emphase */
|
364
368
|
static size_t
|
365
|
-
parse_emph2(struct buf *ob, struct render *rndr,
|
366
|
-
|
369
|
+
parse_emph2(struct buf *ob, struct render *rndr, char *data, size_t size, char c)
|
370
|
+
{
|
367
371
|
size_t i = 0, len;
|
368
372
|
struct buf *work = 0;
|
369
373
|
int r;
|
@@ -389,14 +393,14 @@ parse_emph2(struct buf *ob, struct render *rndr,
|
|
389
393
|
rndr->work.size -= 1;
|
390
394
|
return r ? i + 2 : 0; }
|
391
395
|
i += 1; }
|
392
|
-
return 0;
|
393
|
-
|
396
|
+
return 0;
|
397
|
+
}
|
394
398
|
|
395
399
|
/* parse_emph3 • parsing single emphase */
|
396
400
|
/* finds the first closing tag, and delegates to the other emph */
|
397
401
|
static size_t
|
398
|
-
parse_emph3(struct buf *ob, struct render *rndr,
|
399
|
-
|
402
|
+
parse_emph3(struct buf *ob, struct render *rndr, char *data, size_t size, char c)
|
403
|
+
{
|
400
404
|
size_t i = 0, len;
|
401
405
|
int r;
|
402
406
|
|
@@ -435,13 +439,13 @@ parse_emph3(struct buf *ob, struct render *rndr,
|
|
435
439
|
len = parse_emph2(ob, rndr, data - 1, size + 1, c);
|
436
440
|
if (!len) return 0;
|
437
441
|
else return len - 1; } }
|
438
|
-
return 0;
|
439
|
-
|
442
|
+
return 0;
|
443
|
+
}
|
440
444
|
|
441
445
|
/* char_emphasis • single and double emphasis parsing */
|
442
446
|
static size_t
|
443
|
-
char_emphasis(struct buf *ob, struct render *rndr,
|
444
|
-
|
447
|
+
char_emphasis(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
|
448
|
+
{
|
445
449
|
char c = data[0];
|
446
450
|
size_t ret;
|
447
451
|
if (size > 2 && data[1] != c) {
|
@@ -460,13 +464,14 @@ char_emphasis(struct buf *ob, struct render *rndr,
|
|
460
464
|
|| (ret = parse_emph3(ob, rndr, data + 3, size - 3, c)) == 0)
|
461
465
|
return 0;
|
462
466
|
return ret + 3; }
|
463
|
-
return 0;
|
467
|
+
return 0;
|
468
|
+
}
|
464
469
|
|
465
470
|
|
466
471
|
/* char_linebreak • '\n' preceded by two spaces (assuming linebreak != 0) */
|
467
472
|
static size_t
|
468
|
-
char_linebreak(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
|
469
|
-
|
473
|
+
char_linebreak(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
|
474
|
+
{
|
470
475
|
if (offset < 2 || data[-1] != ' ' || data[-2] != ' ')
|
471
476
|
return 0;
|
472
477
|
|
@@ -516,8 +521,8 @@ char_codespan(struct buf *ob, struct render *rndr, char *data, size_t offset, si
|
|
516
521
|
|
517
522
|
/* char_escape • '\\' backslash escape */
|
518
523
|
static size_t
|
519
|
-
char_escape(struct buf *ob, struct render *rndr,
|
520
|
-
|
524
|
+
char_escape(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
|
525
|
+
{
|
521
526
|
struct buf work = { 0, 0, 0, 0, 0 };
|
522
527
|
if (size > 1) {
|
523
528
|
if (rndr->make.normal_text) {
|
@@ -525,14 +530,14 @@ char_escape(struct buf *ob, struct render *rndr,
|
|
525
530
|
work.size = 1;
|
526
531
|
rndr->make.normal_text(ob, &work, &rndr->make.render_options); }
|
527
532
|
else bufputc(ob, data[1]); }
|
528
|
-
return 2;
|
529
|
-
|
533
|
+
return 2;
|
534
|
+
}
|
530
535
|
|
531
536
|
/* char_entity • '&' escaped when it doesn't belong to an entity */
|
532
537
|
/* valid entities are assumed to be anything mathing &#?[A-Za-z0-9]+; */
|
533
538
|
static size_t
|
534
|
-
char_entity(struct buf *ob, struct render *rndr,
|
535
|
-
|
539
|
+
char_entity(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
|
540
|
+
{
|
536
541
|
size_t end = 1;
|
537
542
|
struct buf work;
|
538
543
|
if (end < size && data[end] == '#') end += 1;
|
@@ -552,13 +557,13 @@ char_entity(struct buf *ob, struct render *rndr,
|
|
552
557
|
work.size = end;
|
553
558
|
rndr->make.entity(ob, &work, &rndr->make.render_options); }
|
554
559
|
else bufput(ob, data, end);
|
555
|
-
return end;
|
556
|
-
|
560
|
+
return end;
|
561
|
+
}
|
557
562
|
|
558
563
|
/* char_langle_tag • '<' when tags or autolinks are allowed */
|
559
564
|
static size_t
|
560
|
-
char_langle_tag(struct buf *ob, struct render *rndr,
|
561
|
-
|
565
|
+
char_langle_tag(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
|
566
|
+
{
|
562
567
|
enum mkd_autolink altype = MKDA_NOT_AUTOLINK;
|
563
568
|
size_t end = tag_length(data, size, &altype);
|
564
569
|
struct buf work = { data, end, 0, 0, 0 };
|
@@ -573,13 +578,14 @@ char_langle_tag(struct buf *ob, struct render *rndr,
|
|
573
578
|
ret = rndr->make.raw_html_tag(ob, &work,
|
574
579
|
&rndr->make.render_options); }
|
575
580
|
if (!ret) return 0;
|
576
|
-
else return end;
|
581
|
+
else return end;
|
582
|
+
}
|
577
583
|
|
578
584
|
|
579
585
|
/* char_link • '[': parsing a link or an image */
|
580
586
|
static size_t
|
581
|
-
char_link(struct buf *ob, struct render *rndr,
|
582
|
-
|
587
|
+
char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
|
588
|
+
{
|
583
589
|
int is_img = (offset && data[-1] == '!'), level;
|
584
590
|
size_t i = 1, txt_e, link_b = 0, link_e = 0, title_b = 0, title_e = 0;
|
585
591
|
struct buf *content = 0;
|
@@ -785,16 +791,18 @@ char_link(struct buf *ob, struct render *rndr,
|
|
785
791
|
|
786
792
|
/* is_empty • returns the line length when it is empty, 0 otherwise */
|
787
793
|
static size_t
|
788
|
-
is_empty(char *data, size_t size)
|
794
|
+
is_empty(char *data, size_t size)
|
795
|
+
{
|
789
796
|
size_t i;
|
790
797
|
for (i = 0; i < size && data[i] != '\n'; i += 1)
|
791
798
|
if (data[i] != ' ' && data[i] != '\t') return 0;
|
792
|
-
return i + 1;
|
793
|
-
|
799
|
+
return i + 1;
|
800
|
+
}
|
794
801
|
|
795
802
|
/* is_hrule • returns whether a line is a horizontal rule */
|
796
803
|
static int
|
797
|
-
is_hrule(char *data, size_t size)
|
804
|
+
is_hrule(char *data, size_t size)
|
805
|
+
{
|
798
806
|
size_t i = 0, n = 0;
|
799
807
|
char c;
|
800
808
|
|
@@ -817,12 +825,13 @@ is_hrule(char *data, size_t size) {
|
|
817
825
|
return 0;
|
818
826
|
i += 1; }
|
819
827
|
|
820
|
-
return n >= 3;
|
821
|
-
|
828
|
+
return n >= 3;
|
829
|
+
}
|
822
830
|
|
823
831
|
/* is_headerline • returns whether the line is a setext-style hdr underline */
|
824
832
|
static int
|
825
|
-
is_headerline(char *data, size_t size)
|
833
|
+
is_headerline(char *data, size_t size)
|
834
|
+
{
|
826
835
|
size_t i = 0;
|
827
836
|
|
828
837
|
/* test of level 1 header */
|
@@ -837,12 +846,13 @@ is_headerline(char *data, size_t size) {
|
|
837
846
|
while (i < size && (data[i] == ' ' || data[i] == '\t')) i += 1;
|
838
847
|
return (i >= size || data[i] == '\n') ? 2 : 0; }
|
839
848
|
|
840
|
-
return 0;
|
841
|
-
|
849
|
+
return 0;
|
850
|
+
}
|
842
851
|
|
843
852
|
/* prefix_quote • returns blockquote prefix length */
|
844
853
|
static size_t
|
845
|
-
prefix_quote(char *data, size_t size)
|
854
|
+
prefix_quote(char *data, size_t size)
|
855
|
+
{
|
846
856
|
size_t i = 0;
|
847
857
|
if (i < size && data[i] == ' ') i += 1;
|
848
858
|
if (i < size && data[i] == ' ') i += 1;
|
@@ -851,20 +861,23 @@ prefix_quote(char *data, size_t size) {
|
|
851
861
|
if (i + 1 < size && (data[i + 1] == ' ' || data[i+1] == '\t'))
|
852
862
|
return i + 2;
|
853
863
|
else return i + 1; }
|
854
|
-
else return 0;
|
855
|
-
|
864
|
+
else return 0;
|
865
|
+
}
|
856
866
|
|
857
867
|
/* prefix_code • returns prefix length for block code*/
|
858
868
|
static size_t
|
859
|
-
prefix_code(char *data, size_t size)
|
869
|
+
prefix_code(char *data, size_t size)
|
870
|
+
{
|
860
871
|
if (size > 0 && data[0] == '\t') return 1;
|
861
872
|
if (size > 3 && data[0] == ' ' && data[1] == ' '
|
862
873
|
&& data[2] == ' ' && data[3] == ' ') return 4;
|
863
|
-
return 0;
|
874
|
+
return 0;
|
875
|
+
}
|
864
876
|
|
865
877
|
/* prefix_oli • returns ordered list item prefix */
|
866
878
|
static size_t
|
867
|
-
prefix_oli(char *data, size_t size)
|
879
|
+
prefix_oli(char *data, size_t size)
|
880
|
+
{
|
868
881
|
size_t i = 0;
|
869
882
|
if (i < size && data[i] == ' ') i += 1;
|
870
883
|
if (i < size && data[i] == ' ') i += 1;
|
@@ -873,12 +886,13 @@ prefix_oli(char *data, size_t size) {
|
|
873
886
|
while (i < size && data[i] >= '0' && data[i] <= '9') i += 1;
|
874
887
|
if (i + 1 >= size || data[i] != '.'
|
875
888
|
|| (data[i + 1] != ' ' && data[i + 1] != '\t')) return 0;
|
876
|
-
return i + 2;
|
877
|
-
|
889
|
+
return i + 2;
|
890
|
+
}
|
878
891
|
|
879
892
|
/* prefix_uli • returns ordered list item prefix */
|
880
893
|
static size_t
|
881
|
-
prefix_uli(char *data, size_t size)
|
894
|
+
prefix_uli(char *data, size_t size)
|
895
|
+
{
|
882
896
|
size_t i = 0;
|
883
897
|
if (i < size && data[i] == ' ') i += 1;
|
884
898
|
if (i < size && data[i] == ' ') i += 1;
|
@@ -887,7 +901,8 @@ prefix_uli(char *data, size_t size) {
|
|
887
901
|
|| (data[i] != '*' && data[i] != '+' && data[i] != '-')
|
888
902
|
|| (data[i + 1] != ' ' && data[i + 1] != '\t'))
|
889
903
|
return 0;
|
890
|
-
return i + 2;
|
904
|
+
return i + 2;
|
905
|
+
}
|
891
906
|
|
892
907
|
|
893
908
|
/* parse_block • parsing of one block, returning next char to parse */
|
@@ -897,7 +912,8 @@ static void parse_block(struct buf *ob, struct render *rndr,
|
|
897
912
|
|
898
913
|
/* parse_blockquote • hanldes parsing of a blockquote fragment */
|
899
914
|
static size_t
|
900
|
-
parse_blockquote(struct buf *ob, struct render *rndr, char *data, size_t size, int depth)
|
915
|
+
parse_blockquote(struct buf *ob, struct render *rndr, char *data, size_t size, int depth)
|
916
|
+
{
|
901
917
|
size_t beg, end = 0, pre, work_size = 0;
|
902
918
|
char *work_data = 0;
|
903
919
|
struct buf *out = 0;
|
@@ -942,8 +958,8 @@ parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, in
|
|
942
958
|
|
943
959
|
/* parse_blockquote • hanldes parsing of a regular paragraph */
|
944
960
|
static size_t
|
945
|
-
parse_paragraph(struct buf *ob, struct render *rndr,
|
946
|
-
|
961
|
+
parse_paragraph(struct buf *ob, struct render *rndr, char *data, size_t size)
|
962
|
+
{
|
947
963
|
size_t i = 0, end = 0;
|
948
964
|
int level = 0;
|
949
965
|
struct buf work = { data, 0, 0, 0, 0 }; /* volatile working buffer */
|
@@ -1015,14 +1031,14 @@ parse_paragraph(struct buf *ob, struct render *rndr,
|
|
1015
1031
|
work.size = i - beg; }
|
1016
1032
|
else work.size = i; }
|
1017
1033
|
if (rndr->make.header)
|
1018
|
-
rndr->make.header(ob, &work, level, &rndr->make.render_options);}
|
1019
|
-
return end;
|
1020
|
-
|
1034
|
+
rndr->make.header(ob, &work, level, rndr->header_count++, &rndr->make.render_options);}
|
1035
|
+
return end;
|
1036
|
+
}
|
1021
1037
|
|
1022
1038
|
/* parse_blockquote • hanldes parsing of a block-level code fragment */
|
1023
1039
|
static size_t
|
1024
|
-
parse_blockcode(struct buf *ob, struct render *rndr,
|
1025
|
-
|
1040
|
+
parse_blockcode(struct buf *ob, struct render *rndr, char *data, size_t size)
|
1041
|
+
{
|
1026
1042
|
size_t beg, end, pre;
|
1027
1043
|
struct buf *work = 0;
|
1028
1044
|
|
@@ -1056,8 +1072,8 @@ parse_blockcode(struct buf *ob, struct render *rndr,
|
|
1056
1072
|
if (rndr->make.blockcode)
|
1057
1073
|
rndr->make.blockcode(ob, work, &rndr->make.render_options);
|
1058
1074
|
rndr->work.size -= 1;
|
1059
|
-
return beg;
|
1060
|
-
|
1075
|
+
return beg;
|
1076
|
+
}
|
1061
1077
|
|
1062
1078
|
/* parse_listitem • parsing of a single list item */
|
1063
1079
|
/* assuming initial prefix is already removed */
|
@@ -1188,7 +1204,8 @@ parse_listitem(struct buf *ob, struct render *rndr, char *data, size_t size, int
|
|
1188
1204
|
|
1189
1205
|
/* parse_list • parsing ordered or unordered list block */
|
1190
1206
|
static size_t
|
1191
|
-
parse_list(struct buf *ob, struct render *rndr, char *data, size_t size, int flags, int depth)
|
1207
|
+
parse_list(struct buf *ob, struct render *rndr, char *data, size_t size, int flags, int depth)
|
1208
|
+
{
|
1192
1209
|
struct buf *work = 0;
|
1193
1210
|
size_t i = 0, j;
|
1194
1211
|
|
@@ -1216,7 +1233,8 @@ parse_list(struct buf *ob, struct render *rndr, char *data, size_t size, int fla
|
|
1216
1233
|
|
1217
1234
|
/* parse_atxheader • parsing of atx-style headers */
|
1218
1235
|
static size_t
|
1219
|
-
parse_atxheader(struct buf *ob, struct render *rndr, char *data, size_t size)
|
1236
|
+
parse_atxheader(struct buf *ob, struct render *rndr, char *data, size_t size)
|
1237
|
+
{
|
1220
1238
|
size_t level = 0;
|
1221
1239
|
size_t i, end, skip;
|
1222
1240
|
struct buf work = { data, 0, 0, 0, 0 };
|
@@ -1232,7 +1250,7 @@ parse_atxheader(struct buf *ob, struct render *rndr, char *data, size_t size) {
|
|
1232
1250
|
while (end && (data[end - 1] == ' ' || data[end - 1] == '\t')) end -= 1;
|
1233
1251
|
work.size = end - i;
|
1234
1252
|
if (rndr->make.header)
|
1235
|
-
rndr->make.header(ob, &work, (int)level, &rndr->make.render_options);
|
1253
|
+
rndr->make.header(ob, &work, (int)level, rndr->header_count++, &rndr->make.render_options);
|
1236
1254
|
return skip;
|
1237
1255
|
}
|
1238
1256
|
|
@@ -1240,7 +1258,8 @@ parse_atxheader(struct buf *ob, struct render *rndr, char *data, size_t size) {
|
|
1240
1258
|
/* htmlblock_end • checking end of HTML block : </tag>[ \t]*\n[ \t*]\n */
|
1241
1259
|
/* returns the length on match, 0 otherwise */
|
1242
1260
|
static size_t
|
1243
|
-
htmlblock_end(struct html_tag *tag, char *data, size_t size)
|
1261
|
+
htmlblock_end(struct html_tag *tag, char *data, size_t size)
|
1262
|
+
{
|
1244
1263
|
size_t i, w;
|
1245
1264
|
|
1246
1265
|
/* assuming data[0] == '<' && data[1] == '/' already tested */
|
@@ -1274,7 +1293,8 @@ htmlblock_end(struct html_tag *tag, char *data, size_t size) {
|
|
1274
1293
|
|
1275
1294
|
/* parse_htmlblock • parsing of inline HTML block */
|
1276
1295
|
static size_t
|
1277
|
-
parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, int do_render)
|
1296
|
+
parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, int do_render)
|
1297
|
+
{
|
1278
1298
|
size_t i, j = 0;
|
1279
1299
|
struct html_tag *curtag;
|
1280
1300
|
int found;
|
@@ -1382,7 +1402,8 @@ parse_htmlblock(struct buf *ob, struct render *rndr, char *data, size_t size, in
|
|
1382
1402
|
|
1383
1403
|
/* parse_block • parsing of one block, returning next char to parse */
|
1384
1404
|
static void
|
1385
|
-
parse_block(struct buf *ob, struct render *rndr, char *data, size_t size, int depth)
|
1405
|
+
parse_block(struct buf *ob, struct render *rndr, char *data, size_t size, int depth)
|
1406
|
+
{
|
1386
1407
|
size_t beg, end, i;
|
1387
1408
|
char *txt_data;
|
1388
1409
|
beg = 0;
|
@@ -1426,7 +1447,8 @@ parse_block(struct buf *ob, struct render *rndr, char *data, size_t size, int de
|
|
1426
1447
|
|
1427
1448
|
/* is_ref • returns whether a line is a reference or not */
|
1428
1449
|
static int
|
1429
|
-
is_ref(char *data, size_t beg, size_t end, size_t *last, struct array *refs)
|
1450
|
+
is_ref(char *data, size_t beg, size_t end, size_t *last, struct array *refs)
|
1451
|
+
{
|
1430
1452
|
/* int n; */
|
1431
1453
|
size_t i = 0;
|
1432
1454
|
size_t id_offset, id_end;
|
@@ -1523,13 +1545,9 @@ is_ref(char *data, size_t beg, size_t end, size_t *last, struct array *refs) {
|
|
1523
1545
|
bufput(lr->title, data + title_offset,
|
1524
1546
|
title_end - title_offset); }
|
1525
1547
|
else lr->title = 0;
|
1526
|
-
return 1;
|
1527
|
-
|
1528
|
-
|
1548
|
+
return 1;
|
1549
|
+
}
|
1529
1550
|
|
1530
|
-
/**********************
|
1531
|
-
* EXPORTED FUNCTIONS *
|
1532
|
-
**********************/
|
1533
1551
|
static void expand_tabs(struct buf *ob, const char *line, size_t size)
|
1534
1552
|
{
|
1535
1553
|
size_t i = 0, tab = 0;
|
@@ -1555,6 +1573,10 @@ static void expand_tabs(struct buf *ob, const char *line, size_t size)
|
|
1555
1573
|
}
|
1556
1574
|
}
|
1557
1575
|
|
1576
|
+
/**********************
|
1577
|
+
* EXPORTED FUNCTIONS *
|
1578
|
+
**********************/
|
1579
|
+
|
1558
1580
|
/* markdown • parses the input buffer and renders it into the output buffer */
|
1559
1581
|
void
|
1560
1582
|
markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
|
@@ -1564,7 +1586,9 @@ markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
|
|
1564
1586
|
struct render rndr;
|
1565
1587
|
|
1566
1588
|
/* filling the render structure */
|
1567
|
-
if (!rndrer)
|
1589
|
+
if (!rndrer)
|
1590
|
+
return;
|
1591
|
+
|
1568
1592
|
rndr.make = *rndrer;
|
1569
1593
|
arr_init(&rndr.refs, sizeof (struct link_ref));
|
1570
1594
|
parr_init(&rndr.work);
|
@@ -1591,6 +1615,8 @@ markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
|
|
1591
1615
|
rndr.active_char['\\'] = char_escape;
|
1592
1616
|
rndr.active_char['&'] = char_entity;
|
1593
1617
|
|
1618
|
+
rndr.header_count = 1;
|
1619
|
+
|
1594
1620
|
/* first pass: looking for references, copying everything else */
|
1595
1621
|
beg = 0;
|
1596
1622
|
while (beg < ib->size) /* iterating over lines */
|
@@ -1628,6 +1654,8 @@ markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
|
|
1628
1654
|
|
1629
1655
|
/* second pass: actual rendering */
|
1630
1656
|
parse_block(ob, &rndr, text->data, text->size, 0 /* initial depth */);
|
1657
|
+
if (rndr.make.finalize)
|
1658
|
+
rndr.make.finalize(ob, &rndr.make.render_options);
|
1631
1659
|
|
1632
1660
|
/* clean-up */
|
1633
1661
|
bufrelease(text);
|
data/ext/markdown.h
CHANGED
@@ -37,7 +37,11 @@ enum mkd_autolink {
|
|
37
37
|
};
|
38
38
|
|
39
39
|
struct mkd_renderopt {
|
40
|
-
|
40
|
+
union {
|
41
|
+
int data;
|
42
|
+
void *ptr;
|
43
|
+
} opaque;
|
44
|
+
|
41
45
|
unsigned int flags;
|
42
46
|
};
|
43
47
|
|
@@ -52,7 +56,7 @@ struct mkd_renderer {
|
|
52
56
|
void (*blockcode)(struct buf *ob, struct buf *text, struct mkd_renderopt *opaque);
|
53
57
|
void (*blockquote)(struct buf *ob, struct buf *text, struct mkd_renderopt *opaque);
|
54
58
|
void (*blockhtml)(struct buf *ob, struct buf *text, struct mkd_renderopt *opaque);
|
55
|
-
void (*header)(struct buf *ob, struct buf *text, int level, struct mkd_renderopt *opaque);
|
59
|
+
void (*header)(struct buf *ob, struct buf *text, int level, int header_count, struct mkd_renderopt *opaque);
|
56
60
|
void (*hrule)(struct buf *ob, struct mkd_renderopt *opaque);
|
57
61
|
void (*list)(struct buf *ob, struct buf *text, int flags, struct mkd_renderopt *opaque);
|
58
62
|
void (*listitem)(struct buf *ob, struct buf *text, int flags, struct mkd_renderopt *opaque);
|
@@ -73,6 +77,9 @@ struct mkd_renderer {
|
|
73
77
|
void (*entity)(struct buf *ob, struct buf *entity, struct mkd_renderopt *opaque);
|
74
78
|
void (*normal_text)(struct buf *ob, struct buf *text, struct mkd_renderopt *opaque);
|
75
79
|
|
80
|
+
/* finalizer */
|
81
|
+
void (*finalize)(struct buf *ob, struct mkd_renderopt *opaque);
|
82
|
+
|
76
83
|
/* renderer data */
|
77
84
|
const char *emph_chars; /* chars that trigger emphasis rendering */
|
78
85
|
|
@@ -99,6 +106,7 @@ typedef enum {
|
|
99
106
|
RENDER_EXPAND_TABS = (1 << 5),
|
100
107
|
RENDER_AUTOLINK = (1 << 6),
|
101
108
|
RENDER_SAFELINK = (1 << 7),
|
109
|
+
RENDER_TOC = (1 << 8),
|
102
110
|
} render_mode;
|
103
111
|
|
104
112
|
typedef enum {
|
@@ -114,10 +122,12 @@ void
|
|
114
122
|
markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndr);
|
115
123
|
|
116
124
|
void
|
117
|
-
|
118
|
-
unsigned int render_flags,
|
125
|
+
init_xhtml_renderer(struct mkd_renderer *renderer,
|
126
|
+
unsigned int render_flags,
|
119
127
|
unsigned int parser_flags, int recursion_depth);
|
120
128
|
|
129
|
+
void
|
130
|
+
init_toc_renderer(struct mkd_renderer *renderer, int recursion_depth);
|
121
131
|
|
122
132
|
#endif /* ndef LITHIUM_MARKDOWN_H */
|
123
133
|
|
data/ext/redcarpet.c
CHANGED
@@ -3,9 +3,17 @@
|
|
3
3
|
|
4
4
|
#include "markdown.h"
|
5
5
|
|
6
|
+
#define REDCARPET_RECURSION_LIMIT 16
|
7
|
+
|
8
|
+
typedef enum
|
9
|
+
{
|
10
|
+
REDCARPET_RENDER_XHTML,
|
11
|
+
REDCARPET_RENDER_TOC
|
12
|
+
} RendererType;
|
13
|
+
|
6
14
|
static VALUE rb_cRedcarpet;
|
7
15
|
|
8
|
-
static void
|
16
|
+
static void rb_redcarpet__setup_xhtml(struct mkd_renderer *rnd, VALUE ruby_obj)
|
9
17
|
{
|
10
18
|
unsigned int render_flags = RENDER_EXPAND_TABS;
|
11
19
|
unsigned int parser_flags = 0;
|
@@ -38,22 +46,23 @@ static void rb_redcarpet__setup_render(VALUE ruby_obj, struct mkd_renderer *rnd)
|
|
38
46
|
if (rb_funcall(ruby_obj, rb_intern("safelink"), 0) == Qtrue)
|
39
47
|
render_flags |= RENDER_SAFELINK;
|
40
48
|
|
49
|
+
if (rb_funcall(ruby_obj, rb_intern("generate_toc"), 0) == Qtrue)
|
50
|
+
render_flags |= RENDER_TOC;
|
41
51
|
|
42
52
|
/* parser - strict */
|
43
53
|
if (rb_funcall(ruby_obj, rb_intern("strict"), 0) == Qtrue)
|
44
54
|
parser_flags |= PARSER_STRICT;
|
45
55
|
|
46
|
-
|
47
|
-
init_renderer(rnd, render_flags, NULL, parser_flags, 16);
|
56
|
+
init_xhtml_renderer(rnd, render_flags, parser_flags, REDCARPET_RECURSION_LIMIT);
|
48
57
|
}
|
49
58
|
|
50
|
-
static VALUE
|
59
|
+
static VALUE rb_redcarpet__render(VALUE self, RendererType render_type)
|
51
60
|
{
|
52
61
|
VALUE text = rb_funcall(self, rb_intern("text"), 0);
|
53
62
|
VALUE result;
|
54
63
|
|
55
64
|
struct buf input_buf, *output_buf;
|
56
|
-
struct mkd_renderer
|
65
|
+
struct mkd_renderer renderer;
|
57
66
|
|
58
67
|
Check_Type(text, T_STRING);
|
59
68
|
|
@@ -63,8 +72,20 @@ static VALUE rb_redcarpet_to_html(int argc, VALUE *argv, VALUE self)
|
|
63
72
|
|
64
73
|
output_buf = bufnew(64);
|
65
74
|
|
66
|
-
|
67
|
-
|
75
|
+
switch (render_type) {
|
76
|
+
case REDCARPET_RENDER_XHTML:
|
77
|
+
rb_redcarpet__setup_xhtml(&renderer, self);
|
78
|
+
break;
|
79
|
+
|
80
|
+
case REDCARPET_RENDER_TOC:
|
81
|
+
init_toc_renderer(&renderer, REDCARPET_RECURSION_LIMIT);
|
82
|
+
break;
|
83
|
+
|
84
|
+
default:
|
85
|
+
return Qnil;
|
86
|
+
}
|
87
|
+
|
88
|
+
markdown(output_buf, &input_buf, &renderer);
|
68
89
|
|
69
90
|
result = rb_str_new(output_buf->data, output_buf->size);
|
70
91
|
bufrelease(output_buf);
|
@@ -78,9 +99,22 @@ static VALUE rb_redcarpet_to_html(int argc, VALUE *argv, VALUE self)
|
|
78
99
|
return result;
|
79
100
|
}
|
80
101
|
|
102
|
+
static VALUE
|
103
|
+
rb_redcarpet_toc(int argc, VALUE *argv, VALUE self)
|
104
|
+
{
|
105
|
+
return rb_redcarpet__render(self, REDCARPET_RENDER_TOC);
|
106
|
+
}
|
107
|
+
|
108
|
+
static VALUE
|
109
|
+
rb_redcarpet_to_html(int argc, VALUE *argv, VALUE self)
|
110
|
+
{
|
111
|
+
return rb_redcarpet__render(self, REDCARPET_RENDER_XHTML);
|
112
|
+
}
|
113
|
+
|
81
114
|
void Init_redcarpet()
|
82
115
|
{
|
83
116
|
rb_cRedcarpet = rb_define_class("Redcarpet", rb_cObject);
|
84
117
|
rb_define_method(rb_cRedcarpet, "to_html", rb_redcarpet_to_html, -1);
|
118
|
+
rb_define_method(rb_cRedcarpet, "toc_content", rb_redcarpet_toc, -1);
|
85
119
|
}
|
86
120
|
|
data/ext/render.c
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c) 2011, Vicent Marti
|
3
2
|
* Copyright (c) 2009, Natacha Porté
|
3
|
+
* Copyright (c) 2011, Vicent Marti
|
4
4
|
*
|
5
5
|
* Permission to use, copy, modify, and distribute this software for any
|
6
6
|
* purpose with or without fee is hereby granted, provided that the above
|
@@ -53,7 +53,6 @@ put_scaped_char(struct buf *ob, char c)
|
|
53
53
|
}
|
54
54
|
}
|
55
55
|
|
56
|
-
|
57
56
|
/* lus_attr_escape • copy the buffer entity-escaping '<', '>', '&' and '"' */
|
58
57
|
static void
|
59
58
|
lus_attr_escape(struct buf *ob, const char *src, size_t size)
|
@@ -168,9 +167,14 @@ rndr_emphasis(struct buf *ob, struct buf *text, char c, struct mkd_renderopt *op
|
|
168
167
|
}
|
169
168
|
|
170
169
|
static void
|
171
|
-
rndr_header(struct buf *ob, struct buf *text, int level, struct mkd_renderopt *options)
|
170
|
+
rndr_header(struct buf *ob, struct buf *text, int level, int header_count, struct mkd_renderopt *options)
|
172
171
|
{
|
173
|
-
if (ob->size)
|
172
|
+
if (ob->size)
|
173
|
+
bufputc(ob, '\n');
|
174
|
+
|
175
|
+
if (options->flags & RENDER_TOC)
|
176
|
+
bufprintf(ob, "<a name=\"toc_%d\"></a>", header_count);
|
177
|
+
|
174
178
|
bufprintf(ob, "<h%d>", level);
|
175
179
|
if (text) bufput(ob, text->data, text->size);
|
176
180
|
bufprintf(ob, "</h%d>\n", level);
|
@@ -552,8 +556,8 @@ rndr_normal_text(struct buf *ob, struct buf *text, struct mkd_renderopt *options
|
|
552
556
|
}
|
553
557
|
|
554
558
|
void
|
555
|
-
|
556
|
-
unsigned int render_flags,
|
559
|
+
init_xhtml_renderer(struct mkd_renderer *renderer,
|
560
|
+
unsigned int render_flags,
|
557
561
|
unsigned int parser_flags, int recursion_depth)
|
558
562
|
{
|
559
563
|
static const struct mkd_renderer renderer_default = {
|
@@ -578,10 +582,11 @@ init_renderer(struct mkd_renderer *renderer,
|
|
578
582
|
|
579
583
|
NULL,
|
580
584
|
rndr_normal_text,
|
585
|
+
NULL,
|
581
586
|
|
582
587
|
"*_",
|
583
588
|
|
584
|
-
{
|
589
|
+
{ 0, 0 },
|
585
590
|
{ 0, 0 },
|
586
591
|
};
|
587
592
|
|
@@ -597,8 +602,6 @@ init_renderer(struct mkd_renderer *renderer,
|
|
597
602
|
|
598
603
|
renderer->parser_options.recursion_depth = recursion_depth;
|
599
604
|
renderer->parser_options.flags = parser_flags;
|
600
|
-
|
601
|
-
renderer->render_options.opaque = opaque;
|
602
605
|
renderer->render_options.flags = render_flags;
|
603
606
|
}
|
604
607
|
|
data/ext/toc.c
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2011, Vicent Marti
|
3
|
+
*
|
4
|
+
* Permission to use, copy, modify, and distribute this software for any
|
5
|
+
* purpose with or without fee is hereby granted, provided that the above
|
6
|
+
* copyright notice and this permission notice appear in all copies.
|
7
|
+
*
|
8
|
+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
9
|
+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
10
|
+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
11
|
+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
12
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
13
|
+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
14
|
+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
15
|
+
*/
|
16
|
+
|
17
|
+
#include "markdown.h"
|
18
|
+
|
19
|
+
#include <strings.h>
|
20
|
+
#include <stdlib.h>
|
21
|
+
#include <stdio.h>
|
22
|
+
|
23
|
+
static void
|
24
|
+
toc_header(struct buf *ob, struct buf *text, int level, int header_id, struct mkd_renderopt *options)
|
25
|
+
{
|
26
|
+
int current_level = (int)options->opaque.data;
|
27
|
+
|
28
|
+
if (level > current_level) {
|
29
|
+
if (level > 1)
|
30
|
+
BUFPUTSL(ob, "<li>");
|
31
|
+
BUFPUTSL(ob, "<ul>\n");
|
32
|
+
}
|
33
|
+
|
34
|
+
if (level < current_level) {
|
35
|
+
BUFPUTSL(ob, "</ul>");
|
36
|
+
if (current_level > 1)
|
37
|
+
BUFPUTSL(ob, "</li>\n");
|
38
|
+
}
|
39
|
+
|
40
|
+
options->opaque.data = level;
|
41
|
+
|
42
|
+
bufprintf(ob, "<li><a href=\"#toc_%d\">", header_id);
|
43
|
+
if (text)
|
44
|
+
bufput(ob, text->data, text->size);
|
45
|
+
BUFPUTSL(ob, "</a></li>\n");
|
46
|
+
}
|
47
|
+
|
48
|
+
static void
|
49
|
+
toc_finalize(struct buf *ob, struct mkd_renderopt *options)
|
50
|
+
{
|
51
|
+
int current_level = (int)options->opaque.data;
|
52
|
+
|
53
|
+
while (current_level > 1) {
|
54
|
+
BUFPUTSL(ob, "</ul></li>\n");
|
55
|
+
current_level--;
|
56
|
+
}
|
57
|
+
|
58
|
+
if (current_level)
|
59
|
+
BUFPUTSL(ob, "</ul>\n");
|
60
|
+
}
|
61
|
+
|
62
|
+
void
|
63
|
+
init_toc_renderer(struct mkd_renderer *renderer, int recursion_depth)
|
64
|
+
{
|
65
|
+
static const struct mkd_renderer toc_render = {
|
66
|
+
NULL,
|
67
|
+
NULL,
|
68
|
+
NULL,
|
69
|
+
toc_header,
|
70
|
+
NULL,
|
71
|
+
NULL,
|
72
|
+
NULL,
|
73
|
+
NULL,
|
74
|
+
|
75
|
+
NULL,
|
76
|
+
NULL,
|
77
|
+
NULL,
|
78
|
+
NULL,
|
79
|
+
NULL,
|
80
|
+
NULL,
|
81
|
+
NULL,
|
82
|
+
NULL,
|
83
|
+
NULL,
|
84
|
+
|
85
|
+
NULL,
|
86
|
+
NULL,
|
87
|
+
toc_finalize,
|
88
|
+
|
89
|
+
NULL,
|
90
|
+
|
91
|
+
{ 0, 0 },
|
92
|
+
{ 0, 0 },
|
93
|
+
};
|
94
|
+
|
95
|
+
memcpy(renderer, &toc_render, sizeof(struct mkd_renderer));
|
96
|
+
|
97
|
+
renderer->parser_options.recursion_depth = recursion_depth;
|
98
|
+
renderer->render_options.flags = RENDER_TOC;
|
99
|
+
renderer->render_options.opaque.data = 0;
|
100
|
+
}
|
101
|
+
|
data/lib/redcarpet.rb
CHANGED
@@ -26,7 +26,7 @@
|
|
26
26
|
# end
|
27
27
|
#
|
28
28
|
class Redcarpet
|
29
|
-
VERSION = '1.
|
29
|
+
VERSION = '1.2.0'
|
30
30
|
|
31
31
|
# Original Markdown formatted text.
|
32
32
|
attr_reader :text
|
@@ -57,14 +57,13 @@ class Redcarpet
|
|
57
57
|
# Don't make hyperlinks from <tt>[][]</tt> links that have unknown URL types.
|
58
58
|
attr_accessor :safelink
|
59
59
|
|
60
|
+
# Add TOC anchors to every header
|
61
|
+
attr_accessor :generate_toc
|
62
|
+
|
60
63
|
def initialize(text, *extensions)
|
61
64
|
@text = text
|
62
65
|
extensions.each { |e| send("#{e}=", true) }
|
63
66
|
end
|
64
|
-
|
65
|
-
def generate_toc
|
66
|
-
raise NotImplementedError
|
67
|
-
end
|
68
67
|
end
|
69
68
|
|
70
69
|
Markdown = Redcarpet unless defined? Markdown
|
data/redcarpet.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'redcarpet'
|
3
|
-
s.version = '1.
|
3
|
+
s.version = '1.2.0'
|
4
4
|
s.summary = "Ruby bindings for libupskirt"
|
5
5
|
s.date = '2011-04-02'
|
6
6
|
s.email = 'vicent@github.com'
|
@@ -22,6 +22,7 @@ Gem::Specification.new do |s|
|
|
22
22
|
ext/markdown.h
|
23
23
|
ext/redcarpet.c
|
24
24
|
ext/render.c
|
25
|
+
ext/toc.c
|
25
26
|
lib/markdown.rb
|
26
27
|
lib/redcarpet.rb
|
27
28
|
redcarpet.gemspec
|
data/test/redcarpet_test.rb
CHANGED
@@ -109,4 +109,17 @@ class RedcarpetTest < Test::Unit::TestCase
|
|
109
109
|
assert_equal "<pre><code>This is a code block\nThis is a link [[1]] inside\n</code></pre>\n",
|
110
110
|
markdown.to_html
|
111
111
|
end
|
112
|
+
|
113
|
+
def test_that_generate_toc_sets_toc_ids
|
114
|
+
rd = Redcarpet.new("# Level 1\n\n## Level 2", :generate_toc)
|
115
|
+
assert rd.generate_toc
|
116
|
+
assert_equal %(<a name="toc_1"></a><h1>Level 1</h1>\n\n<a name="toc_2"></a><h2>Level 2</h2>\n), rd.to_html
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_should_get_the_generated_toc
|
120
|
+
rd = Redcarpet.new("# Level 1\n\n## Level 2", :generate_toc)
|
121
|
+
exp = %(<ul>\n<li><a href="#toc_1">Level 1</a></li>\n<li><ul>\n<li><a href="#toc_2">Level 2</a></li>\n</ul></li>\n</ul>)
|
122
|
+
assert_equal exp, rd.toc_content.strip
|
123
|
+
end
|
124
|
+
|
112
125
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redcarpet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 31
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 1.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 1.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- "Natacha Port\xC3\xA9"
|
@@ -42,6 +42,7 @@ files:
|
|
42
42
|
- ext/markdown.h
|
43
43
|
- ext/redcarpet.c
|
44
44
|
- ext/render.c
|
45
|
+
- ext/toc.c
|
45
46
|
- lib/markdown.rb
|
46
47
|
- lib/redcarpet.rb
|
47
48
|
- redcarpet.gemspec
|