greenmat 3.2.2.4 → 3.5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +19 -4
- data/CHANGELOG.md +4 -0
- data/COPYING +17 -11
- data/Gemfile +2 -2
- data/README.md +19 -13
- data/bin/greenmat +4 -40
- data/ext/greenmat/autolink.c +24 -12
- data/ext/greenmat/buffer.c +24 -17
- data/ext/greenmat/buffer.h +18 -13
- data/ext/greenmat/gm_markdown.c +35 -13
- data/ext/greenmat/gm_render.c +60 -21
- data/ext/greenmat/greenmat.h +22 -0
- data/ext/greenmat/houdini.h +22 -0
- data/ext/greenmat/houdini_href_e.c +27 -11
- data/ext/greenmat/houdini_html_e.c +22 -1
- data/ext/greenmat/html.c +127 -45
- data/ext/greenmat/html.h +19 -14
- data/ext/greenmat/html_blocks.h +68 -70
- data/ext/greenmat/html_smartypants.c +47 -20
- data/ext/greenmat/markdown.c +42 -30
- data/ext/greenmat/markdown.h +17 -15
- data/ext/greenmat/stack.c +22 -0
- data/ext/greenmat/stack.h +22 -0
- data/greenmat.gemspec +3 -3
- data/lib/greenmat.rb +1 -1
- data/lib/greenmat/cli.rb +86 -0
- data/lib/greenmat/compat.rb +0 -5
- data/lib/greenmat/render_strip.rb +13 -1
- data/lib/greenmat/version.rb +1 -1
- data/test/custom_render_test.rb +41 -2
- data/test/greenmat_bin_test.rb +80 -0
- data/test/greenmat_compat_test.rb +6 -6
- data/test/html5_test.rb +51 -38
- data/test/html_render_test.rb +161 -127
- data/test/html_toc_render_test.rb +74 -11
- data/test/markdown_test.rb +258 -182
- data/test/safe_render_test.rb +5 -6
- data/test/smarty_html_test.rb +19 -13
- data/test/smarty_pants_test.rb +10 -0
- data/test/stripdown_render_test.rb +38 -9
- data/test/test_helper.rb +30 -9
- metadata +15 -13
data/ext/greenmat/gm_render.c
CHANGED
@@ -1,17 +1,23 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright (c)
|
2
|
+
* Copyright (c) 2015, Vicent Marti
|
3
3
|
*
|
4
|
-
* Permission
|
5
|
-
*
|
6
|
-
*
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
9
|
+
* furnished to do so, subject to the following conditions:
|
7
10
|
*
|
8
|
-
*
|
9
|
-
*
|
10
|
-
*
|
11
|
-
*
|
12
|
-
*
|
13
|
-
*
|
14
|
-
* OR
|
11
|
+
* The above copyright notice and this permission notice shall be included in
|
12
|
+
* all copies or substantial portions of the Software.
|
13
|
+
*
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
* THE SOFTWARE.
|
15
21
|
*/
|
16
22
|
|
17
23
|
#include "greenmat.h"
|
@@ -34,10 +40,10 @@
|
|
34
40
|
}
|
35
41
|
|
36
42
|
extern VALUE rb_mGreenmat;
|
43
|
+
extern VALUE rb_cRenderHTML_TOC;
|
37
44
|
VALUE rb_mRender;
|
38
45
|
VALUE rb_cRenderBase;
|
39
46
|
VALUE rb_cRenderHTML;
|
40
|
-
VALUE rb_cRenderHTML_TOC;
|
41
47
|
VALUE rb_mSmartyPants;
|
42
48
|
|
43
49
|
#define buf2str(t) ((t) ? rb_enc_str_new((const char*)(t)->data, (t)->size, opt->active_enc) : Qnil)
|
@@ -369,16 +375,22 @@ static void rb_greenmat_rbase_mark(struct rb_greenmat_rndr *rndr)
|
|
369
375
|
rb_gc_mark(rndr->options.link_attributes);
|
370
376
|
}
|
371
377
|
|
378
|
+
static void rndr_deallocate(void *rndr)
|
379
|
+
{
|
380
|
+
xfree(rndr);
|
381
|
+
}
|
382
|
+
|
372
383
|
static VALUE rb_greenmat_rbase_alloc(VALUE klass)
|
373
384
|
{
|
374
385
|
struct rb_greenmat_rndr *rndr = ALLOC(struct rb_greenmat_rndr);
|
375
386
|
memset(rndr, 0x0, sizeof(struct rb_greenmat_rndr));
|
376
|
-
return Data_Wrap_Struct(klass, rb_greenmat_rbase_mark,
|
387
|
+
return Data_Wrap_Struct(klass, rb_greenmat_rbase_mark, rndr_deallocate, rndr);
|
377
388
|
}
|
378
389
|
|
379
390
|
static void rb_greenmat__overload(VALUE self, VALUE base_class)
|
380
391
|
{
|
381
392
|
struct rb_greenmat_rndr *rndr;
|
393
|
+
VALUE options_ivar;
|
382
394
|
|
383
395
|
Data_Get_Struct(self, struct rb_greenmat_rndr, rndr);
|
384
396
|
rndr->options.self = self;
|
@@ -399,6 +411,10 @@ static void rb_greenmat__overload(VALUE self, VALUE base_class)
|
|
399
411
|
dest[i] = source[i];
|
400
412
|
}
|
401
413
|
}
|
414
|
+
|
415
|
+
options_ivar = rb_attr_get(self, rb_intern("@options"));
|
416
|
+
if (options_ivar == Qundef || options_ivar == Qnil)
|
417
|
+
rb_iv_set(self, "@options", rb_hash_new());
|
402
418
|
}
|
403
419
|
|
404
420
|
static VALUE rb_greenmat_rbase_init(VALUE self)
|
@@ -418,6 +434,9 @@ static VALUE rb_greenmat_html_init(int argc, VALUE *argv, VALUE self)
|
|
418
434
|
if (rb_scan_args(argc, argv, "01", &hash) == 1) {
|
419
435
|
Check_Type(hash, T_HASH);
|
420
436
|
|
437
|
+
/* Give access to the passed options through `@options` */
|
438
|
+
rb_iv_set(self, "@options", hash);
|
439
|
+
|
421
440
|
/* escape_html */
|
422
441
|
if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue)
|
423
442
|
render_flags |= HTML_ESCAPE;
|
@@ -472,25 +491,45 @@ static VALUE rb_greenmat_html_init(int argc, VALUE *argv, VALUE self)
|
|
472
491
|
static VALUE rb_greenmat_htmltoc_init(int argc, VALUE *argv, VALUE self)
|
473
492
|
{
|
474
493
|
struct rb_greenmat_rndr *rndr;
|
475
|
-
int
|
476
|
-
VALUE hash,
|
494
|
+
unsigned int render_flags = HTML_TOC;
|
495
|
+
VALUE hash, nesting_level = Qnil;
|
477
496
|
|
478
497
|
Data_Get_Struct(self, struct rb_greenmat_rndr, rndr);
|
479
498
|
|
480
499
|
if (rb_scan_args(argc, argv, "01", &hash) == 1) {
|
481
500
|
Check_Type(hash, T_HASH);
|
482
501
|
|
483
|
-
|
502
|
+
/* Give access to the passed options through `@options` */
|
503
|
+
rb_iv_set(self, "@options", hash);
|
484
504
|
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
505
|
+
/* escape_html */
|
506
|
+
if (rb_hash_aref(hash, CSTR2SYM("escape_html")) == Qtrue)
|
507
|
+
render_flags |= HTML_ESCAPE;
|
508
|
+
|
509
|
+
/* Nesting level */
|
510
|
+
nesting_level = rb_hash_aref(hash, CSTR2SYM("nesting_level"));
|
489
511
|
}
|
490
512
|
|
491
|
-
sdhtml_toc_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html,
|
513
|
+
sdhtml_toc_renderer(&rndr->callbacks, (struct html_renderopt *)&rndr->options.html, render_flags);
|
492
514
|
rb_greenmat__overload(self, rb_cRenderHTML_TOC);
|
493
515
|
|
516
|
+
/* Check whether we are dealing with a Range object by
|
517
|
+
checking whether the object responds to min and max */
|
518
|
+
if (rb_respond_to(nesting_level, rb_intern("min")) &&
|
519
|
+
rb_respond_to(nesting_level, rb_intern("max"))) {
|
520
|
+
int min = NUM2INT(rb_funcall(nesting_level, rb_intern("min"), 0));
|
521
|
+
int max = NUM2INT(rb_funcall(nesting_level, rb_intern("max"), 0));
|
522
|
+
|
523
|
+
rndr->options.html.toc_data.nesting_bounds[0] = min;
|
524
|
+
rndr->options.html.toc_data.nesting_bounds[1] = max;
|
525
|
+
} else if (FIXNUM_P(nesting_level)) {
|
526
|
+
rndr->options.html.toc_data.nesting_bounds[0] = 1;
|
527
|
+
rndr->options.html.toc_data.nesting_bounds[1] = NUM2INT(nesting_level);
|
528
|
+
} else {
|
529
|
+
rndr->options.html.toc_data.nesting_bounds[0] = 1;
|
530
|
+
rndr->options.html.toc_data.nesting_bounds[1] = 6;
|
531
|
+
}
|
532
|
+
|
494
533
|
return Qnil;
|
495
534
|
}
|
496
535
|
|
data/ext/greenmat/greenmat.h
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2015, Vicent Marti
|
3
|
+
*
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
9
|
+
* furnished to do so, subject to the following conditions:
|
10
|
+
*
|
11
|
+
* The above copyright notice and this permission notice shall be included in
|
12
|
+
* all copies or substantial portions of the Software.
|
13
|
+
*
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
* THE SOFTWARE.
|
21
|
+
*/
|
22
|
+
|
1
23
|
#ifndef GREENMAT_H__
|
2
24
|
#define GREENMAT_H__
|
3
25
|
|
data/ext/greenmat/houdini.h
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2015, Vicent Marti
|
3
|
+
*
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
9
|
+
* furnished to do so, subject to the following conditions:
|
10
|
+
*
|
11
|
+
* The above copyright notice and this permission notice shall be included in
|
12
|
+
* all copies or substantial portions of the Software.
|
13
|
+
*
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
* THE SOFTWARE.
|
21
|
+
*/
|
22
|
+
|
1
23
|
#ifndef HOUDINI_H__
|
2
24
|
#define HOUDINI_H__
|
3
25
|
|
@@ -1,3 +1,25 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2015, Vicent Marti
|
3
|
+
*
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
9
|
+
* furnished to do so, subject to the following conditions:
|
10
|
+
*
|
11
|
+
* The above copyright notice and this permission notice shall be included in
|
12
|
+
* all copies or substantial portions of the Software.
|
13
|
+
*
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
* THE SOFTWARE.
|
21
|
+
*/
|
22
|
+
|
1
23
|
#include <assert.h>
|
2
24
|
#include <stdio.h>
|
3
25
|
#include <string.h>
|
@@ -22,10 +44,10 @@
|
|
22
44
|
* have its native function (i.e. as an URL
|
23
45
|
* component/separator) and hence needs no escaping.
|
24
46
|
*
|
25
|
-
* There
|
26
|
-
*
|
27
|
-
*
|
28
|
-
*
|
47
|
+
* There is one exception: the ' (single quote)
|
48
|
+
* character does not appear in the table.
|
49
|
+
* It is meant to appear in the URL as components,
|
50
|
+
* however it require special HTML-entity escaping
|
29
51
|
* to generate valid HTML markup.
|
30
52
|
*
|
31
53
|
* All other characters will be escaped to %XX.
|
@@ -34,7 +56,7 @@
|
|
34
56
|
static const char HREF_SAFE[] = {
|
35
57
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
36
58
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
37
|
-
0, 1, 0, 1, 1, 1,
|
59
|
+
0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
38
60
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
|
39
61
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
40
62
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
|
@@ -73,12 +95,6 @@ houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size)
|
|
73
95
|
break;
|
74
96
|
|
75
97
|
switch (src[i]) {
|
76
|
-
/* amp appears all the time in URLs, but needs
|
77
|
-
* HTML-entity escaping to be inside an href */
|
78
|
-
case '&':
|
79
|
-
BUFPUTSL(ob, "&");
|
80
|
-
break;
|
81
|
-
|
82
98
|
/* the single quote is a valid URL character
|
83
99
|
* according to the standard; it needs HTML
|
84
100
|
* entity escaping too */
|
@@ -1,3 +1,25 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2015, Vicent Marti
|
3
|
+
*
|
4
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
* of this software and associated documentation files (the "Software"), to deal
|
6
|
+
* in the Software without restriction, including without limitation the rights
|
7
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
* copies of the Software, and to permit persons to whom the Software is
|
9
|
+
* furnished to do so, subject to the following conditions:
|
10
|
+
*
|
11
|
+
* The above copyright notice and this permission notice shall be included in
|
12
|
+
* all copies or substantial portions of the Software.
|
13
|
+
*
|
14
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
20
|
+
* THE SOFTWARE.
|
21
|
+
*/
|
22
|
+
|
1
23
|
#include <assert.h>
|
2
24
|
#include <stdio.h>
|
3
25
|
#include <string.h>
|
@@ -80,4 +102,3 @@ houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size)
|
|
80
102
|
{
|
81
103
|
houdini_escape_html0(ob, src, size, 1);
|
82
104
|
}
|
83
|
-
|
data/ext/greenmat/html.c
CHANGED
@@ -1,23 +1,28 @@
|
|
1
1
|
/*
|
2
2
|
* Copyright (c) 2009, Natacha Porté
|
3
|
-
* Copyright (c)
|
3
|
+
* Copyright (c) 2015, Vicent Marti
|
4
4
|
*
|
5
|
-
* Permission
|
6
|
-
*
|
7
|
-
*
|
5
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
* of this software and associated documentation files (the "Software"), to deal
|
7
|
+
* in the Software without restriction, including without limitation the rights
|
8
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
* copies of the Software, and to permit persons to whom the Software is
|
10
|
+
* furnished to do so, subject to the following conditions:
|
8
11
|
*
|
9
|
-
*
|
10
|
-
*
|
11
|
-
*
|
12
|
-
*
|
13
|
-
*
|
14
|
-
*
|
15
|
-
* OR
|
12
|
+
* The above copyright notice and this permission notice shall be included in
|
13
|
+
* all copies or substantial portions of the Software.
|
14
|
+
*
|
15
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
* THE SOFTWARE.
|
16
22
|
*/
|
17
23
|
|
18
24
|
#include "markdown.h"
|
19
25
|
#include "html.h"
|
20
|
-
#include "ruby.h"
|
21
26
|
#include <string.h>
|
22
27
|
#include <stdlib.h>
|
23
28
|
#include <stdio.h>
|
@@ -250,8 +255,15 @@ rndr_quote(struct buf *ob, const struct buf *text, void *opaque)
|
|
250
255
|
if (!text || !text->size)
|
251
256
|
return 0;
|
252
257
|
|
258
|
+
struct html_renderopt *options = opaque;
|
259
|
+
|
253
260
|
BUFPUTSL(ob, "<q>");
|
254
|
-
|
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
|
+
|
255
267
|
BUFPUTSL(ob, "</q>");
|
256
268
|
|
257
269
|
return 1;
|
@@ -265,17 +277,52 @@ rndr_linebreak(struct buf *ob, void *opaque)
|
|
265
277
|
return 1;
|
266
278
|
}
|
267
279
|
|
268
|
-
|
280
|
+
static void
|
281
|
+
rndr_header_anchor(struct buf *out, const struct buf *anchor)
|
269
282
|
{
|
270
|
-
|
271
|
-
VALUE space_regex = rb_reg_new(" +", 2 /* length */, 0);
|
272
|
-
VALUE tags_regex = rb_reg_new("<\\/?[^>]*>", 10, 0);
|
283
|
+
static const char *STRIPPED = " -&+$,/:;=?@\"#{}|^~[]`\\*()%.!'";
|
273
284
|
|
274
|
-
|
275
|
-
|
276
|
-
|
285
|
+
const uint8_t *a = anchor->data;
|
286
|
+
const size_t size = anchor->size;
|
287
|
+
size_t i = 0;
|
288
|
+
int stripped = 0, inserted = 0;
|
277
289
|
|
278
|
-
|
290
|
+
for (; i < size; ++i) {
|
291
|
+
// skip html tags
|
292
|
+
if (a[i] == '<') {
|
293
|
+
while (i < size && a[i] != '>')
|
294
|
+
i++;
|
295
|
+
// skip html entities
|
296
|
+
} else if (a[i] == '&') {
|
297
|
+
while (i < size && a[i] != ';')
|
298
|
+
i++;
|
299
|
+
}
|
300
|
+
// replace non-ascii or invalid characters with dashes
|
301
|
+
else if (!isascii(a[i]) || strchr(STRIPPED, a[i])) {
|
302
|
+
if (inserted && !stripped)
|
303
|
+
bufputc(out, '-');
|
304
|
+
// and do it only once
|
305
|
+
stripped = 1;
|
306
|
+
}
|
307
|
+
else {
|
308
|
+
bufputc(out, tolower(a[i]));
|
309
|
+
stripped = 0;
|
310
|
+
inserted++;
|
311
|
+
}
|
312
|
+
}
|
313
|
+
|
314
|
+
// replace the last dash if there was anything added
|
315
|
+
if (stripped && inserted)
|
316
|
+
out->size--;
|
317
|
+
|
318
|
+
// if anchor found empty, use djb2 hash for it
|
319
|
+
if (!inserted && anchor->size) {
|
320
|
+
unsigned long hash = 5381;
|
321
|
+
for (i = 0; i < size; ++i) {
|
322
|
+
hash = ((hash << 5) + hash) + a[i]; /* h * 33 + c */
|
323
|
+
}
|
324
|
+
bufprintf(out, "part-%lx", hash);
|
325
|
+
}
|
279
326
|
}
|
280
327
|
|
281
328
|
static void
|
@@ -286,8 +333,12 @@ rndr_header(struct buf *ob, const struct buf *text, int level, void *opaque)
|
|
286
333
|
if (ob->size)
|
287
334
|
bufputc(ob, '\n');
|
288
335
|
|
289
|
-
if ((options->flags & HTML_TOC) &&
|
290
|
-
|
336
|
+
if ((options->flags & HTML_TOC) && level >= options->toc_data.nesting_bounds[0] &&
|
337
|
+
level <= options->toc_data.nesting_bounds[1]) {
|
338
|
+
bufprintf(ob, "<h%d id=\"", level);
|
339
|
+
rndr_header_anchor(ob, text);
|
340
|
+
BUFPUTSL(ob, "\">");
|
341
|
+
}
|
291
342
|
else
|
292
343
|
bufprintf(ob, "<h%d>", level);
|
293
344
|
|
@@ -395,15 +446,30 @@ rndr_paragraph(struct buf *ob, const struct buf *text, void *opaque)
|
|
395
446
|
static void
|
396
447
|
rndr_raw_block(struct buf *ob, const struct buf *text, void *opaque)
|
397
448
|
{
|
398
|
-
size_t org,
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
449
|
+
size_t org, size;
|
450
|
+
struct html_renderopt *options = opaque;
|
451
|
+
|
452
|
+
if (!text)
|
453
|
+
return;
|
454
|
+
|
455
|
+
size = text->size;
|
456
|
+
while (size > 0 && text->data[size - 1] == '\n')
|
457
|
+
size--;
|
458
|
+
|
459
|
+
for (org = 0; org < size && text->data[org] == '\n'; ++org)
|
460
|
+
|
461
|
+
if (org >= size)
|
462
|
+
return;
|
463
|
+
|
464
|
+
/* Remove style tags if the `:no_styles` option is enabled */
|
465
|
+
if ((options->flags & HTML_SKIP_STYLE) != 0 &&
|
466
|
+
sdhtml_is_tag(text->data, size, "style"))
|
467
|
+
return;
|
468
|
+
|
469
|
+
if (ob->size)
|
470
|
+
bufputc(ob, '\n');
|
471
|
+
|
472
|
+
bufput(ob, text->data + org, size - org);
|
407
473
|
bufputc(ob, '\n');
|
408
474
|
}
|
409
475
|
|
@@ -429,10 +495,15 @@ static int
|
|
429
495
|
rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque)
|
430
496
|
{
|
431
497
|
struct html_renderopt *options = opaque;
|
432
|
-
|
498
|
+
|
499
|
+
if (link != NULL && (options->flags & HTML_SAFELINK) != 0 && !sd_autolink_issafe(link->data, link->size))
|
500
|
+
return 0;
|
433
501
|
|
434
502
|
BUFPUTSL(ob, "<img src=\"");
|
435
|
-
|
503
|
+
|
504
|
+
if (link && link->size)
|
505
|
+
escape_href(ob, link->data, link->size);
|
506
|
+
|
436
507
|
BUFPUTSL(ob, "\" alt=\"");
|
437
508
|
|
438
509
|
if (alt && alt->size)
|
@@ -440,7 +511,8 @@ rndr_image(struct buf *ob, const struct buf *link, const struct buf *title, cons
|
|
440
511
|
|
441
512
|
if (title && title->size) {
|
442
513
|
BUFPUTSL(ob, "\" title=\"");
|
443
|
-
escape_html(ob, title->data, title->size);
|
514
|
+
escape_html(ob, title->data, title->size);
|
515
|
+
}
|
444
516
|
|
445
517
|
bufputs(ob, USE_XHTML(options) ? "\"/>" : "\">");
|
446
518
|
return 1;
|
@@ -452,7 +524,7 @@ rndr_raw_html(struct buf *ob, const struct buf *text, void *opaque)
|
|
452
524
|
struct html_renderopt *options = opaque;
|
453
525
|
|
454
526
|
/* HTML_ESCAPE overrides SKIP_HTML, SKIP_STYLE, SKIP_LINKS and SKIP_IMAGES
|
455
|
-
|
527
|
+
It doesn't see if there are any valid tags, just escape all of them. */
|
456
528
|
if((options->flags & HTML_ESCAPE) != 0) {
|
457
529
|
escape_html(ob, text->data, text->size);
|
458
530
|
return 1;
|
@@ -591,7 +663,7 @@ rndr_footnote_def(struct buf *ob, const struct buf *text, unsigned int num, void
|
|
591
663
|
bufprintf(ob, "\n<li id=\"fn%d\">\n", num);
|
592
664
|
if (pfound) {
|
593
665
|
bufput(ob, text->data, i);
|
594
|
-
bufprintf(ob, " <a href=\"#fnref%d\"
|
666
|
+
bufprintf(ob, " <a href=\"#fnref%d\">↩</a>", num);
|
595
667
|
bufput(ob, text->data + i, text->size - i);
|
596
668
|
} else if (text) {
|
597
669
|
bufput(ob, text->data, text->size);
|
@@ -602,7 +674,7 @@ rndr_footnote_def(struct buf *ob, const struct buf *text, unsigned int num, void
|
|
602
674
|
static int
|
603
675
|
rndr_footnote_ref(struct buf *ob, unsigned int num, void *opaque)
|
604
676
|
{
|
605
|
-
bufprintf(ob, "<sup id=\"fnref%d\"><a href=\"#fn%d\"
|
677
|
+
bufprintf(ob, "<sup id=\"fnref%d\"><a href=\"#fn%d\">%d</a></sup>", num, num, num);
|
606
678
|
return 1;
|
607
679
|
}
|
608
680
|
|
@@ -611,7 +683,8 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
|
|
611
683
|
{
|
612
684
|
struct html_renderopt *options = opaque;
|
613
685
|
|
614
|
-
if (level
|
686
|
+
if (level >= options->toc_data.nesting_bounds[0] &&
|
687
|
+
level <= options->toc_data.nesting_bounds[1]) {
|
615
688
|
/* set the level offset if this is the first header
|
616
689
|
* we're parsing for the document */
|
617
690
|
if (options->toc_data.current_level == 0)
|
@@ -635,8 +708,17 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
|
|
635
708
|
BUFPUTSL(ob,"</li>\n<li>\n");
|
636
709
|
}
|
637
710
|
|
638
|
-
bufprintf(ob, "<a href=\"
|
639
|
-
|
711
|
+
bufprintf(ob, "<a href=\"#");
|
712
|
+
rndr_header_anchor(ob, text);
|
713
|
+
BUFPUTSL(ob, "\">");
|
714
|
+
|
715
|
+
if (text) {
|
716
|
+
if (options->flags & HTML_ESCAPE)
|
717
|
+
escape_html(ob, text->data, text->size);
|
718
|
+
else
|
719
|
+
bufput(ob, text->data, text->size);
|
720
|
+
}
|
721
|
+
|
640
722
|
BUFPUTSL(ob, "</a>\n");
|
641
723
|
}
|
642
724
|
}
|
@@ -661,7 +743,7 @@ toc_finalize(struct buf *ob, void *opaque)
|
|
661
743
|
}
|
662
744
|
|
663
745
|
void
|
664
|
-
sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options, int
|
746
|
+
sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options, unsigned int render_flags)
|
665
747
|
{
|
666
748
|
static const struct sd_callbacks cb_default = {
|
667
749
|
NULL,
|
@@ -702,8 +784,7 @@ sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *optio
|
|
702
784
|
};
|
703
785
|
|
704
786
|
memset(options, 0x0, sizeof(struct html_renderopt));
|
705
|
-
options->flags =
|
706
|
-
options->toc_data.nesting_level = nesting_level;
|
787
|
+
options->flags = render_flags;
|
707
788
|
|
708
789
|
memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks));
|
709
790
|
}
|
@@ -752,7 +833,8 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options,
|
|
752
833
|
/* Prepare the options pointer */
|
753
834
|
memset(options, 0x0, sizeof(struct html_renderopt));
|
754
835
|
options->flags = render_flags;
|
755
|
-
options->toc_data.
|
836
|
+
options->toc_data.nesting_bounds[0] = 1;
|
837
|
+
options->toc_data.nesting_bounds[1] = 6;
|
756
838
|
|
757
839
|
/* Prepare the callbacks */
|
758
840
|
memcpy(callbacks, &cb_default, sizeof(struct sd_callbacks));
|