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.
- checksums.yaml +7 -0
- data/Gemfile +11 -0
- data/README.markdown +43 -25
- data/Rakefile +4 -1
- data/bin/redcarpet +8 -3
- data/ext/redcarpet/autolink.h +2 -2
- data/ext/redcarpet/buffer.c +2 -31
- data/ext/redcarpet/buffer.h +2 -8
- data/ext/redcarpet/houdini.h +0 -8
- data/ext/redcarpet/houdini_html_e.c +3 -8
- data/ext/redcarpet/html.c +124 -33
- data/ext/redcarpet/html.h +4 -4
- data/ext/redcarpet/markdown.c +345 -22
- data/ext/redcarpet/markdown.h +10 -13
- data/ext/redcarpet/rc_markdown.c +6 -0
- data/ext/redcarpet/rc_render.c +49 -5
- data/ext/redcarpet/stack.c +0 -19
- data/ext/redcarpet/stack.h +0 -3
- data/lib/redcarpet.rb +8 -8
- data/lib/redcarpet/render_strip.rb +4 -2
- data/redcarpet.gemspec +4 -4
- data/test/html_render_test.rb +88 -4
- data/test/html_toc_render_test.rb +55 -0
- data/test/markdown_test.rb +43 -6
- data/test/smarty_html_test.rb +15 -0
- metadata +10 -48
checksums.yaml
ADDED
@@ -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
data/README.markdown
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Redcarpet
|
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
|
22
|
-
|
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
|
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
|
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
|
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
|
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
|
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
|
-
*
|
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
|
-
|
317
|
-
|
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'
|
data/bin/redcarpet
CHANGED
@@ -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
|
data/ext/redcarpet/autolink.h
CHANGED
data/ext/redcarpet/buffer.c
CHANGED
@@ -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
|
-
|
data/ext/redcarpet/buffer.h
CHANGED
@@ -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
|
|
data/ext/redcarpet/houdini.h
CHANGED
@@ -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
|
-
|
72
|
-
|
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
|
}
|
data/ext/redcarpet/html.c
CHANGED
@@ -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=\"
|
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, "
|
513
|
+
BUFPUTSL(ob, " style=\"text-align: center\">");
|
488
514
|
break;
|
489
515
|
|
490
516
|
case MKD_TABLE_ALIGN_L:
|
491
|
-
BUFPUTSL(ob, "
|
517
|
+
BUFPUTSL(ob, " style=\"text-align: left\">");
|
492
518
|
break;
|
493
519
|
|
494
520
|
case MKD_TABLE_ALIGN_R:
|
495
|
-
BUFPUTSL(ob, "
|
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
|
-
|
556
|
+
rndr_footnotes(struct buf *ob, const struct buf *text, void *opaque)
|
531
557
|
{
|
532
558
|
struct html_renderopt *options = opaque;
|
533
559
|
|
534
|
-
|
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
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
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, "<
|
558
|
-
if (
|
559
|
-
|
560
|
-
|
591
|
+
bufprintf(ob, "\n<li id=\"fn%d\">\n", num);
|
592
|
+
if (pfound) {
|
593
|
+
bufput(ob, text->data, i);
|
594
|
+
bufprintf(ob, " <a href=\"#fnref%d\" rev=\"footnote\">↩</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));
|