redcarpet 3.0.0 → 3.1.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.

@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ee4e45848c356f4bb824bd36e7273f9851c30615
4
+ data.tar.gz: 754d5adba9649e196ea9c44e438c3bd3fba3790f
5
+ SHA512:
6
+ metadata.gz: 45c02fb54daa68e55d57d42bbc20a3dc2241e62b63c71ea99563b1c6166020198482dc7da89e206eebcd607b5db8161eecb09039d46bd01afc90c6c603b97335
7
+ data.tar.gz: 3ffc35a94e837ac2ace0aee26f6cbb52c5932369282e7305259efcc714483dd13bbcf223458306018d3f454091b6355554aa36a87ab64d618da0c47a8d3c5a33
data/Gemfile CHANGED
@@ -1,2 +1,13 @@
1
1
  source "https://rubygems.org/"
2
+
2
3
  gemspec
4
+
5
+ group :benchmark do
6
+ gem "bluecloth", "~> 2.2.0"
7
+ gem "kramdown", "~> 1.0.2"
8
+ end
9
+
10
+ platforms :rbx do
11
+ gem "rubysl"
12
+ gem "racc"
13
+ end
@@ -1,4 +1,4 @@
1
- Redcarpet 2 is written with sugar, spice and everything nice
1
+ Redcarpet is written with sugar, spice and everything nice
2
2
  ============================================================
3
3
 
4
4
  [![Build Status](https://travis-ci.org/vmg/redcarpet.png?branch=master)](https://travis-ci.org/vmg/redcarpet)
@@ -6,33 +6,28 @@ Redcarpet 2 is written with sugar, spice and everything nice
6
6
  Redcarpet is Ruby library for Markdown processing that smells like
7
7
  butterflies and popcorn.
8
8
 
9
- Redcarpet used to be a drop-in replacement for Redcloth. This is no longer the
10
- case since version 2 -- it now has its own API, but retains the old name. Yes,
11
- that does mean that Redcarpet 2 is not backwards-compatible with the 1.X
12
- versions.
13
-
14
- Redcarpet is based on the [Sundown](https://www.github.com/vmg/sundown)
15
- library. You might want to find out more about Sundown to see what makes this
16
- Ruby library so awesome.
17
-
18
9
  This library is written by people
19
10
  ---------------------------------
20
11
 
21
- Redcarpet 2 has been rewritten from scratch by Vicent Martí (@vmg). Why
22
- are you not following me on Twitter?
12
+ Redcarpet was written by [Vicent Martí](https://github.com/vmg). It is maintained by
13
+ [Robin Dupret](https://github.com/robin850) and [Matt Rogers](https://github.com/mattr-).
23
14
 
24
- Redcarpet would not be possible without the Sundown library and its authors
25
- (Natacha Porté, Vicent Martí, and its many awesome contributors).
15
+ Redcarpet would not be possible without the [Sundown](https://www.github.com/vmg/sundown)
16
+ library and its authors (Natacha Porté, Vicent Martí, and its many awesome contributors).
26
17
 
27
18
  You can totally install it as a Gem
28
19
  -----------------------------------
29
20
 
30
21
  Redcarpet is readily available as a Ruby gem. It will build some native
31
22
  extensions, but the parser is standalone and requires no installed libraries.
32
- Redcarpet requires at least Ruby 1.9.2 on your system.
23
+ Starting with Redcarpet 3.0, the minimum required Ruby version is 1.9.2 (or Rubinius in 1.9 mode).
33
24
 
34
25
  $ [sudo] gem install redcarpet
35
26
 
27
+ If you need to use it with Ruby 1.8.7, you will need to stick with 2.3.0:
28
+
29
+ $ [sudo] gem install redcarpet -v 2.3.0
30
+
36
31
  The Redcarpet source is available at GitHub:
37
32
 
38
33
  $ git clone git://github.com/vmg/redcarpet.git
@@ -45,12 +40,12 @@ instance of the class is attached to a `Renderer` object; the Markdown class
45
40
  performs parsing of a document and uses the attached renderer to generate
46
41
  output.
47
42
 
48
- The `Markdown` object is encouraged to be instantiated once with the required
49
- settings, and reused between parses.
43
+ The `Redcarpet::Markdown` object is encouraged to be instantiated once with the
44
+ required settings, and reused between parses.
50
45
 
51
46
  ~~~~~ ruby
52
47
  # Initializes a Markdown parser
53
- Markdown.new(renderer, extensions = {})
48
+ Redcarpet::Markdown.new(renderer, extensions = {})
54
49
  ~~~~~
55
50
 
56
51
 
@@ -67,7 +62,7 @@ Strings such as `foo_bar_baz` will not generate `<em>` tags.
67
62
  * `:tables`: parse tables, PHP-Markdown style.
68
63
 
69
64
  * `:fenced_code_blocks`: parse fenced code blocks, PHP-Markdown
70
- style. Blocks delimited with 3 or more `~` or backtickswill be considered
65
+ style. Blocks delimited with 3 or more `~` or backticks will be considered
71
66
  as code, without the need to be indented. An optional language name may
72
67
  be added at the end of the opening fence for the code block.
73
68
 
@@ -82,7 +77,7 @@ the front of each line to code blocks. This options
82
77
  prevents it from doing so. Recommended to use
83
78
  with `fenced_code_blocks: true`.
84
79
 
85
- * `:strikethrough`: parse strikethrough, PHP-Markdown style
80
+ * `:strikethrough`: parse strikethrough, PHP-Markdown style.
86
81
  Two `~` characters mark the start of a strikethrough,
87
82
  e.g. `this is ~~good~~ bad`.
88
83
 
@@ -93,7 +88,9 @@ empty line as in the Markdown standard.
93
88
  at the beginning of a header and its name, e.g. `#this is my header`
94
89
  would not be a valid header.
95
90
 
96
- * `:superscript`: parse superscripts after the `^` character; contiguous superscripts are nested together, and complex values can be enclosed in parenthesis, e.g. `this is the 2^(nd) time`
91
+ * `:superscript`: parse superscripts after the `^` character; contiguous superscripts
92
+ are nested together, and complex values can be enclosed in parenthesis, e.g.
93
+ `this is the 2^(nd) time`.
97
94
 
98
95
  * `:underline`: parse underscored emphasis as underlines.
99
96
  `This is _underlined_ but this is still *italic*`.
@@ -101,6 +98,14 @@ would not be a valid header.
101
98
  * `:highlight`: parse highlights.
102
99
  `This is ==highlighted==`. It looks like this: `<mark>highlighted</mark>`
103
100
 
101
+ * `:quote`: parse quotes.
102
+ `This is a "quote"`. It looks like this: `<q>quote</q>`
103
+
104
+ * `:footnotes`: parse footnotes, PHP-Markdown style. A footnote works very much
105
+ like a reference-style link: it consists of a marker next to the text (e.g.
106
+ `This is a sentence.[^1]`) and a footnote definition on its own line anywhere
107
+ within the document (e.g. `[^1]: This is a footnote.`).
108
+
104
109
  Example:
105
110
 
106
111
  ~~~~~ ruby
@@ -172,6 +177,10 @@ The `HTML` renderer has an alternate version, `Redcarpet::Render::HTML_TOC`,
172
177
  which will output a table of contents in HTML based on the headers of the
173
178
  Markdown document.
174
179
 
180
+ When instantiating this render object, you can optionally pass a `nesting_level`
181
+ option which takes an integer and allows you to make it render only headers
182
+ until a specific level.
183
+
175
184
  Furthermore, the abstract base class `Redcarpet::Render::Base` can be used
176
185
  to write a custom renderer purely in Ruby, or extending an existing renderer.
177
186
  See the following section for more information.
@@ -224,7 +233,9 @@ end
224
233
  * block_code(code, language)
225
234
  * block_quote(quote)
226
235
  * block_html(raw_html)
227
- * header(text, header_level)
236
+ * footnotes(content)
237
+ * footnote_def(content, number)
238
+ * header(text, header_level, anchor)
228
239
  * hrule()
229
240
  * list(contents, list_type)
230
241
  * list_item(text, list_type)
@@ -252,6 +263,8 @@ be copied verbatim:
252
263
  * superscript(text)
253
264
  * underline(text)
254
265
  * highlight(text)
266
+ * quote(text)
267
+ * footnote_ref(number)
255
268
 
256
269
  ### Low level rendering
257
270
 
@@ -313,14 +326,19 @@ inside the content of HTML tags and inside specific HTML blocks such as
313
326
  What? You really want to mix Markdown renderers?
314
327
  ------------------------------------------------
315
328
 
316
- What a terrible idea! Markdown is already ill-specified enough; if you create
317
- software that is renderer-independent, the results will be completely unreliable!
329
+ Redcarpet used to be a drop-in replacement for Redcloth. This is no longer the
330
+ case since version 2 -- it now has its own API, but retains the old name. Yes,
331
+ that does mean that Redcarpet is not backwards-compatible with the 1.X
332
+ versions.
318
333
 
319
334
  Each renderer has its own API and its own set of extensions: you should choose one
320
335
  (it doesn't have to be Redcarpet, though that would be great!), write your
321
336
  software accordingly, and force your users to install it. That's the
322
337
  only way to have reliable and predictable Markdown output on your program.
323
338
 
339
+ Markdown is already ill-specified enough; if you create software that is
340
+ renderer-independent, the results will be completely unreliable!
341
+
324
342
  Still, if major forces (let's say, tornadoes or other natural disasters) force you
325
343
  to keep a Markdown-compatibility layer, Redcarpet also supports this:
326
344
 
@@ -349,7 +367,7 @@ Tests run a lot faster without `bundle exec` :)
349
367
  Boring legal stuff
350
368
  ------------------
351
369
 
352
- Copyright (c) 2011, Vicent Martí
370
+ Copyright (c) 2011-2013, Vicent Martí
353
371
 
354
372
  Permission to use, copy, modify, and/or distribute this software for any
355
373
  purpose with or without fee is hereby granted, provided that the above
data/Rakefile CHANGED
@@ -5,8 +5,11 @@ require 'digest/md5'
5
5
 
6
6
  task :default => [:test]
7
7
 
8
+ # Gem Spec
9
+ gem_spec = Gem::Specification.load('redcarpet.gemspec')
10
+
8
11
  # Ruby Extension
9
- Rake::ExtensionTask.new('redcarpet')
12
+ Rake::ExtensionTask.new('redcarpet', gem_spec)
10
13
 
11
14
  # Packaging
12
15
  require 'bundler/gem_tasks'
@@ -4,18 +4,23 @@
4
4
  # no <file> or when <file> is '-', read Markdown source text from standard input.
5
5
  # With <extension>s, perform additional Markdown processing before writing output.
6
6
  # With --smarty, use the SmartyHTML renderer
7
- if ARGV.include?('--help')
7
+ if ARGV.include?('--help') or ARGV.include?('-h')
8
8
  File.read(__FILE__).split("\n").grep(/^# /).each do |line|
9
9
  puts line[2..-1]
10
10
  end
11
11
  exit 0
12
12
  end
13
13
 
14
+ require 'redcarpet'
15
+
16
+ if ARGV.include?('--version') or ARGV.include?('-v')
17
+ puts "Redcarpet #{Redcarpet::VERSION}"
18
+ exit 0
19
+ end
20
+
14
21
  root = File.expand_path('../../', __FILE__)
15
22
  $:.unshift File.expand_path('lib', root)
16
23
 
17
- require 'redcarpet'
18
-
19
24
  render_extensions = {}
20
25
  parse_extensions = {}
21
26
  renderer = Redcarpet::Render::HTML
@@ -14,8 +14,8 @@
14
14
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
15
  */
16
16
 
17
- #ifndef UPSKIRT_AUTOLINK_H
18
- #define UPSKIRT_AUTOLINK_H
17
+ #ifndef AUTOLINK_H__
18
+ #define AUTOLINK_H__
19
19
 
20
20
  #include "buffer.h"
21
21
 
@@ -94,7 +94,7 @@ 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
 
@@ -120,7 +120,7 @@ bufprintf(struct buf *buf, const char *fmt, ...)
120
120
 
121
121
  if (buf->size >= buf->asize && bufgrow(buf, buf->size + 1) < 0)
122
122
  return;
123
-
123
+
124
124
  va_start(ap, fmt);
125
125
  n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap);
126
126
  va_end(ap);
@@ -194,32 +194,3 @@ bufrelease(struct buf *buf)
194
194
  free(buf->data);
195
195
  free(buf);
196
196
  }
197
-
198
-
199
- /* bufreset: frees internal data of the buffer */
200
- void
201
- bufreset(struct buf *buf)
202
- {
203
- if (!buf)
204
- return;
205
-
206
- free(buf->data);
207
- buf->data = NULL;
208
- buf->size = buf->asize = 0;
209
- }
210
-
211
- /* bufslurp: removes a given number of bytes from the head of the array */
212
- void
213
- bufslurp(struct buf *buf, size_t len)
214
- {
215
- assert(buf && buf->unit);
216
-
217
- if (len >= buf->size) {
218
- buf->size = 0;
219
- return;
220
- }
221
-
222
- buf->size -= len;
223
- memmove(buf->data, buf->data + len, buf->size);
224
- }
225
-
@@ -1,4 +1,4 @@
1
- /*
1
+ /*
2
2
  * Copyright (c) 2008, Natacha Porté
3
3
  * Copyright (c) 2011, Vicent Martí
4
4
  *
@@ -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);
@@ -72,12 +72,6 @@ void bufputc(struct buf *, int);
72
72
  /* bufrelease: decrease the reference count and free the buffer if needed */
73
73
  void bufrelease(struct buf *);
74
74
 
75
- /* bufreset: frees internal data of the buffer */
76
- void bufreset(struct buf *);
77
-
78
- /* bufslurp: removes a given number of bytes from the head of the array */
79
- void bufslurp(struct buf *, size_t);
80
-
81
75
  /* bufprintf: formatted printing to a buffer */
82
76
  void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3)));
83
77
 
@@ -20,15 +20,7 @@ extern "C" {
20
20
 
21
21
  extern void houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size);
22
22
  extern void houdini_escape_html0(struct buf *ob, const uint8_t *src, size_t size, int secure);
23
- extern void houdini_unescape_html(struct buf *ob, const uint8_t *src, size_t size);
24
- extern void houdini_escape_xml(struct buf *ob, const uint8_t *src, size_t size);
25
- extern void houdini_escape_uri(struct buf *ob, const uint8_t *src, size_t size);
26
- extern void houdini_escape_url(struct buf *ob, const uint8_t *src, size_t size);
27
23
  extern void houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size);
28
- extern void houdini_unescape_uri(struct buf *ob, const uint8_t *src, size_t size);
29
- extern void houdini_unescape_url(struct buf *ob, const uint8_t *src, size_t size);
30
- extern void houdini_escape_js(struct buf *ob, const uint8_t *src, size_t size);
31
- extern void houdini_unescape_js(struct buf *ob, const uint8_t *src, size_t size);
32
24
 
33
25
  #ifdef __cplusplus
34
26
  }
@@ -66,15 +66,10 @@ houdini_escape_html0(struct buf *ob, const uint8_t *src, size_t size, int secure
66
66
  break;
67
67
 
68
68
  /* The forward slash is only escaped in secure mode */
69
- if (src[i] == '/' && !secure) {
69
+ if (src[i] == '/' && !secure)
70
70
  bufputc(ob, '/');
71
- } else {
72
- /* The left and right tags (< and >) aren't escaped in comments */
73
- if ((src[i] == '<' && src[i + 1] == '!') || (src[i] == '>' && src[i - 1] == '-'))
74
- bufputc(ob, src[i]);
75
- else
76
- bufputs(ob, HTML_ESCAPES[esc]);
77
- }
71
+ else
72
+ bufputs(ob, HTML_ESCAPES[esc]);
78
73
 
79
74
  i++;
80
75
  }
@@ -17,7 +17,7 @@
17
17
 
18
18
  #include "markdown.h"
19
19
  #include "html.h"
20
-
20
+ #include "ruby.h"
21
21
  #include <string.h>
22
22
  #include <stdlib.h>
23
23
  #include <stdio.h>
@@ -125,7 +125,7 @@ rndr_blockcode(struct buf *ob, const struct buf *text, const struct buf *lang, v
125
125
  if (lang && lang->size) {
126
126
  size_t i, cls;
127
127
  if (options->flags & HTML_PRETTIFY) {
128
- BUFPUTSL(ob, "<pre><code class=\"prettyprint");
128
+ BUFPUTSL(ob, "<pre><code class=\"prettyprint ");
129
129
  cls++;
130
130
  } else {
131
131
  BUFPUTSL(ob, "<pre><code class=\"");
@@ -244,6 +244,19 @@ rndr_highlight(struct buf *ob, const struct buf *text, void *opaque)
244
244
  return 1;
245
245
  }
246
246
 
247
+ static int
248
+ rndr_quote(struct buf *ob, const struct buf *text, void *opaque)
249
+ {
250
+ if (!text || !text->size)
251
+ return 0;
252
+
253
+ BUFPUTSL(ob, "<q>");
254
+ bufput(ob, text->data, text->size);
255
+ BUFPUTSL(ob, "</q>");
256
+
257
+ return 1;
258
+ }
259
+
247
260
  static int
248
261
  rndr_linebreak(struct buf *ob, void *opaque)
249
262
  {
@@ -252,16 +265,29 @@ rndr_linebreak(struct buf *ob, void *opaque)
252
265
  return 1;
253
266
  }
254
267
 
268
+ char *header_anchor(const struct buf *text)
269
+ {
270
+ VALUE str = rb_str_new2(bufcstr(text));
271
+ VALUE space_regex = rb_reg_new(" +", 2 /* length */, 0);
272
+ VALUE tags_regex = rb_reg_new("<\\/?[^>]*>", 10, 0);
273
+
274
+ VALUE heading = rb_funcall(str, rb_intern("gsub"), 2, space_regex, rb_str_new2("-"));
275
+ heading = rb_funcall(heading, rb_intern("gsub"), 2, tags_regex, rb_str_new2(""));
276
+ heading = rb_funcall(heading, rb_intern("downcase"), 0);
277
+
278
+ return StringValueCStr(heading);
279
+ }
280
+
255
281
  static void
256
- rndr_header(struct buf *ob, const struct buf *text, int level, void *opaque)
282
+ rndr_header(struct buf *ob, const struct buf *text, int level, char *anchor, void *opaque)
257
283
  {
258
284
  struct html_renderopt *options = opaque;
259
285
 
260
286
  if (ob->size)
261
287
  bufputc(ob, '\n');
262
288
 
263
- if (options->flags & HTML_TOC)
264
- bufprintf(ob, "<h%d id=\"toc_%d\">", level, options->toc_data.header_count++);
289
+ if ((options->flags & HTML_TOC) && (level <= options->toc_data.nesting_level))
290
+ bufprintf(ob, "<h%d id=\"%s\">", level, anchor);
265
291
  else
266
292
  bufprintf(ob, "<h%d>", level);
267
293
 
@@ -484,15 +510,15 @@ rndr_tablecell(struct buf *ob, const struct buf *text, int flags, void *opaque)
484
510
 
485
511
  switch (flags & MKD_TABLE_ALIGNMASK) {
486
512
  case MKD_TABLE_ALIGN_CENTER:
487
- BUFPUTSL(ob, " align=\"center\">");
513
+ BUFPUTSL(ob, " style=\"text-align: center\">");
488
514
  break;
489
515
 
490
516
  case MKD_TABLE_ALIGN_L:
491
- BUFPUTSL(ob, " align=\"left\">");
517
+ BUFPUTSL(ob, " style=\"text-align: left\">");
492
518
  break;
493
519
 
494
520
  case MKD_TABLE_ALIGN_R:
495
- BUFPUTSL(ob, " align=\"right\">");
521
+ BUFPUTSL(ob, " style=\"text-align: right\">");
496
522
  break;
497
523
 
498
524
  default:
@@ -527,37 +553,92 @@ rndr_normal_text(struct buf *ob, const struct buf *text, void *opaque)
527
553
  }
528
554
 
529
555
  static void
530
- toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
556
+ rndr_footnotes(struct buf *ob, const struct buf *text, void *opaque)
531
557
  {
532
558
  struct html_renderopt *options = opaque;
533
559
 
534
- /* set the level offset if this is the first header
535
- * we're parsing for the document */
536
- if (options->toc_data.current_level == 0) {
537
- options->toc_data.level_offset = level - 1;
538
- }
539
- level -= options->toc_data.level_offset;
560
+ if (ob->size) bufputc(ob, '\n');
540
561
 
541
- if (level > options->toc_data.current_level) {
542
- while (level > options->toc_data.current_level) {
543
- BUFPUTSL(ob, "<ul>\n<li>\n");
544
- options->toc_data.current_level++;
545
- }
546
- } else if (level < options->toc_data.current_level) {
547
- BUFPUTSL(ob, "</li>\n");
548
- while (level < options->toc_data.current_level) {
549
- BUFPUTSL(ob, "</ul>\n</li>\n");
550
- options->toc_data.current_level--;
562
+ BUFPUTSL(ob, "<div class=\"footnotes\">\n");
563
+ bufputs(ob, USE_XHTML(options) ? "<hr/>\n" : "<hr>\n");
564
+ BUFPUTSL(ob, "<ol>\n");
565
+
566
+ if (text)
567
+ bufput(ob, text->data, text->size);
568
+
569
+ BUFPUTSL(ob, "\n</ol>\n</div>\n");
570
+ }
571
+
572
+ static void
573
+ rndr_footnote_def(struct buf *ob, const struct buf *text, unsigned int num, void *opaque)
574
+ {
575
+ size_t i = 0;
576
+ int pfound = 0;
577
+
578
+ /* insert anchor at the end of first paragraph block */
579
+ if (text) {
580
+ while ((i+3) < text->size) {
581
+ if (text->data[i++] != '<') continue;
582
+ if (text->data[i++] != '/') continue;
583
+ if (text->data[i++] != 'p' && text->data[i] != 'P') continue;
584
+ if (text->data[i] != '>') continue;
585
+ i -= 3;
586
+ pfound = 1;
587
+ break;
551
588
  }
552
- BUFPUTSL(ob,"<li>\n");
553
- } else {
554
- BUFPUTSL(ob,"</li>\n<li>\n");
555
589
  }
556
590
 
557
- bufprintf(ob, "<a href=\"#toc_%d\">", options->toc_data.header_count++);
558
- if (text)
559
- escape_html(ob, text->data, text->size);
560
- BUFPUTSL(ob, "</a>\n");
591
+ bufprintf(ob, "\n<li id=\"fn%d\">\n", num);
592
+ if (pfound) {
593
+ bufput(ob, text->data, i);
594
+ bufprintf(ob, "&nbsp;<a href=\"#fnref%d\" rev=\"footnote\">&#8617;</a>", num);
595
+ bufput(ob, text->data + i, text->size - i);
596
+ } else if (text) {
597
+ bufput(ob, text->data, text->size);
598
+ }
599
+ BUFPUTSL(ob, "</li>\n");
600
+ }
601
+
602
+ static int
603
+ rndr_footnote_ref(struct buf *ob, unsigned int num, void *opaque)
604
+ {
605
+ bufprintf(ob, "<sup id=\"fnref%d\"><a href=\"#fn%d\" rel=\"footnote\">%d</a></sup>", num, num, num);
606
+ return 1;
607
+ }
608
+
609
+ static void
610
+ toc_header(struct buf *ob, const struct buf *text, int level, char *anchor, void *opaque)
611
+ {
612
+ struct html_renderopt *options = opaque;
613
+
614
+ if (level <= options->toc_data.nesting_level) {
615
+ /* set the level offset if this is the first header
616
+ * we're parsing for the document */
617
+ if (options->toc_data.current_level == 0)
618
+ options->toc_data.level_offset = level - 1;
619
+
620
+ level -= options->toc_data.level_offset;
621
+
622
+ if (level > options->toc_data.current_level) {
623
+ while (level > options->toc_data.current_level) {
624
+ BUFPUTSL(ob, "<ul>\n<li>\n");
625
+ options->toc_data.current_level++;
626
+ }
627
+ } else if (level < options->toc_data.current_level) {
628
+ BUFPUTSL(ob, "</li>\n");
629
+ while (level < options->toc_data.current_level) {
630
+ BUFPUTSL(ob, "</ul>\n</li>\n");
631
+ options->toc_data.current_level--;
632
+ }
633
+ BUFPUTSL(ob,"<li>\n");
634
+ } else {
635
+ BUFPUTSL(ob,"</li>\n<li>\n");
636
+ }
637
+
638
+ bufprintf(ob, "<a href=\"#%s\">", anchor);
639
+ if (text) escape_html(ob, text->data, text->size);
640
+ BUFPUTSL(ob, "</a>\n");
641
+ }
561
642
  }
562
643
 
563
644
  static int
@@ -580,7 +661,7 @@ toc_finalize(struct buf *ob, void *opaque)
580
661
  }
581
662
 
582
663
  void
583
- sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options)
664
+ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options, int nesting_level)
584
665
  {
585
666
  static const struct sd_callbacks cb_default = {
586
667
  NULL,
@@ -594,6 +675,8 @@ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *optio
594
675
  NULL,
595
676
  NULL,
596
677
  NULL,
678
+ rndr_footnotes,
679
+ rndr_footnote_def,
597
680
 
598
681
  NULL,
599
682
  rndr_codespan,
@@ -601,6 +684,7 @@ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *optio
601
684
  rndr_emphasis,
602
685
  rndr_underline,
603
686
  rndr_highlight,
687
+ rndr_quote,
604
688
  NULL,
605
689
  NULL,
606
690
  toc_link,
@@ -608,6 +692,7 @@ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *optio
608
692
  rndr_triple_emphasis,
609
693
  rndr_strikethrough,
610
694
  rndr_superscript,
695
+ rndr_footnote_ref,
611
696
 
612
697
  NULL,
613
698
  NULL,
@@ -618,6 +703,7 @@ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *optio
618
703
 
619
704
  memset(options, 0x0, sizeof(struct html_renderopt));
620
705
  options->flags = HTML_TOC;
706
+ options->toc_data.nesting_level = nesting_level;
621
707
 
622
708
  memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks));
623
709
  }
@@ -637,6 +723,8 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options,
637
723
  rndr_table,
638
724
  rndr_tablerow,
639
725
  rndr_tablecell,
726
+ rndr_footnotes,
727
+ rndr_footnote_def,
640
728
 
641
729
  rndr_autolink,
642
730
  rndr_codespan,
@@ -644,6 +732,7 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options,
644
732
  rndr_emphasis,
645
733
  rndr_underline,
646
734
  rndr_highlight,
735
+ rndr_quote,
647
736
  rndr_image,
648
737
  rndr_linebreak,
649
738
  rndr_link,
@@ -651,6 +740,7 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options,
651
740
  rndr_triple_emphasis,
652
741
  rndr_strikethrough,
653
742
  rndr_superscript,
743
+ rndr_footnote_ref,
654
744
 
655
745
  NULL,
656
746
  rndr_normal_text,
@@ -662,6 +752,7 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options,
662
752
  /* Prepare the options pointer */
663
753
  memset(options, 0x0, sizeof(struct html_renderopt));
664
754
  options->flags = render_flags;
755
+ options->toc_data.nesting_level = 99;
665
756
 
666
757
  /* Prepare the callbacks */
667
758
  memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks));