redcarpet 3.3.4 → 3.5.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/Gemfile +2 -2
- data/README.markdown +45 -34
- data/ext/redcarpet/autolink.c +7 -1
- data/ext/redcarpet/buffer.h +0 -1
- data/ext/redcarpet/houdini_href_e.c +5 -11
- data/ext/redcarpet/houdini_html_e.c +0 -1
- data/ext/redcarpet/html.c +34 -7
- data/ext/redcarpet/html.h +1 -2
- data/ext/redcarpet/html_blocks.h +68 -70
- data/ext/redcarpet/html_smartypants.c +20 -5
- data/ext/redcarpet/markdown.c +5 -7
- data/ext/redcarpet/rc_markdown.c +17 -2
- data/ext/redcarpet/rc_render.c +28 -5
- data/lib/redcarpet/cli.rb +1 -1
- data/lib/redcarpet/compat.rb +0 -2
- data/lib/redcarpet/render_strip.rb +1 -1
- data/lib/redcarpet.rb +1 -1
- data/redcarpet.gemspec +5 -4
- data/test/custom_render_test.rb +40 -1
- data/test/html5_test.rb +51 -38
- data/test/html_render_test.rb +86 -60
- data/test/html_toc_render_test.rb +41 -4
- data/test/markdown_test.rb +226 -181
- data/test/redcarpet_bin_test.rb +2 -2
- data/test/smarty_html_test.rb +11 -5
- data/test/smarty_pants_test.rb +5 -0
- data/test/stripdown_render_test.rb +14 -6
- data/test/test_helper.rb +9 -1
- metadata +24 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3e6ea78031a1e40620168cd57fcbfae06bec5bafabc8f6e600adc552a4fe5b40
|
4
|
+
data.tar.gz: 658dd33e836daa11effa88e0491d09387963ea349751efd278e9fbdac7026066
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b17b0208c25d4e8566fb4a154d0f66e778b702abcf58d1d1227fa2510be421c7496e20fd6402066adba3485778e935b46aff73fd412802eedb89e44470a7ad94
|
7
|
+
data.tar.gz: 1e1c8dd559979b8bd5f4de2d20e1127b2a964c03a267133c3d9a3703f71bce44a2f4dc2efdb0dc0cc331e0ab779bfad23e9b62af0ffc4ee9078896376bd86865
|
data/Gemfile
CHANGED
data/README.markdown
CHANGED
@@ -3,6 +3,7 @@ Redcarpet is written with sugar, spice and everything nice
|
|
3
3
|
|
4
4
|
[![Build Status](https://travis-ci.org/vmg/redcarpet.svg?branch=master)](https://travis-ci.org/vmg/redcarpet)
|
5
5
|
[![Dependency Status](https://www.versioneye.com/ruby/redcarpet/badge.svg)](https://www.versioneye.com/ruby/redcarpet)
|
6
|
+
[![Help Contribute to Open Source](https://www.codetriage.com/vmg/redcarpet/badges/users.svg)](https://www.codetriage.com/vmg/redcarpet)
|
6
7
|
|
7
8
|
Redcarpet is a Ruby library for Markdown processing that smells like
|
8
9
|
butterflies and popcorn.
|
@@ -25,7 +26,7 @@ Starting with Redcarpet 3.0, the minimum required Ruby version is 1.9.2 (or Rubi
|
|
25
26
|
|
26
27
|
$ [sudo] gem install redcarpet
|
27
28
|
|
28
|
-
If you need to use it with Ruby 1.8.7, you will
|
29
|
+
If you need to use it with Ruby 1.8.7, you will have to stick with 2.3.0:
|
29
30
|
|
30
31
|
$ [sudo] gem install redcarpet -v 2.3.0
|
31
32
|
|
@@ -45,10 +46,10 @@ output.
|
|
45
46
|
The `Redcarpet::Markdown` object is encouraged to be instantiated once with the
|
46
47
|
required settings, and reused between parses.
|
47
48
|
|
48
|
-
|
49
|
+
~~~~ ruby
|
49
50
|
# Initializes a Markdown parser
|
50
51
|
markdown = Redcarpet::Markdown.new(renderer, extensions = {})
|
51
|
-
|
52
|
+
~~~~
|
52
53
|
|
53
54
|
Here, the `renderer` variable refers to a renderer object, inheriting
|
54
55
|
from `Redcarpet::Render::Base`. If the given object has not been
|
@@ -59,10 +60,10 @@ Unlike in the RedCloth API, the text to render is passed as an argument
|
|
59
60
|
and not stored inside the `Markdown` instance, to encourage reusability.
|
60
61
|
Example:
|
61
62
|
|
62
|
-
|
63
|
+
~~~~ ruby
|
63
64
|
markdown.render("This is *bongos*, indeed.")
|
64
65
|
# => "<p>This is <em>bongos</em>, indeed.</p>"
|
65
|
-
|
66
|
+
~~~~
|
66
67
|
|
67
68
|
You can also specify a hash containing the Markdown extensions which the
|
68
69
|
parser will identify. The following extensions are accepted:
|
@@ -119,9 +120,9 @@ within the document (e.g. `[^1]: This is a footnote.`).
|
|
119
120
|
|
120
121
|
Example:
|
121
122
|
|
122
|
-
|
123
|
+
~~~~ ruby
|
123
124
|
markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML, autolink: true, tables: true)
|
124
|
-
|
125
|
+
~~~~
|
125
126
|
|
126
127
|
Darling, I packed you a couple renderers for lunch
|
127
128
|
--------------------------------------------------
|
@@ -136,9 +137,9 @@ All the rendering flags that previously applied only to HTML output have
|
|
136
137
|
now been moved to the `Redcarpet::Render::HTML` class, and may be enabled when
|
137
138
|
instantiating the renderer:
|
138
139
|
|
139
|
-
|
140
|
+
~~~~ ruby
|
140
141
|
Redcarpet::Render::HTML.new(render_options = {})
|
141
|
-
|
142
|
+
~~~~
|
142
143
|
|
143
144
|
Initializes an HTML renderer. The following flags are available:
|
144
145
|
|
@@ -172,9 +173,9 @@ Markdown document had newlines (by default, Markdown ignores these newlines).
|
|
172
173
|
|
173
174
|
Example:
|
174
175
|
|
175
|
-
|
176
|
+
~~~~ ruby
|
176
177
|
renderer = Redcarpet::Render::HTML.new(no_links: true, hard_wrap: true)
|
177
|
-
|
178
|
+
~~~~
|
178
179
|
|
179
180
|
|
180
181
|
The `HTML` renderer has an alternate version, `Redcarpet::Render::HTML_TOC`,
|
@@ -182,12 +183,21 @@ which will output a table of contents in HTML based on the headers of the
|
|
182
183
|
Markdown document.
|
183
184
|
|
184
185
|
When instantiating this render object, you can optionally pass a `nesting_level`
|
185
|
-
option which takes an integer and allows you to make it render only
|
186
|
-
|
186
|
+
option which takes an integer or a range and allows you to make it render only
|
187
|
+
headers at certain levels.
|
187
188
|
|
188
|
-
|
189
|
-
|
190
|
-
|
189
|
+
Redcarpet also includes a plaintext renderer, `Redcarpet::Render::StripDown`, that
|
190
|
+
strips out all the formatting:
|
191
|
+
|
192
|
+
~~~~ ruby
|
193
|
+
require 'redcarpet'
|
194
|
+
require 'redcarpet/render_strip'
|
195
|
+
|
196
|
+
markdown = Redcarpet::Markdown.new(Redcarpet::Render::StripDown)
|
197
|
+
|
198
|
+
markdown.render("**This** _is_ an [example](http://example.org/).")
|
199
|
+
# => "This is an example (http://example.org/)."
|
200
|
+
~~~~
|
191
201
|
|
192
202
|
|
193
203
|
And you can even cook your own
|
@@ -196,25 +206,26 @@ And you can even cook your own
|
|
196
206
|
Custom renderers are created by inheriting from an existing renderer. The
|
197
207
|
built-in renderers, `HTML` and `XHTML` may be extended as such:
|
198
208
|
|
199
|
-
|
200
|
-
#
|
201
|
-
class
|
202
|
-
def
|
203
|
-
|
209
|
+
~~~~ ruby
|
210
|
+
# Create a custom renderer that sets a custom class for block-quotes.
|
211
|
+
class CustomRender < Redcarpet::Render::HTML
|
212
|
+
def block_quote(quote)
|
213
|
+
%(<blockquote class="my-custom-class">#{quote}</blockquote>)
|
204
214
|
end
|
205
215
|
end
|
206
216
|
|
207
|
-
markdown = Redcarpet::Markdown.new(
|
208
|
-
|
217
|
+
markdown = Redcarpet::Markdown.new(CustomRender, fenced_code_blocks: true)
|
218
|
+
~~~~
|
209
219
|
|
210
|
-
But new renderers can also be created from scratch
|
211
|
-
|
220
|
+
But new renderers can also be created from scratch by extending the abstract
|
221
|
+
base class `Redcarpet::Render::Base` (see `lib/redcarpet/render_man.rb` for
|
222
|
+
an example implementation of a Manpage renderer):
|
212
223
|
|
213
|
-
|
224
|
+
~~~~ ruby
|
214
225
|
class ManPage < Redcarpet::Render::Base
|
215
226
|
# you get the drill -- keep going from here
|
216
227
|
end
|
217
|
-
|
228
|
+
~~~~
|
218
229
|
|
219
230
|
The following instance methods may be implemented by the renderer:
|
220
231
|
|
@@ -302,7 +313,7 @@ or after the rendering process begins:
|
|
302
313
|
* postprocess(full_document)
|
303
314
|
|
304
315
|
You can look at
|
305
|
-
["How to extend the Redcarpet 2 Markdown library?"](http://dev.af83.com/2012/02/27/howto-extend-the-redcarpet2-markdown-lib.html)
|
316
|
+
["How to extend the Redcarpet 2 Markdown library?"](https://web.archive.org/web/20170505231254/http://dev.af83.com/2012/02/27/howto-extend-the-redcarpet2-markdown-lib.html)
|
306
317
|
for some more explanations.
|
307
318
|
|
308
319
|
Also, now our Pants are much smarter
|
@@ -327,7 +338,7 @@ end
|
|
327
338
|
|
328
339
|
# Standalone
|
329
340
|
Redcarpet::Render::SmartyPants.render("<p>Oh SmartyPants, you're so crazy...</p>")
|
330
|
-
|
341
|
+
~~~~
|
331
342
|
|
332
343
|
SmartyPants works on top of already-rendered HTML, and will ignore replacements
|
333
344
|
inside the content of HTML tags and inside specific HTML blocks such as
|
@@ -352,16 +363,16 @@ renderer-independent, the results will be completely unreliable!
|
|
352
363
|
Still, if major forces (let's say, tornadoes or other natural disasters) force you
|
353
364
|
to keep a Markdown-compatibility layer, Redcarpet also supports this:
|
354
365
|
|
355
|
-
|
366
|
+
~~~~ ruby
|
356
367
|
require 'redcarpet/compat'
|
357
|
-
|
368
|
+
~~~~
|
358
369
|
|
359
370
|
Requiring the compatibility library will declare a `Markdown` class with the
|
360
371
|
classical RedCloth API, e.g.
|
361
372
|
|
362
|
-
|
373
|
+
~~~~ ruby
|
363
374
|
Markdown.new('this is my text').to_html
|
364
|
-
|
375
|
+
~~~~
|
365
376
|
|
366
377
|
This class renders 100% standards compliant Markdown with 0 extensions. Nada.
|
367
378
|
Don't even try to enable extensions with a compatibility layer, because
|
@@ -373,7 +384,7 @@ monkeypatches the Markdown class, you're a terrible human being. Just saying.
|
|
373
384
|
Boring legal stuff
|
374
385
|
------------------
|
375
386
|
|
376
|
-
Copyright (c) 2011-
|
387
|
+
Copyright (c) 2011-2016, Vicent Martí
|
377
388
|
|
378
389
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
379
390
|
of this software and associated documentation files (the "Software"), to deal
|
data/ext/redcarpet/autolink.c
CHANGED
@@ -294,9 +294,15 @@ sd_autolink__url(
|
|
294
294
|
if (link_end == 0)
|
295
295
|
return 0;
|
296
296
|
|
297
|
+
/**
|
298
|
+
* In certain cases, we may refer to a link at the end of a
|
299
|
+
* sentence so the period should not be part of the URL.
|
300
|
+
*/
|
301
|
+
if (data[link_end - 1] == '.')
|
302
|
+
link_end--;
|
303
|
+
|
297
304
|
bufput(link, data - rewind, link_end + rewind);
|
298
305
|
*rewind_p = rewind;
|
299
306
|
|
300
307
|
return link_end;
|
301
308
|
}
|
302
|
-
|
data/ext/redcarpet/buffer.h
CHANGED
@@ -44,10 +44,10 @@
|
|
44
44
|
* have its native function (i.e. as an URL
|
45
45
|
* component/separator) and hence needs no escaping.
|
46
46
|
*
|
47
|
-
* There
|
48
|
-
*
|
49
|
-
*
|
50
|
-
*
|
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
|
51
51
|
* to generate valid HTML markup.
|
52
52
|
*
|
53
53
|
* All other characters will be escaped to %XX.
|
@@ -56,7 +56,7 @@
|
|
56
56
|
static const char HREF_SAFE[] = {
|
57
57
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
58
58
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
59
|
-
0, 1, 0, 1, 1, 1,
|
59
|
+
0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1,
|
60
60
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1,
|
61
61
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
62
62
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
|
@@ -95,12 +95,6 @@ houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size)
|
|
95
95
|
break;
|
96
96
|
|
97
97
|
switch (src[i]) {
|
98
|
-
/* amp appears all the time in URLs, but needs
|
99
|
-
* HTML-entity escaping to be inside an href */
|
100
|
-
case '&':
|
101
|
-
BUFPUTSL(ob, "&");
|
102
|
-
break;
|
103
|
-
|
104
98
|
/* the single quote is a valid URL character
|
105
99
|
* according to the standard; it needs HTML
|
106
100
|
* entity escaping too */
|
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
|
-
|
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;
|
@@ -281,13 +288,20 @@ rndr_header_anchor(struct buf *out, const struct buf *anchor)
|
|
281
288
|
int stripped = 0, inserted = 0;
|
282
289
|
|
283
290
|
for (; i < size; ++i) {
|
291
|
+
// skip html tags
|
284
292
|
if (a[i] == '<') {
|
285
293
|
while (i < size && a[i] != '>')
|
286
294
|
i++;
|
295
|
+
// skip html entities
|
296
|
+
} else if (a[i] == '&') {
|
297
|
+
while (i < size && a[i] != ';')
|
298
|
+
i++;
|
287
299
|
}
|
300
|
+
// replace non-ascii or invalid characters with dashes
|
288
301
|
else if (!isascii(a[i]) || strchr(STRIPPED, a[i])) {
|
289
302
|
if (inserted && !stripped)
|
290
303
|
bufputc(out, '-');
|
304
|
+
// and do it only once
|
291
305
|
stripped = 1;
|
292
306
|
}
|
293
307
|
else {
|
@@ -297,8 +311,18 @@ rndr_header_anchor(struct buf *out, const struct buf *anchor)
|
|
297
311
|
}
|
298
312
|
}
|
299
313
|
|
300
|
-
if
|
314
|
+
// replace the last dash if there was anything added
|
315
|
+
if (stripped && inserted)
|
301
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
|
+
}
|
302
326
|
}
|
303
327
|
|
304
328
|
static void
|
@@ -309,7 +333,8 @@ rndr_header(struct buf *ob, const struct buf *text, int level, void *opaque)
|
|
309
333
|
if (ob->size)
|
310
334
|
bufputc(ob, '\n');
|
311
335
|
|
312
|
-
if ((options->flags & HTML_TOC) &&
|
336
|
+
if ((options->flags & HTML_TOC) && level >= options->toc_data.nesting_bounds[0] &&
|
337
|
+
level <= options->toc_data.nesting_bounds[1]) {
|
313
338
|
bufprintf(ob, "<h%d id=\"", level);
|
314
339
|
rndr_header_anchor(ob, text);
|
315
340
|
BUFPUTSL(ob, "\">");
|
@@ -638,7 +663,7 @@ rndr_footnote_def(struct buf *ob, const struct buf *text, unsigned int num, void
|
|
638
663
|
bufprintf(ob, "\n<li id=\"fn%d\">\n", num);
|
639
664
|
if (pfound) {
|
640
665
|
bufput(ob, text->data, i);
|
641
|
-
bufprintf(ob, " <a href=\"#fnref%d\"
|
666
|
+
bufprintf(ob, " <a href=\"#fnref%d\">↩</a>", num);
|
642
667
|
bufput(ob, text->data + i, text->size - i);
|
643
668
|
} else if (text) {
|
644
669
|
bufput(ob, text->data, text->size);
|
@@ -649,7 +674,7 @@ rndr_footnote_def(struct buf *ob, const struct buf *text, unsigned int num, void
|
|
649
674
|
static int
|
650
675
|
rndr_footnote_ref(struct buf *ob, unsigned int num, void *opaque)
|
651
676
|
{
|
652
|
-
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);
|
653
678
|
return 1;
|
654
679
|
}
|
655
680
|
|
@@ -658,7 +683,8 @@ toc_header(struct buf *ob, const struct buf *text, int level, void *opaque)
|
|
658
683
|
{
|
659
684
|
struct html_renderopt *options = opaque;
|
660
685
|
|
661
|
-
if (level
|
686
|
+
if (level >= options->toc_data.nesting_bounds[0] &&
|
687
|
+
level <= options->toc_data.nesting_bounds[1]) {
|
662
688
|
/* set the level offset if this is the first header
|
663
689
|
* we're parsing for the document */
|
664
690
|
if (options->toc_data.current_level == 0)
|
@@ -807,7 +833,8 @@ sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options,
|
|
807
833
|
/* Prepare the options pointer */
|
808
834
|
memset(options, 0x0, sizeof(struct html_renderopt));
|
809
835
|
options->flags = render_flags;
|
810
|
-
options->toc_data.
|
836
|
+
options->toc_data.nesting_bounds[0] = 1;
|
837
|
+
options->toc_data.nesting_bounds[1] = 6;
|
811
838
|
|
812
839
|
/* Prepare the callbacks */
|
813
840
|
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
|
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
|
-
|
data/ext/redcarpet/html_blocks.h
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
/* C code produced by gperf version 3.0.
|
1
|
+
/* C code produced by gperf version 3.0.3 */
|
2
2
|
/* Command-line: gperf -N find_block_tag -H hash_block_tag -C -c -E --ignore-case html_block_names.txt */
|
3
|
-
/* See
|
3
|
+
/* See https://git.io/vPLqa for the list of recognized elements */
|
4
4
|
/* Computed positions: -k'1-2' */
|
5
5
|
|
6
6
|
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
|
@@ -30,7 +30,7 @@
|
|
30
30
|
error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gnu-gperf@gnu.org>."
|
31
31
|
#endif
|
32
32
|
|
33
|
-
/* maximum key range =
|
33
|
+
/* maximum key range = 72, duplicates = 0 */
|
34
34
|
|
35
35
|
#ifndef GPERF_DOWNCASE
|
36
36
|
#define GPERF_DOWNCASE 1
|
@@ -94,34 +94,34 @@ hash_block_tag (str, len)
|
|
94
94
|
{
|
95
95
|
static const unsigned char asso_values[] =
|
96
96
|
{
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
0,
|
105
|
-
0,
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
97
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
98
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
99
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
100
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
101
|
+
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,
|
105
|
+
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,
|
109
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
110
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
111
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
112
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
113
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
114
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
115
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
116
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
117
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
118
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
119
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
120
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
121
|
+
73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
|
122
|
+
73, 73, 73, 73, 73, 73, 73
|
123
123
|
};
|
124
|
-
register int hval = len;
|
124
|
+
register unsigned int hval = len;
|
125
125
|
|
126
126
|
switch (hval)
|
127
127
|
{
|
@@ -135,12 +135,6 @@ hash_block_tag (str, len)
|
|
135
135
|
return hval;
|
136
136
|
}
|
137
137
|
|
138
|
-
#ifdef __GNUC__
|
139
|
-
__inline
|
140
|
-
#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__
|
141
|
-
__attribute__ ((__gnu_inline__))
|
142
|
-
#endif
|
143
|
-
#endif
|
144
138
|
const char *
|
145
139
|
find_block_tag (str, len)
|
146
140
|
register const char *str;
|
@@ -148,76 +142,80 @@ find_block_tag (str, len)
|
|
148
142
|
{
|
149
143
|
enum
|
150
144
|
{
|
151
|
-
TOTAL_KEYWORDS =
|
145
|
+
TOTAL_KEYWORDS = 43,
|
152
146
|
MIN_WORD_LENGTH = 1,
|
153
147
|
MAX_WORD_LENGTH = 10,
|
154
148
|
MIN_HASH_VALUE = 1,
|
155
|
-
MAX_HASH_VALUE =
|
149
|
+
MAX_HASH_VALUE = 72
|
156
150
|
};
|
157
151
|
|
158
152
|
static const char * const wordlist[] =
|
159
153
|
{
|
160
154
|
"",
|
161
155
|
"p",
|
162
|
-
"
|
163
|
-
"
|
156
|
+
"dl",
|
157
|
+
"del",
|
164
158
|
"form",
|
165
|
-
"
|
159
|
+
"",
|
166
160
|
"footer",
|
167
|
-
"
|
168
|
-
"",
|
161
|
+
"details",
|
162
|
+
"div",
|
163
|
+
"", "",
|
169
164
|
"figure",
|
170
|
-
"
|
165
|
+
"ul",
|
171
166
|
"fieldset",
|
172
|
-
"
|
167
|
+
"",
|
173
168
|
"figcaption",
|
174
169
|
"header",
|
175
|
-
"
|
176
|
-
"
|
177
|
-
"",
|
178
|
-
"
|
170
|
+
"ol",
|
171
|
+
"pre",
|
172
|
+
"math",
|
173
|
+
"video",
|
179
174
|
"script",
|
180
|
-
"
|
181
|
-
"
|
175
|
+
"section",
|
176
|
+
"noscript",
|
182
177
|
"",
|
183
|
-
"
|
178
|
+
"blockquote",
|
184
179
|
"hgroup",
|
185
|
-
"
|
186
|
-
"
|
187
|
-
"",
|
180
|
+
"hr",
|
181
|
+
"ins",
|
182
|
+
"",
|
183
|
+
"style",
|
184
|
+
"output",
|
185
|
+
"summary",
|
186
|
+
"nav",
|
187
|
+
"",
|
188
|
+
"audio",
|
188
189
|
"canvas",
|
189
190
|
"dd",
|
190
|
-
"
|
191
|
+
"h1",
|
191
192
|
"abbr",
|
192
|
-
"audio",
|
193
|
-
"iframe",
|
194
|
-
"address",
|
195
|
-
"ins",
|
196
|
-
"",
|
197
193
|
"table",
|
198
|
-
"",
|
199
|
-
"
|
194
|
+
"iframe",
|
195
|
+
"article",
|
200
196
|
"", "",
|
201
197
|
"aside",
|
202
|
-
"
|
203
|
-
"
|
198
|
+
"",
|
199
|
+
"h6",
|
204
200
|
"", "",
|
205
201
|
"tfoot",
|
206
202
|
"",
|
203
|
+
"h5",
|
204
|
+
"", "", "", "",
|
207
205
|
"h4",
|
208
206
|
"", "", "", "",
|
209
|
-
"
|
207
|
+
"address",
|
210
208
|
"", "", "", "",
|
211
|
-
"
|
209
|
+
"h3",
|
212
210
|
"", "", "", "",
|
213
|
-
"
|
211
|
+
"h2"
|
214
212
|
};
|
215
213
|
|
216
214
|
if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
|
217
215
|
{
|
218
|
-
|
216
|
+
unsigned int key = hash_block_tag (str, len);
|
219
217
|
|
220
|
-
if (key <= MAX_HASH_VALUE
|
218
|
+
if (key <= MAX_HASH_VALUE)
|
221
219
|
{
|
222
220
|
register const char *s = wordlist[key];
|
223
221
|
|
@@ -151,6 +151,9 @@ smartypants_squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previo
|
|
151
151
|
return next_squote_len;
|
152
152
|
}
|
153
153
|
|
154
|
+
if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote))
|
155
|
+
return 0;
|
156
|
+
|
154
157
|
// trailing single quotes: students', tryin'
|
155
158
|
if (word_boundary(t1)) {
|
156
159
|
BUFPUTSL(ob, "’");
|
@@ -178,9 +181,6 @@ smartypants_squote(struct buf *ob, struct smartypants_data *smrt, uint8_t previo
|
|
178
181
|
}
|
179
182
|
}
|
180
183
|
|
181
|
-
if (smartypants_quotes(ob, previous_char, size > 0 ? text[1] : 0, 's', &smrt->in_squote))
|
182
|
-
return 0;
|
183
|
-
|
184
184
|
bufput(ob, squote_text, squote_size);
|
185
185
|
return 0;
|
186
186
|
}
|
@@ -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("'", text+(i+1), 5) == 0) {
|
386
|
+
bufput(ob, "’", 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
|
-
|