├── test ├── MarkdownTest_1.0.3 │ ├── Tests │ │ ├── Nested blockquotes.text │ │ ├── Tidyness.text │ │ ├── Strong and em together.text │ │ ├── Literal quotes in titles.text │ │ ├── Nested blockquotes.html │ │ ├── Tidyness.html │ │ ├── Code Spans.text │ │ ├── Literal quotes in titles.html │ │ ├── Blockquotes with code blocks.text │ │ ├── Inline HTML (Advanced).text │ │ ├── Inline HTML comments.text │ │ ├── Code Spans.html │ │ ├── Inline HTML (Advanced).html │ │ ├── Strong and em together.html │ │ ├── Hard-wrapped paragraphs with list-like lines.text │ │ ├── Code Blocks.text │ │ ├── Inline HTML comments.html │ │ ├── Hard-wrapped paragraphs with list-like lines.html │ │ ├── Blockquotes with code blocks.html │ │ ├── Links, inline style.text │ │ ├── Links, shortcut references.html │ │ ├── Auto links.text │ │ ├── Links, shortcut references.text │ │ ├── Code Blocks.html │ │ ├── Tabs.text │ │ ├── Links, inline style.html │ │ ├── Amps and angle encoding.text │ │ ├── Tabs.html │ │ ├── Amps and angle encoding.html │ │ ├── Horizontal rules.text │ │ ├── Auto links.html │ │ ├── Horizontal rules.html │ │ ├── Inline HTML (Simple).text │ │ ├── Inline HTML (Simple).html │ │ ├── Links, reference style.text │ │ ├── Links, reference style.html │ │ ├── Ordered and unordered lists.text │ │ ├── Backslash escapes.text │ │ ├── Backslash escapes.html │ │ ├── Ordered and unordered lists.html │ │ ├── Markdown Documentation - Basics.text │ │ └── Markdown Documentation - Basics.html │ └── MarkdownTest.pl ├── MarkdownTest_1.0 │ ├── Tests │ │ ├── Nested blockquotes.text │ │ ├── Tidyness.text │ │ ├── Literal quotes in titles.text │ │ ├── Strong and em together.text │ │ ├── Nested blockquotes.html │ │ ├── Tidyness.html │ │ ├── Literal quotes in titles.html │ │ ├── Blockquotes with code blocks.text │ │ ├── Inline HTML (Advanced).text │ │ ├── Links, inline style.text │ │ ├── Inline HTML (Advanced).html │ │ ├── Inline HTML comments.text │ │ ├── Strong and em together.html │ │ ├── Hard-wrapped paragraphs with list-like lines.text │ │ ├── Inline HTML comments.html │ │ ├── Blockquotes with code blocks.html │ │ ├── Hard-wrapped paragraphs with list-like lines.html │ │ ├── Auto links.text │ │ ├── Links, inline style.html │ │ ├── Tabs.text │ │ ├── Links, reference style.text │ │ ├── Amps and angle encoding.text │ │ ├── Links, reference style.html │ │ ├── Tabs.html │ │ ├── Amps and angle encoding.html │ │ ├── Horizontal rules.text │ │ ├── Auto links.html │ │ ├── Horizontal rules.html │ │ ├── Inline HTML (Simple).text │ │ ├── Inline HTML (Simple).html │ │ ├── Backslash escapes.text │ │ ├── Ordered and unordered lists.text │ │ ├── Backslash escapes.html │ │ ├── Ordered and unordered lists.html │ │ ├── Markdown Documentation - Basics.text │ │ └── Markdown Documentation - Basics.html │ └── MarkdownTest.pl ├── benchmark.rb ├── custom_render_test.rb ├── pathological_inputs_test.rb ├── test_helper.rb ├── safe_render_test.rb ├── redcarpet_compat_test.rb ├── smarty_html_test.rb ├── html5_test.rb ├── stripdown_render_test.rb ├── redcarpet_bin_test.rb ├── smarty_pants_test.rb ├── html_toc_render_test.rb ├── html_render_test.rb └── fixtures │ └── benchmark.md ├── .gitignore ├── ext └── redcarpet │ ├── extconf.rb │ ├── stack.h │ ├── redcarpet.h │ ├── autolink.h │ ├── houdini.h │ ├── stack.c │ ├── html.h │ ├── buffer.h │ ├── houdini_html_e.c │ ├── houdini_href_e.c │ ├── buffer.c │ ├── rc_markdown.c │ ├── markdown.h │ ├── autolink.c │ └── html_blocks.h ├── bin └── redcarpet ├── Gemfile ├── .travis.yml ├── COPYING ├── lib ├── redcarpet │ ├── render_man.rb │ ├── render_strip.rb │ ├── compat.rb │ └── cli.rb └── redcarpet.rb ├── CONTRIBUTING.md ├── Rakefile ├── redcarpet.gemspec └── CHANGELOG.md /test/MarkdownTest_1.0.3/Tests/Nested blockquotes.text: -------------------------------------------------------------------------------- 1 | > foo 2 | > 3 | > > bar 4 | > 5 | > foo 6 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Nested blockquotes.text: -------------------------------------------------------------------------------- 1 | > foo 2 | > 3 | > > bar 4 | > 5 | > foo 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bundle 2 | *.o 3 | *.so 4 | *.swp 5 | /ext/redcarpet/Makefile 6 | /tmp 7 | Gemfile.lock 8 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Tidyness.text: -------------------------------------------------------------------------------- 1 | > A list within a blockquote: 2 | > 3 | > * asterisk 1 4 | > * asterisk 2 5 | > * asterisk 3 6 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Tidyness.text: -------------------------------------------------------------------------------- 1 | > A list within a blockquote: 2 | > 3 | > * asterisk 1 4 | > * asterisk 2 5 | > * asterisk 3 6 | -------------------------------------------------------------------------------- /ext/redcarpet/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | 3 | $CFLAGS << ' -fvisibility=hidden' 4 | 5 | dir_config('redcarpet') 6 | create_makefile('redcarpet') 7 | -------------------------------------------------------------------------------- /bin/redcarpet: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | lib_path = File.expand_path('../../lib', __FILE__) 3 | $:.unshift(lib_path) 4 | 5 | require 'redcarpet/cli' 6 | 7 | Redcarpet::CLI.process(ARGV) 8 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Strong and em together.text: -------------------------------------------------------------------------------- 1 | ***This is strong and em.*** 2 | 3 | So is ***this*** word. 4 | 5 | ___This is strong and em.___ 6 | 7 | So is ___this___ word. 8 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Literal quotes in titles.text: -------------------------------------------------------------------------------- 1 | Foo [bar][]. 2 | 3 | Foo [bar](/url/ "Title with "quotes" inside"). 4 | 5 | 6 | [bar]: /url/ "Title with "quotes" inside" 7 | 8 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Strong and em together.text: -------------------------------------------------------------------------------- 1 | ***This is strong and em.*** 2 | 3 | So is ***this*** word. 4 | 5 | ___This is strong and em.___ 6 | 7 | So is ___this___ word. 8 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Literal quotes in titles.text: -------------------------------------------------------------------------------- 1 | Foo [bar][]. 2 | 3 | Foo [bar](/url/ "Title with "quotes" inside"). 4 | 5 | 6 | [bar]: /url/ "Title with "quotes" inside" 7 | 8 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Nested blockquotes.html: -------------------------------------------------------------------------------- 1 |
2 |

foo

3 | 4 |
5 |

bar

6 |
7 | 8 |

foo

9 |
10 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Nested blockquotes.html: -------------------------------------------------------------------------------- 1 |
2 |

foo

3 | 4 |
5 |

bar

6 |
7 | 8 |

foo

9 |
10 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Tidyness.html: -------------------------------------------------------------------------------- 1 |
2 |

A list within a blockquote:

3 | 8 |
9 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Tidyness.html: -------------------------------------------------------------------------------- 1 |
2 |

A list within a blockquote:

3 | 8 |
9 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org/" 2 | 3 | gemspec 4 | 5 | group :benchmark do 6 | gem "benchmark-ips", "~> 2.3.0" 7 | gem "bluecloth", "~> 2.2.0" 8 | gem "kramdown", "~> 1.8.0" 9 | end 10 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Literal quotes in titles.html: -------------------------------------------------------------------------------- 1 |

Foo bar.

2 | 3 |

Foo bar.

4 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Code Spans.text: -------------------------------------------------------------------------------- 1 | `` 2 | 3 | Fix for backticks within HTML tag: like this 4 | 5 | Here's how you put `` `backticks` `` in a code span. 6 | 7 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Literal quotes in titles.html: -------------------------------------------------------------------------------- 1 |

Foo bar.

2 | 3 |

Foo bar.

4 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Blockquotes with code blocks.text: -------------------------------------------------------------------------------- 1 | > Example: 2 | > 3 | > sub status { 4 | > print "working"; 5 | > } 6 | > 7 | > Or: 8 | > 9 | > sub status { 10 | > return "working"; 11 | > } 12 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.text: -------------------------------------------------------------------------------- 1 | > Example: 2 | > 3 | > sub status { 4 | > print "working"; 5 | > } 6 | > 7 | > Or: 8 | > 9 | > sub status { 10 | > return "working"; 11 | > } 12 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Inline HTML (Advanced).text: -------------------------------------------------------------------------------- 1 | Simple block on one line: 2 | 3 |
foo
4 | 5 | And nested without indentation: 6 | 7 |
8 |
9 |
10 | foo 11 |
12 |
13 |
bar
14 |
15 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Links, inline style.text: -------------------------------------------------------------------------------- 1 | Just a [URL](/url/). 2 | 3 | [URL and title](/url/ "title"). 4 | 5 | [URL and title](/url/ "title preceded by two spaces"). 6 | 7 | [URL and title](/url/ "title preceded by a tab"). 8 | 9 | [Empty](). 10 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Inline HTML (Advanced).html: -------------------------------------------------------------------------------- 1 |

Simple block on one line:

2 | 3 |
foo
4 | 5 |

And nested without indentation:

6 | 7 |
8 |
9 |
10 | foo 11 |
12 |
13 |
bar
14 |
15 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Inline HTML comments.text: -------------------------------------------------------------------------------- 1 | Paragraph one. 2 | 3 | 4 | 5 | 8 | 9 | Paragraph two. 10 | 11 | 12 | 13 | The end. 14 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).text: -------------------------------------------------------------------------------- 1 | Simple block on one line: 2 | 3 |
foo
4 | 5 | And nested without indentation: 6 | 7 |
8 |
9 |
10 | foo 11 |
12 |
13 |
14 |
bar
15 |
16 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Inline HTML comments.text: -------------------------------------------------------------------------------- 1 | Paragraph one. 2 | 3 | 4 | 5 | 8 | 9 | Paragraph two. 10 | 11 | 12 | 13 | The end. 14 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Code Spans.html: -------------------------------------------------------------------------------- 1 |

<test a=" content of attribute ">

2 | 3 |

Fix for backticks within HTML tag: like this

4 | 5 |

Here's how you put `backticks` in a code span.

6 | 7 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Inline HTML (Advanced).html: -------------------------------------------------------------------------------- 1 |

Simple block on one line:

2 | 3 |
foo
4 | 5 |

And nested without indentation:

6 | 7 |
8 |
9 |
10 | foo 11 |
12 |
13 |
14 |
bar
15 |
16 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Strong and em together.html: -------------------------------------------------------------------------------- 1 |

This is strong and em.

2 | 3 |

So is this word.

4 | 5 |

This is strong and em.

6 | 7 |

So is this word.

8 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Strong and em together.html: -------------------------------------------------------------------------------- 1 |

This is strong and em.

2 | 3 |

So is this word.

4 | 5 |

This is strong and em.

6 | 7 |

So is this word.

8 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.text: -------------------------------------------------------------------------------- 1 | In Markdown 1.0.0 and earlier. Version 2 | 8. This line turns into a list item. 3 | Because a hard-wrapped line in the 4 | middle of a paragraph looked like a 5 | list item. 6 | 7 | Here's one with a bullet. 8 | * criminey. 9 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Hard-wrapped paragraphs with list-like lines.text: -------------------------------------------------------------------------------- 1 | In Markdown 1.0.0 and earlier. Version 2 | 8. This line turns into a list item. 3 | Because a hard-wrapped line in the 4 | middle of a paragraph looked like a 5 | list item. 6 | 7 | Here's one with a bullet. 8 | * criminey. 9 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Inline HTML comments.html: -------------------------------------------------------------------------------- 1 |

Paragraph one.

2 | 3 | 4 | 5 | 8 | 9 |

Paragraph two.

10 | 11 | 12 | 13 |

The end.

14 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Code Blocks.text: -------------------------------------------------------------------------------- 1 | code block on the first line 2 | 3 | Regular text. 4 | 5 | code block indented by spaces 6 | 7 | Regular text. 8 | 9 | the lines in this block 10 | all contain trailing spaces 11 | 12 | Regular Text. 13 | 14 | code block on the last line -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Inline HTML comments.html: -------------------------------------------------------------------------------- 1 |

Paragraph one.

2 | 3 | 4 | 5 | 8 | 9 |

Paragraph two.

10 | 11 | 12 | 13 |

The end.

14 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Hard-wrapped paragraphs with list-like lines.html: -------------------------------------------------------------------------------- 1 |

In Markdown 1.0.0 and earlier. Version 2 | 8. This line turns into a list item. 3 | Because a hard-wrapped line in the 4 | middle of a paragraph looked like a 5 | list item.

6 | 7 |

Here's one with a bullet. 8 | * criminey.

9 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Blockquotes with code blocks.html: -------------------------------------------------------------------------------- 1 |
2 |

Example:

3 | 4 |
sub status {
 5 |     print "working";
 6 | }
 7 | 
8 | 9 |

Or:

10 | 11 |
sub status {
12 |     return "working";
13 | }
14 | 
15 |
16 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Hard-wrapped paragraphs with list-like lines.html: -------------------------------------------------------------------------------- 1 |

In Markdown 1.0.0 and earlier. Version 2 | 8. This line turns into a list item. 3 | Because a hard-wrapped line in the 4 | middle of a paragraph looked like a 5 | list item.

6 | 7 |

Here's one with a bullet. 8 | * criminey.

9 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Blockquotes with code blocks.html: -------------------------------------------------------------------------------- 1 |
2 |

Example:

3 | 4 |
sub status {
 5 |     print "working";
 6 | }
 7 | 
8 | 9 |

Or:

10 | 11 |
sub status {
12 |     return "working";
13 | }
14 | 
15 |
16 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | addons: 4 | apt: 5 | packages: 6 | - tidy 7 | 8 | install: travis_retry bundle install --without=benchmark 9 | 10 | rvm: 11 | - 1.9.2 12 | - 1.9.3 13 | - 2.0.0 14 | - 2.1 15 | - 2.2 16 | - rbx-2 17 | - ruby-head 18 | 19 | notifications: 20 | email: false 21 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Links, inline style.text: -------------------------------------------------------------------------------- 1 | Just a [URL](/url/). 2 | 3 | [URL and title](/url/ "title"). 4 | 5 | [URL and title](/url/ "title preceded by two spaces"). 6 | 7 | [URL and title](/url/ "title preceded by a tab"). 8 | 9 | [URL and title](/url/ "title has spaces afterward" ). 10 | 11 | 12 | [Empty](). 13 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Links, shortcut references.html: -------------------------------------------------------------------------------- 1 |

This is the simple case.

2 | 3 |

This one has a line 4 | break.

5 | 6 |

This one has a line 7 | break with a line-ending space.

8 | 9 |

this and the other

10 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Auto links.text: -------------------------------------------------------------------------------- 1 | Link: . 2 | 3 | With an ampersand: 4 | 5 | * In a list? 6 | * 7 | * It should. 8 | 9 | > Blockquoted: 10 | 11 | Auto-links should not occur here: `` 12 | 13 | or here: -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Auto links.text: -------------------------------------------------------------------------------- 1 | Link: . 2 | 3 | With an ampersand: 4 | 5 | * In a list? 6 | * 7 | * It should. 8 | 9 | > Blockquoted: 10 | 11 | Auto-links should not occur here: `` 12 | 13 | or here: -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Links, inline style.html: -------------------------------------------------------------------------------- 1 |

Just a URL.

2 | 3 |

URL and title.

4 | 5 |

URL and title.

6 | 7 |

URL and title.

8 | 9 |

Empty.

10 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Links, shortcut references.text: -------------------------------------------------------------------------------- 1 | This is the [simple case]. 2 | 3 | [simple case]: /simple 4 | 5 | 6 | 7 | This one has a [line 8 | break]. 9 | 10 | This one has a [line 11 | break] with a line-ending space. 12 | 13 | [line break]: /foo 14 | 15 | 16 | [this] [that] and the [other] 17 | 18 | [this]: /this 19 | [that]: /that 20 | [other]: /other 21 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Code Blocks.html: -------------------------------------------------------------------------------- 1 |
code block on the first line
 2 | 
3 | 4 |

Regular text.

5 | 6 |
code block indented by spaces
 7 | 
8 | 9 |

Regular text.

10 | 11 |
the lines in this block  
12 | all contain trailing spaces  
13 | 
14 | 15 |

Regular Text.

16 | 17 |
code block on the last line
18 | 
19 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Tabs.text: -------------------------------------------------------------------------------- 1 | + this is a list item 2 | indented with tabs 3 | 4 | + this is a list item 5 | indented with spaces 6 | 7 | Code: 8 | 9 | this code block is indented by one tab 10 | 11 | And: 12 | 13 | this code block is indented by two tabs 14 | 15 | And: 16 | 17 | + this is an example list item 18 | indented with tabs 19 | 20 | + this is an example list item 21 | indented with spaces 22 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Tabs.text: -------------------------------------------------------------------------------- 1 | + this is a list item 2 | indented with tabs 3 | 4 | + this is a list item 5 | indented with spaces 6 | 7 | Code: 8 | 9 | this code block is indented by one tab 10 | 11 | And: 12 | 13 | this code block is indented by two tabs 14 | 15 | And: 16 | 17 | + this is an example list item 18 | indented with tabs 19 | 20 | + this is an example list item 21 | indented with spaces 22 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Links, inline style.html: -------------------------------------------------------------------------------- 1 |

Just a URL.

2 | 3 |

URL and title.

4 | 5 |

URL and title.

6 | 7 |

URL and title.

8 | 9 |

URL and title.

10 | 11 |

Empty.

12 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Links, reference style.text: -------------------------------------------------------------------------------- 1 | Foo [bar] [1]. 2 | 3 | Foo [bar][1]. 4 | 5 | Foo [bar] 6 | [1]. 7 | 8 | [1]: /url/ "Title" 9 | 10 | 11 | With [embedded [brackets]] [b]. 12 | 13 | 14 | Indented [once][]. 15 | 16 | Indented [twice][]. 17 | 18 | Indented [thrice][]. 19 | 20 | Indented [four][] times. 21 | 22 | [once]: /url 23 | 24 | [twice]: /url 25 | 26 | [thrice]: /url 27 | 28 | [four]: /url 29 | 30 | 31 | [b]: /url/ 32 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Amps and angle encoding.text: -------------------------------------------------------------------------------- 1 | AT&T has an ampersand in their name. 2 | 3 | AT&T is another way to write it. 4 | 5 | This & that. 6 | 7 | 4 < 5. 8 | 9 | 6 > 5. 10 | 11 | Here's a [link] [1] with an ampersand in the URL. 12 | 13 | Here's a link with an amersand in the link text: [AT&T] [2]. 14 | 15 | Here's an inline [link](/script?foo=1&bar=2). 16 | 17 | Here's an inline [link](). 18 | 19 | 20 | [1]: http://example.com/?foo=1&bar=2 21 | [2]: http://att.com/ "AT&T" -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Amps and angle encoding.text: -------------------------------------------------------------------------------- 1 | AT&T has an ampersand in their name. 2 | 3 | AT&T is another way to write it. 4 | 5 | This & that. 6 | 7 | 4 < 5. 8 | 9 | 6 > 5. 10 | 11 | Here's a [link] [1] with an ampersand in the URL. 12 | 13 | Here's a link with an amersand in the link text: [AT&T] [2]. 14 | 15 | Here's an inline [link](/script?foo=1&bar=2). 16 | 17 | Here's an inline [link](). 18 | 19 | 20 | [1]: http://example.com/?foo=1&bar=2 21 | [2]: http://att.com/ "AT&T" -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Links, reference style.html: -------------------------------------------------------------------------------- 1 |

Foo bar.

2 | 3 |

Foo bar.

4 | 5 |

Foo bar.

6 | 7 |

With embedded [brackets].

8 | 9 |

Indented once.

10 | 11 |

Indented twice.

12 | 13 |

Indented thrice.

14 | 15 |

Indented [four][] times.

16 | 17 |
[four]: /url
18 | 
19 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Tabs.html: -------------------------------------------------------------------------------- 1 |
    2 |
  • this is a list item 3 | indented with tabs

  • 4 |
  • this is a list item 5 | indented with spaces

  • 6 |
7 | 8 |

Code:

9 | 10 |
this code block is indented by one tab
11 | 
12 | 13 |

And:

14 | 15 |
    this code block is indented by two tabs
16 | 
17 | 18 |

And:

19 | 20 |
+   this is an example list item
21 |     indented with tabs
22 | 
23 | +   this is an example list item
24 |     indented with spaces
25 | 
26 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Tabs.html: -------------------------------------------------------------------------------- 1 |
    2 |
  • this is a list item 3 | indented with tabs

  • 4 |
  • this is a list item 5 | indented with spaces

  • 6 |
7 | 8 |

Code:

9 | 10 |
this code block is indented by one tab
11 | 
12 | 13 |

And:

14 | 15 |
    this code block is indented by two tabs
16 | 
17 | 18 |

And:

19 | 20 |
+   this is an example list item
21 |     indented with tabs
22 | 
23 | +   this is an example list item
24 |     indented with spaces
25 | 
26 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Amps and angle encoding.html: -------------------------------------------------------------------------------- 1 |

AT&T has an ampersand in their name.

2 | 3 |

AT&T is another way to write it.

4 | 5 |

This & that.

6 | 7 |

4 < 5.

8 | 9 |

6 > 5.

10 | 11 |

Here's a link with an ampersand in the URL.

12 | 13 |

Here's a link with an amersand in the link text: AT&T.

14 | 15 |

Here's an inline link.

16 | 17 |

Here's an inline link.

18 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Amps and angle encoding.html: -------------------------------------------------------------------------------- 1 |

AT&T has an ampersand in their name.

2 | 3 |

AT&T is another way to write it.

4 | 5 |

This & that.

6 | 7 |

4 < 5.

8 | 9 |

6 > 5.

10 | 11 |

Here's a link with an ampersand in the URL.

12 | 13 |

Here's a link with an amersand in the link text: AT&T.

14 | 15 |

Here's an inline link.

16 | 17 |

Here's an inline link.

18 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Horizontal rules.text: -------------------------------------------------------------------------------- 1 | Dashes: 2 | 3 | --- 4 | 5 | --- 6 | 7 | --- 8 | 9 | --- 10 | 11 | --- 12 | 13 | - - - 14 | 15 | - - - 16 | 17 | - - - 18 | 19 | - - - 20 | 21 | - - - 22 | 23 | 24 | Asterisks: 25 | 26 | *** 27 | 28 | *** 29 | 30 | *** 31 | 32 | *** 33 | 34 | *** 35 | 36 | * * * 37 | 38 | * * * 39 | 40 | * * * 41 | 42 | * * * 43 | 44 | * * * 45 | 46 | 47 | Underscores: 48 | 49 | ___ 50 | 51 | ___ 52 | 53 | ___ 54 | 55 | ___ 56 | 57 | ___ 58 | 59 | _ _ _ 60 | 61 | _ _ _ 62 | 63 | _ _ _ 64 | 65 | _ _ _ 66 | 67 | _ _ _ 68 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Horizontal rules.text: -------------------------------------------------------------------------------- 1 | Dashes: 2 | 3 | --- 4 | 5 | --- 6 | 7 | --- 8 | 9 | --- 10 | 11 | --- 12 | 13 | - - - 14 | 15 | - - - 16 | 17 | - - - 18 | 19 | - - - 20 | 21 | - - - 22 | 23 | 24 | Asterisks: 25 | 26 | *** 27 | 28 | *** 29 | 30 | *** 31 | 32 | *** 33 | 34 | *** 35 | 36 | * * * 37 | 38 | * * * 39 | 40 | * * * 41 | 42 | * * * 43 | 44 | * * * 45 | 46 | 47 | Underscores: 48 | 49 | ___ 50 | 51 | ___ 52 | 53 | ___ 54 | 55 | ___ 56 | 57 | ___ 58 | 59 | _ _ _ 60 | 61 | _ _ _ 62 | 63 | _ _ _ 64 | 65 | _ _ _ 66 | 67 | _ _ _ 68 | -------------------------------------------------------------------------------- /test/benchmark.rb: -------------------------------------------------------------------------------- 1 | # coding: UTF-8 2 | # Thanks Kramdown for the inspiration! 3 | require 'benchmark/ips' 4 | 5 | require 'redcarpet' 6 | require 'bluecloth' 7 | require 'kramdown' 8 | 9 | markdown = File.read(File.join(File.dirname(__FILE__), "fixtures/benchmark.md")) 10 | 11 | # Let's bench! 12 | Benchmark.ips do |bench| 13 | bench.report("Redcarpet") do 14 | Redcarpet::Markdown.new(Redcarpet::Render::HTML).render(markdown) 15 | end 16 | 17 | bench.report("BlueCloth") do 18 | BlueCloth.new(markdown).to_html 19 | end 20 | 21 | bench.report("Kramdown") do 22 | Kramdown::Document.new(markdown).to_html 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Auto links.html: -------------------------------------------------------------------------------- 1 |

Link: http://example.com/.

2 | 3 |

With an ampersand: http://example.com/?foo=1&bar=2

4 | 5 | 10 | 11 |
12 |

Blockquoted: http://example.com/

13 |
14 | 15 |

Auto-links should not occur here: <http://example.com/>

16 | 17 |
or here: <http://example.com/>
18 | 
19 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Auto links.html: -------------------------------------------------------------------------------- 1 |

Link: http://example.com/.

2 | 3 |

With an ampersand: http://example.com/?foo=1&bar=2

4 | 5 | 10 | 11 |
12 |

Blockquoted: http://example.com/

13 |
14 | 15 |

Auto-links should not occur here: <http://example.com/>

16 | 17 |
or here: <http://example.com/>
18 | 
19 | -------------------------------------------------------------------------------- /test/custom_render_test.rb: -------------------------------------------------------------------------------- 1 | # coding: UTF-8 2 | require 'test_helper' 3 | 4 | class CustomRenderTest < Redcarpet::TestCase 5 | class SimpleRender < Redcarpet::Render::HTML 6 | def emphasis(text) 7 | "#{text}" 8 | end 9 | end 10 | 11 | def test_simple_overload 12 | md = Redcarpet::Markdown.new(SimpleRender) 13 | assert_equal "

This is just a test

\n", 14 | md.render("This is *just* a test") 15 | end 16 | 17 | class NilPreprocessRenderer < Redcarpet::Render::HTML 18 | def preprocess(fulldoc) 19 | nil 20 | end 21 | end 22 | 23 | def test_preprocess_returning_nil 24 | md = Redcarpet::Markdown.new(NilPreprocessRenderer) 25 | assert_equal(nil,md.render("Anything")) 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Horizontal rules.html: -------------------------------------------------------------------------------- 1 |

Dashes:

2 | 3 |
4 | 5 |
6 | 7 |
8 | 9 |
10 | 11 |
---
12 | 
13 | 14 |
15 | 16 |
17 | 18 |
19 | 20 |
21 | 22 |
- - -
23 | 
24 | 25 |

Asterisks:

26 | 27 |
28 | 29 |
30 | 31 |
32 | 33 |
34 | 35 |
***
36 | 
37 | 38 |
39 | 40 |
41 | 42 |
43 | 44 |
45 | 46 |
* * *
47 | 
48 | 49 |

Underscores:

50 | 51 |
52 | 53 |
54 | 55 |
56 | 57 |
58 | 59 |
___
60 | 
61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 | 70 |
_ _ _
71 | 
72 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Horizontal rules.html: -------------------------------------------------------------------------------- 1 |

Dashes:

2 | 3 |
4 | 5 |
6 | 7 |
8 | 9 |
10 | 11 |
---
12 | 
13 | 14 |
15 | 16 |
17 | 18 |
19 | 20 |
21 | 22 |
- - -
23 | 
24 | 25 |

Asterisks:

26 | 27 |
28 | 29 |
30 | 31 |
32 | 33 |
34 | 35 |
***
36 | 
37 | 38 |
39 | 40 |
41 | 42 |
43 | 44 |
45 | 46 |
* * *
47 | 
48 | 49 |

Underscores:

50 | 51 |
52 | 53 |
54 | 55 |
56 | 57 |
58 | 59 |
___
60 | 
61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 | 70 |
_ _ _
71 | 
72 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Inline HTML (Simple).text: -------------------------------------------------------------------------------- 1 | Here's a simple block: 2 | 3 |
4 | foo 5 |
6 | 7 | This should be a code block, though: 8 | 9 |
10 | foo 11 |
12 | 13 | As should this: 14 | 15 |
foo
16 | 17 | Now, nested: 18 | 19 |
20 |
21 |
22 | foo 23 |
24 |
25 |
26 | 27 | This should just be an HTML comment: 28 | 29 | 30 | 31 | Multiline: 32 | 33 | 37 | 38 | Code block: 39 | 40 | 41 | 42 | Just plain comment, with trailing spaces on the line: 43 | 44 | 45 | 46 | Code: 47 | 48 |
49 | 50 | Hr's: 51 | 52 |
53 | 54 |
55 | 56 |
57 | 58 |
59 | 60 |
61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 | 70 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Inline HTML (Simple).text: -------------------------------------------------------------------------------- 1 | Here's a simple block: 2 | 3 |
4 | foo 5 |
6 | 7 | This should be a code block, though: 8 | 9 |
10 | foo 11 |
12 | 13 | As should this: 14 | 15 |
foo
16 | 17 | Now, nested: 18 | 19 |
20 |
21 |
22 | foo 23 |
24 |
25 |
26 | 27 | This should just be an HTML comment: 28 | 29 | 30 | 31 | Multiline: 32 | 33 | 37 | 38 | Code block: 39 | 40 | 41 | 42 | Just plain comment, with trailing spaces on the line: 43 | 44 | 45 | 46 | Code: 47 | 48 |
49 | 50 | Hr's: 51 | 52 |
53 | 54 |
55 | 56 |
57 | 58 |
59 | 60 |
61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 | 70 | -------------------------------------------------------------------------------- /test/pathological_inputs_test.rb: -------------------------------------------------------------------------------- 1 | # coding: UTF-8 2 | require 'test_helper' 3 | 4 | # Disabled by default 5 | # (these are the easy ones -- the evil ones are not disclosed) 6 | class PathologicalInputsTest # < Redcarpet::TestCase 7 | def setup 8 | @markdown = Redcarpet::Markdown.new(Redcarpet::Render::HTML) 9 | end 10 | 11 | def test_pathological_1 12 | star = '*' * 250000 13 | @markdown.render("#{star}#{star} hi #{star}#{star}") 14 | end 15 | 16 | def test_pathological_2 17 | crt = '^' * 255 18 | str = "#{crt}(\\)" 19 | @markdown.render("#{str*300}") 20 | end 21 | 22 | def test_pathological_3 23 | c = "`t`t`t`t`t`t" * 20000000 24 | @markdown.render(c) 25 | end 26 | 27 | def test_pathological_4 28 | @markdown.render(" [^a]: #{ "A" * 10000 }\n#{ "[^a][]" * 1000000 }\n") 29 | end 30 | 31 | def test_unbound_recursion 32 | @markdown.render(("[" * 10000) + "foo" + ("](bar)" * 10000)) 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | # coding: UTF-8 2 | $:.unshift(File.expand_path('../../lib', __FILE__)) 3 | Encoding.default_internal = 'UTF-8' 4 | 5 | require 'test/unit' 6 | 7 | require 'redcarpet' 8 | require 'redcarpet/render_strip' 9 | require 'redcarpet/render_man' 10 | 11 | class Redcarpet::TestCase < Test::Unit::TestCase 12 | def assert_renders(html, markdown) 13 | assert_equal html, render(markdown) 14 | end 15 | 16 | def render(markdown, options = {}) 17 | options = options.fetch(:with, {}) 18 | 19 | if options.kind_of?(Array) 20 | options = Hash[options.map {|o| [o, true]}] 21 | end 22 | 23 | render = begin 24 | renderer.new(options) 25 | rescue ArgumentError 26 | renderer.new 27 | end 28 | 29 | parser = Redcarpet::Markdown.new(render, options) 30 | 31 | parser.render(markdown) 32 | end 33 | 34 | private 35 | 36 | def renderer 37 | @renderer ||= Redcarpet::Render::HTML 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /test/safe_render_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class SafeRenderTest < Redcarpet::TestCase 4 | def setup 5 | @renderer = Redcarpet::Render::Safe 6 | end 7 | 8 | def test_safe_links_only_is_enabled_by_default 9 | markdown = "[foo](javascript:alert('foo'))" 10 | output = render(markdown) 11 | 12 | assert_not_match %r{a href}, output 13 | end 14 | 15 | def test_escape_html_is_enabled_by_default 16 | markdown = "

Hello world!

" 17 | output = render(markdown) 18 | 19 | assert_match %r{<}, output 20 | end 21 | 22 | def test_html_escaping_in_code_blocks 23 | markdown = "~~~\n

Hello!

\n~~~" 24 | output = render(markdown) 25 | 26 | assert_match %r{<p>}, output 27 | end 28 | 29 | def test_lang_class_is_removed 30 | markdown = "~~~ruby\nclass Foo; end\n~~~" 31 | output = render(markdown, with: [:fenced_code_blocks]) 32 | 33 | assert_not_match %r{ruby}, output 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Inline HTML (Simple).html: -------------------------------------------------------------------------------- 1 |

Here's a simple block:

2 | 3 |
4 | foo 5 |
6 | 7 |

This should be a code block, though:

8 | 9 |
<div>
10 |     foo
11 | </div>
12 | 
13 | 14 |

As should this:

15 | 16 |
<div>foo</div>
17 | 
18 | 19 |

Now, nested:

20 | 21 |
22 |
23 |
24 | foo 25 |
26 |
27 |
28 | 29 |

This should just be an HTML comment:

30 | 31 | 32 | 33 |

Multiline:

34 | 35 | 39 | 40 |

Code block:

41 | 42 |
<!-- Comment -->
43 | 
44 | 45 |

Just plain comment, with trailing spaces on the line:

46 | 47 | 48 | 49 |

Code:

50 | 51 |
<hr />
52 | 
53 | 54 |

Hr's:

55 | 56 |
57 | 58 |
59 | 60 |
61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 | 70 |
71 | 72 |
73 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009, Natacha Porté 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 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Inline HTML (Simple).html: -------------------------------------------------------------------------------- 1 |

Here's a simple block:

2 | 3 |
4 | foo 5 |
6 | 7 |

This should be a code block, though:

8 | 9 |
<div>
10 |     foo
11 | </div>
12 | 
13 | 14 |

As should this:

15 | 16 |
<div>foo</div>
17 | 
18 | 19 |

Now, nested:

20 | 21 |
22 |
23 |
24 | foo 25 |
26 |
27 |
28 | 29 |

This should just be an HTML comment:

30 | 31 | 32 | 33 |

Multiline:

34 | 35 | 39 | 40 |

Code block:

41 | 42 |
<!-- Comment -->
43 | 
44 | 45 |

Just plain comment, with trailing spaces on the line:

46 | 47 | 48 | 49 |

Code:

50 | 51 |
<hr />
52 | 
53 | 54 |

Hr's:

55 | 56 |
57 | 58 |
59 | 60 |
61 | 62 |
63 | 64 |
65 | 66 |
67 | 68 |
69 | 70 |
71 | 72 |
73 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Links, reference style.text: -------------------------------------------------------------------------------- 1 | Foo [bar] [1]. 2 | 3 | Foo [bar][1]. 4 | 5 | Foo [bar] 6 | [1]. 7 | 8 | [1]: /url/ "Title" 9 | 10 | 11 | With [embedded [brackets]] [b]. 12 | 13 | 14 | Indented [once][]. 15 | 16 | Indented [twice][]. 17 | 18 | Indented [thrice][]. 19 | 20 | Indented [four][] times. 21 | 22 | [once]: /url 23 | 24 | [twice]: /url 25 | 26 | [thrice]: /url 27 | 28 | [four]: /url 29 | 30 | 31 | [b]: /url/ 32 | 33 | * * * 34 | 35 | [this] [this] should work 36 | 37 | So should [this][this]. 38 | 39 | And [this] []. 40 | 41 | And [this][]. 42 | 43 | And [this]. 44 | 45 | But not [that] []. 46 | 47 | Nor [that][]. 48 | 49 | Nor [that]. 50 | 51 | [Something in brackets like [this][] should work] 52 | 53 | [Same with [this].] 54 | 55 | In this case, [this](/somethingelse/) points to something else. 56 | 57 | Backslashing should suppress \[this] and [this\]. 58 | 59 | [this]: foo 60 | 61 | 62 | * * * 63 | 64 | Here's one where the [link 65 | breaks] across lines. 66 | 67 | Here's another where the [link 68 | breaks] across lines, but with a line-ending space. 69 | 70 | 71 | [link breaks]: /url/ 72 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Links, reference style.html: -------------------------------------------------------------------------------- 1 |

Foo bar.

2 | 3 |

Foo bar.

4 | 5 |

Foo bar.

6 | 7 |

With embedded [brackets].

8 | 9 |

Indented once.

10 | 11 |

Indented twice.

12 | 13 |

Indented thrice.

14 | 15 |

Indented [four][] times.

16 | 17 |
[four]: /url
18 | 
19 | 20 |
21 | 22 |

this should work

23 | 24 |

So should this.

25 | 26 |

And this.

27 | 28 |

And this.

29 | 30 |

And this.

31 | 32 |

But not [that] [].

33 | 34 |

Nor [that][].

35 | 36 |

Nor [that].

37 | 38 |

[Something in brackets like this should work]

39 | 40 |

[Same with this.]

41 | 42 |

In this case, this points to something else.

43 | 44 |

Backslashing should suppress [this] and [this].

45 | 46 |
47 | 48 |

Here's one where the link 49 | breaks across lines.

50 | 51 |

Here's another where the link 52 | breaks across lines, but with a line-ending space.

53 | -------------------------------------------------------------------------------- /lib/redcarpet/render_man.rb: -------------------------------------------------------------------------------- 1 | module Redcarpet 2 | module Render 3 | class ManPage < Base 4 | 5 | def normal_text(text) 6 | text.gsub('-', '\\-').strip 7 | end 8 | 9 | def block_code(code, language) 10 | "\n.nf\n#{normal_text(code)}\n.fi\n" 11 | end 12 | 13 | def codespan(code) 14 | block_code(code, nil) 15 | end 16 | 17 | def header(title, level) 18 | case level 19 | when 1 20 | "\n.TH #{title}\n" 21 | 22 | when 2 23 | "\n.SH #{title}\n" 24 | 25 | when 3 26 | "\n.SS #{title}\n" 27 | end 28 | end 29 | 30 | def double_emphasis(text) 31 | "\\fB#{text}\\fP" 32 | end 33 | 34 | def emphasis(text) 35 | "\\fI#{text}\\fP" 36 | end 37 | 38 | def linebreak 39 | "\n.LP\n" 40 | end 41 | 42 | def paragraph(text) 43 | "\n.TP\n#{text}\n" 44 | end 45 | 46 | def list(content, list_type) 47 | case list_type 48 | when :ordered 49 | "\n\n.nr step 0 1\n#{content}\n" 50 | when :unordered 51 | "\n.\n#{content}\n" 52 | end 53 | end 54 | 55 | def list_item(content, list_type) 56 | case list_type 57 | when :ordered 58 | ".IP \\n+[step]\n#{content.strip}\n" 59 | when :unordered 60 | ".IP \\[bu] 2 \n#{content.strip}\n" 61 | end 62 | end 63 | end 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Backslash escapes.text: -------------------------------------------------------------------------------- 1 | These should all get escaped: 2 | 3 | Backslash: \\ 4 | 5 | Backtick: \` 6 | 7 | Asterisk: \* 8 | 9 | Underscore: \_ 10 | 11 | Left brace: \{ 12 | 13 | Right brace: \} 14 | 15 | Left bracket: \[ 16 | 17 | Right bracket: \] 18 | 19 | Left paren: \( 20 | 21 | Right paren: \) 22 | 23 | Greater-than: \> 24 | 25 | Hash: \# 26 | 27 | Period: \. 28 | 29 | Bang: \! 30 | 31 | Plus: \+ 32 | 33 | Minus: \- 34 | 35 | 36 | 37 | These should not, because they occur within a code block: 38 | 39 | Backslash: \\ 40 | 41 | Backtick: \` 42 | 43 | Asterisk: \* 44 | 45 | Underscore: \_ 46 | 47 | Left brace: \{ 48 | 49 | Right brace: \} 50 | 51 | Left bracket: \[ 52 | 53 | Right bracket: \] 54 | 55 | Left paren: \( 56 | 57 | Right paren: \) 58 | 59 | Greater-than: \> 60 | 61 | Hash: \# 62 | 63 | Period: \. 64 | 65 | Bang: \! 66 | 67 | Plus: \+ 68 | 69 | Minus: \- 70 | 71 | 72 | Nor should these, which occur in code spans: 73 | 74 | Backslash: `\\` 75 | 76 | Backtick: `` \` `` 77 | 78 | Asterisk: `\*` 79 | 80 | Underscore: `\_` 81 | 82 | Left brace: `\{` 83 | 84 | Right brace: `\}` 85 | 86 | Left bracket: `\[` 87 | 88 | Right bracket: `\]` 89 | 90 | Left paren: `\(` 91 | 92 | Right paren: `\)` 93 | 94 | Greater-than: `\>` 95 | 96 | Hash: `\#` 97 | 98 | Period: `\.` 99 | 100 | Bang: `\!` 101 | 102 | Plus: `\+` 103 | 104 | Minus: `\-` 105 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Submitting a Pull Request 2 | 3 | 1. [Fork the repository.][fork] 4 | 2. [Create a topic branch.][branch] 5 | 3. Check which version of Ruby is installed on your machine with `ruby -v`. 6 | The list of supported Ruby versions is listed in [.travis.yml][travis_yml]. 7 | Set up one of these versions; use of [RVM][rvm] is recommended to switch 8 | easily between different versions. 9 | 4. [Install bundler.][bundler] 10 | 5. Make sure to have the `tidy` command on your system: 11 | 12 | * `apt-get install tidy` 13 | * `yum install tidy` 14 | * `pacman -S tidyhtml` 15 | 16 | 6. Check that unit tests pass with `rake test`. 17 | 7. Write a failing test to capture existing bug or lack of feature. 18 | 8. Run `rake test` to verify that test fails. 19 | 9. Implement your feature or bug fix. 20 | 10. Ensure tests pass. 21 | 11. If it's a new feature or a bug fix, please add an entry to the changelog file. 22 | 12. Add, commit, and push your changes. 23 | 13. [Submit a pull request.][pr] 24 | 14. You will get some feedback and may need to push additional commits 25 | with more fixes to the same branch; this will update your pull request 26 | automatically. 27 | 28 | [branch]: http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches 29 | [bundler]: http://bundler.io 30 | [fork]: https://help.github.com/articles/fork-a-repo 31 | [pr]: https://help.github.com/articles/using-pull-requests 32 | [rvm]: https://rvm.io 33 | [travis_yml]: https://github.com/vmg/redcarpet/blob/master/.travis.yml 34 | -------------------------------------------------------------------------------- /test/redcarpet_compat_test.rb: -------------------------------------------------------------------------------- 1 | # coding: UTF-8 2 | require 'test_helper' 3 | 4 | class RedcarpetCompatTest < Redcarpet::TestCase 5 | def test_simple_compat_api 6 | html = RedcarpetCompat.new("This is_just_a test").to_html 7 | assert_equal "

This isjusta test

\n", html 8 | end 9 | 10 | def test_compat_api_enables_extensions 11 | html = RedcarpetCompat.new("This is_just_a test", :no_intra_emphasis).to_html 12 | assert_equal "

This is_just_a test

\n", html 13 | end 14 | 15 | def test_compat_api_knows_fenced_code_extension 16 | text = "```ruby\nx = 'foo'\n```" 17 | html = RedcarpetCompat.new(text, :fenced_code).to_html 18 | assert_equal "
x = 'foo'\n
\n", html 19 | end 20 | 21 | def test_compat_api_ignores_gh_blockcode_extension 22 | text = "```ruby\nx = 'foo'\n```" 23 | html = RedcarpetCompat.new(text, :fenced_code, :gh_blockcode).to_html 24 | assert_equal "
x = 'foo'\n
\n", html 25 | end 26 | 27 | def test_compat_api_knows_no_intraemphasis_extension 28 | html = RedcarpetCompat.new("This is_just_a test", :no_intraemphasis).to_html 29 | assert_equal "

This is_just_a test

\n", html 30 | end 31 | 32 | def test_translate_outdated_extensions 33 | # these extensions are no longer used 34 | exts = [:gh_blockcode, :no_tables, :smart, :strict] 35 | html = RedcarpetCompat.new('"TEST"', *exts).to_html 36 | assert_equal "

"TEST"

\n", html 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Ordered and unordered lists.text: -------------------------------------------------------------------------------- 1 | ## Unordered 2 | 3 | Asterisks tight: 4 | 5 | * asterisk 1 6 | * asterisk 2 7 | * asterisk 3 8 | 9 | 10 | Asterisks loose: 11 | 12 | * asterisk 1 13 | 14 | * asterisk 2 15 | 16 | * asterisk 3 17 | 18 | * * * 19 | 20 | Pluses tight: 21 | 22 | + Plus 1 23 | + Plus 2 24 | + Plus 3 25 | 26 | 27 | Pluses loose: 28 | 29 | + Plus 1 30 | 31 | + Plus 2 32 | 33 | + Plus 3 34 | 35 | * * * 36 | 37 | 38 | Minuses tight: 39 | 40 | - Minus 1 41 | - Minus 2 42 | - Minus 3 43 | 44 | 45 | Minuses loose: 46 | 47 | - Minus 1 48 | 49 | - Minus 2 50 | 51 | - Minus 3 52 | 53 | 54 | ## Ordered 55 | 56 | Tight: 57 | 58 | 1. First 59 | 2. Second 60 | 3. Third 61 | 62 | and: 63 | 64 | 1. One 65 | 2. Two 66 | 3. Three 67 | 68 | 69 | Loose using tabs: 70 | 71 | 1. First 72 | 73 | 2. Second 74 | 75 | 3. Third 76 | 77 | and using spaces: 78 | 79 | 1. One 80 | 81 | 2. Two 82 | 83 | 3. Three 84 | 85 | Multiple paragraphs: 86 | 87 | 1. Item 1, graf one. 88 | 89 | Item 2. graf two. The quick brown fox jumped over the lazy dog's 90 | back. 91 | 92 | 2. Item 2. 93 | 94 | 3. Item 3. 95 | 96 | 97 | 98 | ## Nested 99 | 100 | * Tab 101 | * Tab 102 | * Tab 103 | 104 | Here's another: 105 | 106 | 1. First 107 | 2. Second: 108 | * Fee 109 | * Fie 110 | * Foe 111 | 3. Third 112 | 113 | Same thing but with paragraphs: 114 | 115 | 1. First 116 | 117 | 2. Second: 118 | * Fee 119 | * Fie 120 | * Foe 121 | 122 | 3. Third 123 | -------------------------------------------------------------------------------- /test/smarty_html_test.rb: -------------------------------------------------------------------------------- 1 | # coding: UTF-8 2 | require 'test_helper' 3 | 4 | class SmartyHTMLTest < Redcarpet::TestCase 5 | def setup 6 | @renderer = Redcarpet::Render::SmartyHTML 7 | end 8 | 9 | def test_that_smartyhtml_converts_single_quotes 10 | markdown = render("They're not for sale.") 11 | assert_equal "

They’re not for sale.

\n", markdown 12 | end 13 | 14 | def test_that_smartyhtml_converts_double_quotes 15 | rd = render(%("Quoted text")) 16 | assert_equal %(

“Quoted text”

\n), rd 17 | end 18 | 19 | def test_that_smartyhtml_converts_double_hyphen 20 | rd = render("double hyphen -- ndash") 21 | assert_equal "

double hyphen – ndash

\n", rd 22 | end 23 | 24 | def test_that_smartyhtml_converts_triple_hyphen 25 | rd = render("triple hyphen --- mdash") 26 | assert_equal "

triple hyphen — mdash

\n", rd 27 | end 28 | 29 | def test_that_smartyhtml_ignores_double_hyphen_in_code 30 | rd = render("double hyphen in `--option`") 31 | assert_equal "

double hyphen in --option

\n", rd 32 | end 33 | 34 | def test_that_smartyhtml_ignores_pre 35 | rd = render(" It's a test of \"pre\"\n") 36 | expected = "It's a test of "pre"" 37 | assert rd.include?(expected), "\"#{rd}\" should contain \"#{expected}\"" 38 | end 39 | 40 | def test_that_smartyhtml_ignores_code 41 | rd = render("`It's a test of \"code\"`\n") 42 | expected = "It's a test of "code"" 43 | assert rd.include?(expected), "\"#{rd}\" should contain \"#{expected}\"" 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'date' 2 | require 'rake/clean' 3 | require 'rake/extensiontask' 4 | require 'digest/md5' 5 | 6 | task :default => [:test] 7 | 8 | # Gem Spec 9 | gem_spec = Gem::Specification.load('redcarpet.gemspec') 10 | 11 | # Ruby Extension 12 | Rake::ExtensionTask.new('redcarpet', gem_spec) 13 | 14 | # Packaging 15 | require 'bundler/gem_tasks' 16 | 17 | # Testing 18 | require 'rake/testtask' 19 | 20 | Rake::TestTask.new('test:unit') do |t| 21 | t.libs << 'lib' 22 | t.libs << 'test' 23 | t.pattern = 'test/*_test.rb' 24 | t.verbose = true 25 | t.warning = false 26 | end 27 | 28 | task 'test:unit' => :compile 29 | 30 | desc 'Run conformance tests (MARKDOWN_TEST_VER=1.0.3)' 31 | task 'test:conformance' => :compile do |t| 32 | script = "#{pwd}/bin/redcarpet" 33 | version = ENV['MARKDOWN_TEST_VER'] || '1.0.3' 34 | lib_dir = "#{pwd}/lib" 35 | 36 | chdir("test/MarkdownTest_#{version}") do 37 | sh "RUBYLIB=#{lib_dir} ./MarkdownTest.pl --script='#{script}' --tidy" 38 | end 39 | end 40 | 41 | desc 'Run version 1.0 conformance suite' 42 | task 'test:conformance:1.0' => :compile do |t| 43 | ENV['MARKDOWN_TEST_VER'] = '1.0' 44 | Rake::Task['test:conformance'].invoke 45 | end 46 | 47 | desc 'Run 1.0.3 conformance suite' 48 | task 'test:conformance:1.0.3' => :compile do |t| 49 | ENV['MARKDOWN_TEST_VER'] = '1.0.3' 50 | Rake::Task['test:conformance'].invoke 51 | end 52 | 53 | desc 'Run unit and conformance tests' 54 | task :test => %w[test:unit test:conformance] 55 | 56 | desc 'Run benchmarks' 57 | task :benchmark => :compile do |t| 58 | $:.unshift 'lib' 59 | load 'test/benchmark.rb' 60 | end 61 | -------------------------------------------------------------------------------- /lib/redcarpet/render_strip.rb: -------------------------------------------------------------------------------- 1 | module Redcarpet 2 | module Render 3 | # Markdown-stripping renderer. Turns Markdown into plaintext 4 | # Thanks to @toupeira (Markus Koller) 5 | class StripDown < Base 6 | # Methods where the first argument is the text content 7 | [ 8 | # block-level calls 9 | :block_code, :block_quote, 10 | :block_html, :list, :list_item, 11 | 12 | # span-level calls 13 | :autolink, :codespan, :double_emphasis, 14 | :emphasis, :underline, :raw_html, 15 | :triple_emphasis, :strikethrough, 16 | :superscript, :highlight, 17 | 18 | # footnotes 19 | :footnotes, :footnote_def, :footnote_ref, 20 | 21 | # low level rendering 22 | :entity, :normal_text 23 | ].each do |method| 24 | define_method method do |*args| 25 | args.first 26 | end 27 | end 28 | 29 | # Other methods where we don't return only a specific argument 30 | def link(link, title, content) 31 | "#{content} (#{link})" 32 | end 33 | 34 | def image(link, title, content) 35 | content &&= content + " " 36 | "#{content}#{link}" 37 | end 38 | 39 | def paragraph(text) 40 | text + "\n" 41 | end 42 | 43 | def header(text, header_level) 44 | text + "\n" 45 | end 46 | 47 | def table(header, body) 48 | "#{header}#{body}" 49 | end 50 | 51 | def table_row(content) 52 | content + "\n" 53 | end 54 | 55 | def table_cell(content, alignment) 56 | content + "\t" 57 | end 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /test/html5_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class HTML5Test < Redcarpet::TestCase 4 | def test_that_html5_works 5 | section = < 7 |

The quick brown fox jumps over the lazy dog.

8 | 9 | EOS 10 | 11 | figure = < 13 | 14 |
15 |

Hello world!

16 |
17 | 18 | EOS 19 | 20 | assert_renders section, section 21 | assert_renders figure, figure 22 | end 23 | 24 | def test_that_html5_works_with_code_blocks 25 | section = < 27 | \t\t

The quick brown fox jumps over the lazy dog.

28 | \t 29 | EOS 30 | 31 | section_expected = <<section> 33 | <p>The quick brown fox jumps over the lazy dog.</p> 34 | </section> 35 | 36 | EOE 37 | 38 | header = < 40 |
41 |

Section heading

42 |

Subhead

43 |
44 | 45 | EOS 46 | 47 | header_expected = <<header> 49 | <hgroup> 50 | <h1>Section heading</h1> 51 | <h2>Subhead</h2> 52 | </hgroup> 53 | </header> 54 | 55 | EOE 56 | 57 | assert_renders section_expected, section 58 | assert_renders header_expected, header 59 | end 60 | 61 | def test_script_tag_recognition 62 | markdown = <<-Md 63 | 66 | Md 67 | assert_renders markdown, markdown 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Ordered and unordered lists.text: -------------------------------------------------------------------------------- 1 | ## Unordered 2 | 3 | Asterisks tight: 4 | 5 | * asterisk 1 6 | * asterisk 2 7 | * asterisk 3 8 | 9 | 10 | Asterisks loose: 11 | 12 | * asterisk 1 13 | 14 | * asterisk 2 15 | 16 | * asterisk 3 17 | 18 | * * * 19 | 20 | Pluses tight: 21 | 22 | + Plus 1 23 | + Plus 2 24 | + Plus 3 25 | 26 | 27 | Pluses loose: 28 | 29 | + Plus 1 30 | 31 | + Plus 2 32 | 33 | + Plus 3 34 | 35 | * * * 36 | 37 | 38 | Minuses tight: 39 | 40 | - Minus 1 41 | - Minus 2 42 | - Minus 3 43 | 44 | 45 | Minuses loose: 46 | 47 | - Minus 1 48 | 49 | - Minus 2 50 | 51 | - Minus 3 52 | 53 | 54 | ## Ordered 55 | 56 | Tight: 57 | 58 | 1. First 59 | 2. Second 60 | 3. Third 61 | 62 | and: 63 | 64 | 1. One 65 | 2. Two 66 | 3. Three 67 | 68 | 69 | Loose using tabs: 70 | 71 | 1. First 72 | 73 | 2. Second 74 | 75 | 3. Third 76 | 77 | and using spaces: 78 | 79 | 1. One 80 | 81 | 2. Two 82 | 83 | 3. Three 84 | 85 | Multiple paragraphs: 86 | 87 | 1. Item 1, graf one. 88 | 89 | Item 2. graf two. The quick brown fox jumped over the lazy dog's 90 | back. 91 | 92 | 2. Item 2. 93 | 94 | 3. Item 3. 95 | 96 | 97 | 98 | ## Nested 99 | 100 | * Tab 101 | * Tab 102 | * Tab 103 | 104 | Here's another: 105 | 106 | 1. First 107 | 2. Second: 108 | * Fee 109 | * Fie 110 | * Foe 111 | 3. Third 112 | 113 | Same thing but with paragraphs: 114 | 115 | 1. First 116 | 117 | 2. Second: 118 | * Fee 119 | * Fie 120 | * Foe 121 | 122 | 3. Third 123 | 124 | 125 | This was an error in Markdown 1.0.1: 126 | 127 | * this 128 | 129 | * sub 130 | 131 | that 132 | -------------------------------------------------------------------------------- /ext/redcarpet/stack.h: -------------------------------------------------------------------------------- 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 | 23 | #ifndef STACK_H__ 24 | #define STACK_H__ 25 | 26 | #include 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | struct stack { 33 | void **item; 34 | size_t size; 35 | size_t asize; 36 | }; 37 | 38 | void redcarpet_stack_free(struct stack *); 39 | int redcarpet_stack_grow(struct stack *, size_t); 40 | int redcarpet_stack_init(struct stack *, size_t); 41 | 42 | int redcarpet_stack_push(struct stack *, void *); 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /ext/redcarpet/redcarpet.h: -------------------------------------------------------------------------------- 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 | 23 | #ifndef REDCARPET_H__ 24 | #define REDCARPET_H__ 25 | 26 | #define RSTRING_NOT_MODIFIED 27 | #include "ruby.h" 28 | #include 29 | 30 | #include 31 | 32 | #include "markdown.h" 33 | #include "html.h" 34 | 35 | #define CSTR2SYM(s) (ID2SYM(rb_intern((s)))) 36 | 37 | void Init_redcarpet_rndr(); 38 | 39 | struct redcarpet_renderopt { 40 | struct html_renderopt html; 41 | VALUE link_attributes; 42 | VALUE self; 43 | VALUE base_class; 44 | rb_encoding *active_enc; 45 | }; 46 | 47 | struct rb_redcarpet_rndr { 48 | struct sd_callbacks callbacks; 49 | struct redcarpet_renderopt options; 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Backslash escapes.html: -------------------------------------------------------------------------------- 1 |

These should all get escaped:

2 | 3 |

Backslash: \

4 | 5 |

Backtick: `

6 | 7 |

Asterisk: *

8 | 9 |

Underscore: _

10 | 11 |

Left brace: {

12 | 13 |

Right brace: }

14 | 15 |

Left bracket: [

16 | 17 |

Right bracket: ]

18 | 19 |

Left paren: (

20 | 21 |

Right paren: )

22 | 23 |

Greater-than: >

24 | 25 |

Hash: #

26 | 27 |

Period: .

28 | 29 |

Bang: !

30 | 31 |

Plus: +

32 | 33 |

Minus: -

34 | 35 |

These should not, because they occur within a code block:

36 | 37 |
Backslash: \\
 38 | 
 39 | Backtick: \`
 40 | 
 41 | Asterisk: \*
 42 | 
 43 | Underscore: \_
 44 | 
 45 | Left brace: \{
 46 | 
 47 | Right brace: \}
 48 | 
 49 | Left bracket: \[
 50 | 
 51 | Right bracket: \]
 52 | 
 53 | Left paren: \(
 54 | 
 55 | Right paren: \)
 56 | 
 57 | Greater-than: \>
 58 | 
 59 | Hash: \#
 60 | 
 61 | Period: \.
 62 | 
 63 | Bang: \!
 64 | 
 65 | Plus: \+
 66 | 
 67 | Minus: \-
 68 | 
69 | 70 |

Nor should these, which occur in code spans:

71 | 72 |

Backslash: \\

73 | 74 |

Backtick: \`

75 | 76 |

Asterisk: \*

77 | 78 |

Underscore: \_

79 | 80 |

Left brace: \{

81 | 82 |

Right brace: \}

83 | 84 |

Left bracket: \[

85 | 86 |

Right bracket: \]

87 | 88 |

Left paren: \(

89 | 90 |

Right paren: \)

91 | 92 |

Greater-than: \>

93 | 94 |

Hash: \#

95 | 96 |

Period: \.

97 | 98 |

Bang: \!

99 | 100 |

Plus: \+

101 | 102 |

Minus: \-

103 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Backslash escapes.text: -------------------------------------------------------------------------------- 1 | These should all get escaped: 2 | 3 | Backslash: \\ 4 | 5 | Backtick: \` 6 | 7 | Asterisk: \* 8 | 9 | Underscore: \_ 10 | 11 | Left brace: \{ 12 | 13 | Right brace: \} 14 | 15 | Left bracket: \[ 16 | 17 | Right bracket: \] 18 | 19 | Left paren: \( 20 | 21 | Right paren: \) 22 | 23 | Greater-than: \> 24 | 25 | Hash: \# 26 | 27 | Period: \. 28 | 29 | Bang: \! 30 | 31 | Plus: \+ 32 | 33 | Minus: \- 34 | 35 | 36 | 37 | These should not, because they occur within a code block: 38 | 39 | Backslash: \\ 40 | 41 | Backtick: \` 42 | 43 | Asterisk: \* 44 | 45 | Underscore: \_ 46 | 47 | Left brace: \{ 48 | 49 | Right brace: \} 50 | 51 | Left bracket: \[ 52 | 53 | Right bracket: \] 54 | 55 | Left paren: \( 56 | 57 | Right paren: \) 58 | 59 | Greater-than: \> 60 | 61 | Hash: \# 62 | 63 | Period: \. 64 | 65 | Bang: \! 66 | 67 | Plus: \+ 68 | 69 | Minus: \- 70 | 71 | 72 | Nor should these, which occur in code spans: 73 | 74 | Backslash: `\\` 75 | 76 | Backtick: `` \` `` 77 | 78 | Asterisk: `\*` 79 | 80 | Underscore: `\_` 81 | 82 | Left brace: `\{` 83 | 84 | Right brace: `\}` 85 | 86 | Left bracket: `\[` 87 | 88 | Right bracket: `\]` 89 | 90 | Left paren: `\(` 91 | 92 | Right paren: `\)` 93 | 94 | Greater-than: `\>` 95 | 96 | Hash: `\#` 97 | 98 | Period: `\.` 99 | 100 | Bang: `\!` 101 | 102 | Plus: `\+` 103 | 104 | Minus: `\-` 105 | 106 | 107 | These should get escaped, even though they're matching pairs for 108 | other Markdown constructs: 109 | 110 | \*asterisks\* 111 | 112 | \_underscores\_ 113 | 114 | \`backticks\` 115 | 116 | This is a code span with a literal backslash-backtick sequence: `` \` `` 117 | 118 | This is a tag with unescaped backticks bar. 119 | 120 | This is a tag with backslashes bar. 121 | -------------------------------------------------------------------------------- /test/stripdown_render_test.rb: -------------------------------------------------------------------------------- 1 | # coding: UTF-8 2 | require 'test_helper' 3 | 4 | class StripDownRender < Redcarpet::TestCase 5 | def setup 6 | @renderer = Redcarpet::Render::StripDown 7 | end 8 | 9 | def test_titles 10 | markdown = "# Foo bar" 11 | output = render(markdown) 12 | 13 | assert_equal "Foo bar\n", output 14 | end 15 | 16 | def test_code_blocks 17 | markdown = "\tclass Foo\n\tend" 18 | output = render(markdown) 19 | 20 | assert_equal "class Foo\nend\n", output 21 | end 22 | 23 | def test_images 24 | markdown = "Look at this ![picture](http://example.org/picture.png)\n" \ 25 | "And this: ![](http://example.org/image.jpg)" 26 | expected = "Look at this picture http://example.org/picture.png\n" \ 27 | "And this: http://example.org/image.jpg\n" 28 | output = render(markdown) 29 | 30 | assert_equal expected, output 31 | end 32 | 33 | def test_links 34 | markdown = "Here's an [example](https://github.com)" 35 | expected = "Here's an example (https://github.com)\n" 36 | output = render(markdown) 37 | 38 | assert_equal expected, output 39 | end 40 | 41 | def test_tables 42 | markdown = "| Left-Aligned | Centre Aligned | Right Aligned |\n" \ 43 | "| :------------ |:---------------:| -----:|\n" \ 44 | "| col 3 is | some wordy text | $1600 |\n" \ 45 | "| col 2 is | centered | $12 |" 46 | expected = "Left-Aligned\tCentre Aligned\tRight Aligned\t\n" \ 47 | "col 3 is\tsome wordy text\t$1600\t\n" \ 48 | "col 2 is\tcentered\t$12\t\n" 49 | output = render(markdown, with: [:tables]) 50 | 51 | assert_equal expected, output 52 | end 53 | 54 | def test_highlight 55 | markdown = "==Hello world!==" 56 | expected = "Hello world!\n" 57 | output = render(markdown, with: [:highlight]) 58 | 59 | assert_equal expected, output 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /ext/redcarpet/autolink.h: -------------------------------------------------------------------------------- 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 | 23 | #ifndef AUTOLINK_H__ 24 | #define AUTOLINK_H__ 25 | 26 | #include "buffer.h" 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | enum { 33 | SD_AUTOLINK_SHORT_DOMAINS = (1 << 0), 34 | }; 35 | 36 | int 37 | sd_autolink_issafe(const uint8_t *link, size_t link_len); 38 | 39 | size_t 40 | sd_autolink__www(size_t *rewind_p, struct buf *link, 41 | uint8_t *data, size_t offset, size_t size, unsigned int flags); 42 | 43 | size_t 44 | sd_autolink__email(size_t *rewind_p, struct buf *link, 45 | uint8_t *data, size_t offset, size_t size, unsigned int flags); 46 | 47 | size_t 48 | sd_autolink__url(size_t *rewind_p, struct buf *link, 49 | uint8_t *data, size_t offset, size_t size, unsigned int flags); 50 | 51 | #ifdef __cplusplus 52 | } 53 | #endif 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /ext/redcarpet/houdini.h: -------------------------------------------------------------------------------- 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 | 23 | #ifndef HOUDINI_H__ 24 | #define HOUDINI_H__ 25 | 26 | #include "buffer.h" 27 | 28 | #ifdef __cplusplus 29 | extern "C" { 30 | #endif 31 | 32 | #ifdef HOUDINI_USE_LOCALE 33 | # define _isxdigit(c) isxdigit(c) 34 | # define _isdigit(c) isdigit(c) 35 | #else 36 | /* 37 | * Helper _isdigit methods -- do not trust the current locale 38 | * */ 39 | # define _isxdigit(c) (strchr("0123456789ABCDEFabcdef", (c)) != NULL) 40 | # define _isdigit(c) ((c) >= '0' && (c) <= '9') 41 | #endif 42 | 43 | extern void houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size); 44 | extern void houdini_escape_html0(struct buf *ob, const uint8_t *src, size_t size, int secure); 45 | extern void houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /test/redcarpet_bin_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | require 'tempfile' 3 | 4 | class RedcarpetBinTest < Redcarpet::TestCase 5 | def setup 6 | @fixture_file = Tempfile.new('bin') 7 | @fixture_path = @fixture_file.path 8 | 9 | @fixture_file.write "A ==simple== fixture file -- with " \ 10 | "a [link](https://github.com)." 11 | @fixture_file.rewind 12 | end 13 | 14 | def teardown 15 | @fixture_file.unlink 16 | end 17 | 18 | def test_vanilla_bin 19 | run_bin(@fixture_path) 20 | 21 | expected = "

A ==simple== fixture file -- with " \ 22 | "a link.

\n" 23 | 24 | assert_equal expected, @output 25 | end 26 | 27 | def test_enabling_a_parse_option 28 | run_bin("--parse", "highlight", @fixture_path) 29 | 30 | assert_output "" 31 | refute_output "==" 32 | end 33 | 34 | def test_enabling_a_render_option 35 | run_bin("--render", "no-links", @fixture_path) 36 | 37 | assert_output "[link]" 38 | refute_output "" 39 | end 40 | 41 | def test_enabling_smarty_pants 42 | run_bin("--smarty", @fixture_path) 43 | 44 | assert_output "&ndash" 45 | refute_output "--" 46 | end 47 | 48 | def test_version_option 49 | run_bin("--version") 50 | assert_output "Redcarpet #{Redcarpet::VERSION}" 51 | end 52 | 53 | def test_legacy_option_parsing 54 | run_bin("--parse-highlight", "--render-no-links", @fixture_path) 55 | 56 | assert_output "" 57 | refute_output "==" 58 | 59 | assert_output "[link]" 60 | refute_output "" 61 | end 62 | 63 | private 64 | 65 | def run_bin(*args) 66 | bin_path = File.expand_path('../../bin/redcarpet', __FILE__) 67 | 68 | IO.popen("#{bin_path} #{args.join(" ")}") do |stream| 69 | @output = stream.read 70 | end 71 | end 72 | 73 | def assert_output(pattern) 74 | assert_match pattern, @output 75 | end 76 | 77 | def refute_output(pattern) 78 | refute_match Regexp.new(pattern), @output 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /test/smarty_pants_test.rb: -------------------------------------------------------------------------------- 1 | # coding: UTF-8 2 | require 'test_helper' 3 | 4 | class SmartyPantsTest < Redcarpet::TestCase 5 | def setup 6 | @pants = Redcarpet::Render::SmartyPants 7 | end 8 | 9 | def test_that_smart_converts_single_quotes_in_words_that_end_in_re 10 | markdown = @pants.render("

They're not for sale.

") 11 | assert_equal "

They’re not for sale.

", markdown 12 | end 13 | 14 | def test_that_smart_converts_single_quotes_in_words_that_end_in_ll 15 | markdown = @pants.render("

Well that'll be the day

") 16 | assert_equal "

Well that’ll be the day

", markdown 17 | end 18 | 19 | def test_that_smart_converts_double_quotes_to_curly_quotes 20 | rd = @pants.render(%(

"Quoted text"

)) 21 | assert_equal %(

“Quoted text”

), rd 22 | end 23 | 24 | def test_that_smart_gives_ve_suffix_a_rsquo 25 | rd = @pants.render("

I've been meaning to tell you ..

") 26 | assert_equal "

I’ve been meaning to tell you ..

", rd 27 | end 28 | 29 | def test_that_smart_gives_m_suffix_a_rsquo 30 | rd = @pants.render("

I'm not kidding

") 31 | assert_equal "

I’m not kidding

", rd 32 | end 33 | 34 | def test_that_smart_gives_d_suffix_a_rsquo 35 | rd = @pants.render("

what'd you say?

") 36 | assert_equal "

what’d you say?

", rd 37 | end 38 | 39 | def test_that_backticks_are_preserved 40 | rd = @pants.render("

single `backticks` in HTML should be preserved

") 41 | assert_equal "

single `backticks` in HTML should be preserved

", rd 42 | end 43 | 44 | def test_that_smart_converts_trailing_single_quotes_to_curly_quotes 45 | rd = @pants.render("

Hopin' that this bug gets some fixin'.

") 46 | assert_equal "

Hopin’ that this bug gets some fixin’.

", rd 47 | end 48 | 49 | def test_that_is_not_confused_by_fractions 50 | rd = @pants.render('I am 1/4... of the way to 1/4/2000') 51 | assert_equal "I am ¼… of the way to 1/4/2000", rd 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /redcarpet.gemspec: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | Gem::Specification.new do |s| 3 | s.name = 'redcarpet' 4 | s.version = '3.3.2' 5 | s.summary = "Markdown that smells nice" 6 | s.description = 'A fast, safe and extensible Markdown to (X)HTML parser' 7 | s.date = '2015-06-22' 8 | s.email = 'vicent@github.com' 9 | s.homepage = 'http://github.com/vmg/redcarpet' 10 | s.authors = ["Natacha Porté", "Vicent Martí"] 11 | s.license = 'MIT' 12 | s.required_ruby_version = '>= 1.9.2' 13 | # = MANIFEST = 14 | s.files = %w[ 15 | COPYING 16 | Gemfile 17 | README.markdown 18 | Rakefile 19 | bin/redcarpet 20 | ext/redcarpet/autolink.c 21 | ext/redcarpet/autolink.h 22 | ext/redcarpet/buffer.c 23 | ext/redcarpet/buffer.h 24 | ext/redcarpet/extconf.rb 25 | ext/redcarpet/houdini.h 26 | ext/redcarpet/houdini_href_e.c 27 | ext/redcarpet/houdini_html_e.c 28 | ext/redcarpet/html.c 29 | ext/redcarpet/html.h 30 | ext/redcarpet/html_blocks.h 31 | ext/redcarpet/html_smartypants.c 32 | ext/redcarpet/markdown.c 33 | ext/redcarpet/markdown.h 34 | ext/redcarpet/rc_markdown.c 35 | ext/redcarpet/rc_render.c 36 | ext/redcarpet/redcarpet.h 37 | ext/redcarpet/stack.c 38 | ext/redcarpet/stack.h 39 | lib/redcarpet.rb 40 | lib/redcarpet/cli.rb 41 | lib/redcarpet/compat.rb 42 | lib/redcarpet/render_man.rb 43 | lib/redcarpet/render_strip.rb 44 | redcarpet.gemspec 45 | test/benchmark.rb 46 | test/custom_render_test.rb 47 | test/fixtures/benchmark.md 48 | test/html5_test.rb 49 | test/html_render_test.rb 50 | test/html_toc_render_test.rb 51 | test/markdown_test.rb 52 | test/pathological_inputs_test.rb 53 | test/redcarpet_bin_test.rb 54 | test/redcarpet_compat_test.rb 55 | test/safe_render_test.rb 56 | test/smarty_html_test.rb 57 | test/smarty_pants_test.rb 58 | test/stripdown_render_test.rb 59 | test/test_helper.rb 60 | ] 61 | # = MANIFEST = 62 | s.test_files = s.files.grep(%r{^test/}) 63 | s.extra_rdoc_files = ["COPYING"] 64 | s.extensions = ["ext/redcarpet/extconf.rb"] 65 | s.executables = ["redcarpet"] 66 | s.require_paths = ["lib"] 67 | 68 | s.add_development_dependency "rake-compiler", "~> 0.9.5" 69 | s.add_development_dependency "test-unit", "~> 3.1.3" 70 | end 71 | -------------------------------------------------------------------------------- /lib/redcarpet/compat.rb: -------------------------------------------------------------------------------- 1 | require 'redcarpet' 2 | 3 | # Creates an instance of Redcarpet with the RedCloth API. 4 | class RedcarpetCompat 5 | attr_accessor :text 6 | 7 | def initialize(text, *exts) 8 | exts_hash, render_hash = *parse_extensions_and_renderer_options(exts) 9 | @text = text 10 | renderer = Redcarpet::Render::HTML.new(render_hash) 11 | @markdown = Redcarpet::Markdown.new(renderer, exts_hash) 12 | end 13 | 14 | def to_html(*_dummy) 15 | @markdown.render(text) 16 | end 17 | 18 | private 19 | 20 | EXTENSION_MAP = { 21 | # old name => new name 22 | :autolink => :autolink, 23 | :fenced_code => :fenced_code_blocks, 24 | :filter_html => :filter_html, 25 | :hard_wrap => :hard_wrap, 26 | :prettify => :prettify, 27 | :lax_htmlblock => :lax_spacing, 28 | :no_image => :no_images, 29 | :no_intraemphasis => :no_intra_emphasis, 30 | :no_links => :no_links, 31 | :filter_styles => :no_styles, 32 | :safelink => :safe_links_only, 33 | :space_header => :space_after_headers, 34 | :strikethrough => :strikethrough, 35 | :tables => :tables, 36 | :generate_toc => :with_toc_data, 37 | :xhtml => :xhtml, 38 | 39 | # old names with no new mapping 40 | :gh_blockcode => nil, 41 | :no_tables => nil, 42 | :smart => nil, 43 | :strict => nil 44 | } 45 | 46 | RENDERER_OPTIONS = [:filter_html, :no_images, :no_links, :no_styles, 47 | :safe_links_only, :with_toc_data, :hard_wrap, :prettify, :xhtml] 48 | 49 | def rename_extensions(exts) 50 | exts.map do |old_name| 51 | if new_name = EXTENSION_MAP[old_name] 52 | new_name 53 | else 54 | old_name 55 | end 56 | end.compact 57 | end 58 | 59 | # Returns two hashes, the extensions and renderer options 60 | # given the extension list 61 | def parse_extensions_and_renderer_options(exts) 62 | exts = rename_extensions(exts) 63 | exts.partition {|ext| !RENDERER_OPTIONS.include?(ext) }. 64 | map {|list| list_to_truthy_hash(list) } 65 | end 66 | 67 | # Turns a list of symbols into a hash of symbol => true. 68 | def list_to_truthy_hash(list) 69 | list.inject({}) {|h, k| h[k] = true; h } 70 | end 71 | end 72 | 73 | Markdown = RedcarpetCompat unless defined? Markdown 74 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/Tests/Ordered and unordered lists.html: -------------------------------------------------------------------------------- 1 |

Unordered

2 | 3 |

Asterisks tight:

4 | 5 |
    6 |
  • asterisk 1
  • 7 |
  • asterisk 2
  • 8 |
  • asterisk 3
  • 9 |
10 | 11 |

Asterisks loose:

12 | 13 |
    14 |
  • asterisk 1

  • 15 |
  • asterisk 2

  • 16 |
  • asterisk 3

  • 17 |
18 | 19 |
20 | 21 |

Pluses tight:

22 | 23 |
    24 |
  • Plus 1
  • 25 |
  • Plus 2
  • 26 |
  • Plus 3
  • 27 |
28 | 29 |

Pluses loose:

30 | 31 |
    32 |
  • Plus 1

  • 33 |
  • Plus 2

  • 34 |
  • Plus 3

  • 35 |
36 | 37 |
38 | 39 |

Minuses tight:

40 | 41 |
    42 |
  • Minus 1
  • 43 |
  • Minus 2
  • 44 |
  • Minus 3
  • 45 |
46 | 47 |

Minuses loose:

48 | 49 |
    50 |
  • Minus 1

  • 51 |
  • Minus 2

  • 52 |
  • Minus 3

  • 53 |
54 | 55 |

Ordered

56 | 57 |

Tight:

58 | 59 |
    60 |
  1. First
  2. 61 |
  3. Second
  4. 62 |
  5. Third
  6. 63 |
64 | 65 |

and:

66 | 67 |
    68 |
  1. One
  2. 69 |
  3. Two
  4. 70 |
  5. Three
  6. 71 |
72 | 73 |

Loose using tabs:

74 | 75 |
    76 |
  1. First

  2. 77 |
  3. Second

  4. 78 |
  5. Third

  6. 79 |
80 | 81 |

and using spaces:

82 | 83 |
    84 |
  1. One

  2. 85 |
  3. Two

  4. 86 |
  5. Three

  6. 87 |
88 | 89 |

Multiple paragraphs:

90 | 91 |
    92 |
  1. Item 1, graf one.

    93 | 94 |

    Item 2. graf two. The quick brown fox jumped over the lazy dog's 95 | back.

  2. 96 |
  3. Item 2.

  4. 97 |
  5. Item 3.

  6. 98 |
99 | 100 |

Nested

101 | 102 |
    103 |
  • Tab 104 |
      105 |
    • Tab 106 |
        107 |
      • Tab
      • 108 |
    • 109 |
  • 110 |
111 | 112 |

Here's another:

113 | 114 |
    115 |
  1. First
  2. 116 |
  3. Second: 117 |
      118 |
    • Fee
    • 119 |
    • Fie
    • 120 |
    • Foe
    • 121 |
  4. 122 |
  5. Third
  6. 123 |
124 | 125 |

Same thing but with paragraphs:

126 | 127 |
    128 |
  1. First

  2. 129 |
  3. Second:

    130 | 131 |
      132 |
    • Fee
    • 133 |
    • Fie
    • 134 |
    • Foe
    • 135 |
  4. 136 |
  5. Third

  6. 137 |
138 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Backslash escapes.html: -------------------------------------------------------------------------------- 1 |

These should all get escaped:

2 | 3 |

Backslash: \

4 | 5 |

Backtick: `

6 | 7 |

Asterisk: *

8 | 9 |

Underscore: _

10 | 11 |

Left brace: {

12 | 13 |

Right brace: }

14 | 15 |

Left bracket: [

16 | 17 |

Right bracket: ]

18 | 19 |

Left paren: (

20 | 21 |

Right paren: )

22 | 23 |

Greater-than: >

24 | 25 |

Hash: #

26 | 27 |

Period: .

28 | 29 |

Bang: !

30 | 31 |

Plus: +

32 | 33 |

Minus: -

34 | 35 |

These should not, because they occur within a code block:

36 | 37 |
Backslash: \\
 38 | 
 39 | Backtick: \`
 40 | 
 41 | Asterisk: \*
 42 | 
 43 | Underscore: \_
 44 | 
 45 | Left brace: \{
 46 | 
 47 | Right brace: \}
 48 | 
 49 | Left bracket: \[
 50 | 
 51 | Right bracket: \]
 52 | 
 53 | Left paren: \(
 54 | 
 55 | Right paren: \)
 56 | 
 57 | Greater-than: \>
 58 | 
 59 | Hash: \#
 60 | 
 61 | Period: \.
 62 | 
 63 | Bang: \!
 64 | 
 65 | Plus: \+
 66 | 
 67 | Minus: \-
 68 | 
69 | 70 |

Nor should these, which occur in code spans:

71 | 72 |

Backslash: \\

73 | 74 |

Backtick: \`

75 | 76 |

Asterisk: \*

77 | 78 |

Underscore: \_

79 | 80 |

Left brace: \{

81 | 82 |

Right brace: \}

83 | 84 |

Left bracket: \[

85 | 86 |

Right bracket: \]

87 | 88 |

Left paren: \(

89 | 90 |

Right paren: \)

91 | 92 |

Greater-than: \>

93 | 94 |

Hash: \#

95 | 96 |

Period: \.

97 | 98 |

Bang: \!

99 | 100 |

Plus: \+

101 | 102 |

Minus: \-

103 | 104 | 105 |

These should get escaped, even though they're matching pairs for 106 | other Markdown constructs:

107 | 108 |

*asterisks*

109 | 110 |

_underscores_

111 | 112 |

`backticks`

113 | 114 |

This is a code span with a literal backslash-backtick sequence: \`

115 | 116 |

This is a tag with unescaped backticks bar.

117 | 118 |

This is a tag with backslashes bar.

119 | -------------------------------------------------------------------------------- /ext/redcarpet/stack.c: -------------------------------------------------------------------------------- 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 | 23 | #include "stack.h" 24 | #include 25 | 26 | int 27 | redcarpet_stack_grow(struct stack *st, size_t new_size) 28 | { 29 | void **new_st; 30 | 31 | if (st->asize >= new_size) 32 | return 0; 33 | 34 | new_st = realloc(st->item, new_size * sizeof(void *)); 35 | if (new_st == NULL) 36 | return -1; 37 | 38 | memset(new_st + st->asize, 0x0, 39 | (new_size - st->asize) * sizeof(void *)); 40 | 41 | st->item = new_st; 42 | st->asize = new_size; 43 | 44 | if (st->size > new_size) 45 | st->size = new_size; 46 | 47 | return 0; 48 | } 49 | 50 | void 51 | redcarpet_stack_free(struct stack *st) 52 | { 53 | if (!st) 54 | return; 55 | 56 | free(st->item); 57 | 58 | st->item = NULL; 59 | st->size = 0; 60 | st->asize = 0; 61 | } 62 | 63 | int 64 | redcarpet_stack_init(struct stack *st, size_t initial_size) 65 | { 66 | st->item = NULL; 67 | st->size = 0; 68 | st->asize = 0; 69 | 70 | if (!initial_size) 71 | initial_size = 8; 72 | 73 | return redcarpet_stack_grow(st, initial_size); 74 | } 75 | 76 | int 77 | redcarpet_stack_push(struct stack *st, void *item) 78 | { 79 | if (redcarpet_stack_grow(st, st->size * 2) < 0) 80 | return -1; 81 | 82 | st->item[st->size++] = item; 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /test/html_toc_render_test.rb: -------------------------------------------------------------------------------- 1 | # coding: UTF-8 2 | require 'test_helper' 3 | 4 | class HTMLTOCRenderTest < Redcarpet::TestCase 5 | def setup 6 | @renderer = Redcarpet::Render::HTML_TOC 7 | @markdown = "# A title \n## A __nice__ subtitle\n## Another one \n### A sub-sub-title" 8 | end 9 | 10 | def test_simple_toc_render 11 | output = render(@markdown).strip 12 | 13 | assert output.start_with?("
    ") 14 | assert output.end_with?("
") 15 | 16 | assert_equal 3, output.scan("
    ").length 17 | assert_equal 4, output.scan("
  • ").length 18 | end 19 | 20 | def test_granular_toc_render 21 | output = render(@markdown, with: { nesting_level: 2 }).strip 22 | 23 | assert output.start_with?("
      ") 24 | assert output.end_with?("
    ") 25 | 26 | assert_equal 3, output.scan("
  • ").length 27 | assert !output.include?("A sub-sub title") 28 | end 29 | 30 | def test_toc_heading_id 31 | output = render(@markdown) 32 | 33 | assert_match /a-title/, output 34 | assert_match /a-nice-subtitle/, output 35 | assert_match /another-one/, output 36 | assert_match /a-sub-sub-title/, output 37 | end 38 | 39 | def test_toc_heading_with_hyphen_and_equal 40 | output = render("# Hello World\n\n-\n\n=") 41 | 42 | assert_equal 1, output.scan("
  • ").length 43 | assert !output.include?('') 44 | end 45 | 46 | def test_anchor_generation_with_edge_cases 47 | # Imported from ActiveSupport::Inflector#parameterize's tests 48 | titles = { 49 | "Donald E. Knuth" => "donald-e-knuth", 50 | "Random text with *(bad)* characters" => "random-text-with-bad-characters", 51 | "!@#Surrounding bad characters!@#" => "surrounding-bad-characters", 52 | "Squeeze separators" => "squeeze-separators", 53 | "Test with + sign" => "test-with-sign", 54 | "Test with a Namespaced::Class" => "test-with-a-namespaced-class" 55 | } 56 | 57 | titles.each do |title, anchor| 58 | assert_match %("##{anchor}"), render("# #{title}") 59 | end 60 | end 61 | 62 | def test_inline_markup_is_not_escaped 63 | output = render(@markdown) 64 | 65 | assert_match "A nice subtitle", output 66 | assert_no_match %r{<}, output 67 | end 68 | 69 | def test_inline_markup_escaping 70 | output = render(@markdown, with: [:escape_html]) 71 | 72 | assert_match "<strong>", output 73 | assert_no_match %r{}, output 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/Tests/Ordered and unordered lists.html: -------------------------------------------------------------------------------- 1 |

    Unordered

    2 | 3 |

    Asterisks tight:

    4 | 5 |
      6 |
    • asterisk 1
    • 7 |
    • asterisk 2
    • 8 |
    • asterisk 3
    • 9 |
    10 | 11 |

    Asterisks loose:

    12 | 13 |
      14 |
    • asterisk 1

    • 15 |
    • asterisk 2

    • 16 |
    • asterisk 3

    • 17 |
    18 | 19 |
    20 | 21 |

    Pluses tight:

    22 | 23 |
      24 |
    • Plus 1
    • 25 |
    • Plus 2
    • 26 |
    • Plus 3
    • 27 |
    28 | 29 |

    Pluses loose:

    30 | 31 |
      32 |
    • Plus 1

    • 33 |
    • Plus 2

    • 34 |
    • Plus 3

    • 35 |
    36 | 37 |
    38 | 39 |

    Minuses tight:

    40 | 41 |
      42 |
    • Minus 1
    • 43 |
    • Minus 2
    • 44 |
    • Minus 3
    • 45 |
    46 | 47 |

    Minuses loose:

    48 | 49 |
      50 |
    • Minus 1

    • 51 |
    • Minus 2

    • 52 |
    • Minus 3

    • 53 |
    54 | 55 |

    Ordered

    56 | 57 |

    Tight:

    58 | 59 |
      60 |
    1. First
    2. 61 |
    3. Second
    4. 62 |
    5. Third
    6. 63 |
    64 | 65 |

    and:

    66 | 67 |
      68 |
    1. One
    2. 69 |
    3. Two
    4. 70 |
    5. Three
    6. 71 |
    72 | 73 |

    Loose using tabs:

    74 | 75 |
      76 |
    1. First

    2. 77 |
    3. Second

    4. 78 |
    5. Third

    6. 79 |
    80 | 81 |

    and using spaces:

    82 | 83 |
      84 |
    1. One

    2. 85 |
    3. Two

    4. 86 |
    5. Three

    6. 87 |
    88 | 89 |

    Multiple paragraphs:

    90 | 91 |
      92 |
    1. Item 1, graf one.

      93 | 94 |

      Item 2. graf two. The quick brown fox jumped over the lazy dog's 95 | back.

    2. 96 |
    3. Item 2.

    4. 97 |
    5. Item 3.

    6. 98 |
    99 | 100 |

    Nested

    101 | 102 |
      103 |
    • Tab 104 |
        105 |
      • Tab 106 |
          107 |
        • Tab
        • 108 |
      • 109 |
    • 110 |
    111 | 112 |

    Here's another:

    113 | 114 |
      115 |
    1. First
    2. 116 |
    3. Second: 117 |
        118 |
      • Fee
      • 119 |
      • Fie
      • 120 |
      • Foe
      • 121 |
    4. 122 |
    5. Third
    6. 123 |
    124 | 125 |

    Same thing but with paragraphs:

    126 | 127 |
      128 |
    1. First

    2. 129 |
    3. Second:

      130 | 131 |
        132 |
      • Fee
      • 133 |
      • Fie
      • 134 |
      • Foe
      • 135 |
    4. 136 |
    5. Third

    6. 137 |
    138 | 139 | 140 |

    This was an error in Markdown 1.0.1:

    141 | 142 |
      143 |
    • this

      144 | 145 |
      • sub
      146 | 147 |

      that

    • 148 |
    149 | -------------------------------------------------------------------------------- /lib/redcarpet.rb: -------------------------------------------------------------------------------- 1 | require 'redcarpet.so' 2 | require 'redcarpet/compat' 3 | 4 | module Redcarpet 5 | VERSION = '3.3.2' 6 | 7 | class Markdown 8 | attr_reader :renderer 9 | end 10 | 11 | module Render 12 | 13 | # XHTML Renderer 14 | class XHTML < HTML 15 | def initialize(extensions = {}) 16 | super(extensions.merge(xhtml: true)) 17 | end 18 | end 19 | 20 | # HTML + SmartyPants renderer 21 | class SmartyHTML < HTML 22 | include SmartyPants 23 | end 24 | 25 | # A renderer object you can use to deal with users' input. It 26 | # enables +escape_html+ and +safe_links_only+ by default. 27 | # 28 | # The +block_code+ callback is also overriden not to include 29 | # the lang's class as the user can basically specify anything 30 | # with the vanilla one. 31 | class Safe < HTML 32 | def initialize(extensions = {}) 33 | super({ 34 | escape_html: true, 35 | safe_links_only: true 36 | }.merge(extensions)) 37 | end 38 | 39 | def block_code(code, lang) 40 | "
    " \
    41 |           "#{html_escape(code)}" \
    42 |         "
    " 43 | end 44 | 45 | private 46 | 47 | # TODO: This is far from ideal to have such method as we 48 | # are duplicating existing code from Houdini. This method 49 | # should be defined at the C level. 50 | def html_escape(string) 51 | string.gsub(/['&\"<>\/]/, { 52 | '&' => '&', 53 | '<' => '<', 54 | '>' => '>', 55 | '"' => '"', 56 | "'" => ''', 57 | "/" => '/', 58 | }) 59 | end 60 | end 61 | 62 | # SmartyPants Mixin module 63 | # 64 | # Implements SmartyPants.postprocess, which 65 | # performs smartypants replacements on the HTML file, 66 | # once it has been fully rendered. 67 | # 68 | # To add SmartyPants postprocessing to your custom 69 | # renderers, just mixin the module `include SmartyPants` 70 | # 71 | # You can also use this as a standalone SmartyPants 72 | # implementation. 73 | # 74 | # Example: 75 | # 76 | # # Mixin 77 | # class CoolRenderer < HTML 78 | # include SmartyPants 79 | # # more code here 80 | # end 81 | # 82 | # # Standalone 83 | # Redcarpet::Render::SmartyPants.render("you're") 84 | # 85 | module SmartyPants 86 | extend self 87 | def self.render(text) 88 | postprocess text 89 | end 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /ext/redcarpet/html.h: -------------------------------------------------------------------------------- 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 | 23 | #ifndef HTML_H__ 24 | #define HTML_H__ 25 | 26 | #include "markdown.h" 27 | #include "buffer.h" 28 | #include 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | struct html_renderopt { 35 | struct { 36 | int current_level; 37 | int level_offset; 38 | int nesting_level; 39 | } toc_data; 40 | 41 | unsigned int flags; 42 | 43 | /* extra callbacks */ 44 | void (*link_attributes)(struct buf *ob, const struct buf *url, void *self); 45 | }; 46 | 47 | typedef enum { 48 | HTML_SKIP_HTML = (1 << 0), 49 | HTML_SKIP_STYLE = (1 << 1), 50 | HTML_SKIP_IMAGES = (1 << 2), 51 | HTML_SKIP_LINKS = (1 << 3), 52 | HTML_EXPAND_TABS = (1 << 4), 53 | HTML_SAFELINK = (1 << 5), 54 | HTML_TOC = (1 << 6), 55 | HTML_HARD_WRAP = (1 << 7), 56 | HTML_USE_XHTML = (1 << 8), 57 | HTML_ESCAPE = (1 << 9), 58 | HTML_PRETTIFY = (1 << 10), 59 | } html_render_mode; 60 | 61 | typedef enum { 62 | HTML_TAG_NONE = 0, 63 | HTML_TAG_OPEN, 64 | HTML_TAG_CLOSE, 65 | } html_tag; 66 | 67 | int 68 | sdhtml_is_tag(const uint8_t *tag_data, size_t tag_size, const char *tagname); 69 | 70 | extern void 71 | sdhtml_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, unsigned int render_flags); 72 | 73 | extern void 74 | sdhtml_toc_renderer(struct sd_callbacks *callbacks, struct html_renderopt *options_ptr, unsigned int render_flags); 75 | 76 | extern void 77 | sdhtml_smartypants(struct buf *ob, const uint8_t *text, size_t size); 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | 83 | #endif 84 | 85 | -------------------------------------------------------------------------------- /lib/redcarpet/cli.rb: -------------------------------------------------------------------------------- 1 | require 'redcarpet' 2 | require 'optparse' 3 | 4 | module Redcarpet 5 | # This class aims at easing the creation of custom 6 | # binary for your needs. For example, you can add new 7 | # options or change the existing ones. The parsing 8 | # is handled by Ruby's OptionParser. For instance: 9 | # 10 | # class Custom::CLI < Redcarpet::CLI 11 | # def self.options_parser 12 | # super.tap do |opts| 13 | # opts.on("--rainbow") do 14 | # @@options[:rainbow] = true 15 | # end 16 | # end 17 | # end 18 | # 19 | # def self.render_object 20 | # @@options[:rainbow] ? RainbowRender : super 21 | # end 22 | # end 23 | class CLI 24 | def self.options_parser 25 | @@options = { 26 | render_extensions: {}, 27 | parse_extensions: {}, 28 | smarty_pants: false 29 | } 30 | 31 | OptionParser.new do |opts| 32 | opts.banner = "Usage: redcarpet [--parse ...] " \ 33 | "[--render ...] [--smarty] ..." 34 | 35 | opts.on("--parse EXTENSION", "Enable a parsing extension") do |ext| 36 | ext = ext.gsub('-', '_').to_sym 37 | @@options[:parse_extensions][ext] = true 38 | end 39 | 40 | opts.on("--render EXTENSION", "Enable a rendering extension") do |ext| 41 | ext = ext.gsub('-', '_').to_sym 42 | @@options[:render_extensions][ext] = true 43 | end 44 | 45 | opts.on("--smarty", "Enable Smarty Pants") do 46 | @@options[:smarty_pants] = true 47 | end 48 | 49 | opts.on_tail("-v", "--version", "Display the current version") do 50 | STDOUT.write "Redcarpet #{Redcarpet::VERSION}" 51 | exit 52 | end 53 | 54 | opts.on_tail("-h", "--help", "Display this help message") do 55 | puts opts 56 | exit 57 | end 58 | end 59 | end 60 | 61 | def self.process(args) 62 | self.legacy_parse!(args) 63 | self.options_parser.parse!(args) 64 | STDOUT.write parser_object.render(ARGF.read) 65 | end 66 | 67 | def self.render_object 68 | @@options[:smarty_pants] ? Render::SmartyHTML : Render::HTML 69 | end 70 | 71 | def self.parser_object 72 | renderer = render_object.new(@@options[:render_extensions]) 73 | Redcarpet::Markdown.new(renderer, @@options[:parse_extensions]) 74 | end 75 | 76 | def self.legacy_parse!(args) # :nodoc: 77 | # Workaround for backward compatibility as OptionParser 78 | # doesn't support the --flag-OPTION syntax. 79 | args.select {|a| a =~ /--(parse|render)-/ }.each do |arg| 80 | args.delete(arg) 81 | arg = arg.partition(/\b-/) 82 | args.push(arg.first, arg.last) 83 | end 84 | end 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /ext/redcarpet/buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008, Natacha Porté 3 | * Copyright (c) 2015, Vicent Marti 4 | * 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: 11 | * 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. 22 | */ 23 | 24 | #ifndef BUFFER_H__ 25 | #define BUFFER_H__ 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif 34 | 35 | #if defined(_MSC_VER) 36 | #define __attribute__(x) 37 | #define inline 38 | #endif 39 | 40 | typedef enum { 41 | BUF_OK = 0, 42 | BUF_ENOMEM = -1, 43 | } buferror_t; 44 | 45 | /* struct buf: character array buffer */ 46 | struct buf { 47 | uint8_t *data; /* actual character data */ 48 | size_t size; /* size of the string */ 49 | size_t asize; /* allocated size (0 = volatile buffer) */ 50 | size_t unit; /* reallocation unit size (0 = read-only buffer) */ 51 | }; 52 | 53 | /* BUFPUTSL: optimized bufputs of a string literal */ 54 | #define BUFPUTSL(output, literal) \ 55 | bufput(output, literal, sizeof literal - 1) 56 | 57 | /* bufgrow: increasing the allocated size to the given value */ 58 | int bufgrow(struct buf *, size_t); 59 | 60 | /* bufnew: allocation of a new buffer */ 61 | struct buf *bufnew(size_t) __attribute__ ((malloc)); 62 | 63 | /* bufnullterm: NUL-termination of the string array (making a C-string) */ 64 | const char *bufcstr(const struct buf *); 65 | 66 | /* bufprefix: compare the beginning of a buffer with a string */ 67 | int bufprefix(const struct buf *buf, const char *prefix); 68 | 69 | /* bufput: appends raw data to a buffer */ 70 | void bufput(struct buf *, const void *, size_t); 71 | 72 | /* bufputs: appends a NUL-terminated string to a buffer */ 73 | void bufputs(struct buf *, const char *); 74 | 75 | /* bufputc: appends a single char to a buffer */ 76 | void bufputc(struct buf *, int); 77 | 78 | /* bufrelease: decrease the reference count and free the buffer if needed */ 79 | void bufrelease(struct buf *); 80 | 81 | /* bufprintf: formatted printing to a buffer */ 82 | void bufprintf(struct buf *, const char *, ...) __attribute__ ((format (printf, 2, 3))); 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | 88 | #endif 89 | 90 | -------------------------------------------------------------------------------- /ext/redcarpet/houdini_html_e.c: -------------------------------------------------------------------------------- 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 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "houdini.h" 28 | 29 | #define ESCAPE_GROW_FACTOR(x) (((x) * 12) / 10) /* this is very scientific, yes */ 30 | 31 | /** 32 | * According to the OWASP rules: 33 | * 34 | * & --> & 35 | * < --> < 36 | * > --> > 37 | * " --> " 38 | * ' --> ' ' is not recommended 39 | * / --> / forward slash is included as it helps end an HTML entity 40 | * 41 | */ 42 | static const char HTML_ESCAPE_TABLE[] = { 43 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 44 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45 | 0, 0, 1, 0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0, 0, 4, 46 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 0, 47 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 57 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59 | }; 60 | 61 | static const char *HTML_ESCAPES[] = { 62 | "", 63 | """, 64 | "&", 65 | "'", 66 | "/", 67 | "<", 68 | ">" 69 | }; 70 | 71 | void 72 | houdini_escape_html0(struct buf *ob, const uint8_t *src, size_t size, int secure) 73 | { 74 | size_t i = 0, org, esc = 0; 75 | 76 | bufgrow(ob, ESCAPE_GROW_FACTOR(size)); 77 | 78 | while (i < size) { 79 | org = i; 80 | while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0) 81 | i++; 82 | 83 | if (i > org) 84 | bufput(ob, src + org, i - org); 85 | 86 | /* escaping */ 87 | if (i >= size) 88 | break; 89 | 90 | /* The forward slash is only escaped in secure mode */ 91 | if (src[i] == '/' && !secure) 92 | bufputc(ob, '/'); 93 | else 94 | bufputs(ob, HTML_ESCAPES[esc]); 95 | 96 | i++; 97 | } 98 | } 99 | 100 | void 101 | houdini_escape_html(struct buf *ob, const uint8_t *src, size_t size) 102 | { 103 | houdini_escape_html0(ob, src, size, 1); 104 | } 105 | 106 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0/MarkdownTest.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # 4 | # MarkdownTester -- Run tests for Markdown implementations 5 | # 6 | # Copyright (c) 2004 John Gruber 7 | # 8 | # 9 | 10 | use strict; 11 | use warnings; 12 | use Getopt::Long; 13 | use Benchmark; 14 | 15 | our $VERSION = '1.0'; 16 | # Mon 13 Dec 2004 17 | 18 | my $time_start = new Benchmark; 19 | my $test_dir = "Tests"; 20 | my $script = "./Markdown.pl"; 21 | my $use_tidy = 0; 22 | my ($flag_version); 23 | 24 | GetOptions ( 25 | "script=s" => \$script, 26 | "testdir=s" => \$test_dir, 27 | "tidy" => \$use_tidy, 28 | "version" => \$flag_version, 29 | ); 30 | 31 | if($flag_version) { 32 | my $progname = $0; 33 | $progname =~ s{.*/}{}; 34 | die "$progname version $VERSION\n"; 35 | } 36 | 37 | unless (-d $test_dir) { die "'$test_dir' is not a directory.\n"; } 38 | unless (-f $script) { die "$script does not exist.\n"; } 39 | unless (-x $script) { die "$script is not executable.\n"; } 40 | 41 | my $tests_passed = 0; 42 | my $tests_failed = 0; 43 | 44 | foreach my $testfile (glob "$test_dir/*.text") { 45 | my $testname = $testfile; 46 | $testname =~ s{.*/(.+)\.text$}{$1}i; 47 | print "$testname ... "; 48 | 49 | # Look for a corresponding .html file for each .text file: 50 | my $resultfile = $testfile; 51 | $resultfile =~ s{\.text$}{\.html}i; 52 | unless (-f $resultfile) {die "'$resultfile' does not exist.\n";} 53 | 54 | # open(TEST, $testfile) || die("Can't open testfile: $!"); 55 | open(RESULT, $resultfile) || die("Can't open resultfile: $!"); 56 | undef $/; 57 | # my $t_input = ; 58 | my $t_result = ; 59 | 60 | my $t_output = `$script '$testfile'`; 61 | 62 | # Normalize the output and expected result strings: 63 | $t_result =~ s/\s+\z//; # trim trailing whitespace 64 | $t_output =~ s/\s+\z//; # trim trailing whitespace 65 | if ($use_tidy) { 66 | # Escape the strings, pass them through to CLI tidy tool for tag-level equivalency 67 | $t_result =~ s{'}{'\\''}g; # escape ' chars for shell 68 | $t_output =~ s{'}{'\\''}g; 69 | $t_result = `echo '$t_result' | tidy --show-body-only 1 --quiet 1 --show-warnings 0`; 70 | $t_output = `echo '$t_output' | tidy --show-body-only 1 --quiet 1 --show-warnings 0`; 71 | } 72 | 73 | if ($t_output eq $t_result) { 74 | print "OK\n"; 75 | $tests_passed++; 76 | } 77 | else { 78 | print "FAILED\n\n"; 79 | $tests_failed++; 80 | } 81 | } 82 | 83 | print "\n\n"; 84 | print "$tests_passed passed; $tests_failed failed.\n"; 85 | 86 | my $time_end = new Benchmark; 87 | my $time_diff = timediff($time_end, $time_start); 88 | print "Benchmark: ", timestr($time_diff), "\n"; 89 | 90 | if ($tests_failed ne 0) { 91 | exit 1; 92 | } else { 93 | exit 0; 94 | } 95 | 96 | __END__ 97 | 98 | =pod 99 | 100 | =head1 NAME 101 | 102 | B 103 | 104 | 105 | =head1 SYNOPSIS 106 | 107 | B [ B<--options> ] [ I ... ] 108 | 109 | 110 | =head1 DESCRIPTION 111 | 112 | 113 | =head1 OPTIONS 114 | 115 | Use "--" to end switch parsing. For example, to open a file named "-z", use: 116 | 117 | MarkdownTest.pl -- -z 118 | 119 | =over 4 120 | 121 | =item B<--script> 122 | 123 | Specify the path to the Markdown script to test. Defaults to 124 | "./Markdown.pl". Example: 125 | 126 | ./MarkdownTest.pl --script ./PHP-Markdown/php-markdown 127 | 128 | =item B<--testdir> 129 | 130 | Specify the path to a directory containing test data. Defaults to "Tests". 131 | 132 | =item B<--tidy> 133 | 134 | Flag to turn on using the command line 'tidy' tool to normalize HTML 135 | output before comparing script output to the expected test result. 136 | Assumes that the 'tidy' command is available in your PATH. Defaults to 137 | off. 138 | 139 | =back 140 | 141 | 142 | 143 | =head1 BUGS 144 | 145 | 146 | 147 | =head1 VERSION HISTORY 148 | 149 | 1.0 Mon 13 Dec 2004 150 | 151 | 152 | 153 | =head1 COPYRIGHT AND LICENSE 154 | 155 | Copyright (c) 2004 John Gruber 156 | 157 | All rights reserved. 158 | 159 | This is free software; you may redistribute it and/or modify it under 160 | the same terms as Perl itself. 161 | 162 | =cut 163 | -------------------------------------------------------------------------------- /ext/redcarpet/houdini_href_e.c: -------------------------------------------------------------------------------- 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 | 23 | #include 24 | #include 25 | #include 26 | 27 | #include "houdini.h" 28 | 29 | #define ESCAPE_GROW_FACTOR(x) (((x) * 12) / 10) 30 | 31 | /* 32 | * The following characters will not be escaped: 33 | * 34 | * -_.+!*'(),%#@?=;:/,+&$ alphanum 35 | * 36 | * Note that this character set is the addition of: 37 | * 38 | * - The characters which are safe to be in an URL 39 | * - The characters which are *not* safe to be in 40 | * an URL because they are RESERVED characters. 41 | * 42 | * We asume (lazily) that any RESERVED char that 43 | * appears inside an URL is actually meant to 44 | * have its native function (i.e. as an URL 45 | * component/separator) and hence needs no escaping. 46 | * 47 | * There are two exceptions: the chacters & (amp) 48 | * and ' (single quote) do not appear in the table. 49 | * They are meant to appear in the URL as components, 50 | * yet they require special HTML-entity escaping 51 | * to generate valid HTML markup. 52 | * 53 | * All other characters will be escaped to %XX. 54 | * 55 | */ 56 | static const char HREF_SAFE[] = { 57 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 58 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59 | 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 60 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 61 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 62 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 63 | 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 64 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 65 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 71 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73 | }; 74 | 75 | void 76 | houdini_escape_href(struct buf *ob, const uint8_t *src, size_t size) 77 | { 78 | static const char hex_chars[] = "0123456789ABCDEF"; 79 | size_t i = 0, org; 80 | char hex_str[3]; 81 | 82 | bufgrow(ob, ESCAPE_GROW_FACTOR(size)); 83 | hex_str[0] = '%'; 84 | 85 | while (i < size) { 86 | org = i; 87 | while (i < size && HREF_SAFE[src[i]] != 0) 88 | i++; 89 | 90 | if (i > org) 91 | bufput(ob, src + org, i - org); 92 | 93 | /* escaping */ 94 | if (i >= size) 95 | break; 96 | 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 | /* the single quote is a valid URL character 105 | * according to the standard; it needs HTML 106 | * entity escaping too */ 107 | case '\'': 108 | BUFPUTSL(ob, "'"); 109 | break; 110 | 111 | /* the space can be escaped to %20 or a plus 112 | * sign. we're going with the generic escape 113 | * for now. the plus thing is more commonly seen 114 | * when building GET strings */ 115 | #if 0 116 | case ' ': 117 | bufputc(ob, '+'); 118 | break; 119 | #endif 120 | 121 | /* every other character goes with a %XX escaping */ 122 | default: 123 | hex_str[1] = hex_chars[(src[i] >> 4) & 0xF]; 124 | hex_str[2] = hex_chars[src[i] & 0xF]; 125 | bufput(ob, hex_str, 3); 126 | } 127 | 128 | i++; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /test/MarkdownTest_1.0.3/MarkdownTest.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # 4 | # MarkdownTester -- Run tests for Markdown implementations 5 | # 6 | # Copyright (c) 2004-2005 John Gruber 7 | # 8 | # 9 | 10 | use strict; 11 | use warnings; 12 | use Getopt::Long; 13 | use Benchmark; 14 | 15 | our $VERSION = '1.0.2'; 16 | # Sat 24 Dec 2005 17 | 18 | my $time_start = new Benchmark; 19 | my $test_dir = "Tests"; 20 | my $script = "./Markdown.pl"; 21 | my $use_tidy = 0; 22 | my ($flag_version); 23 | 24 | GetOptions ( 25 | "script=s" => \$script, 26 | "testdir=s" => \$test_dir, 27 | "tidy" => \$use_tidy, 28 | "version" => \$flag_version, 29 | ); 30 | 31 | if($flag_version) { 32 | my $progname = $0; 33 | $progname =~ s{.*/}{}; 34 | die "$progname version $VERSION\n"; 35 | } 36 | 37 | unless (-d $test_dir) { die "'$test_dir' is not a directory.\n"; } 38 | unless (-f $script) { die "$script does not exist.\n"; } 39 | unless (-x $script) { die "$script is not executable.\n"; } 40 | 41 | my $tests_passed = 0; 42 | my $tests_failed = 0; 43 | 44 | TEST: 45 | foreach my $testfile (glob "$test_dir/*.text") { 46 | my $testname = $testfile; 47 | $testname =~ s{.*/(.+)\.text$}{$1}i; 48 | print "$testname ... "; 49 | 50 | # Look for a corresponding .html file for each .text file: 51 | my $resultfile = $testfile; 52 | $resultfile =~ s{\.text$}{\.html}i; 53 | unless (-f $resultfile) { 54 | print "'$resultfile' does not exist.\n\n"; 55 | next TEST; 56 | } 57 | 58 | # open(TEST, $testfile) || die("Can't open testfile: $!"); 59 | open(RESULT, $resultfile) || die("Can't open resultfile: $!"); 60 | undef $/; 61 | # my $t_input = ; 62 | my $t_result = ; 63 | 64 | my $t_output = `'$script' '$testfile'`; 65 | 66 | # Normalize the output and expected result strings: 67 | $t_result =~ s/\s+\z//; # trim trailing whitespace 68 | $t_output =~ s/\s+\z//; # trim trailing whitespace 69 | if ($use_tidy) { 70 | # Escape the strings, pass them through to CLI tidy tool for tag-level equivalency 71 | $t_result =~ s{'}{'\\''}g; # escape ' chars for shell 72 | $t_output =~ s{'}{'\\''}g; 73 | $t_result = `echo '$t_result' | tidy --show-body-only 1 --quiet 1 --show-warnings 0`; 74 | $t_output = `echo '$t_output' | tidy --show-body-only 1 --quiet 1 --show-warnings 0`; 75 | } 76 | 77 | if ($t_output eq $t_result) { 78 | print "OK\n"; 79 | $tests_passed++; 80 | } 81 | else { 82 | print "FAILED\n\n"; 83 | # This part added by JM to print diffs 84 | open(OUT, '>tmp1') or die $!; 85 | print OUT $t_output or die $!; 86 | open(RES, '>tmp2') or die $!; 87 | print RES $t_result or die $!; 88 | print `diff tmp1 tmp2`; 89 | close RES; 90 | close OUT; 91 | print "\n"; 92 | `rm tmp?`; 93 | # End of added part 94 | $tests_failed++; 95 | } 96 | } 97 | 98 | print "\n\n"; 99 | print "$tests_passed passed; $tests_failed failed.\n"; 100 | 101 | my $time_end = new Benchmark; 102 | my $time_diff = timediff($time_end, $time_start); 103 | print "Benchmark: ", timestr($time_diff), "\n"; 104 | 105 | if ($tests_failed ne 0) { 106 | exit 1; 107 | } else { 108 | exit 0; 109 | } 110 | 111 | __END__ 112 | 113 | =pod 114 | 115 | =head1 NAME 116 | 117 | B 118 | 119 | 120 | =head1 SYNOPSIS 121 | 122 | B [ B<--options> ] [ I ... ] 123 | 124 | 125 | =head1 DESCRIPTION 126 | 127 | 128 | =head1 OPTIONS 129 | 130 | Use "--" to end switch parsing. For example, to open a file named "-z", use: 131 | 132 | MarkdownTest.pl -- -z 133 | 134 | =over 4 135 | 136 | =item B<--script> 137 | 138 | Specify the path to the Markdown script to test. Defaults to 139 | "./Markdown.pl". Example: 140 | 141 | ./MarkdownTest.pl --script ./PHP-Markdown/php-markdown 142 | 143 | =item B<--testdir> 144 | 145 | Specify the path to a directory containing test data. Defaults to "Tests". 146 | 147 | =item B<--tidy> 148 | 149 | Flag to turn on using the command line 'tidy' tool to normalize HTML 150 | output before comparing script output to the expected test result. 151 | Assumes that the 'tidy' command is available in your PATH. Defaults to 152 | off. 153 | 154 | =back 155 | 156 | 157 | 158 | =head1 BUGS 159 | 160 | 161 | 162 | =head1 VERSION HISTORY 163 | 164 | 1.0 Mon 13 Dec 2004-2005 165 | 166 | 1.0.1 Mon 19 Sep 2005 167 | 168 | + Better handling of case when foo.text exists, but foo.html doesn't. 169 | It now prints a message and moves on, rather than dying. 170 | 171 | 172 | =head1 COPYRIGHT AND LICENSE 173 | 174 | Copyright (c) 2004-2005 John Gruber 175 | 176 | All rights reserved. 177 | 178 | This is free software; you may redistribute it and/or modify it under 179 | the same terms as Perl itself. 180 | 181 | =cut 182 | -------------------------------------------------------------------------------- /ext/redcarpet/buffer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2008, Natacha Porté 3 | * Copyright (c) 2015, Vicent Marti 4 | * 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: 11 | * 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. 22 | */ 23 | 24 | #define BUFFER_MAX_ALLOC_SIZE (1024 * 1024 * 16) //16mb 25 | 26 | #include "buffer.h" 27 | 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | /* MSVC compat */ 34 | #if defined(_MSC_VER) 35 | # define _buf_vsnprintf _vsnprintf 36 | #else 37 | # define _buf_vsnprintf vsnprintf 38 | #endif 39 | 40 | int 41 | bufprefix(const struct buf *buf, const char *prefix) 42 | { 43 | size_t i; 44 | assert(buf && buf->unit); 45 | 46 | for (i = 0; i < buf->size; ++i) { 47 | if (prefix[i] == 0) 48 | return 0; 49 | 50 | if (buf->data[i] != prefix[i]) 51 | return buf->data[i] - prefix[i]; 52 | } 53 | 54 | return 0; 55 | } 56 | 57 | /* bufgrow: increasing the allocated size to the given value */ 58 | int 59 | bufgrow(struct buf *buf, size_t neosz) 60 | { 61 | size_t neoasz; 62 | void *neodata; 63 | 64 | assert(buf && buf->unit); 65 | 66 | if (neosz > BUFFER_MAX_ALLOC_SIZE) 67 | return BUF_ENOMEM; 68 | 69 | if (buf->asize >= neosz) 70 | return BUF_OK; 71 | 72 | neoasz = buf->asize + buf->unit; 73 | while (neoasz < neosz) 74 | neoasz += buf->unit; 75 | 76 | neodata = realloc(buf->data, neoasz); 77 | if (!neodata) 78 | return BUF_ENOMEM; 79 | 80 | buf->data = neodata; 81 | buf->asize = neoasz; 82 | return BUF_OK; 83 | } 84 | 85 | 86 | /* bufnew: allocation of a new buffer */ 87 | struct buf * 88 | bufnew(size_t unit) 89 | { 90 | struct buf *ret; 91 | ret = malloc(sizeof (struct buf)); 92 | 93 | if (ret) { 94 | ret->data = 0; 95 | ret->size = ret->asize = 0; 96 | ret->unit = unit; 97 | } 98 | return ret; 99 | } 100 | 101 | /* bufnullterm: NULL-termination of the string array */ 102 | const char * 103 | bufcstr(const struct buf *buf) 104 | { 105 | assert(buf && buf->unit); 106 | 107 | if (buf->size < buf->asize && buf->data[buf->size] == 0) 108 | return (char *)buf->data; 109 | 110 | if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1) == BUF_OK) { 111 | buf->data[buf->size] = 0; 112 | return (char *)buf->data; 113 | } 114 | 115 | return NULL; 116 | } 117 | 118 | /* bufprintf: formatted printing to a buffer */ 119 | void 120 | bufprintf(struct buf *buf, const char *fmt, ...) 121 | { 122 | va_list ap; 123 | int n; 124 | 125 | assert(buf && buf->unit); 126 | 127 | if (buf->size >= buf->asize && bufgrow(buf, buf->size + 1) < BUF_OK) 128 | return; 129 | 130 | va_start(ap, fmt); 131 | n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap); 132 | va_end(ap); 133 | 134 | if (n < 0) { 135 | #ifdef _MSC_VER 136 | va_start(ap, fmt); 137 | n = _vscprintf(fmt, ap); 138 | va_end(ap); 139 | #else 140 | return; 141 | #endif 142 | } 143 | 144 | if ((size_t)n >= buf->asize - buf->size) { 145 | if (bufgrow(buf, buf->size + n + 1) < BUF_OK) 146 | return; 147 | 148 | va_start(ap, fmt); 149 | n = _buf_vsnprintf((char *)buf->data + buf->size, buf->asize - buf->size, fmt, ap); 150 | va_end(ap); 151 | } 152 | 153 | if (n < 0) 154 | return; 155 | 156 | buf->size += n; 157 | } 158 | 159 | /* bufput: appends raw data to a buffer */ 160 | void 161 | bufput(struct buf *buf, const void *data, size_t len) 162 | { 163 | assert(buf && buf->unit); 164 | 165 | if (buf->size + len > buf->asize && bufgrow(buf, buf->size + len) < BUF_OK) 166 | return; 167 | 168 | memcpy(buf->data + buf->size, data, len); 169 | buf->size += len; 170 | } 171 | 172 | /* bufputs: appends a NUL-terminated string to a buffer */ 173 | void 174 | bufputs(struct buf *buf, const char *str) 175 | { 176 | bufput(buf, str, strlen(str)); 177 | } 178 | 179 | 180 | /* bufputc: appends a single uint8_t to a buffer */ 181 | void 182 | bufputc(struct buf *buf, int c) 183 | { 184 | assert(buf && buf->unit); 185 | 186 | if (buf->size + 1 > buf->asize && bufgrow(buf, buf->size + 1) < BUF_OK) 187 | return; 188 | 189 | buf->data[buf->size] = c; 190 | buf->size += 1; 191 | } 192 | 193 | /* bufrelease: decrease the reference count and free the buffer if needed */ 194 | void 195 | bufrelease(struct buf *buf) 196 | { 197 | if (!buf) 198 | return; 199 | 200 | free(buf->data); 201 | free(buf); 202 | } 203 | -------------------------------------------------------------------------------- /ext/redcarpet/rc_markdown.c: -------------------------------------------------------------------------------- 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 | 23 | #include "redcarpet.h" 24 | 25 | VALUE rb_mRedcarpet; 26 | VALUE rb_cMarkdown; 27 | 28 | extern VALUE rb_cRenderBase; 29 | 30 | static void rb_redcarpet_md_flags(VALUE hash, unsigned int *enabled_extensions_p) 31 | { 32 | unsigned int extensions = 0; 33 | 34 | Check_Type(hash, T_HASH); 35 | 36 | /** 37 | * Markdown extensions -- all disabled by default 38 | */ 39 | if (rb_hash_lookup(hash, CSTR2SYM("no_intra_emphasis")) == Qtrue) 40 | extensions |= MKDEXT_NO_INTRA_EMPHASIS; 41 | 42 | if (rb_hash_lookup(hash, CSTR2SYM("tables")) == Qtrue) 43 | extensions |= MKDEXT_TABLES; 44 | 45 | if (rb_hash_lookup(hash, CSTR2SYM("fenced_code_blocks")) == Qtrue) 46 | extensions |= MKDEXT_FENCED_CODE; 47 | 48 | if (rb_hash_lookup(hash, CSTR2SYM("disable_indented_code_blocks")) == Qtrue) 49 | extensions |= MKDEXT_DISABLE_INDENTED_CODE; 50 | 51 | if (rb_hash_lookup(hash, CSTR2SYM("autolink")) == Qtrue) 52 | extensions |= MKDEXT_AUTOLINK; 53 | 54 | if (rb_hash_lookup(hash, CSTR2SYM("strikethrough")) == Qtrue) 55 | extensions |= MKDEXT_STRIKETHROUGH; 56 | 57 | if (rb_hash_lookup(hash, CSTR2SYM("underline")) == Qtrue) 58 | extensions |= MKDEXT_UNDERLINE; 59 | 60 | if (rb_hash_lookup(hash, CSTR2SYM("highlight")) == Qtrue) 61 | extensions |= MKDEXT_HIGHLIGHT; 62 | 63 | if (rb_hash_lookup(hash, CSTR2SYM("quote")) == Qtrue) 64 | extensions |= MKDEXT_QUOTE; 65 | 66 | if (rb_hash_lookup(hash, CSTR2SYM("lax_spacing")) == Qtrue) 67 | extensions |= MKDEXT_LAX_SPACING; 68 | 69 | if (rb_hash_lookup(hash, CSTR2SYM("space_after_headers")) == Qtrue) 70 | extensions |= MKDEXT_SPACE_HEADERS; 71 | 72 | if (rb_hash_lookup(hash, CSTR2SYM("superscript")) == Qtrue) 73 | extensions |= MKDEXT_SUPERSCRIPT; 74 | 75 | if (rb_hash_lookup(hash, CSTR2SYM("footnotes")) == Qtrue) 76 | extensions |= MKDEXT_FOOTNOTES; 77 | 78 | *enabled_extensions_p = extensions; 79 | } 80 | 81 | static void 82 | rb_redcarpet_md__free(void *markdown) 83 | { 84 | sd_markdown_free((struct sd_markdown *)markdown); 85 | } 86 | 87 | static VALUE rb_redcarpet_md__new(int argc, VALUE *argv, VALUE klass) 88 | { 89 | VALUE rb_markdown, rb_rndr, hash; 90 | unsigned int extensions = 0; 91 | 92 | struct rb_redcarpet_rndr *rndr; 93 | struct sd_markdown *markdown; 94 | 95 | if (rb_scan_args(argc, argv, "11", &rb_rndr, &hash) == 2) 96 | rb_redcarpet_md_flags(hash, &extensions); 97 | 98 | if (rb_obj_is_kind_of(rb_rndr, rb_cClass)) 99 | rb_rndr = rb_funcall(rb_rndr, rb_intern("new"), 0); 100 | 101 | if (!rb_obj_is_kind_of(rb_rndr, rb_cRenderBase)) 102 | rb_raise(rb_eTypeError, "Invalid Renderer instance given"); 103 | 104 | Data_Get_Struct(rb_rndr, struct rb_redcarpet_rndr, rndr); 105 | 106 | markdown = sd_markdown_new(extensions, 16, &rndr->callbacks, &rndr->options); 107 | if (!markdown) 108 | rb_raise(rb_eRuntimeError, "Failed to create new Renderer class"); 109 | 110 | rb_markdown = Data_Wrap_Struct(klass, NULL, rb_redcarpet_md__free, markdown); 111 | rb_iv_set(rb_markdown, "@renderer", rb_rndr); 112 | 113 | return rb_markdown; 114 | } 115 | 116 | static VALUE rb_redcarpet_md_render(VALUE self, VALUE text) 117 | { 118 | VALUE rb_rndr; 119 | struct buf *output_buf; 120 | struct sd_markdown *markdown; 121 | 122 | Check_Type(text, T_STRING); 123 | 124 | rb_rndr = rb_iv_get(self, "@renderer"); 125 | Data_Get_Struct(self, struct sd_markdown, markdown); 126 | 127 | if (rb_respond_to(rb_rndr, rb_intern("preprocess"))) 128 | text = rb_funcall(rb_rndr, rb_intern("preprocess"), 1, text); 129 | if (NIL_P(text)) 130 | return Qnil; 131 | 132 | struct rb_redcarpet_rndr *renderer; 133 | Data_Get_Struct(rb_rndr, struct rb_redcarpet_rndr, renderer); 134 | renderer->options.active_enc = rb_enc_get(text); 135 | 136 | /* initialize buffers */ 137 | output_buf = bufnew(128); 138 | 139 | /* render the magic */ 140 | sd_markdown_render( 141 | output_buf, 142 | (const uint8_t*)RSTRING_PTR(text), 143 | RSTRING_LEN(text), 144 | markdown); 145 | 146 | /* build the Ruby string */ 147 | text = rb_enc_str_new((const char*)output_buf->data, output_buf->size, rb_enc_get(text)); 148 | 149 | bufrelease(output_buf); 150 | 151 | if (rb_respond_to(rb_rndr, rb_intern("postprocess"))) 152 | text = rb_funcall(rb_rndr, rb_intern("postprocess"), 1, text); 153 | 154 | return text; 155 | } 156 | 157 | __attribute__((visibility("default"))) 158 | void Init_redcarpet() 159 | { 160 | rb_mRedcarpet = rb_define_module("Redcarpet"); 161 | 162 | rb_cMarkdown = rb_define_class_under(rb_mRedcarpet, "Markdown", rb_cObject); 163 | rb_define_singleton_method(rb_cMarkdown, "new", rb_redcarpet_md__new, -1); 164 | rb_define_method(rb_cMarkdown, "render", rb_redcarpet_md_render, 1); 165 | 166 | Init_redcarpet_rndr(); 167 | } 168 | 169 | -------------------------------------------------------------------------------- /ext/redcarpet/markdown.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009, Natacha Porté 3 | * Copyright (c) 2015, Vicent Marti 4 | * 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: 11 | * 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. 22 | */ 23 | 24 | #ifndef MARKDOWN_H__ 25 | #define MARKDOWN_H__ 26 | 27 | #include "buffer.h" 28 | #include "autolink.h" 29 | 30 | #ifdef __cplusplus 31 | extern "C" { 32 | #endif 33 | 34 | /******************** 35 | * TYPE DEFINITIONS * 36 | ********************/ 37 | 38 | /* mkd_autolink - type of autolink */ 39 | enum mkd_autolink { 40 | MKDA_NOT_AUTOLINK, /* used internally when it is not an autolink*/ 41 | MKDA_NORMAL, /* normal http/http/ftp/mailto/etc link */ 42 | MKDA_EMAIL, /* e-mail link without explit mailto: */ 43 | }; 44 | 45 | enum mkd_tableflags { 46 | MKD_TABLE_ALIGN_L = 1, 47 | MKD_TABLE_ALIGN_R = 2, 48 | MKD_TABLE_ALIGN_CENTER = 3, 49 | MKD_TABLE_ALIGNMASK = 3, 50 | MKD_TABLE_HEADER = 4 51 | }; 52 | 53 | enum mkd_extensions { 54 | MKDEXT_NO_INTRA_EMPHASIS = (1 << 0), 55 | MKDEXT_TABLES = (1 << 1), 56 | MKDEXT_FENCED_CODE = (1 << 2), 57 | MKDEXT_AUTOLINK = (1 << 3), 58 | MKDEXT_STRIKETHROUGH = (1 << 4), 59 | MKDEXT_UNDERLINE = (1 << 5), 60 | MKDEXT_SPACE_HEADERS = (1 << 6), 61 | MKDEXT_SUPERSCRIPT = (1 << 7), 62 | MKDEXT_LAX_SPACING = (1 << 8), 63 | MKDEXT_DISABLE_INDENTED_CODE = (1 << 9), 64 | MKDEXT_HIGHLIGHT = (1 << 10), 65 | MKDEXT_FOOTNOTES = (1 << 11), 66 | MKDEXT_QUOTE = (1 << 12) 67 | }; 68 | 69 | /* sd_callbacks - functions for rendering parsed data */ 70 | struct sd_callbacks { 71 | /* block level callbacks - NULL skips the block */ 72 | void (*blockcode)(struct buf *ob, const struct buf *text, const struct buf *lang, void *opaque); 73 | void (*blockquote)(struct buf *ob, const struct buf *text, void *opaque); 74 | void (*blockhtml)(struct buf *ob,const struct buf *text, void *opaque); 75 | void (*header)(struct buf *ob, const struct buf *text, int level, void *opaque); 76 | void (*hrule)(struct buf *ob, void *opaque); 77 | void (*list)(struct buf *ob, const struct buf *text, int flags, void *opaque); 78 | void (*listitem)(struct buf *ob, const struct buf *text, int flags, void *opaque); 79 | void (*paragraph)(struct buf *ob, const struct buf *text, void *opaque); 80 | void (*table)(struct buf *ob, const struct buf *header, const struct buf *body, void *opaque); 81 | void (*table_row)(struct buf *ob, const struct buf *text, void *opaque); 82 | void (*table_cell)(struct buf *ob, const struct buf *text, int flags, void *opaque); 83 | void (*footnotes)(struct buf *ob, const struct buf *text, void *opaque); 84 | void (*footnote_def)(struct buf *ob, const struct buf *text, unsigned int num, void *opaque); 85 | 86 | /* span level callbacks - NULL or return 0 prints the span verbatim */ 87 | int (*autolink)(struct buf *ob, const struct buf *link, enum mkd_autolink type, void *opaque); 88 | int (*codespan)(struct buf *ob, const struct buf *text, void *opaque); 89 | int (*double_emphasis)(struct buf *ob, const struct buf *text, void *opaque); 90 | int (*emphasis)(struct buf *ob, const struct buf *text, void *opaque); 91 | int (*underline)(struct buf *ob, const struct buf *text, void *opaque); 92 | int (*highlight)(struct buf *ob, const struct buf *text, void *opaque); 93 | int (*quote)(struct buf *ob, const struct buf *text, void *opaque); 94 | int (*image)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *alt, void *opaque); 95 | int (*linebreak)(struct buf *ob, void *opaque); 96 | int (*link)(struct buf *ob, const struct buf *link, const struct buf *title, const struct buf *content, void *opaque); 97 | int (*raw_html_tag)(struct buf *ob, const struct buf *tag, void *opaque); 98 | int (*triple_emphasis)(struct buf *ob, const struct buf *text, void *opaque); 99 | int (*strikethrough)(struct buf *ob, const struct buf *text, void *opaque); 100 | int (*superscript)(struct buf *ob, const struct buf *text, void *opaque); 101 | int (*footnote_ref)(struct buf *ob, unsigned int num, void *opaque); 102 | 103 | /* low level callbacks - NULL copies input directly into the output */ 104 | void (*entity)(struct buf *ob, const struct buf *entity, void *opaque); 105 | void (*normal_text)(struct buf *ob, const struct buf *text, void *opaque); 106 | 107 | /* header and footer */ 108 | void (*doc_header)(struct buf *ob, void *opaque); 109 | void (*doc_footer)(struct buf *ob, void *opaque); 110 | }; 111 | 112 | struct sd_markdown; 113 | 114 | /********* 115 | * FLAGS * 116 | *********/ 117 | 118 | /* list/listitem flags */ 119 | #define MKD_LIST_ORDERED 1 120 | #define MKD_LI_BLOCK 2 /*
  • containing block data */ 121 | 122 | /********************** 123 | * EXPORTED FUNCTIONS * 124 | **********************/ 125 | 126 | extern struct sd_markdown * 127 | sd_markdown_new( 128 | unsigned int extensions, 129 | size_t max_nesting, 130 | const struct sd_callbacks *callbacks, 131 | void *opaque); 132 | 133 | extern void 134 | sd_markdown_render(struct buf *ob, const uint8_t *document, size_t doc_size, struct sd_markdown *md); 135 | 136 | extern void 137 | sd_markdown_free(struct sd_markdown *md); 138 | 139 | #ifdef __cplusplus 140 | } 141 | #endif 142 | 143 | #endif 144 | -------------------------------------------------------------------------------- /test/html_render_test.rb: -------------------------------------------------------------------------------- 1 | # coding: UTF-8 2 | require 'test_helper' 3 | 4 | class HTMLRenderTest < Redcarpet::TestCase 5 | def setup 6 | @renderer = Redcarpet::Render::HTML 7 | end 8 | 9 | # Hint: overrides filter_html, no_images and no_links 10 | def test_that_escape_html_works 11 | source = <NO 13 | 14 | 15 | 16 | 17 | EOS 18 | expected = <Through <em>NO</em> <script>DOUBLE NO</script>

    20 | 21 |

    <script>BAD</script>

    22 | 23 |

    <img src="/favicon.ico" />

    24 | EOE 25 | 26 | assert_equal expected, render(source, with: [:escape_html]) 27 | end 28 | 29 | def test_that_filter_html_works 30 | markdown = 'Through NO ' 31 | output = render(markdown, with: [:filter_html]) 32 | 33 | assert_equal "

    Through NO DOUBLE NO

    \n", output 34 | end 35 | 36 | def test_filter_html_doesnt_break_two_space_hard_break 37 | markdown = "Lorem, \nipsum\n" 38 | output = render(markdown, with: [:filter_html]) 39 | 40 | assert_equal "

    Lorem,
    \nipsum

    \n", output 41 | end 42 | 43 | def test_that_no_image_flag_works 44 | markdown = %(![dust mite](http://dust.mite/image.png) ) 45 | output = render(markdown, with: [:no_images]) 46 | 47 | assert_no_match %r{links) 52 | output = render(markdown, with: [:no_links]) 53 | 54 | assert_no_match %r{[IRC](irc://chat.freenode.org/#freenode)

    \n", output 62 | end 63 | 64 | def test_that_hard_wrap_works 65 | markdown = <}, output 75 | end 76 | 77 | def test_that_link_attributes_work 78 | rndr = Redcarpet::Render::HTML.new(:link_attributes => {:rel => 'blank'}) 79 | md = Redcarpet::Markdown.new(rndr) 80 | assert md.render('This is a [simple](http://test.com) test.').include?('rel="blank"') 81 | end 82 | 83 | def test_that_link_works_with_quotes 84 | markdown = %([This'link"is](http://example.net/)) 85 | expected = %(

    This'link"is

    \n) 86 | 87 | assert_equal expected, render(markdown) 88 | assert_equal expected, render(markdown, with: [:escape_html]) 89 | end 90 | 91 | def test_that_code_emphasis_work 92 | markdown = <<-MD 93 | This should be **`a bold codespan`** 94 | However, this should be *`an emphasised codespan`* 95 | 96 | * **`ABC`** or **`DEF`** 97 | * Foo bar 98 | MD 99 | 100 | html = <This should be a bold codespan 102 | However, this should be an emphasised codespan

    103 | 104 |
      105 |
    • ABC or DEF
    • 106 |
    • Foo bar
    • 107 |
    108 | HTML 109 | 110 | assert_equal html, render(markdown) 111 | end 112 | 113 | def test_that_parenthesis_are_handled_into_links 114 | markdown = %(The [bash man page](man:bash(1))!) 115 | expected = %(

    The bash man page!

    \n) 116 | 117 | assert_equal expected, render(markdown) 118 | end 119 | 120 | def test_autolinking_works_as_expected 121 | markdown = "Uri ftp://user:pass@example.com/. Email foo@bar.com and link http://bar.com" 122 | output = render(markdown, with: [:autolink]) 123 | 124 | assert output.include? 'ftp://user:pass@example.com/' 125 | assert output.include? 'mailto:foo@bar.com' 126 | assert output.include? '' 127 | end 128 | 129 | def test_that_footnotes_work 130 | markdown = <<-MD 131 | This is a footnote.[^1] 132 | 133 | [^1]: It provides additional information. 134 | MD 135 | 136 | html = <This is a footnote.1

    138 | 139 |
    140 |
    141 |
      142 | 143 |
    1. 144 |

      It provides additional information. 

      145 |
    2. 146 | 147 |
    148 |
    149 | HTML 150 | 151 | output = render(markdown, with: [:footnotes]) 152 | assert_equal html, output 153 | end 154 | 155 | def test_footnotes_enabled_but_missing_marker 156 | markdown = <Some text without a marker

    163 | 164 |

    [^1] And a trailing definition

    165 | HTML 166 | 167 | output = render(markdown, with: [:footnotes]) 168 | assert_equal html, output 169 | end 170 | 171 | def test_footnotes_enabled_but_missing_definition 172 | markdown = "Some text with a marker[^1] but no definition." 173 | expected = "

    Some text with a marker[^1] but no definition.

    \n" 174 | 175 | output = render(markdown, with: [:footnotes]) 176 | assert_equal expected, output 177 | end 178 | 179 | def test_autolink_short_domains 180 | markdown = "Example of uri ftp://auto/short/domains. Email auto@l.n and link http://a/u/t/o/s/h/o/r/t" 181 | output = render(markdown, with: [:autolink]) 182 | 183 | assert output.include? 'ftp://auto/short/domains' 184 | assert output.include? 'mailto:auto@l.n' 185 | assert output.include? 'http://a/u/t/o/s/h/o/r/t' 186 | end 187 | 188 | def test_that_prettify_works 189 | markdown = "\tclass Foo\nend" 190 | output = render(markdown, with: [:prettify]) 191 | 192 | assert output.include?("
    ")
    193 | 
    194 |     markdown = "`class`"
    195 |     output   = render(markdown, with: [:prettify])
    196 | 
    197 |     assert output.include?("")
    198 |   end
    199 | 
    200 |   def test_prettify_with_fenced_code_blocks
    201 |     markdown = "~~~ruby\ncode\n~~~"
    202 |     output   = render(markdown, with: [:fenced_code_blocks, :prettify])
    203 | 
    204 |     assert output.include?("")
    205 |   end
    206 | 
    207 |   def test_safe_links_only_with_anchors
    208 |     markdown = "An [anchor link](#anchor) on a page."
    209 |     output   = render(markdown, with: [:safe_links_only])
    210 | 
    211 |     assert_match %r{anchor link}, output
    212 |   end
    213 | 
    214 |   def test_autolink_with_link_attributes
    215 |     options = { autolink: true, link_attributes: {rel: "nofollow"} }
    216 |     output  = render("https://github.com/", with: options)
    217 | 
    218 |     assert_match %r{rel="nofollow"}, output
    219 |   end
    220 | 
    221 |   def test_image_unsafe_src_with_safe_links_only
    222 |     markdown = "![foo](javascript:while(1);)"
    223 |     output   = render(markdown, with: [:safe_links_only])
    224 | 
    225 |     assert_not_match %r{img src}, output
    226 |   end
    227 | 
    228 |   def test_no_styles_option_inside_a_paragraph
    229 |     markdown = "Hello  !"
    230 |     output   = render(markdown, with: [:no_styles])
    231 | 
    232 |     assert_no_match %r{"
    237 |     output   = render(markdown, with: [:no_styles])
    238 | 
    239 |     assert_no_match %r{