├── .gitignore ├── .travis.yml ├── Data ├── Amps and angle encoding.html ├── Amps and angle encoding.text ├── Auto links.html ├── Auto links.text ├── Backslash escapes.html ├── Backslash escapes.text ├── Blockquotes with code blocks.html ├── Blockquotes with code blocks.text ├── Hard-wrapped paragraphs with list-like lines.html ├── Hard-wrapped paragraphs with list-like lines.text ├── Horizontal rules.html ├── Horizontal rules.text ├── Inline HTML (Advanced).html ├── Inline HTML (Advanced).text ├── Inline HTML (Simple).html ├── Inline HTML (Simple).text ├── Inline HTML comments.html ├── Inline HTML comments.text ├── Links, inline style.html ├── Links, inline style.text ├── Links, reference style.html ├── Links, reference style.text ├── Literal quotes in titles.html ├── Literal quotes in titles.text ├── Markdown Documentation - Basics.html ├── Markdown Documentation - Basics.text ├── Markdown Documentation - Syntax.html ├── Markdown Documentation - Syntax.text ├── Nested blockquotes.html ├── Nested blockquotes.text ├── Ordered and unordered lists.html ├── Ordered and unordered lists.text ├── Strong and em together.html ├── Strong and em together.text ├── Tabs.html ├── Tabs.text ├── Tidyness.html └── Tidyness.text ├── Package.swift ├── README.md ├── Sources ├── SmarkDown │ ├── RegularExpressions.swift │ ├── SmarkDown.swift │ ├── SpecialCharacters.swift │ └── Strings.swift └── markdown │ └── main.swift └── Tests ├── LinuxMain.swift └── SmarkDown └── Test Sets ├── DetabTests.swift ├── HashHTMLTests.swift ├── RegexTests.swift └── StandardMarkDownTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .build 2 | Packages -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | before_install: 4 | - wget -q -O - https://swift.org/keys/all-keys.asc | gpg --import - 5 | - wget https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-03-01-a/swift-DEVELOPMENT-SNAPSHOT-2016-03-01-a-ubuntu14.04.tar.gz 6 | - tar xzf swift-DEVELOPMENT-SNAPSHOT-2016-03-01-a-ubuntu14.04.tar.gz 7 | - export PATH=${PWD}/swift-DEVELOPMENT-SNAPSHOT-2016-03-01-a-ubuntu14.04/usr/bin:"${PATH}" 8 | script: 9 | - swift build 10 | - swift test 11 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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" -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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: -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/Inline HTML comments.html: -------------------------------------------------------------------------------- 1 |

Paragraph one.

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

Paragraph two.

10 | 11 | 12 | 13 |

The end.

14 | -------------------------------------------------------------------------------- /Data/Inline HTML comments.text: -------------------------------------------------------------------------------- 1 | Paragraph one. 2 | 3 | 4 | 5 | 8 | 9 | Paragraph two. 10 | 11 | 12 | 13 | The end. 14 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/Literal quotes in titles.html: -------------------------------------------------------------------------------- 1 |

Foo bar.

2 | 3 |

Foo bar.

4 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/Markdown Documentation - Basics.html: -------------------------------------------------------------------------------- 1 |

Markdown: Basics

2 | 3 | 10 | 11 |

Getting the Gist of Markdown's Formatting Syntax

12 | 13 |

This page offers a brief overview of what it's like to use Markdown. 14 | The syntax page provides complete, detailed documentation for 15 | every feature, but Markdown should be very easy to pick up simply by 16 | looking at a few examples of it in action. The examples on this page 17 | are written in a before/after style, showing example syntax and the 18 | HTML output produced by Markdown.

19 | 20 |

It's also helpful to simply try Markdown out; the Dingus is a 21 | web application that allows you type your own Markdown-formatted text 22 | and translate it to XHTML.

23 | 24 |

Note: This document is itself written using Markdown; you 25 | can see the source for it by adding '.text' to the URL.

26 | 27 |

Paragraphs, Headers, Blockquotes

28 | 29 |

A paragraph is simply one or more consecutive lines of text, separated 30 | by one or more blank lines. (A blank line is any line that looks like a 31 | blank line -- a line containing nothing spaces or tabs is considered 32 | blank.) Normal paragraphs should not be intended with spaces or tabs.

33 | 34 |

Markdown offers two styles of headers: Setext and atx. 35 | Setext-style headers for <h1> and <h2> are created by 36 | "underlining" with equal signs (=) and hyphens (-), respectively. 37 | To create an atx-style header, you put 1-6 hash marks (#) at the 38 | beginning of the line -- the number of hashes equals the resulting 39 | HTML header level.

40 | 41 |

Blockquotes are indicated using email-style '>' angle brackets.

42 | 43 |

Markdown:

44 | 45 |
A First Level Header
 46 | ====================
 47 | 
 48 | A Second Level Header
 49 | ---------------------
 50 | 
 51 | Now is the time for all good men to come to
 52 | the aid of their country. This is just a
 53 | regular paragraph.
 54 | 
 55 | The quick brown fox jumped over the lazy
 56 | dog's back.
 57 | 
 58 | ### Header 3
 59 | 
 60 | > This is a blockquote.
 61 | > 
 62 | > This is the second paragraph in the blockquote.
 63 | >
 64 | > ## This is an H2 in a blockquote
 65 | 
66 | 67 |

Output:

68 | 69 |
<h1>A First Level Header</h1>
 70 | 
 71 | <h2>A Second Level Header</h2>
 72 | 
 73 | <p>Now is the time for all good men to come to
 74 | the aid of their country. This is just a
 75 | regular paragraph.</p>
 76 | 
 77 | <p>The quick brown fox jumped over the lazy
 78 | dog's back.</p>
 79 | 
 80 | <h3>Header 3</h3>
 81 | 
 82 | <blockquote>
 83 |     <p>This is a blockquote.</p>
 84 | 
 85 |     <p>This is the second paragraph in the blockquote.</p>
 86 | 
 87 |     <h2>This is an H2 in a blockquote</h2>
 88 | </blockquote>
 89 | 
90 | 91 |

Phrase Emphasis

92 | 93 |

Markdown uses asterisks and underscores to indicate spans of emphasis.

94 | 95 |

Markdown:

96 | 97 |
Some of these words *are emphasized*.
 98 | Some of these words _are emphasized also_.
 99 | 
100 | Use two asterisks for **strong emphasis**.
101 | Or, if you prefer, __use two underscores instead__.
102 | 
103 | 104 |

Output:

105 | 106 |
<p>Some of these words <em>are emphasized</em>.
107 | Some of these words <em>are emphasized also</em>.</p>
108 | 
109 | <p>Use two asterisks for <strong>strong emphasis</strong>.
110 | Or, if you prefer, <strong>use two underscores instead</strong>.</p>
111 | 
112 | 113 |

Lists

114 | 115 |

Unordered (bulleted) lists use asterisks, pluses, and hyphens (*, 116 | +, and -) as list markers. These three markers are 117 | interchangable; this:

118 | 119 |
*   Candy.
120 | *   Gum.
121 | *   Booze.
122 | 
123 | 124 |

this:

125 | 126 |
+   Candy.
127 | +   Gum.
128 | +   Booze.
129 | 
130 | 131 |

and this:

132 | 133 |
-   Candy.
134 | -   Gum.
135 | -   Booze.
136 | 
137 | 138 |

all produce the same output:

139 | 140 |
<ul>
141 | <li>Candy.</li>
142 | <li>Gum.</li>
143 | <li>Booze.</li>
144 | </ul>
145 | 
146 | 147 |

Ordered (numbered) lists use regular numbers, followed by periods, as 148 | list markers:

149 | 150 |
1.  Red
151 | 2.  Green
152 | 3.  Blue
153 | 
154 | 155 |

Output:

156 | 157 |
<ol>
158 | <li>Red</li>
159 | <li>Green</li>
160 | <li>Blue</li>
161 | </ol>
162 | 
163 | 164 |

If you put blank lines between items, you'll get <p> tags for the 165 | list item text. You can create multi-paragraph list items by indenting 166 | the paragraphs by 4 spaces or 1 tab:

167 | 168 |
*   A list item.
169 | 
170 |     With multiple paragraphs.
171 | 
172 | *   Another item in the list.
173 | 
174 | 175 |

Output:

176 | 177 |
<ul>
178 | <li><p>A list item.</p>
179 | <p>With multiple paragraphs.</p></li>
180 | <li><p>Another item in the list.</p></li>
181 | </ul>
182 | 
183 | 184 |

Links

185 | 186 |

Markdown supports two styles for creating links: inline and 187 | reference. With both styles, you use square brackets to delimit the 188 | text you want to turn into a link.

189 | 190 |

Inline-style links use parentheses immediately after the link text. 191 | For example:

192 | 193 |
This is an [example link](http://example.com/).
194 | 
195 | 196 |

Output:

197 | 198 |
<p>This is an <a href="http://example.com/">
199 | example link</a>.</p>
200 | 
201 | 202 |

Optionally, you may include a title attribute in the parentheses:

203 | 204 |
This is an [example link](http://example.com/ "With a Title").
205 | 
206 | 207 |

Output:

208 | 209 |
<p>This is an <a href="http://example.com/" title="With a Title">
210 | example link</a>.</p>
211 | 
212 | 213 |

Reference-style links allow you to refer to your links by names, which 214 | you define elsewhere in your document:

215 | 216 |
I get 10 times more traffic from [Google][1] than from
217 | [Yahoo][2] or [MSN][3].
218 | 
219 | [1]: http://google.com/        "Google"
220 | [2]: http://search.yahoo.com/  "Yahoo Search"
221 | [3]: http://search.msn.com/    "MSN Search"
222 | 
223 | 224 |

Output:

225 | 226 |
<p>I get 10 times more traffic from <a href="http://google.com/"
227 | title="Google">Google</a> than from <a href="http://search.yahoo.com/"
228 | title="Yahoo Search">Yahoo</a> or <a href="http://search.msn.com/"
229 | title="MSN Search">MSN</a>.</p>
230 | 
231 | 232 |

The title attribute is optional. Link names may contain letters, 233 | numbers and spaces, but are not case sensitive:

234 | 235 |
I start my morning with a cup of coffee and
236 | [The New York Times][NY Times].
237 | 
238 | [ny times]: http://www.nytimes.com/
239 | 
240 | 241 |

Output:

242 | 243 |
<p>I start my morning with a cup of coffee and
244 | <a href="http://www.nytimes.com/">The New York Times</a>.</p>
245 | 
246 | 247 |

Images

248 | 249 |

Image syntax is very much like link syntax.

250 | 251 |

Inline (titles are optional):

252 | 253 |
![alt text](/path/to/img.jpg "Title")
254 | 
255 | 256 |

Reference-style:

257 | 258 |
![alt text][id]
259 | 
260 | [id]: /path/to/img.jpg "Title"
261 | 
262 | 263 |

Both of the above examples produce the same output:

264 | 265 |
<img src="/path/to/img.jpg" alt="alt text" title="Title" />
266 | 
267 | 268 |

Code

269 | 270 |

In a regular paragraph, you can create code span by wrapping text in 271 | backtick quotes. Any ampersands (&) and angle brackets (< or 272 | >) will automatically be translated into HTML entities. This makes 273 | it easy to use Markdown to write about HTML example code:

274 | 275 |
I strongly recommend against using any `<blink>` tags.
276 | 
277 | I wish SmartyPants used named entities like `&mdash;`
278 | instead of decimal-encoded entites like `&#8212;`.
279 | 
280 | 281 |

Output:

282 | 283 |
<p>I strongly recommend against using any
284 | <code>&lt;blink&gt;</code> tags.</p>
285 | 
286 | <p>I wish SmartyPants used named entities like
287 | <code>&amp;mdash;</code> instead of decimal-encoded
288 | entites like <code>&amp;#8212;</code>.</p>
289 | 
290 | 291 |

To specify an entire block of pre-formatted code, indent every line of 292 | the block by 4 spaces or 1 tab. Just like with code spans, &, <, 293 | and > characters will be escaped automatically.

294 | 295 |

Markdown:

296 | 297 |
If you want your page to validate under XHTML 1.0 Strict,
298 | you've got to put paragraph tags in your blockquotes:
299 | 
300 |     <blockquote>
301 |         <p>For example.</p>
302 |     </blockquote>
303 | 
304 | 305 |

Output:

306 | 307 |
<p>If you want your page to validate under XHTML 1.0 Strict,
308 | you've got to put paragraph tags in your blockquotes:</p>
309 | 
310 | <pre><code>&lt;blockquote&gt;
311 |     &lt;p&gt;For example.&lt;/p&gt;
312 | &lt;/blockquote&gt;
313 | </code></pre>
314 | 
315 | -------------------------------------------------------------------------------- /Data/Markdown Documentation - Basics.text: -------------------------------------------------------------------------------- 1 | Markdown: Basics 2 | ================ 3 | 4 | 11 | 12 | 13 | Getting the Gist of Markdown's Formatting Syntax 14 | ------------------------------------------------ 15 | 16 | This page offers a brief overview of what it's like to use Markdown. 17 | The [syntax page] [s] provides complete, detailed documentation for 18 | every feature, but Markdown should be very easy to pick up simply by 19 | looking at a few examples of it in action. The examples on this page 20 | are written in a before/after style, showing example syntax and the 21 | HTML output produced by Markdown. 22 | 23 | It's also helpful to simply try Markdown out; the [Dingus] [d] is a 24 | web application that allows you type your own Markdown-formatted text 25 | and translate it to XHTML. 26 | 27 | **Note:** This document is itself written using Markdown; you 28 | can [see the source for it by adding '.text' to the URL] [src]. 29 | 30 | [s]: /projects/markdown/syntax "Markdown Syntax" 31 | [d]: /projects/markdown/dingus "Markdown Dingus" 32 | [src]: /projects/markdown/basics.text 33 | 34 | 35 | ## Paragraphs, Headers, Blockquotes ## 36 | 37 | A paragraph is simply one or more consecutive lines of text, separated 38 | by one or more blank lines. (A blank line is any line that looks like a 39 | blank line -- a line containing nothing spaces or tabs is considered 40 | blank.) Normal paragraphs should not be intended with spaces or tabs. 41 | 42 | Markdown offers two styles of headers: *Setext* and *atx*. 43 | Setext-style headers for `

` and `

` are created by 44 | "underlining" with equal signs (`=`) and hyphens (`-`), respectively. 45 | To create an atx-style header, you put 1-6 hash marks (`#`) at the 46 | beginning of the line -- the number of hashes equals the resulting 47 | HTML header level. 48 | 49 | Blockquotes are indicated using email-style '`>`' angle brackets. 50 | 51 | Markdown: 52 | 53 | A First Level Header 54 | ==================== 55 | 56 | A Second Level Header 57 | --------------------- 58 | 59 | Now is the time for all good men to come to 60 | the aid of their country. This is just a 61 | regular paragraph. 62 | 63 | The quick brown fox jumped over the lazy 64 | dog's back. 65 | 66 | ### Header 3 67 | 68 | > This is a blockquote. 69 | > 70 | > This is the second paragraph in the blockquote. 71 | > 72 | > ## This is an H2 in a blockquote 73 | 74 | 75 | Output: 76 | 77 |

A First Level Header

78 | 79 |

A Second Level Header

80 | 81 |

Now is the time for all good men to come to 82 | the aid of their country. This is just a 83 | regular paragraph.

84 | 85 |

The quick brown fox jumped over the lazy 86 | dog's back.

87 | 88 |

Header 3

89 | 90 |
91 |

This is a blockquote.

92 | 93 |

This is the second paragraph in the blockquote.

94 | 95 |

This is an H2 in a blockquote

96 |
97 | 98 | 99 | 100 | ### Phrase Emphasis ### 101 | 102 | Markdown uses asterisks and underscores to indicate spans of emphasis. 103 | 104 | Markdown: 105 | 106 | Some of these words *are emphasized*. 107 | Some of these words _are emphasized also_. 108 | 109 | Use two asterisks for **strong emphasis**. 110 | Or, if you prefer, __use two underscores instead__. 111 | 112 | Output: 113 | 114 |

Some of these words are emphasized. 115 | Some of these words are emphasized also.

116 | 117 |

Use two asterisks for strong emphasis. 118 | Or, if you prefer, use two underscores instead.

119 | 120 | 121 | 122 | ## Lists ## 123 | 124 | Unordered (bulleted) lists use asterisks, pluses, and hyphens (`*`, 125 | `+`, and `-`) as list markers. These three markers are 126 | interchangable; this: 127 | 128 | * Candy. 129 | * Gum. 130 | * Booze. 131 | 132 | this: 133 | 134 | + Candy. 135 | + Gum. 136 | + Booze. 137 | 138 | and this: 139 | 140 | - Candy. 141 | - Gum. 142 | - Booze. 143 | 144 | all produce the same output: 145 | 146 |
    147 |
  • Candy.
  • 148 |
  • Gum.
  • 149 |
  • Booze.
  • 150 |
151 | 152 | Ordered (numbered) lists use regular numbers, followed by periods, as 153 | list markers: 154 | 155 | 1. Red 156 | 2. Green 157 | 3. Blue 158 | 159 | Output: 160 | 161 |
    162 |
  1. Red
  2. 163 |
  3. Green
  4. 164 |
  5. Blue
  6. 165 |
166 | 167 | If you put blank lines between items, you'll get `

` tags for the 168 | list item text. You can create multi-paragraph list items by indenting 169 | the paragraphs by 4 spaces or 1 tab: 170 | 171 | * A list item. 172 | 173 | With multiple paragraphs. 174 | 175 | * Another item in the list. 176 | 177 | Output: 178 | 179 |

    180 |
  • A list item.

    181 |

    With multiple paragraphs.

  • 182 |
  • Another item in the list.

  • 183 |
184 | 185 | 186 | 187 | ### Links ### 188 | 189 | Markdown supports two styles for creating links: *inline* and 190 | *reference*. With both styles, you use square brackets to delimit the 191 | text you want to turn into a link. 192 | 193 | Inline-style links use parentheses immediately after the link text. 194 | For example: 195 | 196 | This is an [example link](http://example.com/). 197 | 198 | Output: 199 | 200 |

This is an 201 | example link.

202 | 203 | Optionally, you may include a title attribute in the parentheses: 204 | 205 | This is an [example link](http://example.com/ "With a Title"). 206 | 207 | Output: 208 | 209 |

This is an 210 | example link.

211 | 212 | Reference-style links allow you to refer to your links by names, which 213 | you define elsewhere in your document: 214 | 215 | I get 10 times more traffic from [Google][1] than from 216 | [Yahoo][2] or [MSN][3]. 217 | 218 | [1]: http://google.com/ "Google" 219 | [2]: http://search.yahoo.com/ "Yahoo Search" 220 | [3]: http://search.msn.com/ "MSN Search" 221 | 222 | Output: 223 | 224 |

I get 10 times more traffic from Google than from Yahoo or MSN.

228 | 229 | The title attribute is optional. Link names may contain letters, 230 | numbers and spaces, but are *not* case sensitive: 231 | 232 | I start my morning with a cup of coffee and 233 | [The New York Times][NY Times]. 234 | 235 | [ny times]: http://www.nytimes.com/ 236 | 237 | Output: 238 | 239 |

I start my morning with a cup of coffee and 240 | The New York Times.

241 | 242 | 243 | ### Images ### 244 | 245 | Image syntax is very much like link syntax. 246 | 247 | Inline (titles are optional): 248 | 249 | ![alt text](/path/to/img.jpg "Title") 250 | 251 | Reference-style: 252 | 253 | ![alt text][id] 254 | 255 | [id]: /path/to/img.jpg "Title" 256 | 257 | Both of the above examples produce the same output: 258 | 259 | alt text 260 | 261 | 262 | 263 | ### Code ### 264 | 265 | In a regular paragraph, you can create code span by wrapping text in 266 | backtick quotes. Any ampersands (`&`) and angle brackets (`<` or 267 | `>`) will automatically be translated into HTML entities. This makes 268 | it easy to use Markdown to write about HTML example code: 269 | 270 | I strongly recommend against using any `` tags. 271 | 272 | I wish SmartyPants used named entities like `—` 273 | instead of decimal-encoded entites like `—`. 274 | 275 | Output: 276 | 277 |

I strongly recommend against using any 278 | <blink> tags.

279 | 280 |

I wish SmartyPants used named entities like 281 | &mdash; instead of decimal-encoded 282 | entites like &#8212;.

283 | 284 | 285 | To specify an entire block of pre-formatted code, indent every line of 286 | the block by 4 spaces or 1 tab. Just like with code spans, `&`, `<`, 287 | and `>` characters will be escaped automatically. 288 | 289 | Markdown: 290 | 291 | If you want your page to validate under XHTML 1.0 Strict, 292 | you've got to put paragraph tags in your blockquotes: 293 | 294 |
295 |

For example.

296 |
297 | 298 | Output: 299 | 300 |

If you want your page to validate under XHTML 1.0 Strict, 301 | you've got to put paragraph tags in your blockquotes:

302 | 303 |
<blockquote>
304 |         <p>For example.</p>
305 |     </blockquote>
306 |     
307 | -------------------------------------------------------------------------------- /Data/Markdown Documentation - Syntax.html: -------------------------------------------------------------------------------- 1 |

Markdown: Syntax

2 | 3 | 10 | 11 | 40 | 41 |

Note: This document is itself written using Markdown; you 42 | can see the source for it by adding '.text' to the URL.

43 | 44 |
45 | 46 |

Overview

47 | 48 |

Philosophy

49 | 50 |

Markdown is intended to be as easy-to-read and easy-to-write as is feasible.

51 | 52 |

Readability, however, is emphasized above all else. A Markdown-formatted 53 | document should be publishable as-is, as plain text, without looking 54 | like it's been marked up with tags or formatting instructions. While 55 | Markdown's syntax has been influenced by several existing text-to-HTML 56 | filters -- including Setext, atx, Textile, reStructuredText, 57 | Grutatext, and EtText -- the single biggest source of 58 | inspiration for Markdown's syntax is the format of plain text email.

59 | 60 |

To this end, Markdown's syntax is comprised entirely of punctuation 61 | characters, which punctuation characters have been carefully chosen so 62 | as to look like what they mean. E.g., asterisks around a word actually 63 | look like *emphasis*. Markdown lists look like, well, lists. Even 64 | blockquotes look like quoted passages of text, assuming you've ever 65 | used email.

66 | 67 |

Inline HTML

68 | 69 |

Markdown's syntax is intended for one purpose: to be used as a 70 | format for writing for the web.

71 | 72 |

Markdown is not a replacement for HTML, or even close to it. Its 73 | syntax is very small, corresponding only to a very small subset of 74 | HTML tags. The idea is not to create a syntax that makes it easier 75 | to insert HTML tags. In my opinion, HTML tags are already easy to 76 | insert. The idea for Markdown is to make it easy to read, write, and 77 | edit prose. HTML is a publishing format; Markdown is a writing 78 | format. Thus, Markdown's formatting syntax only addresses issues that 79 | can be conveyed in plain text.

80 | 81 |

For any markup that is not covered by Markdown's syntax, you simply 82 | use HTML itself. There's no need to preface it or delimit it to 83 | indicate that you're switching from Markdown to HTML; you just use 84 | the tags.

85 | 86 |

The only restrictions are that block-level HTML elements -- e.g. <div>, 87 | <table>, <pre>, <p>, etc. -- must be separated from surrounding 88 | content by blank lines, and the start and end tags of the block should 89 | not be indented with tabs or spaces. Markdown is smart enough not 90 | to add extra (unwanted) <p> tags around HTML block-level tags.

91 | 92 |

For example, to add an HTML table to a Markdown article:

93 | 94 |
This is a regular paragraph.
 95 | 
 96 | <table>
 97 |     <tr>
 98 |         <td>Foo</td>
 99 |     </tr>
100 | </table>
101 | 
102 | This is another regular paragraph.
103 | 
104 | 105 |

Note that Markdown formatting syntax is not processed within block-level 106 | HTML tags. E.g., you can't use Markdown-style *emphasis* inside an 107 | HTML block.

108 | 109 |

Span-level HTML tags -- e.g. <span>, <cite>, or <del> -- can be 110 | used anywhere in a Markdown paragraph, list item, or header. If you 111 | want, you can even use HTML tags instead of Markdown formatting; e.g. if 112 | you'd prefer to use HTML <a> or <img> tags instead of Markdown's 113 | link or image syntax, go right ahead.

114 | 115 |

Unlike block-level HTML tags, Markdown syntax is processed within 116 | span-level tags.

117 | 118 |

Automatic Escaping for Special Characters

119 | 120 |

In HTML, there are two characters that demand special treatment: < 121 | and &. Left angle brackets are used to start tags; ampersands are 122 | used to denote HTML entities. If you want to use them as literal 123 | characters, you must escape them as entities, e.g. &lt;, and 124 | &amp;.

125 | 126 |

Ampersands in particular are bedeviling for web writers. If you want to 127 | write about 'AT&T', you need to write 'AT&amp;T'. You even need to 128 | escape ampersands within URLs. Thus, if you want to link to:

129 | 130 |
http://images.google.com/images?num=30&q=larry+bird
131 | 
132 | 133 |

you need to encode the URL as:

134 | 135 |
http://images.google.com/images?num=30&amp;q=larry+bird
136 | 
137 | 138 |

in your anchor tag href attribute. Needless to say, this is easy to 139 | forget, and is probably the single most common source of HTML validation 140 | errors in otherwise well-marked-up web sites.

141 | 142 |

Markdown allows you to use these characters naturally, taking care of 143 | all the necessary escaping for you. If you use an ampersand as part of 144 | an HTML entity, it remains unchanged; otherwise it will be translated 145 | into &amp;.

146 | 147 |

So, if you want to include a copyright symbol in your article, you can write:

148 | 149 |
&copy;
150 | 
151 | 152 |

and Markdown will leave it alone. But if you write:

153 | 154 |
AT&T
155 | 
156 | 157 |

Markdown will translate it to:

158 | 159 |
AT&amp;T
160 | 
161 | 162 |

Similarly, because Markdown supports inline HTML, if you use 163 | angle brackets as delimiters for HTML tags, Markdown will treat them as 164 | such. But if you write:

165 | 166 |
4 < 5
167 | 
168 | 169 |

Markdown will translate it to:

170 | 171 |
4 &lt; 5
172 | 
173 | 174 |

However, inside Markdown code spans and blocks, angle brackets and 175 | ampersands are always encoded automatically. This makes it easy to use 176 | Markdown to write about HTML code. (As opposed to raw HTML, which is a 177 | terrible format for writing about HTML syntax, because every single < 178 | and & in your example code needs to be escaped.)

179 | 180 |
181 | 182 |

Block Elements

183 | 184 |

Paragraphs and Line Breaks

185 | 186 |

A paragraph is simply one or more consecutive lines of text, separated 187 | by one or more blank lines. (A blank line is any line that looks like a 188 | blank line -- a line containing nothing but spaces or tabs is considered 189 | blank.) Normal paragraphs should not be intended with spaces or tabs.

190 | 191 |

The implication of the "one or more consecutive lines of text" rule is 192 | that Markdown supports "hard-wrapped" text paragraphs. This differs 193 | significantly from most other text-to-HTML formatters (including Movable 194 | Type's "Convert Line Breaks" option) which translate every line break 195 | character in a paragraph into a <br /> tag.

196 | 197 |

When you do want to insert a <br /> break tag using Markdown, you 198 | end a line with two or more spaces, then type return.

199 | 200 |

Yes, this takes a tad more effort to create a <br />, but a simplistic 201 | "every line break is a <br />" rule wouldn't work for Markdown. 202 | Markdown's email-style blockquoting and multi-paragraph list items 203 | work best -- and look better -- when you format them with hard breaks.

204 | 205 | 206 | 207 |

Markdown supports two styles of headers, Setext and atx.

208 | 209 |

Setext-style headers are "underlined" using equal signs (for first-level 210 | headers) and dashes (for second-level headers). For example:

211 | 212 |
This is an H1
213 | =============
214 | 
215 | This is an H2
216 | -------------
217 | 
218 | 219 |

Any number of underlining ='s or -'s will work.

220 | 221 |

Atx-style headers use 1-6 hash characters at the start of the line, 222 | corresponding to header levels 1-6. For example:

223 | 224 |
# This is an H1
225 | 
226 | ## This is an H2
227 | 
228 | ###### This is an H6
229 | 
230 | 231 |

Optionally, you may "close" atx-style headers. This is purely 232 | cosmetic -- you can use this if you think it looks better. The 233 | closing hashes don't even need to match the number of hashes 234 | used to open the header. (The number of opening hashes 235 | determines the header level.) :

236 | 237 |
# This is an H1 #
238 | 
239 | ## This is an H2 ##
240 | 
241 | ### This is an H3 ######
242 | 
243 | 244 |

Blockquotes

245 | 246 |

Markdown uses email-style > characters for blockquoting. If you're 247 | familiar with quoting passages of text in an email message, then you 248 | know how to create a blockquote in Markdown. It looks best if you hard 249 | wrap the text and put a > before every line:

250 | 251 |
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
252 | > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
253 | > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
254 | > 
255 | > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
256 | > id sem consectetuer libero luctus adipiscing.
257 | 
258 | 259 |

Markdown allows you to be lazy and only put the > before the first 260 | line of a hard-wrapped paragraph:

261 | 262 |
> This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet,
263 | consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus.
264 | Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus.
265 | 
266 | > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse
267 | id sem consectetuer libero luctus adipiscing.
268 | 
269 | 270 |

Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by 271 | adding additional levels of >:

272 | 273 |
> This is the first level of quoting.
274 | >
275 | > > This is nested blockquote.
276 | >
277 | > Back to the first level.
278 | 
279 | 280 |

Blockquotes can contain other Markdown elements, including headers, lists, 281 | and code blocks:

282 | 283 |
> ## This is a header.
284 | > 
285 | > 1.   This is the first list item.
286 | > 2.   This is the second list item.
287 | > 
288 | > Here's some example code:
289 | > 
290 | >     return shell_exec("echo $input | $markdown_script");
291 | 
292 | 293 |

Any decent text editor should make email-style quoting easy. For 294 | example, with BBEdit, you can make a selection and choose Increase 295 | Quote Level from the Text menu.

296 | 297 |

Lists

298 | 299 |

Markdown supports ordered (numbered) and unordered (bulleted) lists.

300 | 301 |

Unordered lists use asterisks, pluses, and hyphens -- interchangably 302 | -- as list markers:

303 | 304 |
*   Red
305 | *   Green
306 | *   Blue
307 | 
308 | 309 |

is equivalent to:

310 | 311 |
+   Red
312 | +   Green
313 | +   Blue
314 | 
315 | 316 |

and:

317 | 318 |
-   Red
319 | -   Green
320 | -   Blue
321 | 
322 | 323 |

Ordered lists use numbers followed by periods:

324 | 325 |
1.  Bird
326 | 2.  McHale
327 | 3.  Parish
328 | 
329 | 330 |

It's important to note that the actual numbers you use to mark the 331 | list have no effect on the HTML output Markdown produces. The HTML 332 | Markdown produces from the above list is:

333 | 334 |
<ol>
335 | <li>Bird</li>
336 | <li>McHale</li>
337 | <li>Parish</li>
338 | </ol>
339 | 
340 | 341 |

If you instead wrote the list in Markdown like this:

342 | 343 |
1.  Bird
344 | 1.  McHale
345 | 1.  Parish
346 | 
347 | 348 |

or even:

349 | 350 |
3. Bird
351 | 1. McHale
352 | 8. Parish
353 | 
354 | 355 |

you'd get the exact same HTML output. The point is, if you want to, 356 | you can use ordinal numbers in your ordered Markdown lists, so that 357 | the numbers in your source match the numbers in your published HTML. 358 | But if you want to be lazy, you don't have to.

359 | 360 |

If you do use lazy list numbering, however, you should still start the 361 | list with the number 1. At some point in the future, Markdown may support 362 | starting ordered lists at an arbitrary number.

363 | 364 |

List markers typically start at the left margin, but may be indented by 365 | up to three spaces. List markers must be followed by one or more spaces 366 | or a tab.

367 | 368 |

To make lists look nice, you can wrap items with hanging indents:

369 | 370 |
*   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
371 |     Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
372 |     viverra nec, fringilla in, laoreet vitae, risus.
373 | *   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
374 |     Suspendisse id sem consectetuer libero luctus adipiscing.
375 | 
376 | 377 |

But if you want to be lazy, you don't have to:

378 | 379 |
*   Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
380 | Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi,
381 | viverra nec, fringilla in, laoreet vitae, risus.
382 | *   Donec sit amet nisl. Aliquam semper ipsum sit amet velit.
383 | Suspendisse id sem consectetuer libero luctus adipiscing.
384 | 
385 | 386 |

If list items are separated by blank lines, Markdown will wrap the 387 | items in <p> tags in the HTML output. For example, this input:

388 | 389 |
*   Bird
390 | *   Magic
391 | 
392 | 393 |

will turn into:

394 | 395 |
<ul>
396 | <li>Bird</li>
397 | <li>Magic</li>
398 | </ul>
399 | 
400 | 401 |

But this:

402 | 403 |
*   Bird
404 | 
405 | *   Magic
406 | 
407 | 408 |

will turn into:

409 | 410 |
<ul>
411 | <li><p>Bird</p></li>
412 | <li><p>Magic</p></li>
413 | </ul>
414 | 
415 | 416 |

List items may consist of multiple paragraphs. Each subsequent 417 | paragraph in a list item must be intended by either 4 spaces 418 | or one tab:

419 | 420 |
1.  This is a list item with two paragraphs. Lorem ipsum dolor
421 |     sit amet, consectetuer adipiscing elit. Aliquam hendrerit
422 |     mi posuere lectus.
423 | 
424 |     Vestibulum enim wisi, viverra nec, fringilla in, laoreet
425 |     vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
426 |     sit amet velit.
427 | 
428 | 2.  Suspendisse id sem consectetuer libero luctus adipiscing.
429 | 
430 | 431 |

It looks nice if you indent every line of the subsequent 432 | paragraphs, but here again, Markdown will allow you to be 433 | lazy:

434 | 435 |
*   This is a list item with two paragraphs.
436 | 
437 |     This is the second paragraph in the list item. You're
438 | only required to indent the first line. Lorem ipsum dolor
439 | sit amet, consectetuer adipiscing elit.
440 | 
441 | *   Another item in the same list.
442 | 
443 | 444 |

To put a blockquote within a list item, the blockquote's > 445 | delimiters need to be indented:

446 | 447 |
*   A list item with a blockquote:
448 | 
449 |     > This is a blockquote
450 |     > inside a list item.
451 | 
452 | 453 |

To put a code block within a list item, the code block needs 454 | to be indented twice -- 8 spaces or two tabs:

455 | 456 |
*   A list item with a code block:
457 | 
458 |         <code goes here>
459 | 
460 | 461 |

It's worth noting that it's possible to trigger an ordered list by 462 | accident, by writing something like this:

463 | 464 |
1986. What a great season.
465 | 
466 | 467 |

In other words, a number-period-space sequence at the beginning of a 468 | line. To avoid this, you can backslash-escape the period:

469 | 470 |
1986\. What a great season.
471 | 
472 | 473 |

Code Blocks

474 | 475 |

Pre-formatted code blocks are used for writing about programming or 476 | markup source code. Rather than forming normal paragraphs, the lines 477 | of a code block are interpreted literally. Markdown wraps a code block 478 | in both <pre> and <code> tags.

479 | 480 |

To produce a code block in Markdown, simply indent every line of the 481 | block by at least 4 spaces or 1 tab. For example, given this input:

482 | 483 |
This is a normal paragraph:
484 | 
485 |     This is a code block.
486 | 
487 | 488 |

Markdown will generate:

489 | 490 |
<p>This is a normal paragraph:</p>
491 | 
492 | <pre><code>This is a code block.
493 | </code></pre>
494 | 
495 | 496 |

One level of indentation -- 4 spaces or 1 tab -- is removed from each 497 | line of the code block. For example, this:

498 | 499 |
Here is an example of AppleScript:
500 | 
501 |     tell application "Foo"
502 |         beep
503 |     end tell
504 | 
505 | 506 |

will turn into:

507 | 508 |
<p>Here is an example of AppleScript:</p>
509 | 
510 | <pre><code>tell application "Foo"
511 |     beep
512 | end tell
513 | </code></pre>
514 | 
515 | 516 |

A code block continues until it reaches a line that is not indented 517 | (or the end of the article).

518 | 519 |

Within a code block, ampersands (&) and angle brackets (< and >) 520 | are automatically converted into HTML entities. This makes it very 521 | easy to include example HTML source code using Markdown -- just paste 522 | it and indent it, and Markdown will handle the hassle of encoding the 523 | ampersands and angle brackets. For example, this:

524 | 525 |
    <div class="footer">
526 |         &copy; 2004 Foo Corporation
527 |     </div>
528 | 
529 | 530 |

will turn into:

531 | 532 |
<pre><code>&lt;div class="footer"&gt;
533 |     &amp;copy; 2004 Foo Corporation
534 | &lt;/div&gt;
535 | </code></pre>
536 | 
537 | 538 |

Regular Markdown syntax is not processed within code blocks. E.g., 539 | asterisks are just literal asterisks within a code block. This means 540 | it's also easy to use Markdown to write about Markdown's own syntax.

541 | 542 |

Horizontal Rules

543 | 544 |

You can produce a horizontal rule tag (<hr />) by placing three or 545 | more hyphens, asterisks, or underscores on a line by themselves. If you 546 | wish, you may use spaces between the hyphens or asterisks. Each of the 547 | following lines will produce a horizontal rule:

548 | 549 |
* * *
550 | 
551 | ***
552 | 
553 | *****
554 | 
555 | - - -
556 | 
557 | ---------------------------------------
558 | 
559 | _ _ _
560 | 
561 | 562 |
563 | 564 |

Span Elements

565 | 566 | 567 | 568 |

Markdown supports two style of links: inline and reference.

569 | 570 |

In both styles, the link text is delimited by [square brackets].

571 | 572 |

To create an inline link, use a set of regular parentheses immediately 573 | after the link text's closing square bracket. Inside the parentheses, 574 | put the URL where you want the link to point, along with an optional 575 | title for the link, surrounded in quotes. For example:

576 | 577 |
This is [an example](http://example.com/ "Title") inline link.
578 | 
579 | [This link](http://example.net/) has no title attribute.
580 | 
581 | 582 |

Will produce:

583 | 584 |
<p>This is <a href="http://example.com/" title="Title">
585 | an example</a> inline link.</p>
586 | 
587 | <p><a href="http://example.net/">This link</a> has no
588 | title attribute.</p>
589 | 
590 | 591 |

If you're referring to a local resource on the same server, you can 592 | use relative paths:

593 | 594 |
See my [About](/about/) page for details.
595 | 
596 | 597 |

Reference-style links use a second set of square brackets, inside 598 | which you place a label of your choosing to identify the link:

599 | 600 |
This is [an example][id] reference-style link.
601 | 
602 | 603 |

You can optionally use a space to separate the sets of brackets:

604 | 605 |
This is [an example] [id] reference-style link.
606 | 
607 | 608 |

Then, anywhere in the document, you define your link label like this, 609 | on a line by itself:

610 | 611 |
[id]: http://example.com/  "Optional Title Here"
612 | 
613 | 614 |

That is:

615 | 616 |
    617 |
  • Square brackets containing the link identifier (optionally 618 | indented from the left margin using up to three spaces);
  • 619 |
  • followed by a colon;
  • 620 |
  • followed by one or more spaces (or tabs);
  • 621 |
  • followed by the URL for the link;
  • 622 |
  • optionally followed by a title attribute for the link, enclosed 623 | in double or single quotes.
  • 624 |
625 | 626 |

The link URL may, optionally, be surrounded by angle brackets:

627 | 628 |
[id]: <http://example.com/>  "Optional Title Here"
629 | 
630 | 631 |

You can put the title attribute on the next line and use extra spaces 632 | or tabs for padding, which tends to look better with longer URLs:

633 | 634 |
[id]: http://example.com/longish/path/to/resource/here
635 |     "Optional Title Here"
636 | 
637 | 638 |

Link definitions are only used for creating links during Markdown 639 | processing, and are stripped from your document in the HTML output.

640 | 641 |

Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are not case sensitive. E.g. these two links:

642 | 643 |
[link text][a]
644 | [link text][A]
645 | 
646 | 647 |

are equivalent.

648 | 649 |

The implicit link name shortcut allows you to omit the name of the 650 | link, in which case the link text itself is used as the name. 651 | Just use an empty set of square brackets -- e.g., to link the word 652 | "Google" to the google.com web site, you could simply write:

653 | 654 |
[Google][]
655 | 
656 | 657 |

And then define the link:

658 | 659 |
[Google]: http://google.com/
660 | 
661 | 662 |

Because link names may contain spaces, this shortcut even works for 663 | multiple words in the link text:

664 | 665 |
Visit [Daring Fireball][] for more information.
666 | 
667 | 668 |

And then define the link:

669 | 670 |
[Daring Fireball]: http://daringfireball.net/
671 | 
672 | 673 |

Link definitions can be placed anywhere in your Markdown document. I 674 | tend to put them immediately after each paragraph in which they're 675 | used, but if you want, you can put them all at the end of your 676 | document, sort of like footnotes.

677 | 678 |

Here's an example of reference links in action:

679 | 680 |
I get 10 times more traffic from [Google] [1] than from
681 | [Yahoo] [2] or [MSN] [3].
682 | 
683 |   [1]: http://google.com/        "Google"
684 |   [2]: http://search.yahoo.com/  "Yahoo Search"
685 |   [3]: http://search.msn.com/    "MSN Search"
686 | 
687 | 688 |

Using the implicit link name shortcut, you could instead write:

689 | 690 |
I get 10 times more traffic from [Google][] than from
691 | [Yahoo][] or [MSN][].
692 | 
693 |   [google]: http://google.com/        "Google"
694 |   [yahoo]:  http://search.yahoo.com/  "Yahoo Search"
695 |   [msn]:    http://search.msn.com/    "MSN Search"
696 | 
697 | 698 |

Both of the above examples will produce the following HTML output:

699 | 700 |
<p>I get 10 times more traffic from <a href="http://google.com/"
701 | title="Google">Google</a> than from
702 | <a href="http://search.yahoo.com/" title="Yahoo Search">Yahoo</a>
703 | or <a href="http://search.msn.com/" title="MSN Search">MSN</a>.</p>
704 | 
705 | 706 |

For comparison, here is the same paragraph written using 707 | Markdown's inline link style:

708 | 709 |
I get 10 times more traffic from [Google](http://google.com/ "Google")
710 | than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or
711 | [MSN](http://search.msn.com/ "MSN Search").
712 | 
713 | 714 |

The point of reference-style links is not that they're easier to 715 | write. The point is that with reference-style links, your document 716 | source is vastly more readable. Compare the above examples: using 717 | reference-style links, the paragraph itself is only 81 characters 718 | long; with inline-style links, it's 176 characters; and as raw HTML, 719 | it's 234 characters. In the raw HTML, there's more markup than there 720 | is text.

721 | 722 |

With Markdown's reference-style links, a source document much more 723 | closely resembles the final output, as rendered in a browser. By 724 | allowing you to move the markup-related metadata out of the paragraph, 725 | you can add links without interrupting the narrative flow of your 726 | prose.

727 | 728 |

Emphasis

729 | 730 |

Markdown treats asterisks (*) and underscores (_) as indicators of 731 | emphasis. Text wrapped with one * or _ will be wrapped with an 732 | HTML <em> tag; double *'s or _'s will be wrapped with an HTML 733 | <strong> tag. E.g., this input:

734 | 735 |
*single asterisks*
736 | 
737 | _single underscores_
738 | 
739 | **double asterisks**
740 | 
741 | __double underscores__
742 | 
743 | 744 |

will produce:

745 | 746 |
<em>single asterisks</em>
747 | 
748 | <em>single underscores</em>
749 | 
750 | <strong>double asterisks</strong>
751 | 
752 | <strong>double underscores</strong>
753 | 
754 | 755 |

You can use whichever style you prefer; the lone restriction is that 756 | the same character must be used to open and close an emphasis span.

757 | 758 |

Emphasis can be used in the middle of a word:

759 | 760 |
un*fucking*believable
761 | 
762 | 763 |

But if you surround an * or _ with spaces, it'll be treated as a 764 | literal asterisk or underscore.

765 | 766 |

To produce a literal asterisk or underscore at a position where it 767 | would otherwise be used as an emphasis delimiter, you can backslash 768 | escape it:

769 | 770 |
\*this text is surrounded by literal asterisks\*
771 | 
772 | 773 |

Code

774 | 775 |

To indicate a span of code, wrap it with backtick quotes (`). 776 | Unlike a pre-formatted code block, a code span indicates code within a 777 | normal paragraph. For example:

778 | 779 |
Use the `printf()` function.
780 | 
781 | 782 |

will produce:

783 | 784 |
<p>Use the <code>printf()</code> function.</p>
785 | 
786 | 787 |

To include a literal backtick character within a code span, you can use 788 | multiple backticks as the opening and closing delimiters:

789 | 790 |
``There is a literal backtick (`) here.``
791 | 
792 | 793 |

which will produce this:

794 | 795 |
<p><code>There is a literal backtick (`) here.</code></p>
796 | 
797 | 798 |

The backtick delimiters surrounding a code span may include spaces -- 799 | one after the opening, one before the closing. This allows you to place 800 | literal backtick characters at the beginning or end of a code span:

801 | 802 |
A single backtick in a code span: `` ` ``
803 | 
804 | A backtick-delimited string in a code span: `` `foo` ``
805 | 
806 | 807 |

will produce:

808 | 809 |
<p>A single backtick in a code span: <code>`</code></p>
810 | 
811 | <p>A backtick-delimited string in a code span: <code>`foo`</code></p>
812 | 
813 | 814 |

With a code span, ampersands and angle brackets are encoded as HTML 815 | entities automatically, which makes it easy to include example HTML 816 | tags. Markdown will turn this:

817 | 818 |
Please don't use any `<blink>` tags.
819 | 
820 | 821 |

into:

822 | 823 |
<p>Please don't use any <code>&lt;blink&gt;</code> tags.</p>
824 | 
825 | 826 |

You can write this:

827 | 828 |
`&#8212;` is the decimal-encoded equivalent of `&mdash;`.
829 | 
830 | 831 |

to produce:

832 | 833 |
<p><code>&amp;#8212;</code> is the decimal-encoded
834 | equivalent of <code>&amp;mdash;</code>.</p>
835 | 
836 | 837 |

Images

838 | 839 |

Admittedly, it's fairly difficult to devise a "natural" syntax for 840 | placing images into a plain text document format.

841 | 842 |

Markdown uses an image syntax that is intended to resemble the syntax 843 | for links, allowing for two styles: inline and reference.

844 | 845 |

Inline image syntax looks like this:

846 | 847 |
![Alt text](/path/to/img.jpg)
848 | 
849 | ![Alt text](/path/to/img.jpg "Optional title")
850 | 
851 | 852 |

That is:

853 | 854 |
    855 |
  • An exclamation mark: !;
  • 856 |
  • followed by a set of square brackets, containing the alt 857 | attribute text for the image;
  • 858 |
  • followed by a set of parentheses, containing the URL or path to 859 | the image, and an optional title attribute enclosed in double 860 | or single quotes.
  • 861 |
862 | 863 |

Reference-style image syntax looks like this:

864 | 865 |
![Alt text][id]
866 | 
867 | 868 |

Where "id" is the name of a defined image reference. Image references 869 | are defined using syntax identical to link references:

870 | 871 |
[id]: url/to/image  "Optional title attribute"
872 | 
873 | 874 |

As of this writing, Markdown has no syntax for specifying the 875 | dimensions of an image; if this is important to you, you can simply 876 | use regular HTML <img> tags.

877 | 878 |
879 | 880 |

Miscellaneous

881 | 882 | 883 | 884 |

Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this:

885 | 886 |
<http://example.com/>
887 | 
888 | 889 |

Markdown will turn this into:

890 | 891 |
<a href="http://example.com/">http://example.com/</a>
892 | 
893 | 894 |

Automatic links for email addresses work similarly, except that 895 | Markdown will also perform a bit of randomized decimal and hex 896 | entity-encoding to help obscure your address from address-harvesting 897 | spambots. For example, Markdown will turn this:

898 | 899 |
<address@example.com>
900 | 
901 | 902 |

into something like this:

903 | 904 |
<a href="&#x6D;&#x61;i&#x6C;&#x74;&#x6F;:&#x61;&#x64;&#x64;&#x72;&#x65;
905 | &#115;&#115;&#64;&#101;&#120;&#x61;&#109;&#x70;&#x6C;e&#x2E;&#99;&#111;
906 | &#109;">&#x61;&#x64;&#x64;&#x72;&#x65;&#115;&#115;&#64;&#101;&#120;&#x61;
907 | &#109;&#x70;&#x6C;e&#x2E;&#99;&#111;&#109;</a>
908 | 
909 | 910 |

which will render in a browser as a clickable link to "address@example.com".

911 | 912 |

(This sort of entity-encoding trick will indeed fool many, if not 913 | most, address-harvesting bots, but it definitely won't fool all of 914 | them. It's better than nothing, but an address published in this way 915 | will probably eventually start receiving spam.)

916 | 917 |

Backslash Escapes

918 | 919 |

Markdown allows you to use backslash escapes to generate literal 920 | characters which would otherwise have special meaning in Markdown's 921 | formatting syntax. For example, if you wanted to surround a word with 922 | literal asterisks (instead of an HTML <em> tag), you can backslashes 923 | before the asterisks, like this:

924 | 925 |
\*literal asterisks\*
926 | 
927 | 928 |

Markdown provides backslash escapes for the following characters:

929 | 930 |
\   backslash
931 | `   backtick
932 | *   asterisk
933 | _   underscore
934 | {}  curly braces
935 | []  square brackets
936 | ()  parentheses
937 | #   hash mark
938 | +   plus sign
939 | -   minus sign (hyphen)
940 | .   dot
941 | !   exclamation mark
942 | 
943 | -------------------------------------------------------------------------------- /Data/Markdown Documentation - Syntax.text: -------------------------------------------------------------------------------- 1 | Markdown: Syntax 2 | ================ 3 | 4 | 11 | 12 | 13 | * [Overview](#overview) 14 | * [Philosophy](#philosophy) 15 | * [Inline HTML](#html) 16 | * [Automatic Escaping for Special Characters](#autoescape) 17 | * [Block Elements](#block) 18 | * [Paragraphs and Line Breaks](#p) 19 | * [Headers](#header) 20 | * [Blockquotes](#blockquote) 21 | * [Lists](#list) 22 | * [Code Blocks](#precode) 23 | * [Horizontal Rules](#hr) 24 | * [Span Elements](#span) 25 | * [Links](#link) 26 | * [Emphasis](#em) 27 | * [Code](#code) 28 | * [Images](#img) 29 | * [Miscellaneous](#misc) 30 | * [Backslash Escapes](#backslash) 31 | * [Automatic Links](#autolink) 32 | 33 | 34 | **Note:** This document is itself written using Markdown; you 35 | can [see the source for it by adding '.text' to the URL][src]. 36 | 37 | [src]: /projects/markdown/syntax.text 38 | 39 | * * * 40 | 41 |

Overview

42 | 43 |

Philosophy

44 | 45 | Markdown is intended to be as easy-to-read and easy-to-write as is feasible. 46 | 47 | Readability, however, is emphasized above all else. A Markdown-formatted 48 | document should be publishable as-is, as plain text, without looking 49 | like it's been marked up with tags or formatting instructions. While 50 | Markdown's syntax has been influenced by several existing text-to-HTML 51 | filters -- including [Setext] [1], [atx] [2], [Textile] [3], [reStructuredText] [4], 52 | [Grutatext] [5], and [EtText] [6] -- the single biggest source of 53 | inspiration for Markdown's syntax is the format of plain text email. 54 | 55 | [1]: http://docutils.sourceforge.net/mirror/setext.html 56 | [2]: http://www.aaronsw.com/2002/atx/ 57 | [3]: http://textism.com/tools/textile/ 58 | [4]: http://docutils.sourceforge.net/rst.html 59 | [5]: http://www.triptico.com/software/grutatxt.html 60 | [6]: http://ettext.taint.org/doc/ 61 | 62 | To this end, Markdown's syntax is comprised entirely of punctuation 63 | characters, which punctuation characters have been carefully chosen so 64 | as to look like what they mean. E.g., asterisks around a word actually 65 | look like \*emphasis\*. Markdown lists look like, well, lists. Even 66 | blockquotes look like quoted passages of text, assuming you've ever 67 | used email. 68 | 69 | 70 | 71 |

Inline HTML

72 | 73 | Markdown's syntax is intended for one purpose: to be used as a 74 | format for *writing* for the web. 75 | 76 | Markdown is not a replacement for HTML, or even close to it. Its 77 | syntax is very small, corresponding only to a very small subset of 78 | HTML tags. The idea is *not* to create a syntax that makes it easier 79 | to insert HTML tags. In my opinion, HTML tags are already easy to 80 | insert. The idea for Markdown is to make it easy to read, write, and 81 | edit prose. HTML is a *publishing* format; Markdown is a *writing* 82 | format. Thus, Markdown's formatting syntax only addresses issues that 83 | can be conveyed in plain text. 84 | 85 | For any markup that is not covered by Markdown's syntax, you simply 86 | use HTML itself. There's no need to preface it or delimit it to 87 | indicate that you're switching from Markdown to HTML; you just use 88 | the tags. 89 | 90 | The only restrictions are that block-level HTML elements -- e.g. `
`, 91 | ``, `
`, `

`, etc. -- must be separated from surrounding 92 | content by blank lines, and the start and end tags of the block should 93 | not be indented with tabs or spaces. Markdown is smart enough not 94 | to add extra (unwanted) `

` tags around HTML block-level tags. 95 | 96 | For example, to add an HTML table to a Markdown article: 97 | 98 | This is a regular paragraph. 99 | 100 |

101 | 102 | 103 | 104 |
Foo
105 | 106 | This is another regular paragraph. 107 | 108 | Note that Markdown formatting syntax is not processed within block-level 109 | HTML tags. E.g., you can't use Markdown-style `*emphasis*` inside an 110 | HTML block. 111 | 112 | Span-level HTML tags -- e.g. ``, ``, or `` -- can be 113 | used anywhere in a Markdown paragraph, list item, or header. If you 114 | want, you can even use HTML tags instead of Markdown formatting; e.g. if 115 | you'd prefer to use HTML `` or `` tags instead of Markdown's 116 | link or image syntax, go right ahead. 117 | 118 | Unlike block-level HTML tags, Markdown syntax *is* processed within 119 | span-level tags. 120 | 121 | 122 |

Automatic Escaping for Special Characters

123 | 124 | In HTML, there are two characters that demand special treatment: `<` 125 | and `&`. Left angle brackets are used to start tags; ampersands are 126 | used to denote HTML entities. If you want to use them as literal 127 | characters, you must escape them as entities, e.g. `<`, and 128 | `&`. 129 | 130 | Ampersands in particular are bedeviling for web writers. If you want to 131 | write about 'AT&T', you need to write '`AT&T`'. You even need to 132 | escape ampersands within URLs. Thus, if you want to link to: 133 | 134 | http://images.google.com/images?num=30&q=larry+bird 135 | 136 | you need to encode the URL as: 137 | 138 | http://images.google.com/images?num=30&q=larry+bird 139 | 140 | in your anchor tag `href` attribute. Needless to say, this is easy to 141 | forget, and is probably the single most common source of HTML validation 142 | errors in otherwise well-marked-up web sites. 143 | 144 | Markdown allows you to use these characters naturally, taking care of 145 | all the necessary escaping for you. If you use an ampersand as part of 146 | an HTML entity, it remains unchanged; otherwise it will be translated 147 | into `&`. 148 | 149 | So, if you want to include a copyright symbol in your article, you can write: 150 | 151 | © 152 | 153 | and Markdown will leave it alone. But if you write: 154 | 155 | AT&T 156 | 157 | Markdown will translate it to: 158 | 159 | AT&T 160 | 161 | Similarly, because Markdown supports [inline HTML](#html), if you use 162 | angle brackets as delimiters for HTML tags, Markdown will treat them as 163 | such. But if you write: 164 | 165 | 4 < 5 166 | 167 | Markdown will translate it to: 168 | 169 | 4 < 5 170 | 171 | However, inside Markdown code spans and blocks, angle brackets and 172 | ampersands are *always* encoded automatically. This makes it easy to use 173 | Markdown to write about HTML code. (As opposed to raw HTML, which is a 174 | terrible format for writing about HTML syntax, because every single `<` 175 | and `&` in your example code needs to be escaped.) 176 | 177 | 178 | * * * 179 | 180 | 181 |

Block Elements

182 | 183 | 184 |

Paragraphs and Line Breaks

185 | 186 | A paragraph is simply one or more consecutive lines of text, separated 187 | by one or more blank lines. (A blank line is any line that looks like a 188 | blank line -- a line containing nothing but spaces or tabs is considered 189 | blank.) Normal paragraphs should not be intended with spaces or tabs. 190 | 191 | The implication of the "one or more consecutive lines of text" rule is 192 | that Markdown supports "hard-wrapped" text paragraphs. This differs 193 | significantly from most other text-to-HTML formatters (including Movable 194 | Type's "Convert Line Breaks" option) which translate every line break 195 | character in a paragraph into a `
` tag. 196 | 197 | When you *do* want to insert a `
` break tag using Markdown, you 198 | end a line with two or more spaces, then type return. 199 | 200 | Yes, this takes a tad more effort to create a `
`, but a simplistic 201 | "every line break is a `
`" rule wouldn't work for Markdown. 202 | Markdown's email-style [blockquoting][bq] and multi-paragraph [list items][l] 203 | work best -- and look better -- when you format them with hard breaks. 204 | 205 | [bq]: #blockquote 206 | [l]: #list 207 | 208 | 209 | 210 | 211 | 212 | Markdown supports two styles of headers, [Setext] [1] and [atx] [2]. 213 | 214 | Setext-style headers are "underlined" using equal signs (for first-level 215 | headers) and dashes (for second-level headers). For example: 216 | 217 | This is an H1 218 | ============= 219 | 220 | This is an H2 221 | ------------- 222 | 223 | Any number of underlining `=`'s or `-`'s will work. 224 | 225 | Atx-style headers use 1-6 hash characters at the start of the line, 226 | corresponding to header levels 1-6. For example: 227 | 228 | # This is an H1 229 | 230 | ## This is an H2 231 | 232 | ###### This is an H6 233 | 234 | Optionally, you may "close" atx-style headers. This is purely 235 | cosmetic -- you can use this if you think it looks better. The 236 | closing hashes don't even need to match the number of hashes 237 | used to open the header. (The number of opening hashes 238 | determines the header level.) : 239 | 240 | # This is an H1 # 241 | 242 | ## This is an H2 ## 243 | 244 | ### This is an H3 ###### 245 | 246 | 247 |

Blockquotes

248 | 249 | Markdown uses email-style `>` characters for blockquoting. If you're 250 | familiar with quoting passages of text in an email message, then you 251 | know how to create a blockquote in Markdown. It looks best if you hard 252 | wrap the text and put a `>` before every line: 253 | 254 | > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, 255 | > consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. 256 | > Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. 257 | > 258 | > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse 259 | > id sem consectetuer libero luctus adipiscing. 260 | 261 | Markdown allows you to be lazy and only put the `>` before the first 262 | line of a hard-wrapped paragraph: 263 | 264 | > This is a blockquote with two paragraphs. Lorem ipsum dolor sit amet, 265 | consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. 266 | Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. 267 | 268 | > Donec sit amet nisl. Aliquam semper ipsum sit amet velit. Suspendisse 269 | id sem consectetuer libero luctus adipiscing. 270 | 271 | Blockquotes can be nested (i.e. a blockquote-in-a-blockquote) by 272 | adding additional levels of `>`: 273 | 274 | > This is the first level of quoting. 275 | > 276 | > > This is nested blockquote. 277 | > 278 | > Back to the first level. 279 | 280 | Blockquotes can contain other Markdown elements, including headers, lists, 281 | and code blocks: 282 | 283 | > ## This is a header. 284 | > 285 | > 1. This is the first list item. 286 | > 2. This is the second list item. 287 | > 288 | > Here's some example code: 289 | > 290 | > return shell_exec("echo $input | $markdown_script"); 291 | 292 | Any decent text editor should make email-style quoting easy. For 293 | example, with BBEdit, you can make a selection and choose Increase 294 | Quote Level from the Text menu. 295 | 296 | 297 |

Lists

298 | 299 | Markdown supports ordered (numbered) and unordered (bulleted) lists. 300 | 301 | Unordered lists use asterisks, pluses, and hyphens -- interchangably 302 | -- as list markers: 303 | 304 | * Red 305 | * Green 306 | * Blue 307 | 308 | is equivalent to: 309 | 310 | + Red 311 | + Green 312 | + Blue 313 | 314 | and: 315 | 316 | - Red 317 | - Green 318 | - Blue 319 | 320 | Ordered lists use numbers followed by periods: 321 | 322 | 1. Bird 323 | 2. McHale 324 | 3. Parish 325 | 326 | It's important to note that the actual numbers you use to mark the 327 | list have no effect on the HTML output Markdown produces. The HTML 328 | Markdown produces from the above list is: 329 | 330 |
    331 |
  1. Bird
  2. 332 |
  3. McHale
  4. 333 |
  5. Parish
  6. 334 |
335 | 336 | If you instead wrote the list in Markdown like this: 337 | 338 | 1. Bird 339 | 1. McHale 340 | 1. Parish 341 | 342 | or even: 343 | 344 | 3. Bird 345 | 1. McHale 346 | 8. Parish 347 | 348 | you'd get the exact same HTML output. The point is, if you want to, 349 | you can use ordinal numbers in your ordered Markdown lists, so that 350 | the numbers in your source match the numbers in your published HTML. 351 | But if you want to be lazy, you don't have to. 352 | 353 | If you do use lazy list numbering, however, you should still start the 354 | list with the number 1. At some point in the future, Markdown may support 355 | starting ordered lists at an arbitrary number. 356 | 357 | List markers typically start at the left margin, but may be indented by 358 | up to three spaces. List markers must be followed by one or more spaces 359 | or a tab. 360 | 361 | To make lists look nice, you can wrap items with hanging indents: 362 | 363 | * Lorem ipsum dolor sit amet, consectetuer adipiscing elit. 364 | Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, 365 | viverra nec, fringilla in, laoreet vitae, risus. 366 | * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. 367 | Suspendisse id sem consectetuer libero luctus adipiscing. 368 | 369 | But if you want to be lazy, you don't have to: 370 | 371 | * Lorem ipsum dolor sit amet, consectetuer adipiscing elit. 372 | Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, 373 | viverra nec, fringilla in, laoreet vitae, risus. 374 | * Donec sit amet nisl. Aliquam semper ipsum sit amet velit. 375 | Suspendisse id sem consectetuer libero luctus adipiscing. 376 | 377 | If list items are separated by blank lines, Markdown will wrap the 378 | items in `

` tags in the HTML output. For example, this input: 379 | 380 | * Bird 381 | * Magic 382 | 383 | will turn into: 384 | 385 |

    386 |
  • Bird
  • 387 |
  • Magic
  • 388 |
389 | 390 | But this: 391 | 392 | * Bird 393 | 394 | * Magic 395 | 396 | will turn into: 397 | 398 |
    399 |
  • Bird

  • 400 |
  • Magic

  • 401 |
402 | 403 | List items may consist of multiple paragraphs. Each subsequent 404 | paragraph in a list item must be intended by either 4 spaces 405 | or one tab: 406 | 407 | 1. This is a list item with two paragraphs. Lorem ipsum dolor 408 | sit amet, consectetuer adipiscing elit. Aliquam hendrerit 409 | mi posuere lectus. 410 | 411 | Vestibulum enim wisi, viverra nec, fringilla in, laoreet 412 | vitae, risus. Donec sit amet nisl. Aliquam semper ipsum 413 | sit amet velit. 414 | 415 | 2. Suspendisse id sem consectetuer libero luctus adipiscing. 416 | 417 | It looks nice if you indent every line of the subsequent 418 | paragraphs, but here again, Markdown will allow you to be 419 | lazy: 420 | 421 | * This is a list item with two paragraphs. 422 | 423 | This is the second paragraph in the list item. You're 424 | only required to indent the first line. Lorem ipsum dolor 425 | sit amet, consectetuer adipiscing elit. 426 | 427 | * Another item in the same list. 428 | 429 | To put a blockquote within a list item, the blockquote's `>` 430 | delimiters need to be indented: 431 | 432 | * A list item with a blockquote: 433 | 434 | > This is a blockquote 435 | > inside a list item. 436 | 437 | To put a code block within a list item, the code block needs 438 | to be indented *twice* -- 8 spaces or two tabs: 439 | 440 | * A list item with a code block: 441 | 442 | 443 | 444 | 445 | It's worth noting that it's possible to trigger an ordered list by 446 | accident, by writing something like this: 447 | 448 | 1986. What a great season. 449 | 450 | In other words, a *number-period-space* sequence at the beginning of a 451 | line. To avoid this, you can backslash-escape the period: 452 | 453 | 1986\. What a great season. 454 | 455 | 456 | 457 |

Code Blocks

458 | 459 | Pre-formatted code blocks are used for writing about programming or 460 | markup source code. Rather than forming normal paragraphs, the lines 461 | of a code block are interpreted literally. Markdown wraps a code block 462 | in both `
` and `` tags.
463 | 
464 | To produce a code block in Markdown, simply indent every line of the
465 | block by at least 4 spaces or 1 tab. For example, given this input:
466 | 
467 |     This is a normal paragraph:
468 | 
469 |         This is a code block.
470 | 
471 | Markdown will generate:
472 | 
473 |     

This is a normal paragraph:

474 | 475 |
This is a code block.
476 |     
477 | 478 | One level of indentation -- 4 spaces or 1 tab -- is removed from each 479 | line of the code block. For example, this: 480 | 481 | Here is an example of AppleScript: 482 | 483 | tell application "Foo" 484 | beep 485 | end tell 486 | 487 | will turn into: 488 | 489 |

Here is an example of AppleScript:

490 | 491 |
tell application "Foo"
492 |         beep
493 |     end tell
494 |     
495 | 496 | A code block continues until it reaches a line that is not indented 497 | (or the end of the article). 498 | 499 | Within a code block, ampersands (`&`) and angle brackets (`<` and `>`) 500 | are automatically converted into HTML entities. This makes it very 501 | easy to include example HTML source code using Markdown -- just paste 502 | it and indent it, and Markdown will handle the hassle of encoding the 503 | ampersands and angle brackets. For example, this: 504 | 505 | 508 | 509 | will turn into: 510 | 511 |
<div class="footer">
512 |         &copy; 2004 Foo Corporation
513 |     </div>
514 |     
515 | 516 | Regular Markdown syntax is not processed within code blocks. E.g., 517 | asterisks are just literal asterisks within a code block. This means 518 | it's also easy to use Markdown to write about Markdown's own syntax. 519 | 520 | 521 | 522 |

Horizontal Rules

523 | 524 | You can produce a horizontal rule tag (`
`) by placing three or 525 | more hyphens, asterisks, or underscores on a line by themselves. If you 526 | wish, you may use spaces between the hyphens or asterisks. Each of the 527 | following lines will produce a horizontal rule: 528 | 529 | * * * 530 | 531 | *** 532 | 533 | ***** 534 | 535 | - - - 536 | 537 | --------------------------------------- 538 | 539 | _ _ _ 540 | 541 | 542 | * * * 543 | 544 |

Span Elements

545 | 546 | 547 | 548 | Markdown supports two style of links: *inline* and *reference*. 549 | 550 | In both styles, the link text is delimited by [square brackets]. 551 | 552 | To create an inline link, use a set of regular parentheses immediately 553 | after the link text's closing square bracket. Inside the parentheses, 554 | put the URL where you want the link to point, along with an *optional* 555 | title for the link, surrounded in quotes. For example: 556 | 557 | This is [an example](http://example.com/ "Title") inline link. 558 | 559 | [This link](http://example.net/) has no title attribute. 560 | 561 | Will produce: 562 | 563 |

This is 564 | an example inline link.

565 | 566 |

This link has no 567 | title attribute.

568 | 569 | If you're referring to a local resource on the same server, you can 570 | use relative paths: 571 | 572 | See my [About](/about/) page for details. 573 | 574 | Reference-style links use a second set of square brackets, inside 575 | which you place a label of your choosing to identify the link: 576 | 577 | This is [an example][id] reference-style link. 578 | 579 | You can optionally use a space to separate the sets of brackets: 580 | 581 | This is [an example] [id] reference-style link. 582 | 583 | Then, anywhere in the document, you define your link label like this, 584 | on a line by itself: 585 | 586 | [id]: http://example.com/ "Optional Title Here" 587 | 588 | That is: 589 | 590 | * Square brackets containing the link identifier (optionally 591 | indented from the left margin using up to three spaces); 592 | * followed by a colon; 593 | * followed by one or more spaces (or tabs); 594 | * followed by the URL for the link; 595 | * optionally followed by a title attribute for the link, enclosed 596 | in double or single quotes. 597 | 598 | The link URL may, optionally, be surrounded by angle brackets: 599 | 600 | [id]: "Optional Title Here" 601 | 602 | You can put the title attribute on the next line and use extra spaces 603 | or tabs for padding, which tends to look better with longer URLs: 604 | 605 | [id]: http://example.com/longish/path/to/resource/here 606 | "Optional Title Here" 607 | 608 | Link definitions are only used for creating links during Markdown 609 | processing, and are stripped from your document in the HTML output. 610 | 611 | Link definition names may constist of letters, numbers, spaces, and punctuation -- but they are *not* case sensitive. E.g. these two links: 612 | 613 | [link text][a] 614 | [link text][A] 615 | 616 | are equivalent. 617 | 618 | The *implicit link name* shortcut allows you to omit the name of the 619 | link, in which case the link text itself is used as the name. 620 | Just use an empty set of square brackets -- e.g., to link the word 621 | "Google" to the google.com web site, you could simply write: 622 | 623 | [Google][] 624 | 625 | And then define the link: 626 | 627 | [Google]: http://google.com/ 628 | 629 | Because link names may contain spaces, this shortcut even works for 630 | multiple words in the link text: 631 | 632 | Visit [Daring Fireball][] for more information. 633 | 634 | And then define the link: 635 | 636 | [Daring Fireball]: http://daringfireball.net/ 637 | 638 | Link definitions can be placed anywhere in your Markdown document. I 639 | tend to put them immediately after each paragraph in which they're 640 | used, but if you want, you can put them all at the end of your 641 | document, sort of like footnotes. 642 | 643 | Here's an example of reference links in action: 644 | 645 | I get 10 times more traffic from [Google] [1] than from 646 | [Yahoo] [2] or [MSN] [3]. 647 | 648 | [1]: http://google.com/ "Google" 649 | [2]: http://search.yahoo.com/ "Yahoo Search" 650 | [3]: http://search.msn.com/ "MSN Search" 651 | 652 | Using the implicit link name shortcut, you could instead write: 653 | 654 | I get 10 times more traffic from [Google][] than from 655 | [Yahoo][] or [MSN][]. 656 | 657 | [google]: http://google.com/ "Google" 658 | [yahoo]: http://search.yahoo.com/ "Yahoo Search" 659 | [msn]: http://search.msn.com/ "MSN Search" 660 | 661 | Both of the above examples will produce the following HTML output: 662 | 663 |

I get 10 times more traffic from Google than from 665 | Yahoo 666 | or MSN.

667 | 668 | For comparison, here is the same paragraph written using 669 | Markdown's inline link style: 670 | 671 | I get 10 times more traffic from [Google](http://google.com/ "Google") 672 | than from [Yahoo](http://search.yahoo.com/ "Yahoo Search") or 673 | [MSN](http://search.msn.com/ "MSN Search"). 674 | 675 | The point of reference-style links is not that they're easier to 676 | write. The point is that with reference-style links, your document 677 | source is vastly more readable. Compare the above examples: using 678 | reference-style links, the paragraph itself is only 81 characters 679 | long; with inline-style links, it's 176 characters; and as raw HTML, 680 | it's 234 characters. In the raw HTML, there's more markup than there 681 | is text. 682 | 683 | With Markdown's reference-style links, a source document much more 684 | closely resembles the final output, as rendered in a browser. By 685 | allowing you to move the markup-related metadata out of the paragraph, 686 | you can add links without interrupting the narrative flow of your 687 | prose. 688 | 689 | 690 |

Emphasis

691 | 692 | Markdown treats asterisks (`*`) and underscores (`_`) as indicators of 693 | emphasis. Text wrapped with one `*` or `_` will be wrapped with an 694 | HTML `` tag; double `*`'s or `_`'s will be wrapped with an HTML 695 | `` tag. E.g., this input: 696 | 697 | *single asterisks* 698 | 699 | _single underscores_ 700 | 701 | **double asterisks** 702 | 703 | __double underscores__ 704 | 705 | will produce: 706 | 707 | single asterisks 708 | 709 | single underscores 710 | 711 | double asterisks 712 | 713 | double underscores 714 | 715 | You can use whichever style you prefer; the lone restriction is that 716 | the same character must be used to open and close an emphasis span. 717 | 718 | Emphasis can be used in the middle of a word: 719 | 720 | un*fucking*believable 721 | 722 | But if you surround an `*` or `_` with spaces, it'll be treated as a 723 | literal asterisk or underscore. 724 | 725 | To produce a literal asterisk or underscore at a position where it 726 | would otherwise be used as an emphasis delimiter, you can backslash 727 | escape it: 728 | 729 | \*this text is surrounded by literal asterisks\* 730 | 731 | 732 | 733 |

Code

734 | 735 | To indicate a span of code, wrap it with backtick quotes (`` ` ``). 736 | Unlike a pre-formatted code block, a code span indicates code within a 737 | normal paragraph. For example: 738 | 739 | Use the `printf()` function. 740 | 741 | will produce: 742 | 743 |

Use the printf() function.

744 | 745 | To include a literal backtick character within a code span, you can use 746 | multiple backticks as the opening and closing delimiters: 747 | 748 | ``There is a literal backtick (`) here.`` 749 | 750 | which will produce this: 751 | 752 |

There is a literal backtick (`) here.

753 | 754 | The backtick delimiters surrounding a code span may include spaces -- 755 | one after the opening, one before the closing. This allows you to place 756 | literal backtick characters at the beginning or end of a code span: 757 | 758 | A single backtick in a code span: `` ` `` 759 | 760 | A backtick-delimited string in a code span: `` `foo` `` 761 | 762 | will produce: 763 | 764 |

A single backtick in a code span: `

765 | 766 |

A backtick-delimited string in a code span: `foo`

767 | 768 | With a code span, ampersands and angle brackets are encoded as HTML 769 | entities automatically, which makes it easy to include example HTML 770 | tags. Markdown will turn this: 771 | 772 | Please don't use any `` tags. 773 | 774 | into: 775 | 776 |

Please don't use any <blink> tags.

777 | 778 | You can write this: 779 | 780 | `—` is the decimal-encoded equivalent of `—`. 781 | 782 | to produce: 783 | 784 |

&#8212; is the decimal-encoded 785 | equivalent of &mdash;.

786 | 787 | 788 | 789 |

Images

790 | 791 | Admittedly, it's fairly difficult to devise a "natural" syntax for 792 | placing images into a plain text document format. 793 | 794 | Markdown uses an image syntax that is intended to resemble the syntax 795 | for links, allowing for two styles: *inline* and *reference*. 796 | 797 | Inline image syntax looks like this: 798 | 799 | ![Alt text](/path/to/img.jpg) 800 | 801 | ![Alt text](/path/to/img.jpg "Optional title") 802 | 803 | That is: 804 | 805 | * An exclamation mark: `!`; 806 | * followed by a set of square brackets, containing the `alt` 807 | attribute text for the image; 808 | * followed by a set of parentheses, containing the URL or path to 809 | the image, and an optional `title` attribute enclosed in double 810 | or single quotes. 811 | 812 | Reference-style image syntax looks like this: 813 | 814 | ![Alt text][id] 815 | 816 | Where "id" is the name of a defined image reference. Image references 817 | are defined using syntax identical to link references: 818 | 819 | [id]: url/to/image "Optional title attribute" 820 | 821 | As of this writing, Markdown has no syntax for specifying the 822 | dimensions of an image; if this is important to you, you can simply 823 | use regular HTML `` tags. 824 | 825 | 826 | * * * 827 | 828 | 829 |

Miscellaneous

830 | 831 | 832 | 833 | Markdown supports a shortcut style for creating "automatic" links for URLs and email addresses: simply surround the URL or email address with angle brackets. What this means is that if you want to show the actual text of a URL or email address, and also have it be a clickable link, you can do this: 834 | 835 | 836 | 837 | Markdown will turn this into: 838 | 839 | http://example.com/ 840 | 841 | Automatic links for email addresses work similarly, except that 842 | Markdown will also perform a bit of randomized decimal and hex 843 | entity-encoding to help obscure your address from address-harvesting 844 | spambots. For example, Markdown will turn this: 845 | 846 | 847 | 848 | into something like this: 849 | 850 | address@exa 853 | mple.com 854 | 855 | which will render in a browser as a clickable link to "address@example.com". 856 | 857 | (This sort of entity-encoding trick will indeed fool many, if not 858 | most, address-harvesting bots, but it definitely won't fool all of 859 | them. It's better than nothing, but an address published in this way 860 | will probably eventually start receiving spam.) 861 | 862 | 863 | 864 |

Backslash Escapes

865 | 866 | Markdown allows you to use backslash escapes to generate literal 867 | characters which would otherwise have special meaning in Markdown's 868 | formatting syntax. For example, if you wanted to surround a word with 869 | literal asterisks (instead of an HTML `` tag), you can backslashes 870 | before the asterisks, like this: 871 | 872 | \*literal asterisks\* 873 | 874 | Markdown provides backslash escapes for the following characters: 875 | 876 | \ backslash 877 | ` backtick 878 | * asterisk 879 | _ underscore 880 | {} curly braces 881 | [] square brackets 882 | () parentheses 883 | # hash mark 884 | + plus sign 885 | - minus sign (hyphen) 886 | . dot 887 | ! exclamation mark 888 | 889 | -------------------------------------------------------------------------------- /Data/Nested blockquotes.html: -------------------------------------------------------------------------------- 1 |
2 |

foo

3 | 4 |
5 |

bar

6 |
7 | 8 |

foo

9 |
10 | -------------------------------------------------------------------------------- /Data/Nested blockquotes.text: -------------------------------------------------------------------------------- 1 | > foo 2 | > 3 | > > bar 4 | > 5 | > foo 6 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/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 | -------------------------------------------------------------------------------- /Data/Tidyness.html: -------------------------------------------------------------------------------- 1 |
2 |

A list within a blockquote:

3 | 4 |
    5 |
  • asterisk 1
  • 6 |
  • asterisk 2
  • 7 |
  • asterisk 3
  • 8 |
9 |
10 | -------------------------------------------------------------------------------- /Data/Tidyness.text: -------------------------------------------------------------------------------- 1 | > A list within a blockquote: 2 | > 3 | > * asterisk 1 4 | > * asterisk 2 5 | > * asterisk 3 6 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | import PackageDescription 2 | 3 | let package = Package( 4 | name : "SmarkDown", 5 | dependencies: [ 6 | .Package(url: "https://github.com/SwiftStudies/Duration.git", versions: Version(1,0,2)..NSRegularExpression?{ 13 | let key = "\(pattern)/\(multiline ? "m" : "")\(dotMatchesNewlines ? "s" : "")".md5 14 | if let cachedRegex = regexCache[key] { 15 | return cachedRegex 16 | } 17 | 18 | 19 | var options = [NSRegularExpressionOptions]() 20 | 21 | if multiline { 22 | options.append(NSRegularExpressionOptions.AnchorsMatchLines) 23 | } 24 | 25 | if dotMatchesNewlines{ 26 | options.append(NSRegularExpressionOptions.DotMatchesLineSeparators) 27 | } 28 | 29 | let regex : NSRegularExpression 30 | do { 31 | regex = try NSRegularExpression( 32 | pattern: pattern, 33 | options: NSRegularExpressionOptions(options) 34 | ) 35 | } catch { 36 | print("Could not create regular expression from \(pattern)") 37 | return nil 38 | } 39 | 40 | regexCache[key] = regex 41 | 42 | return regex 43 | } 44 | 45 | internal class RegexMatchResult : CustomStringConvertible{ 46 | let nsResult : NSTextCheckingResult 47 | let string : String 48 | let startPos : Int 49 | let startIndex : String.Index 50 | 51 | init(nsResult:NSTextCheckingResult, forString:String, startPos:Int, startIndex:String.Index){ 52 | self.nsResult = nsResult 53 | self.string = forString 54 | self.startPos = startPos 55 | self.startIndex = startIndex 56 | } 57 | 58 | var range : Range{ 59 | return self[0] 60 | } 61 | 62 | var match : String { 63 | return self[0] 64 | } 65 | 66 | var groups : Int { 67 | return nsResult.numberOfRanges 68 | } 69 | 70 | subscript(group:Int)->Bool{ 71 | let rangeAtIndex = nsResult.rangeAtIndex(group) 72 | 73 | return rangeAtIndex.location != NSNotFound && rangeAtIndex.length > 0 74 | } 75 | 76 | subscript(group:Int)->Range{ 77 | let nsRange = nsResult.rangeAtIndex(group) 78 | 79 | let delta = nsRange.location - startPos 80 | 81 | let groupStart = startIndex.advancedBy(delta) 82 | 83 | return groupStart..String{ 88 | return string.substringWithRange(self[group]) 89 | // return string.substringWithNSRange(nsResult.rangeAtIndex(group)) 90 | } 91 | 92 | var description : String { 93 | var result = "Match found:\n" 94 | 95 | for range in 0..String 110 | internal typealias RegexMatchBlock = (RegexMatchResult)->Void 111 | 112 | internal func replacePatternMatchesWithBlock(text:String,pattern:String,block:RegexMatchReplaceBlock)->String{ 113 | return replacePatternMatchesWithBlock(text, pattern: pattern, multiline: false, dotMatchesNewLines: false, block:block) 114 | } 115 | 116 | internal func replacePatternMatchesWithBlock(text:String,pattern:String,multiline:Bool,block:RegexMatchReplaceBlock)->String{ 117 | return replacePatternMatchesWithBlock(text,pattern: pattern, multiline: multiline, dotMatchesNewLines:false,block:block) 118 | } 119 | 120 | internal func replacePatternMatchesWithBlock(text:String,pattern:String,multiline:Bool, dotMatchesNewLines:Bool, block:RegexMatchReplaceBlock)->String{ 121 | guard let regex = buildRegex(pattern,multiline: multiline,dotMatchesNewlines: dotMatchesNewLines) else { 122 | return text 123 | } 124 | 125 | // var lastMatchEnd = 0; 126 | var lastMatchIndex = text.startIndex; 127 | 128 | var watermarkPos = 0 129 | var watermarkIndex = text.startIndex 130 | 131 | var result = "" 132 | 133 | regex.enumerateMatchesInString(text, 134 | options: NSMatchingOptions(), range: NSMakeRange(0,text.characters.count)) { (textCheckingResult, matchingFlags, stop) -> Void in 135 | if let textCheckingResult = textCheckingResult { 136 | watermarkIndex = watermarkIndex.advancedBy(textCheckingResult.range.location - watermarkPos) 137 | watermarkPos = textCheckingResult.range.location 138 | 139 | 140 | //Add anything in the result that's been skipped before this match 141 | // let matchStartDelta = textCheckingResult.range.location - lastMatchEnd 142 | result += text.substringWithRange(lastMatchIndex.. Void in 180 | if let textCheckingResult = textCheckingResult { 181 | 182 | watermarkIndex = watermarkIndex.advancedBy(textCheckingResult.range.location - watermarkPos) 183 | watermarkPos = textCheckingResult.range.location 184 | 185 | block(RegexMatchResult(nsResult: textCheckingResult, forString: text, startPos: watermarkPos, startIndex: watermarkIndex)) 186 | } 187 | } 188 | } 189 | 190 | internal func regexSub(left:String,pattern:String,template:String)->String{ 191 | return regexSub(left, pattern: pattern, template: template, multiline: false, dotMatchesNewLines: false) 192 | } 193 | 194 | internal func regexSub(left:String,pattern:String,template:String, multiline:Bool)->String{ 195 | return regexSub(left, pattern: pattern, template: template, multiline: multiline, dotMatchesNewLines: false) 196 | } 197 | 198 | internal func regexSub(left:String,pattern:String,template:String, multiline:Bool, dotMatchesNewLines:Bool)->String{ 199 | guard let regex = buildRegex(pattern,multiline: multiline,dotMatchesNewlines: dotMatchesNewLines) else { 200 | return left 201 | } 202 | 203 | let mutableText : NSMutableString = "" 204 | mutableText.setString(left) 205 | 206 | regex.replaceMatchesInString( 207 | mutableText, 208 | options: NSMatchingOptions(), 209 | range: NSMakeRange(0,mutableText.length), 210 | withTemplate: template 211 | ) 212 | 213 | return mutableText.description 214 | } 215 | 216 | internal func regexMatches(text:String,pattern:String)->Bool{ 217 | return regexMatches(text, pattern: pattern, multiline: false, dotMatchesNewLines: false) 218 | } 219 | 220 | internal func regexMatches(text:String,pattern:String, multiline:Bool)->Bool{ 221 | return regexMatches(text, pattern: pattern, multiline: multiline, dotMatchesNewLines: false) 222 | } 223 | 224 | internal func regexMatches(text:String,pattern:String, multiline:Bool, dotMatchesNewLines:Bool)->Bool{ 225 | guard let regex = buildRegex(pattern,multiline: multiline,dotMatchesNewlines: dotMatchesNewLines) else { 226 | return false 227 | } 228 | 229 | return regex.firstMatchInString(text, options: NSMatchingOptions(), range: NSMakeRange(0,text.characters.count)) != nil 230 | } 231 | 232 | 233 | -------------------------------------------------------------------------------- /Sources/SmarkDown/SmarkDown.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SmarkDown.swift 3 | // SmarkDown 4 | // 5 | // Copyright © 2016 Swift Studies. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | import Duration 10 | 11 | #if os(Linux) 12 | import Glibc 13 | 14 | private func arc4random_uniform(max:UInt32)->UInt32{ 15 | return UInt32(random()) % (max + 1) 16 | } 17 | #endif 18 | 19 | public extension String{ 20 | var markdown : String { 21 | return SmarkDown().markdown(self) 22 | } 23 | } 24 | 25 | public class SmarkDown { 26 | private let nestedBracketPattern = "(?>[^\\[\\]]+|\\[(.*)\\])*" 27 | private let tabWidth : Int 28 | private let emptyElementSufix = " />" 29 | private var listLevel = 0 30 | 31 | private var htmlBlocks = [String:String]() 32 | private var urlHash = [String:String]() 33 | private var titles = [String:String]() 34 | 35 | public init(){ 36 | tabWidth = 4 37 | } 38 | 39 | public init(tabWidth:Int){ 40 | self.tabWidth = tabWidth 41 | } 42 | 43 | public func markdown(text:String)->String{ 44 | 45 | Duration.pushLogStyle(.None) 46 | 47 | var text = text 48 | 49 | //Clear hashes 50 | htmlBlocks.removeAll() 51 | urlHash.removeAll() 52 | titles.removeAll() 53 | 54 | //Standardize line endings 55 | text = regexSub(text, pattern: "\\r\\n", template: "\n") //DOS to Unix 56 | text = regexSub(text, pattern: "\\r", template: "\n") //Mac to Unix 57 | 58 | //Make sure text ends with a couple of new lines 59 | text += "\n\n" 60 | 61 | //Convert all tabs to spaces 62 | text = detab(text) 63 | 64 | //Strip any lines with only tabs and spaces 65 | text = regexSub(text, pattern: "^[ \\t]+$", template: "", multiline: true) 66 | 67 | //Turn block-level HTML blocks into hash entries 68 | text = hashHTMLBlocks(text) 69 | 70 | //Strip link definitions, store in hashes 71 | text = stripLinkDefinitions(text) 72 | 73 | text = runBlockGamut(text) 74 | 75 | text = unescapeSpecialCharacters(text) 76 | 77 | Duration.popLogStyle() 78 | 79 | return "\(text)\n" 80 | } 81 | 82 | //Called just once, not a big candidate for optimization 83 | internal func stripLinkDefinitions(text:String)->String{ 84 | let lessThanTab = tabWidth-1 85 | 86 | //First grab nested blocks that are against the left margin 87 | var pattern : String = 88 | "^[ ]{0,\(lessThanTab)}\\[(.+)\\]:" + //$1 = id 89 | "[ \\t]*" + 90 | "\\n?" + 91 | "[ \\t]*" + 92 | "?" + //$2 = url 93 | "[ \\t]*" + 94 | "\\n?" + 95 | "[ \\t]*" + 96 | "(?:" + 97 | "(?<=\\s)" + 98 | "[\"(]" + 99 | "(.+?)" + //$3 = title 100 | "[\")]" + 101 | "[ \\t]*" + 102 | ")?" + 103 | "(?:\\n+|\\Z)" 104 | 105 | //The lazy matches in the above pattern seem to break it 106 | pattern = "^[ ]{0,\(lessThanTab)}\\[(.+)\\]:[ \\t]*\\n?[ \\t]*?[ \\t]*\\n?[ \\t]*(?:(?<=\\s)[\"(](.+)[\")][ \\t]*)?(?:\\n+|\\Z)" 107 | 108 | 109 | //TODO: Could just be a match, although will be a small gain 110 | return replacePatternMatchesWithBlock(text, pattern: pattern, multiline: true){ 111 | (match)->String in 112 | 113 | var id : String = match[1] 114 | id = id.lowercaseString 115 | 116 | self.urlHash[id] = self.encodeAmpsAndAngles(match[2]) 117 | if match[3] { 118 | self.titles[id] = regexSub(match[3], pattern: "\"", template: """) 119 | } 120 | 121 | 122 | return "" 123 | } 124 | } 125 | 126 | //For testing purposes 127 | internal func urlForId(id:String)->String?{ 128 | return urlHash[id] 129 | } 130 | 131 | internal func titleForId(id:String)->String?{ 132 | return titles[id] 133 | } 134 | 135 | internal func encodeAmpsAndAngles(text:String)->String{ 136 | 137 | let text = regexSub(text, pattern: "&(?!#?[xX]?(?:[0-9a-fA-F]+|\\w+);)", template: "&") 138 | 139 | 140 | return regexSub(text, pattern: "<(?![a-z/?\\$!])", template: "<") 141 | } 142 | 143 | internal func runBlockGamut(text:String)->String{ 144 | var text = doHeaders(text) 145 | 146 | //Horizontal rules 147 | text = regexSub(text, pattern: "^[ ]{0,2}([ ]?\\*[ ]?){3,}[ \\t]*$", template: "\nString{ 161 | let key = html.md5 162 | 163 | htmlBlocks[key] = html 164 | 165 | return key 166 | } 167 | 168 | internal func runSpanGamut(text:String)->String{ 169 | var text = text 170 | 171 | text = doCodeSpans(text) 172 | text = escapeSpecialChars(text) 173 | text = doImages(text) 174 | text = doAnchors(text) 175 | text = doAutolinks(text) 176 | text = encodeAmpsAndAngles(text) 177 | text = doItalicsAndBold(text) 178 | 179 | //Do hard-breaks 180 | 181 | text = regexSub(text, pattern: " {2,}\\n", template: " String{ 187 | var text = text 188 | 189 | text = replacePatternMatchesWithBlock(text, pattern: "^(.+)[ \\t]*\\n=+[ \\t]*\\n+", multiline: true){ 190 | (match)->String in 191 | 192 | // return self.hashHtml("

\(self.runSpanGamut(match[1]))

")+"\n\n" 193 | return "

\(self.runSpanGamut(match[1]))

\n\n" 194 | } 195 | 196 | text = replacePatternMatchesWithBlock(text, pattern: "^(.+)[ \\t]*\\n-+[ \\t]*\\n+", multiline: true){ 197 | (match)->String in 198 | // return self.hashHtml("

\(self.runSpanGamut(match[1]))

")+"\n\n" 199 | return "

\(self.runSpanGamut(match[1]))

\n\n" 200 | } 201 | 202 | text = replacePatternMatchesWithBlock(text, pattern: "^(\\#{1,6})[ \\t]*(.+?)[ \\t]*\\#*\\n+",multiline: true){ 203 | (match)->String in 204 | 205 | let headerDashes : String = match[1] 206 | let headerLevel = headerDashes.characters.count 207 | 208 | // return self.hashHtml("\(self.runSpanGamut(match[2]))")+"\n\n" 209 | return "\(self.runSpanGamut(match[2]))\n\n" 210 | } 211 | 212 | return text 213 | } 214 | 215 | func doItalicsAndBold(text:String)->String{ 216 | 217 | let text = regexSub(text, pattern: "(\\*\\*|__)(?=\\S)(.+?[*_]*)(?<=\\S)\\1", template: "$2") 218 | 219 | return regexSub(text, pattern: "(\\*|_)(?=\\S)(.+?)(?<=\\S)\\1", template: "$2") 220 | } 221 | 222 | internal func unescapeSpecialCharacters(text:String)->String{ 223 | var text = text 224 | 225 | for escapeCode in SpecialCharacter.all{ 226 | text = escapeCode.unencodeToCharacters(inString: text) 227 | } 228 | 229 | return text 230 | } 231 | 232 | func doCodeSpans(text:String)->String{ 233 | return replacePatternMatchesWithBlock(text, pattern: "(`+)(.+?)(?String in 235 | 236 | var code : String = match[2] 237 | 238 | code = regexSub(code, pattern: "^[ \\t]*", template: "") 239 | code = regexSub(code, pattern: "[ \\t]*$", template: "") 240 | code = self.encodeCode(code) 241 | 242 | return "\(code)" 243 | } 244 | } 245 | 246 | 247 | func doImages(text:String)->String{ 248 | 249 | //Reference style images 250 | var text = replacePatternMatchesWithBlock(text, pattern: "(!\\[(.*?)\\][ ]?(?:\\n[ ]*)?\\[(.*?)\\])",multiline: true){ 251 | (match)->String in 252 | 253 | var result = "" 254 | let wholeMatch : String = match[1] 255 | var altText : String = match[2] 256 | var id : String = match[3].lowercaseString 257 | 258 | if id == "" { 259 | id = altText.lowercaseString 260 | } 261 | 262 | altText = regexSub(altText, pattern: "\"", template: """) 263 | 264 | if var url = self.urlHash[id] { 265 | url = url.stringByEncodingInstanceOf(.Star).stringByEncodingInstanceOf(.Underscore) 266 | 267 | result = "\"\(altText)\""?[ \\t]*((['\"])(.*?)\\5[ \\t]*)?\\))"){ 283 | (match)->String in 284 | 285 | var result = "" 286 | // var wholeMatch : String = match[1] 287 | var altText : String = match[2] 288 | var url : String = match[3] 289 | var title = "" 290 | 291 | if match[6] { 292 | title = match[6] 293 | } 294 | 295 | altText = regexSub(altText, pattern: "\"", template: """) 296 | url = url.stringByEncodingInstanceOf(.Star).stringByEncodingInstanceOf(.Underscore) 297 | 298 | result = "\"\(altText)\""String{ 313 | // 314 | //Reference style links 315 | // 316 | var text = replacePatternMatchesWithBlock(text, pattern: "(\\[((?>[^\\[\\]]+)|\\[(.*)\\])*\\])[ ]?(?:\\n[ ]*)?\\[(.*?)\\]"){ 317 | (match)->String in 318 | 319 | // print("Reference link with pattern: (\\[((?>[^\\[\\]]+)|\\[(.*)\\])*\\])[ ]?(?:\\n[ ]*)?\\[(.*?)\\]") 320 | // print("Produced \(match):") 321 | var result = "" 322 | let wholeMatch : String = match[0] 323 | 324 | let linkText : String 325 | 326 | if match[3] { 327 | //There are embedded brackets 328 | var withOuterBrackets = match[1] as String 329 | 330 | withOuterBrackets = withOuterBrackets.substringWithRange(withOuterBrackets.startIndex.advancedBy(1)..[^\\[\\]]+|\\[(.*)\\])*)\\]\\([ \\t]*?[ \\t]*((['\"])(.*?)\\5)?\\)"){ 366 | (match)->String in 367 | 368 | var result = "" 369 | // print (match) 370 | // let wholeMatch : String = match[1] 371 | let linkText : String = match[1] 372 | var url : String = match[3] 373 | 374 | url = url.stringByEncodingInstanceOf(.Star).stringByEncodingInstanceOf(.Underscore) 375 | 376 | result = "String{ 396 | var text = text 397 | 398 | for specialCharacter in SpecialCharacter.all{ 399 | text = text.stringByEncodingEscapedInstanceOf(specialCharacter) 400 | } 401 | 402 | return text 403 | } 404 | 405 | func tokenizeHtml(str:String)->[(type:String,value:String)]{ 406 | var tokens = [(type:String,value:String)]() 407 | var pos = 0 408 | 409 | let len = str.characters.count 410 | let depth = 6 411 | let nestedTags = ("(?:<[a-z/!$](?:[^<>]" ✕ depth).joinWithSeparator("|") + ")*>)" ✕ depth 412 | 413 | 414 | let pattern = "(?s:)|" + 415 | "(?s:<\\?.*?\\?>)|" + 416 | nestedTags 417 | 418 | replacePatternMatchesWithBlock(str, pattern: pattern){ 419 | (match)->String in 420 | 421 | let wholeTag : String = match[0] 422 | let secStart = match.nsResult.range.location+match.nsResult.range.length 423 | let tagStart = secStart - wholeTag.characters.count 424 | 425 | if (pos < tagStart){ 426 | tokens.append((type: "text", value: str.substringWithNSRange(NSMakeRange(pos, tagStart-pos)))) 427 | } 428 | 429 | tokens.append((type: "tag", value: wholeTag)) 430 | pos = secStart 431 | return "" 432 | } 433 | 434 | tokens.append((type:"text",value:str.substringWithNSRange(NSMakeRange(pos, len-pos)))) 435 | 436 | return tokens 437 | } 438 | 439 | func escapeSpecialChars(text:String)->String{ 440 | 441 | let tokens = tokenizeHtml(text) 442 | 443 | var text = "" 444 | 445 | for currentToken in tokens{ 446 | if (currentToken.type == "tag"){ 447 | text += currentToken.value.stringByEncodingInstanceOf(.Star).stringByEncodingInstanceOf(.Underscore) 448 | } else { 449 | text += encodeBackslashEscapes(currentToken.value) 450 | } 451 | } 452 | 453 | return text 454 | } 455 | 456 | func encodeEmailAddress(address:String)->String{ 457 | 458 | let encoders : [(String)->String] = [ 459 | {(shift)->String in return "&#\(shift.ord);"}, 460 | {(shift)->String in return "&#x\(String(shift.ord, radix: 16, uppercase: false));"}, 461 | {(shift)->String in return shift}, 462 | ] 463 | 464 | var address = replacePatternMatchesWithBlock(address, pattern: "(.)"){ 465 | (match)->String in 466 | 467 | let char : String = match[1] 468 | 469 | if char == "@" { 470 | return encoders[Int(arc4random_uniform(2))](char) 471 | } else if char != ":" { 472 | return encoders[Int(arc4random_uniform(3))](char) 473 | } 474 | 475 | return char 476 | } 477 | 478 | address = "\(address)" 479 | 480 | return regexSub(address, pattern: "\">.+?:", template: "\">") 481 | } 482 | 483 | 484 | func doAutolinks(text:String)->String{ 485 | var text = regexSub(text, pattern: "<((https?|ftp):[^'\">\\s]+)>", template: "$1") 486 | 487 | text = replacePatternMatchesWithBlock(text, pattern: "<(?:mailto:)?([-.\\w]+\\@[-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]+)>"){ 488 | (match)->String in 489 | 490 | return self.encodeEmailAddress(self.unescapeSpecialCharacters(match[0])) 491 | } 492 | 493 | return text 494 | 495 | } 496 | 497 | func doLists(text:String)->String{ 498 | let lessThanTab = tabWidth - 1 499 | let markerULPattern = "[*+-]" 500 | let markerOLPattern = "\\d+[.]" 501 | let markerAnyPattern = "(?:\(markerULPattern)|\(markerOLPattern))" 502 | 503 | func listSearchMatch(match:RegexMatchResult)->String{ 504 | var list = match[1] as String 505 | let listType = regexMatches(match[3],pattern:markerULPattern) ? "ul" : "ol" 506 | 507 | list = regexSub(list, pattern: "\\n{2,}", template: "\n\n\n") 508 | 509 | let result = processListItems(list, marker: markerAnyPattern) 510 | 511 | //Doesn't work becauase it has recursively compressed itself 512 | // return hashHtml("<\(listType)>\n\(result)")+"\n\n" 513 | return "<\(listType)>\n\(result)\n" 514 | } 515 | 516 | 517 | var text = text 518 | 519 | let wholeList = "(([ ]{0,\(lessThanTab)}(\(markerAnyPattern))[ \\t]+)(?s:.+?)(\\z|\\n{2,}(?=\\S)(?![ \\t]*\(markerAnyPattern)[ \\t]+)))" 520 | 521 | if listLevel > 0 { 522 | text = replacePatternMatchesWithBlock(text, pattern: "^\(wholeList)", multiline: true, block:listSearchMatch) 523 | } else { 524 | text = replacePatternMatchesWithBlock(text, pattern: "(?:(?<=\\n\\n)|\\A\\n?)\(wholeList)", multiline: true, block: listSearchMatch) 525 | } 526 | 527 | return text 528 | } 529 | 530 | func processListItems(listString:String, marker:String)->String{ 531 | listLevel += 1 532 | 533 | var listString = regexSub(listString, pattern: "\\n{2,}\\z", template: "\n") 534 | 535 | listString = replacePatternMatchesWithBlock(listString, pattern: "(\\n)?(^[ \\t]*)(\(marker))[ \\t]+((?s:.+?)(\\n{1,2}))(?=\\n*(\\z|\\2(\(marker))[ \\t]+))", multiline: true){ 536 | (match)->String in 537 | 538 | var item = match[4] as String 539 | let leadingLine = match[1] ? match[1] as String : "" 540 | 541 | if leadingLine.characters.count > 0 || regexMatches(item, pattern: "\\n{2,}"){ 542 | item = self.runBlockGamut(self.outdent(item)) 543 | } else { 544 | item = self.doLists(self.outdent(item)) 545 | item = item.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) 546 | item = self.runSpanGamut(item) 547 | } 548 | 549 | return "
  • \(item)
  • \n" 550 | } 551 | 552 | listLevel -= 1 553 | 554 | return listString 555 | } 556 | 557 | func encodeCode(text:String)->String{ 558 | var text = text.stringByReplacingOccurrencesOfString("&", withString: "&") 559 | text = text.stringByReplacingOccurrencesOfString("<", withString: "<") 560 | text = text.stringByReplacingOccurrencesOfString(">", withString: ">") 561 | 562 | text = text.stringByEncodingInstanceOf(.Star) 563 | text = text.stringByEncodingInstanceOf(.Underscore) 564 | text = text.stringByEncodingInstanceOf(.OpenCurly) 565 | text = text.stringByEncodingInstanceOf(.CloseCurly) 566 | text = text.stringByEncodingInstanceOf(.OpenSquare) 567 | text = text.stringByEncodingInstanceOf(.CloseSquare) 568 | text = text.stringByEncodingInstanceOf(.Backslash) 569 | 570 | return text 571 | } 572 | 573 | func outdent(text:String)->String{ 574 | return regexSub(text, pattern: "^(\\t|[ ]{1,\(tabWidth)})", template: "", multiline: true) 575 | } 576 | 577 | func doCodeBlocks(text:String)->String{ 578 | var text = text 579 | 580 | let pattern = "(?:\\n\\n|\\A)((?:(?:[ ]{\(tabWidth)}|\\t).*\\n+)+)((?=^[ ]{0,\(tabWidth)}\\S)|\\Z)" 581 | 582 | text = replacePatternMatchesWithBlock(text, pattern: pattern, multiline: true){ 583 | (match)->String in 584 | 585 | var codeBlock : String = match[1] 586 | 587 | codeBlock = self.encodeCode(self.outdent(codeBlock)) 588 | codeBlock = self.detab(codeBlock) 589 | codeBlock = regexSub(codeBlock, pattern: "\\A\\n+", template: "") 590 | codeBlock = regexSub(codeBlock, pattern: "\\s+\\z", template: "") 591 | 592 | return "\n\n"+self.hashHtml("
    \(codeBlock)\n
    ")+"\n\n" 593 | // return "\n\n
    \(codeBlock)\n
    \n\n" 594 | } 595 | 596 | return text 597 | } 598 | 599 | func doBlockQuotes(text:String)->String{ 600 | var text = text 601 | 602 | let pattern = "(" + //wrap whole match in $1 603 | "(" + 604 | "^[ \\t]*>[ \\t]?" + // > at the start of a line 605 | ".+\\n" + // rest of first line 606 | "(.+\\n)*" + // subsequent consecutive lines 607 | "\\n*" + // blanks 608 | ")+" + 609 | ")" 610 | 611 | text = replacePatternMatchesWithBlock(text, pattern: pattern, multiline: true){ 612 | (match)->String in 613 | 614 | var bq : String = match[1] 615 | bq = regexSub(bq, pattern: "^[ \\t]*>[ \\t]?", template: "", multiline: true) //trim one level of quoting 616 | bq = regexSub(bq, pattern: "^[ \\t]+$", template: "") //trim whitespace-only lines 617 | bq = self.runBlockGamut(bq) //recurse 618 | bq = regexSub(bq, pattern: "^", template: " ", multiline: true) 619 | 620 | //Leading spaces cause problems with
     content, so we need to fix that
    621 |             bq = replacePatternMatchesWithBlock(bq, pattern: "(\\s*
    .+?<\\/pre>)",multiline: false,dotMatchesNewLines: true){
    622 |                 (match)->String in
    623 |                 
    624 |                 let removedSpaces = regexSub(match[0],pattern: "^  ",template: "", multiline:true)
    625 |                 
    626 |                 return removedSpaces
    627 |             }
    628 |             
    629 |             return self.hashHtml("
    \n\(bq)\n
    ")+"\n\n" 630 | // return "
    \n\(bq)\n
    \n\n" 631 | } 632 | 633 | return text 634 | } 635 | 636 | func formParagraphs(text:String)->String{ 637 | var text = text 638 | 639 | text = regexSub(text, pattern: "\\A\\n+", template: "") 640 | text = regexSub(text, pattern: "\\n+\\z", template: "") 641 | 642 | var paragraphs = regexSub(text, pattern: "\\n{2,}", template: "&&&&&&").componentsSeparatedByString("&&&&&&") 643 | 644 | text = "" 645 | var first = true 646 | for p in 0..")+"

    "; 658 | 659 | if result != "

    " { 660 | text += result 661 | } else { 662 | //Skip double new line on the next paragraph 663 | first = true 664 | } 665 | } 666 | } 667 | 668 | 669 | return text 670 | } 671 | 672 | internal func detab(text:String)->String{ 673 | return detab(text,tabWidth: tabWidth) 674 | } 675 | 676 | internal func detab(text:String, tabWidth:Int)->String{ 677 | 678 | return replacePatternMatchesWithBlock(text, pattern: "(.*?)\t"){ 679 | (match)->String in 680 | 681 | var spaces = "" 682 | 683 | for _ in 0..String{ 696 | 697 | func codeLine(text:String, matchStart:String.Index)->Bool{ 698 | // Duration.startMeasurement("Code test") 699 | var lineStart = matchStart 700 | 701 | var inlineBlock = false 702 | 703 | var scanDepth = 0 704 | 705 | //Scan back to the new line 706 | while text.characters[lineStart] != "\n"{ 707 | scanDepth += 1 708 | 709 | if lineStart == text.startIndex { 710 | break 711 | } 712 | 713 | lineStart = lineStart.predecessor() 714 | if inlineBlock { 715 | if text.characters[lineStart] != "\\"{ 716 | // Duration.stopMeasurement("inline code-block (\(scanDepth))") 717 | return true 718 | } 719 | } else if text.characters[lineStart] == "`" { 720 | inlineBlock = true 721 | } 722 | } 723 | var linePrefix = text.substringWithRange(lineStart..) 746 | } 747 | 748 | //Here's the rub... an open block should be less than three spaces before a newline or start of file 749 | let pattern = "(?:<(\\/?)(\(blockTagsA)|hr)(.*?)(\\/?)>|(())[ \\t]*" 750 | 751 | var depth = 0 752 | var blocks = [HTMLBlock]() 753 | 754 | var expensiveTags = 0 755 | var reallyExpensiveTags = 0 756 | var totalTags = 0 757 | 758 | var textPos = 0 759 | var textIndex = text.startIndex 760 | 761 | Duration.startMeasurement("hashHTML") 762 | 763 | Duration.startMeasurement("Finding tags") 764 | matchesWithBlock(text, pattern: pattern, multiline: false, dotMatchesNewLines: true){ 765 | (tagMatch) in 766 | 767 | totalTags += 1 768 | 769 | textIndex = textIndex.advancedBy(tagMatch.nsResult.range.location - textPos) 770 | textPos = tagMatch.nsResult.range.location 771 | 772 | var matchType = "Code Line" 773 | Duration.startMeasurement("Match") 774 | if !codeLine(text, matchStart: textIndex){ 775 | //It's a comment 776 | if tagMatch[5] { 777 | blocks.append(HTMLBlock.Block(range: tagMatch[0])) 778 | Duration.stopMeasurement("Comment") 779 | return 780 | } 781 | 782 | let close = tagMatch[1] as Bool 783 | 784 | //Is this a single element (open and close) 785 | if depth == 0 && !close && tagMatch[4] { 786 | blocks.append(HTMLBlock.Block(range:tagMatch[0])) 787 | Duration.stopMeasurement("Open/Close") 788 | return 789 | } 790 | 791 | expensiveTags += 1 792 | 793 | let tag = tagMatch[2] as String 794 | 795 | //Special case for hr 796 | if depth == 0 && tag == "hr" { 797 | blocks.append(HTMLBlock.Block(range:tagMatch[0])) 798 | Duration.stopMeasurement("hr") 799 | return 800 | } 801 | 802 | if close { 803 | depth -= 1 804 | //If the close brings us back to depth 0 then we should see if it has a matching pair 805 | if depth == 0 { 806 | //If the last block was an open for the same tag, remove it and add a single new block 807 | //for the full range 808 | if let lastBlock = blocks.last{ 809 | switch lastBlock{ 810 | case .Open(let openBlock) where openBlock.tag == tag: 811 | blocks.removeLast() 812 | blocks.append(HTMLBlock.Block(range: text.rangeFromNSRange(NSMakeRange(openBlock.start, (tagMatch.nsResult.range.location+tagMatch.nsResult.range.length)-openBlock.start)))) 813 | reallyExpensiveTags += 1 814 | default: 815 | break 816 | } 817 | } 818 | } 819 | } 820 | 821 | // print("\t" ✕ (depth) + (close ? "/" : "") + tag) 822 | 823 | if !close { 824 | if depth == 0 { 825 | blocks.append(HTMLBlock.Open(tag: tag, start: tagMatch.nsResult.range.location)) 826 | } 827 | depth += 1 828 | } 829 | 830 | matchType="\(tag)" 831 | 832 | } 833 | Duration.stopMeasurement(matchType) 834 | 835 | return 836 | } 837 | Duration.stopMeasurement() 838 | 839 | var pos = text.startIndex 840 | var result = "" 841 | 842 | Duration.startMeasurement("Adding hashes") 843 | for block in blocks { 844 | switch block { 845 | case .Block(let blockRange): 846 | if pos < blockRange.startIndex { 847 | result += text.substringWithRange(pos..String{ 26 | return text.stringByReplacingOccurrencesOfString(escapedValue, withString: encodedValue) 27 | } 28 | 29 | func encodeCharacter(inString text:String)->String{ 30 | return text.stringByReplacingOccurrencesOfString(rawValue, withString: encodedValue) 31 | } 32 | 33 | func unencodeToCharacters(inString text:String)->String{ 34 | return text.stringByReplacingOccurrencesOfString(encodedValue, withString: rawValue) 35 | } 36 | 37 | static var all : [SpecialCharacter] { 38 | return [ 39 | .Backslash, 40 | .Tick, 41 | .Star, 42 | .Underscore, 43 | .GreaterThan, 44 | .Hash, 45 | .Plus, 46 | .Minus, 47 | .Period, 48 | .Pling, 49 | .OpenCurly, 50 | .CloseCurly, 51 | .OpenSquare, 52 | .CloseSquare, 53 | .OpenBrace, 54 | .CloseBrace 55 | ] 56 | } 57 | } 58 | 59 | extension String{ 60 | func stringByEncodingInstanceOf(specialCharacter:SpecialCharacter)->String{ 61 | return specialCharacter.encodeCharacter(inString: self) 62 | } 63 | func stringByEncodingEscapedInstanceOf(specialCharacter:SpecialCharacter)->String{ 64 | return specialCharacter.encodeEscapedValue(inString: self) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /Sources/SmarkDown/Strings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SmarkDownStrings.swift 3 | // SmarkDown 4 | // 5 | // Copyright © 2016 Swift Studies. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | 10 | internal extension String{ 11 | func substringWithNSRange(nsRange:NSRange)->String{ 12 | return self.substringWithRange(rangeFromNSRange(nsRange)) 13 | } 14 | } 15 | 16 | internal extension String { 17 | func rangeFromNSRange(nsRange:NSRange)->Range{ 18 | return self.startIndex.advancedBy(nsRange.location)..String{ 54 | var result = "" 55 | 56 | for _ in 0..<(right >= 0 ? right : 0){ 57 | result += left 58 | } 59 | 60 | return result 61 | } 62 | 63 | func ✕ (left:String, right:Int)->[String]{ 64 | var result = [String]() 65 | 66 | for _ in 0.."); 6 | exit(1) 7 | } 8 | 9 | let fullPath = NSString(string:Process.arguments[1]).stringByExpandingTildeInPath 10 | if let fileContent = try? NSString(contentsOfFile: fullPath, encoding: NSUTF8StringEncoding){ 11 | //For some reason this isn't linking... generates linker error 12 | print(fileContent.description.markdown) 13 | } else { 14 | print("Could not open \(fullPath)") 15 | } 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | @testable import SmarkDown 4 | 5 | func nothing(){ 6 | 7 | } 8 | 9 | //XCTMain([HashHTMLTests()]) 10 | 11 | //XCTMain([ 12 | // testCase(HashHTMLTests.allTests), 13 | // ]) 14 | -------------------------------------------------------------------------------- /Tests/SmarkDown/Test Sets/DetabTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DetabTests.swift 3 | // SmarkDown 4 | // 5 | // Copyright © 2016 Swift Studies. All rights reserved. 6 | // 7 | 8 | import XCTest 9 | @testable import SmarkDown 10 | 11 | class DetabTests: XCTestCase { 12 | 13 | func detab(input:String)->String{ 14 | return SmarkDown().detab(input) 15 | } 16 | 17 | func testSimpleDetab() { 18 | let input = "\tHello" 19 | let expected = " Hello" 20 | let result = detab(input) 21 | 22 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 23 | } 24 | 25 | func testAdvancedDetab() { 26 | let input = " \tHello" 27 | let expected = " Hello" 28 | let result = detab(input) 29 | 30 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 31 | } 32 | 33 | func testMultilineDetab(){ 34 | let input = "\tLine One\n \tLine Two\n \tLine Three" 35 | let expected = " Line One\n Line Two\n Line Three" 36 | let result = detab(input) 37 | 38 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 39 | } 40 | 41 | 42 | func testAdvancedMultilineDetab(){ 43 | let input = "\ta\n \tb\n \tc\n \td\n \te" 44 | let expected = " a\n b\n c\n d\n e" 45 | let result = detab(input) 46 | 47 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 48 | } 49 | } 50 | 51 | #if os(Linux) 52 | extension DetabTests : XCTestCaseProvider { 53 | var allTests : [(String, () throws -> Void)] { 54 | return [ 55 | ("testAdvancedMultilineDetab", testAdvancedMultilineDetab), 56 | ("testMultilineDetab", testMultilineDetab), 57 | ] 58 | } 59 | } 60 | #endif 61 | -------------------------------------------------------------------------------- /Tests/SmarkDown/Test Sets/HashHTMLTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HashHTMLTests.swift 3 | // SmarkDown 4 | // 5 | // Copyright © 2016 Swift Studies. All rights reserved. 6 | // 7 | 8 | import XCTest 9 | @testable import SmarkDown 10 | 11 | class HashHTMLTests: XCTestCase { 12 | 13 | func hashHTMLBlocks(input:String)->String{ 14 | return SmarkDown().hashHTMLBlocks(input) 15 | } 16 | 17 | func testBasic() { 18 | let input = "

    \n\tHello\n

    " 19 | let expected = "\n\n-4799450059411504638\n\n" 20 | let result = hashHTMLBlocks(input) 21 | 22 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 23 | } 24 | 25 | func testHR() { 26 | let input = "
    \n\n
    \n\n
    \t \n\n" 27 | let expected = "\n\n4799450059455835336\n\n"+"\n\n"+"\n\n4799450060392745641\n\n"+"\n\n"+"\n\n-4799450059824225068\n\n\n\n" 28 | let result = hashHTMLBlocks(input) 29 | 30 | print(input.markdown) 31 | 32 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 33 | } 34 | 35 | func testComments() { 36 | let input = "" 37 | let expected = "\n\n4799450059719042522\n\n" 38 | let result = hashHTMLBlocks(input) 39 | 40 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 41 | } 42 | 43 | } 44 | 45 | #if os(Linux) 46 | extension HashHTMLTests : XCTestCaseProvider{ 47 | var allTests : [(String, () throws -> Void)] { 48 | return [("testBasic",testBasic), 49 | ("testHR",testHR), 50 | ("testComments",testComments), 51 | ] 52 | } 53 | } 54 | #endif 55 | -------------------------------------------------------------------------------- /Tests/SmarkDown/Test Sets/RegexTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InternalTests.swift 3 | // SmarkDown 4 | // 5 | // Copyright © 2016 Swift Studies. All rights reserved. 6 | // 7 | 8 | import XCTest 9 | import Foundation 10 | @testable import SmarkDown 11 | 12 | class InternalTests: XCTestCase { 13 | 14 | func testSubstringWithNSRange(){ 15 | 16 | func doTest(text:String,range:NSRange,expected:String){ 17 | let result = text.substringWithNSRange(range) 18 | XCTAssert(result == expected, "Expected '\(expected)' but got '\(result)'") 19 | 20 | let nsStringVersion = NSString(string:text) 21 | let nsStringResult = String(nsStringVersion.substringWithRange(range)) 22 | XCTAssert(nsStringResult == result, "NSString with NSRange returned \(nsStringResult) which is different to \(result) ") 23 | } 24 | 25 | let testString = "Hello World" 26 | 27 | doTest(testString, range: NSRange(location:0, length:1), expected: "H") 28 | doTest(testString, range: NSRange(location:0, length:5), expected: "Hello") 29 | doTest(testString, range: NSRange(location:6, length:5), expected: "World") 30 | } 31 | 32 | func testRegexSubstitution(){ 33 | let after = regexSub("hello",pattern: "hello", template:"world") 34 | 35 | XCTAssert( 36 | regexSub("hello",pattern: "hello", template:"world")=="world", 37 | "Substituion not performed \(after)") 38 | 39 | XCTAssert( 40 | regexSub("\r\n", pattern: "\\r\\n", template: "\n") == "\n" 41 | , "Sub not done correctly" 42 | ) 43 | } 44 | 45 | func testReplacePatternMatchesWithBlock(){ 46 | func doTest(text:String, pattern:String, expected:String,block:RegexMatchReplaceBlock){ 47 | let result = replacePatternMatchesWithBlock(text, pattern: pattern, block: block) 48 | 49 | XCTAssert(expected == result , "Expected '\(expected)' but got '\(result)'") 50 | } 51 | 52 | func inertTemplate(match:RegexMatchResult)->String{ 53 | return match.match 54 | } 55 | 56 | doTest("Hello World", pattern: "kdjfkdlj", expected: "Hello World"){(match)->String in return match.match} 57 | doTest("Hello World", pattern: "Hello", expected:"Goodbye World"){ 58 | (match)->String in 59 | return "Goodbye" 60 | } 61 | doTest("Hello Cruel World", pattern: "Cruel", expected:"Hello Wonderful World"){ 62 | (match)->String in 63 | return "Wonderful" 64 | } 65 | } 66 | 67 | func doItalicsAndBold(input:String)->String{ 68 | return SmarkDown().doItalicsAndBold(input) 69 | } 70 | 71 | func testEmphasis() { 72 | let input = "*hello*" 73 | let expected = "hello" 74 | let result = doItalicsAndBold(input) 75 | 76 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 77 | } 78 | 79 | func testBold() { 80 | let input = "**hello**" 81 | let expected = "hello" 82 | let result = doItalicsAndBold(input) 83 | 84 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 85 | } 86 | 87 | func testBoldAndEmphasis(){ 88 | var input = "***hello***" 89 | let expected = "hello" 90 | let result = doItalicsAndBold(input) 91 | 92 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 93 | input = "___hello___" 94 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 95 | input = "____hello____" 96 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 97 | } 98 | 99 | func doBlockQuotes(input:String)->String{ 100 | return SmarkDown().doBlockQuotes(input) 101 | } 102 | 103 | 104 | func testBlockQuotes(){ 105 | let input = "> foo\n> foo\n" 106 | let expected = "
    \n

    foo\n foo

    \n
    \n" 107 | let result = input.markdown 108 | 109 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 110 | } 111 | 112 | func testHorizontalRule(){ 113 | let inputs = ["---"," ---"," ---","----","***","****","******","********"," *********"] 114 | let expected = "
    \n" 115 | 116 | for input in inputs { 117 | let result = (input+"\n").markdown 118 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 119 | } 120 | 121 | } 122 | 123 | func testAutoLinks(){ 124 | 125 | var failures = [String:(expected:String,actual:String)]() 126 | 127 | let inputs = [ 128 | "" : "http://www.google.com/", //Auto-link 129 | " \nNext Line\n" : "http://www.google.com/
    \nNext Line", 130 | ] 131 | 132 | for (input,expected) in inputs { 133 | let result = input.markdown 134 | let expected = "

    \(expected)

    \n" 135 | 136 | if result != expected { 137 | failures[input] = (expected,result) 138 | } 139 | 140 | // XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 141 | } 142 | 143 | var resultsSummary = "" 144 | for (input,results) in failures { 145 | resultsSummary += "Failed for '\(input.exposedWhiteSpace)':\n'\(results.expected.exposedWhiteSpace)' but got \n'\(results.actual.exposedWhiteSpace)'\n" 146 | } 147 | 148 | XCTAssert(failures.count == 0, "Failed for \(failures.count) out of \(inputs.count) cases:\n\(resultsSummary)") 149 | } 150 | 151 | func testReferenceLinkWithTitle(){ 152 | let inputs = [ 153 | "[Link][link-id]\n\n[link-id]: http://example.com/ \"title\"" : "Link", //Reference with title 154 | ] 155 | 156 | let smarkDown = SmarkDown() 157 | 158 | for (input,expected) in inputs { 159 | let result = smarkDown.markdown(input) 160 | let expected = "

    \(expected)

    \n" 161 | 162 | XCTAssert(smarkDown.titleForId("link-id") == "title","Incorrectly built title hash") 163 | XCTAssert(smarkDown.urlForId("link-id") == "http://example.com/", "URL hash not correct") 164 | 165 | 166 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 167 | } 168 | } 169 | 170 | 171 | func testReferenceLink(){ 172 | let inputs = [ 173 | "[Link][link-id]\n\n[link-id]: http://example.com/" : "Link", //Reference 174 | ] 175 | 176 | let smarkDown = SmarkDown() 177 | 178 | 179 | for (input,expected) in inputs { 180 | let result = smarkDown.markdown(input) 181 | let expected = "

    \(expected)

    \n" 182 | 183 | XCTAssert(smarkDown.titleForId("link-id") == nil,"Incorrectly built title hash") 184 | XCTAssert(smarkDown.urlForId("link-id") == "http://example.com/", "URL hash not correct") 185 | 186 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 187 | } 188 | } 189 | 190 | 191 | func testInlineLinkWithTitle(){ 192 | let inputs = [ 193 | "[This link](http://example.net \"title\")" : "This link", //Inline with title 194 | ] 195 | 196 | for (input,expected) in inputs { 197 | let result = input.markdown 198 | let expected = "

    \(expected)

    \n" 199 | 200 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 201 | } 202 | } 203 | 204 | 205 | func testInlineLink(){ 206 | let inputs = [ 207 | "[This link](http://example.net)" : "This link", //Inline 208 | ] 209 | 210 | for (input,expected) in inputs { 211 | let result = input.markdown 212 | let expected = "

    \(expected)

    \n" 213 | 214 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 215 | } 216 | } 217 | 218 | func testBasic(){ 219 | let input = "hello" 220 | let expected = "

    hello

    \n" 221 | let result = input.markdown 222 | 223 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 224 | } 225 | 226 | func testInlineImage(){ 227 | let input = "![An Image](/someimage.jpg)" 228 | let expected = "

    \"An

    \n" 229 | let result = input.markdown 230 | 231 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 232 | } 233 | 234 | func testInlineImageWithTitle(){ 235 | let input = "![An Image](/someimage.jpg 'title')" 236 | let expected = "

    \"An

    \n" 237 | let result = input.markdown 238 | 239 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 240 | } 241 | 242 | func testReferenceImage(){ 243 | let smarkDown = SmarkDown() 244 | 245 | let input = "![Alt text][image]\n\n[image]: /someimage.jpg" 246 | let expected = "

    \"Alt

    \n" 247 | let result = smarkDown.markdown(input) 248 | 249 | XCTAssert(smarkDown.titleForId("image") == nil,"Incorrectly built title hash") 250 | XCTAssert(smarkDown.urlForId("image") == "/someimage.jpg", "URL hash not correct") 251 | 252 | 253 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 254 | } 255 | 256 | func testReferenceImageWithTitle(){ 257 | let smarkDown = SmarkDown() 258 | 259 | let input = "![Alt text][image]\n\n[image]: /someimage.jpg \"title\"" 260 | let expected = "

    \"Alt

    \n" 261 | let result = smarkDown.markdown(input) 262 | 263 | XCTAssert(smarkDown.titleForId("image") == "title","Incorrectly built title hash") 264 | XCTAssert(smarkDown.urlForId("image") == "/someimage.jpg", "URL hash not correct") 265 | 266 | 267 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 268 | } 269 | 270 | 271 | func testCodeBlock(){ 272 | let input = "Here is an example of AppleScript:\n\n tell application \"Foo\"\n beep\n end tell" 273 | let expected = "

    Here is an example of AppleScript:

    \n\n
    tell application \"Foo\"\n    beep\nend tell\n
    \n" 274 | let result = input.markdown 275 | 276 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 277 | } 278 | 279 | func testSimpleHeader(){ 280 | let input = "## Unordered\n\nResults" 281 | let expected = "

    Unordered

    \n\n

    Results

    \n" 282 | let result = input.markdown 283 | 284 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 285 | } 286 | 287 | func testMalformedHr(){ 288 | let input = "Hr's:\n\n
    \n" 289 | let expected = "

    Hr's:

    \n\n
    \n" 290 | let result = input.markdown 291 | 292 | XCTAssert(result == expected, "Failed for '\(input.exposedWhiteSpace)':\n'\(expected.exposedWhiteSpace)' but got \n'\(result.exposedWhiteSpace)'") 293 | } 294 | } 295 | 296 | #if os(Linux) 297 | extension InternalTests : XCTestCaseProvider { 298 | var allTests : [(String, () throws -> Void)] { 299 | return [ 300 | ("testMalformedHr", testMalformedHr), 301 | ("testSimpleHeader", testSimpleHeader), 302 | ] 303 | } 304 | } 305 | #endif 306 | -------------------------------------------------------------------------------- /Tests/SmarkDown/Test Sets/StandardMarkDownTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SmarkDownTests.swift 3 | // SmarkDownTests 4 | // 5 | // Copyright © 2016 Swift Studies. All rights reserved. 6 | // 7 | 8 | import XCTest 9 | import Foundation 10 | 11 | @testable import SmarkDown 12 | 13 | class SmarkDownTests: XCTestCase { 14 | 15 | #if !os(Linux) 16 | var bundle : NSBundle { 17 | return NSBundle(forClass: self.dynamicType) 18 | } 19 | #endif 20 | 21 | 22 | func doFileTest(fileName:String){ 23 | 24 | var inputFileName = "./Data/\(fileName).text" 25 | var outputFileName = "./Data/\(fileName).html" 26 | 27 | //If we are not on linux see if we are running through XCode and 28 | //need to get at the test data from the bundle 29 | #if !os(Linux) 30 | let bundle = NSBundle(forClass: self.dynamicType) 31 | if let fromBundle = bundle.pathForResource(fileName, ofType: "text"){ 32 | inputFileName = fromBundle 33 | } 34 | 35 | if let fromBundle = bundle.pathForResource(fileName, ofType: "html"){ 36 | outputFileName = fromBundle 37 | } 38 | #endif 39 | 40 | do { 41 | let input : String = try NSString(contentsOfFile: inputFileName, encoding: NSUTF8StringEncoding).description 42 | let expectedOutput : String = try NSString(contentsOfFile: outputFileName, encoding: NSUTF8StringEncoding).description 43 | 44 | let result = input.markdown 45 | 46 | XCTAssert(result == expectedOutput, "\(fileName) not correctly processed got:\n\(result)\n...but expected...\n\(expectedOutput)\nDone") 47 | 48 | 49 | 50 | } catch { 51 | XCTAssert(false, "Could not load \(fileName).(text|html)") 52 | } 53 | } 54 | 55 | func testAmpsAndEncoding(){ 56 | doFileTest("Amps and angle encoding") 57 | } 58 | 59 | func testAutoLinks(){ 60 | doFileTest("Auto links") 61 | } 62 | 63 | func testBackslashEscapes(){ 64 | doFileTest("Backslash escapes") 65 | 66 | } 67 | 68 | func testBlockquotesWithCodeBlocks(){ 69 | doFileTest("Blockquotes with code blocks") 70 | 71 | } 72 | 73 | func testHardwrappedParagraphsWithListLikeLines(){ 74 | doFileTest("Hard-wrapped paragraphs with list-like lines") 75 | 76 | } 77 | 78 | func testHorizontalRules(){ 79 | doFileTest("Horizontal rules") 80 | 81 | } 82 | 83 | //Gruber's implementation fails this test 84 | func testInlineHTMLAdvanced(){ 85 | doFileTest("Inline HTML (Advanced)") 86 | 87 | } 88 | 89 | func testInlineHTMLSimple(){ 90 | doFileTest("Inline HTML (Simple)") 91 | 92 | } 93 | 94 | func testInlineHTMLComments(){ 95 | doFileTest("Inline HTML comments") 96 | 97 | } 98 | 99 | func testLinksInlineStyle(){ 100 | doFileTest("Links, inline style") 101 | 102 | } 103 | 104 | func testLinksReferenceStyle(){ 105 | doFileTest("Links, reference style") 106 | 107 | } 108 | 109 | func testLiteralQuotesInTitles(){ 110 | doFileTest("Literal quotes in titles") 111 | 112 | } 113 | 114 | func testMarkdownDocumentationBasics(){ 115 | doFileTest("Markdown Documentation - Basics") 116 | 117 | } 118 | 119 | func testMarkdownDocumentationSyntax(){ 120 | doFileTest("Markdown Documentation - Syntax") 121 | 122 | } 123 | 124 | func testNestedBlockQuotes(){ 125 | doFileTest("Nested blockquotes") 126 | 127 | } 128 | 129 | func testOrderedAndUnorderedLists(){ 130 | doFileTest("Ordered and unordered lists") 131 | 132 | } 133 | 134 | func testStrongAndEmTogether(){ 135 | doFileTest("Strong and em together") 136 | 137 | } 138 | 139 | func testTabs(){ 140 | doFileTest("Tabs") 141 | 142 | } 143 | 144 | //I prefer the way my code does it! 145 | func testTidyness(){ 146 | doFileTest("Tidyness") 147 | 148 | } 149 | 150 | // Measure block not supported on linux yet 151 | #if !os(Linux) 152 | func testOverallPerformance() { 153 | // This is an example of a performance test case. 154 | self.measureBlock { 155 | self.doFileTest("Markdown Documentation - Syntax") 156 | } 157 | } 158 | #endif 159 | 160 | } 161 | 162 | #if os(Linux) 163 | extension SmarkDownTests : XCTestCaseProvider { 164 | var allTests : [(String, () throws -> Void)] { 165 | return [ 166 | ("testMarkdownDocumentationSyntax", testMarkdownDocumentationSyntax), 167 | ] 168 | } 169 | } 170 | #endif 171 | 172 | --------------------------------------------------------------------------------