redcarpet 3.4.0 → 3.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -102,4 +102,3 @@ houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size)
102
102
  {
103
103
  houdini_escape_html0(ob, src, size, 1);
104
104
  }
105
-
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
- bufput(ob, text->data, text->size);
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) && (level <= options->toc_data.nesting_level)) {
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, "&nbsp;<a href=\"#fnref%d\" rev=\"footnote\">&#8617;</a>", num);
683
+ bufprintf(ob, "&nbsp;<a href=\"#fnref%d\">&#8617;</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\" rel=\"footnote\">%d</a></sup>", num, num, num);
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 <= options->toc_data.nesting_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.nesting_level = 99;
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 nesting_level;
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
@@ -1,6 +1,5 @@
1
- /* C code produced by gperf version 3.0.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-gnu-gperf@gnu.org>."
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
- 26, 60, 55, 45, 40, 35, 73, 73, 73, 73,
103
- 73, 73, 73, 73, 73, 20, 15, 15, 0, 35,
104
- 0, 25, 10, 10, 5, 73, 73, 0, 15, 15,
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, 15,
107
- 0, 35, 0, 25, 10, 10, 5, 73, 73, 0,
108
- 15, 15, 0, 73, 73, 15, 20, 10, 10, 73,
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 = 43,
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
- "ol",
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
- "ins",
173
+ "h1",
182
174
  "",
183
175
  "style",
184
- "output",
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
- "h6",
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("&#39;", text+(i+1), 5) == 0) {
386
+ bufput(ob, "&rsquo;", 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
-
@@ -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; return the
1357
- * width of the code fence */
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
- c = data[i];
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 < 3)
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
- if (syntax) {
1430
- syntax->data = syn_start;
1431
- syntax->size = syn_len;
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, &fence_trail);
1754
- if (fence_end != 0 && fence_trail.size == 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))
@@ -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
- rb_funcall(rndr_options, rb_intern("merge!"), 1, hash);
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
-
@@ -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
- BLOCK_CALLBACK("table_cell", 2, buf2str(text), rb_align);
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
- if (rb_iv_get(self, "@options") == Qnil)
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
- if (!(NIL_P(nesting_level)))
515
- rndr->options.html.toc_data.nesting_level = NUM2INT(nesting_level);
516
- else
517
- rndr->options.html.toc_data.nesting_level = 6;
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
  }
@@ -1,5 +1,3 @@
1
- require 'redcarpet'
2
-
3
1
  # Creates an instance of Redcarpet with the RedCloth API.
4
2
  class RedcarpetCompat
5
3
  attr_accessor :text
@@ -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,
data/lib/redcarpet.rb CHANGED
@@ -2,7 +2,7 @@ require 'redcarpet.so'
2
2
  require 'redcarpet/compat'
3
3
 
4
4
  module Redcarpet
5
- VERSION = '3.4.0'
5
+ VERSION = '3.6.0'
6
6
 
7
7
  class Markdown
8
8
  attr_reader :renderer