diff --git a/src/Markdig.Tests/Markdig.Tests.csproj b/src/Markdig.Tests/Markdig.Tests.csproj index c461cd76..0111c3e2 100644 --- a/src/Markdig.Tests/Markdig.Tests.csproj +++ b/src/Markdig.Tests/Markdig.Tests.csproj @@ -1,138 +1,153 @@ - - - - - Debug - AnyCPU - {A0C5CB5F-5568-40AB-B945-D6D2664D51B0} - Exe - Properties - Markdig.Tests - Markdig.Tests - v4.5.1 - 512 - true - true - - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - - - - True - True - Specs.tt - - - - - - - - - - - - - - - - - - - - - - - - - PreserveNewest - - - PreserveNewest - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TextTemplatingFileGenerator - Specs.cs - - - - - - - - - {8a58a7e2-627c-4f41-933f-5ac92adfab48} - Markdig - - - + + + + + Debug + AnyCPU + {A0C5CB5F-5568-40AB-B945-D6D2664D51B0} + Exe + Properties + Markdig.Tests + Markdig.Tests + v4.5.1 + 512 + true + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {8a58a7e2-627c-4f41-933f-5ac92adfab48} + Markdig + + + + --> \ No newline at end of file diff --git a/src/Markdig.Tests/Specs/AbbreviationSpecs.cs b/src/Markdig.Tests/Specs/AbbreviationSpecs.cs new file mode 100644 index 00000000..29fab1b5 --- /dev/null +++ b/src/Markdig.Tests/Specs/AbbreviationSpecs.cs @@ -0,0 +1,197 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Abbreviations +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.Abbreviations +{ + [TestFixture] + public class TestExtensionsAbbreviation + { + // # Extensions + // + // This section describes the different extensions supported: + // + // ## Abbreviation + // + // Abbreviation can be declared by using the `*[Abbreviation Label]: Abbreviation description` + // + // Abbreviation definition will be removed from the original document. Any Abbreviation label found in literals will be replaced by the abbreviation description: + [Test] + public void ExtensionsAbbreviation_Example001() + { + // Example 1 + // Section: Extensions / Abbreviation + // + // The following Markdown: + // *[HTML]: Hypertext Markup Language + // + // Later in a text we are using HTML and it becomes an abbr tag HTML + // + // Should be rendered as: + //

Later in a text we are using HTML and it becomes an abbr tag HTML

+ + Console.WriteLine("Example 1\nSection Extensions / Abbreviation\n"); + TestParser.TestSpec("*[HTML]: Hypertext Markup Language\n\nLater in a text we are using HTML and it becomes an abbr tag HTML", "

Later in a text we are using HTML and it becomes an abbr tag HTML

", "abbreviations|advanced"); + } + + // An abbreviation definition can be indented at most 3 spaces + [Test] + public void ExtensionsAbbreviation_Example002() + { + // Example 2 + // Section: Extensions / Abbreviation + // + // The following Markdown: + // *[HTML]: Hypertext Markup Language + // *[This]: is not an abbreviation + // + // Should be rendered as: + //
*[This]: is not an abbreviation
+            //     
+ + Console.WriteLine("Example 2\nSection Extensions / Abbreviation\n"); + TestParser.TestSpec("*[HTML]: Hypertext Markup Language\n *[This]: is not an abbreviation", "
*[This]: is not an abbreviation\n
", "abbreviations|advanced"); + } + + // An abbreviation may contain spaces: + [Test] + public void ExtensionsAbbreviation_Example003() + { + // Example 3 + // Section: Extensions / Abbreviation + // + // The following Markdown: + // *[SUPER HTML]: Super Hypertext Markup Language + // + // This is a SUPER HTML document + // + // Should be rendered as: + //

This is a SUPER HTML document

+ + Console.WriteLine("Example 3\nSection Extensions / Abbreviation\n"); + TestParser.TestSpec("*[SUPER HTML]: Super Hypertext Markup Language\n\nThis is a SUPER HTML document ", "

This is a SUPER HTML document

", "abbreviations|advanced"); + } + + // Abbreviation may contain any unicode characters: + [Test] + public void ExtensionsAbbreviation_Example004() + { + // Example 4 + // Section: Extensions / Abbreviation + // + // The following Markdown: + // *[😃 HTML]: Hypertext Markup Language + // + // This is a 😃 HTML document + // + // Should be rendered as: + //

This is a 😃 HTML document

+ + Console.WriteLine("Example 4\nSection Extensions / Abbreviation\n"); + TestParser.TestSpec("*[😃 HTML]: Hypertext Markup Language\n\nThis is a 😃 HTML document ", "

This is a 😃 HTML document

", "abbreviations|advanced"); + } + + // Abbreviations may be similar: + [Test] + public void ExtensionsAbbreviation_Example005() + { + // Example 5 + // Section: Extensions / Abbreviation + // + // The following Markdown: + // *[1A]: First + // *[1A1]: Second + // *[1A2]: Third + // + // We can abbreviate 1A, 1A1 and 1A2! + // + // Should be rendered as: + //

We can abbreviate 1A, 1A1 and 1A2!

+ + Console.WriteLine("Example 5\nSection Extensions / Abbreviation\n"); + TestParser.TestSpec("*[1A]: First\n*[1A1]: Second\n*[1A2]: Third\n\nWe can abbreviate 1A, 1A1 and 1A2!", "

We can abbreviate 1A, 1A1 and 1A2!

", "abbreviations|advanced"); + } + + // Abbreviations should match whole word only: + [Test] + public void ExtensionsAbbreviation_Example006() + { + // Example 6 + // Section: Extensions / Abbreviation + // + // The following Markdown: + // *[1A]: First + // + // We should not abbreviate 1.1A or 11A! + // + // Should be rendered as: + //

We should not abbreviate 1.1A or 11A!

+ + Console.WriteLine("Example 6\nSection Extensions / Abbreviation\n"); + TestParser.TestSpec("*[1A]: First\n\nWe should not abbreviate 1.1A or 11A!", "

We should not abbreviate 1.1A or 11A!

", "abbreviations|advanced"); + } + + // Abbreviations should match whole word only, even if the word is the entire content: + [Test] + public void ExtensionsAbbreviation_Example007() + { + // Example 7 + // Section: Extensions / Abbreviation + // + // The following Markdown: + // *[1A]: First + // + // 1.1A + // + // Should be rendered as: + //

1.1A

+ + Console.WriteLine("Example 7\nSection Extensions / Abbreviation\n"); + TestParser.TestSpec("*[1A]: First\n\n1.1A", "

1.1A

", "abbreviations|advanced"); + } + + // Abbreviations should match whole word only, even if there is another glossary term: + [Test] + public void ExtensionsAbbreviation_Example008() + { + // Example 8 + // Section: Extensions / Abbreviation + // + // The following Markdown: + // *[SCO]: First + // *[SCOM]: Second + // + // SCOM + // + // Should be rendered as: + //

SCOM

+ + Console.WriteLine("Example 8\nSection Extensions / Abbreviation\n"); + TestParser.TestSpec("*[SCO]: First\n*[SCOM]: Second\n\nSCOM", "

SCOM

", "abbreviations|advanced"); + } + + // Abbreviations should only match when surrounded by whitespace: + [Test] + public void ExtensionsAbbreviation_Example009() + { + // Example 9 + // Section: Extensions / Abbreviation + // + // The following Markdown: + // *[PR]: Pull Request + // + // PRAA + // + // Should be rendered as: + //

PRAA

+ + Console.WriteLine("Example 9\nSection Extensions / Abbreviation\n"); + TestParser.TestSpec("*[PR]: Pull Request\n\nPRAA", "

PRAA

", "abbreviations|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/AutoIdentifierSpecs.cs b/src/Markdig.Tests/Specs/AutoIdentifierSpecs.cs new file mode 100644 index 00000000..66e49328 --- /dev/null +++ b/src/Markdig.Tests/Specs/AutoIdentifierSpecs.cs @@ -0,0 +1,224 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Auto Identifiers +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.AutoIdentifiers +{ + [TestFixture] + public class TestExtensionsHeadingAutoIdentifiers + { + // # Extensions + // + // This section describes the auto identifier extension + // + // ## Heading Auto Identifiers + // + // Allows to automatically creates an identifier for a heading: + [Test] + public void ExtensionsHeadingAutoIdentifiers_Example001() + { + // Example 1 + // Section: Extensions / Heading Auto Identifiers + // + // The following Markdown: + // # This is a heading + // + // Should be rendered as: + //

This is a heading

+ + Console.WriteLine("Example 1\nSection Extensions / Heading Auto Identifiers\n"); + TestParser.TestSpec("# This is a heading", "

This is a heading

", "autoidentifiers|advanced"); + } + + // Only punctuation `-`, `_` and `.` is kept, all other non letter characters are discarded. + // Consecutive same character `-`, `_` or `.` are rendered into a single one + // Characters `-`, `_` and `.` at the end of the string are also discarded. + [Test] + public void ExtensionsHeadingAutoIdentifiers_Example002() + { + // Example 2 + // Section: Extensions / Heading Auto Identifiers + // + // The following Markdown: + // # This - is a &@! heading _ with . and ! - + // + // Should be rendered as: + //

This - is a &@! heading _ with . and ! -

+ + Console.WriteLine("Example 2\nSection Extensions / Heading Auto Identifiers\n"); + TestParser.TestSpec("# This - is a &@! heading _ with . and ! -", "

This - is a &@! heading _ with . and ! -

", "autoidentifiers|advanced"); + } + + // Formatting (emphasis) are also discarded: + [Test] + public void ExtensionsHeadingAutoIdentifiers_Example003() + { + // Example 3 + // Section: Extensions / Heading Auto Identifiers + // + // The following Markdown: + // # This is a *heading* + // + // Should be rendered as: + //

This is a heading

+ + Console.WriteLine("Example 3\nSection Extensions / Heading Auto Identifiers\n"); + TestParser.TestSpec("# This is a *heading*", "

This is a heading

", "autoidentifiers|advanced"); + } + + // Links are also removed: + [Test] + public void ExtensionsHeadingAutoIdentifiers_Example004() + { + // Example 4 + // Section: Extensions / Heading Auto Identifiers + // + // The following Markdown: + // # This is a [heading](/url) + // + // Should be rendered as: + //

This is a heading

+ + Console.WriteLine("Example 4\nSection Extensions / Heading Auto Identifiers\n"); + TestParser.TestSpec("# This is a [heading](/url)", "

This is a heading

", "autoidentifiers|advanced"); + } + + // If multiple heading have the same text, -1, -2...-n will be postfix to the header id. + [Test] + public void ExtensionsHeadingAutoIdentifiers_Example005() + { + // Example 5 + // Section: Extensions / Heading Auto Identifiers + // + // The following Markdown: + // # This is a heading + // # This is a heading + // + // Should be rendered as: + //

This is a heading

+ //

This is a heading

+ + Console.WriteLine("Example 5\nSection Extensions / Heading Auto Identifiers\n"); + TestParser.TestSpec("# This is a heading\n# This is a heading", "

This is a heading

\n

This is a heading

", "autoidentifiers|advanced"); + } + + // The heading Id will start on the first letter character of the heading, all previous characters will be discarded: + [Test] + public void ExtensionsHeadingAutoIdentifiers_Example006() + { + // Example 6 + // Section: Extensions / Heading Auto Identifiers + // + // The following Markdown: + // # 1.0 This is a heading + // + // Should be rendered as: + //

1.0 This is a heading

+ + Console.WriteLine("Example 6\nSection Extensions / Heading Auto Identifiers\n"); + TestParser.TestSpec("# 1.0 This is a heading", "

1.0 This is a heading

", "autoidentifiers|advanced"); + } + + // If the heading is all stripped by the previous rules, the id `section` will be used instead: + [Test] + public void ExtensionsHeadingAutoIdentifiers_Example007() + { + // Example 7 + // Section: Extensions / Heading Auto Identifiers + // + // The following Markdown: + // # 1.0 & ^ % * + // # 1.0 & ^ % * + // + // Should be rendered as: + //

1.0 & ^ % *

+ //

1.0 & ^ % *

+ + Console.WriteLine("Example 7\nSection Extensions / Heading Auto Identifiers\n"); + TestParser.TestSpec("# 1.0 & ^ % *\n# 1.0 & ^ % *", "

1.0 & ^ % *

\n

1.0 & ^ % *

", "autoidentifiers|advanced"); + } + + // When the options "AutoLink" is setup, it is possible to link to an existing heading by using the + // exact same Label text as the heading: + [Test] + public void ExtensionsHeadingAutoIdentifiers_Example008() + { + // Example 8 + // Section: Extensions / Heading Auto Identifiers + // + // The following Markdown: + // # This is a heading + // [This is a heading] + // + // Should be rendered as: + //

This is a heading

+ //

This is a heading

+ + Console.WriteLine("Example 8\nSection Extensions / Heading Auto Identifiers\n"); + TestParser.TestSpec("# This is a heading\n[This is a heading]", "

This is a heading

\n

This is a heading

", "autoidentifiers|advanced"); + } + + // Links before the heading are also working: + [Test] + public void ExtensionsHeadingAutoIdentifiers_Example009() + { + // Example 9 + // Section: Extensions / Heading Auto Identifiers + // + // The following Markdown: + // [This is a heading] + // # This is a heading + // + // Should be rendered as: + //

This is a heading

+ //

This is a heading

+ + Console.WriteLine("Example 9\nSection Extensions / Heading Auto Identifiers\n"); + TestParser.TestSpec("[This is a heading]\n# This is a heading", "

This is a heading

\n

This is a heading

", "autoidentifiers|advanced"); + } + + // The text of the link can be changed: + [Test] + public void ExtensionsHeadingAutoIdentifiers_Example010() + { + // Example 10 + // Section: Extensions / Heading Auto Identifiers + // + // The following Markdown: + // [With a new text][This is a heading] + // # This is a heading + // + // Should be rendered as: + //

With a new text

+ //

This is a heading

+ + Console.WriteLine("Example 10\nSection Extensions / Heading Auto Identifiers\n"); + TestParser.TestSpec("[With a new text][This is a heading]\n# This is a heading", "

With a new text

\n

This is a heading

", "autoidentifiers|advanced"); + } + + // An autoidentifier should not conflict with an existing link: + [Test] + public void ExtensionsHeadingAutoIdentifiers_Example011() + { + // Example 11 + // Section: Extensions / Heading Auto Identifiers + // + // The following Markdown: + // ![scenario image][scenario] + // ## Scenario + // [scenario]: ./scenario.png + // + // Should be rendered as: + //

scenario image

+ //

Scenario

+ + Console.WriteLine("Example 11\nSection Extensions / Heading Auto Identifiers\n"); + TestParser.TestSpec("![scenario image][scenario]\n## Scenario\n[scenario]: ./scenario.png", "

\"scenario

\n

Scenario

", "autoidentifiers|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/AutoLinks.cs b/src/Markdig.Tests/Specs/AutoLinks.cs new file mode 100644 index 00000000..4dafb7fe --- /dev/null +++ b/src/Markdig.Tests/Specs/AutoLinks.cs @@ -0,0 +1,449 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Auto Links +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.AutoLinks +{ + [TestFixture] + public class TestExtensionsAutoLinks + { + // # Extensions + // + // This section describes the different extensions supported: + // + // ## AutoLinks + // + // Autolinks will format as a HTML link any string that starts by: + // + // - `http://` or `https://` + // - `ftp://` + // - `mailto:` + // - `www.` + [Test] + public void ExtensionsAutoLinks_Example001() + { + // Example 1 + // Section: Extensions / AutoLinks + // + // The following Markdown: + // This is a http://www.google.com URL and https://www.google.com + // This is a ftp://test.com + // And a mailto:email@toto.com + // And a plain www.google.com + // + // Should be rendered as: + //

This is a http://www.google.com URL and https://www.google.com + // This is a ftp://test.com + // And a email@toto.com + // And a plain www.google.com

+ + Console.WriteLine("Example 1\nSection Extensions / AutoLinks\n"); + TestParser.TestSpec("This is a http://www.google.com URL and https://www.google.com\nThis is a ftp://test.com\nAnd a mailto:email@toto.com\nAnd a plain www.google.com", "

This is a http://www.google.com URL and https://www.google.com\nThis is a ftp://test.com\nAnd a email@toto.com\nAnd a plain www.google.com

", "autolinks|advanced"); + } + + // But incomplete links will not be matched: + [Test] + public void ExtensionsAutoLinks_Example002() + { + // Example 2 + // Section: Extensions / AutoLinks + // + // The following Markdown: + // This is not a http:/www.google.com URL and https:/www.google.com + // This is not a ftp:/test.com + // And not a mailto:emailtoto.com + // And not a plain www. or a www.x + // + // Should be rendered as: + //

This is not a http:/www.google.com URL and https:/www.google.com + // This is not a ftp:/test.com + // And not a mailto:emailtoto.com + // And not a plain www. or a www.x

+ + Console.WriteLine("Example 2\nSection Extensions / AutoLinks\n"); + TestParser.TestSpec("This is not a http:/www.google.com URL and https:/www.google.com\nThis is not a ftp:/test.com\nAnd not a mailto:emailtoto.com\nAnd not a plain www. or a www.x ", "

This is not a http:/www.google.com URL and https:/www.google.com\nThis is not a ftp:/test.com\nAnd not a mailto:emailtoto.com\nAnd not a plain www. or a www.x

", "autolinks|advanced"); + } + + // Previous character must be a punctuation or a valid space (tab, space, new line): + [Test] + public void ExtensionsAutoLinks_Example003() + { + // Example 3 + // Section: Extensions / AutoLinks + // + // The following Markdown: + // This is not a nhttp://www.google.com URL but this is (https://www.google.com) + // + // Should be rendered as: + //

This is not a nhttp://www.google.com URL but this is (https://www.google.com)

+ + Console.WriteLine("Example 3\nSection Extensions / AutoLinks\n"); + TestParser.TestSpec("This is not a nhttp://www.google.com URL but this is (https://www.google.com)", "

This is not a nhttp://www.google.com URL but this is (https://www.google.com)

", "autolinks|advanced"); + } + + // An autolink should not interfere with an `` HTML inline: + [Test] + public void ExtensionsAutoLinks_Example004() + { + // Example 4 + // Section: Extensions / AutoLinks + // + // The following Markdown: + // This is an HTML http://www.google.com link + // + // Should be rendered as: + //

This is an HTML http://www.google.com link

+ + Console.WriteLine("Example 4\nSection Extensions / AutoLinks\n"); + TestParser.TestSpec("This is an HTML http://www.google.com link", "

This is an HTML http://www.google.com link

", "autolinks|advanced"); + } + + // or even within emphasis: + [Test] + public void ExtensionsAutoLinks_Example005() + { + // Example 5 + // Section: Extensions / AutoLinks + // + // The following Markdown: + // This is an HTML **http://www.google.com** link + // + // Should be rendered as: + //

This is an HTML http://www.google.com link

+ + Console.WriteLine("Example 5\nSection Extensions / AutoLinks\n"); + TestParser.TestSpec("This is an HTML **http://www.google.com** link", "

This is an HTML http://www.google.com link

", "autolinks|advanced"); + } + + // An autolink should not interfere with a markdown link: + [Test] + public void ExtensionsAutoLinks_Example006() + { + // Example 6 + // Section: Extensions / AutoLinks + // + // The following Markdown: + // This is an HTML [http://www.google.com](http://www.google.com) link + // + // Should be rendered as: + //

This is an HTML http://www.google.com link

+ + Console.WriteLine("Example 6\nSection Extensions / AutoLinks\n"); + TestParser.TestSpec("This is an HTML [http://www.google.com](http://www.google.com) link", "

This is an HTML http://www.google.com link

", "autolinks|advanced"); + } + + // A link embraced by pending emphasis should let the emphasis takes precedence if characters are placed at the end of the matched link: + [Test] + public void ExtensionsAutoLinks_Example007() + { + // Example 7 + // Section: Extensions / AutoLinks + // + // The following Markdown: + // Check **http://www.a.com** or __http://www.b.com__ + // + // Should be rendered as: + //

Check http://www.a.com or http://www.b.com

+ + Console.WriteLine("Example 7\nSection Extensions / AutoLinks\n"); + TestParser.TestSpec("Check **http://www.a.com** or __http://www.b.com__", "

Check http://www.a.com or http://www.b.com

", "autolinks|advanced"); + } + + // It is not mentioned by the spec, but empty emails won't be matched (only a subset of [RFC2368](https://tools.ietf.org/html/rfc2368) is supported by auto links): + [Test] + public void ExtensionsAutoLinks_Example008() + { + // Example 8 + // Section: Extensions / AutoLinks + // + // The following Markdown: + // mailto:email@test.com is okay, but mailto:@test.com is not + // + // Should be rendered as: + //

email@test.com is okay, but mailto:@test.com is not

+ + Console.WriteLine("Example 8\nSection Extensions / AutoLinks\n"); + TestParser.TestSpec("mailto:email@test.com is okay, but mailto:@test.com is not", "

email@test.com is okay, but mailto:@test.com is not

", "autolinks|advanced"); + } + } + + [TestFixture] + public class TestExtensionsAutoLinksGFMSupport + { + // ### GFM Support + // + // Extract from [GFM Autolinks extensions specs](https://github.github.com/gfm/#autolinks-extension-) + [Test] + public void ExtensionsAutoLinksGFMSupport_Example009() + { + // Example 9 + // Section: Extensions / AutoLinks / GFM Support + // + // The following Markdown: + // www.commonmark.org + // + // Should be rendered as: + //

www.commonmark.org

+ + Console.WriteLine("Example 9\nSection Extensions / AutoLinks / GFM Support\n"); + TestParser.TestSpec("www.commonmark.org", "

www.commonmark.org

", "autolinks|advanced"); + } + + [Test] + public void ExtensionsAutoLinksGFMSupport_Example010() + { + // Example 10 + // Section: Extensions / AutoLinks / GFM Support + // + // The following Markdown: + // Visit www.commonmark.org/help for more information. + // + // Should be rendered as: + //

Visit www.commonmark.org/help for more information.

+ + Console.WriteLine("Example 10\nSection Extensions / AutoLinks / GFM Support\n"); + TestParser.TestSpec("Visit www.commonmark.org/help for more information.", "

Visit www.commonmark.org/help for more information.

", "autolinks|advanced"); + } + + [Test] + public void ExtensionsAutoLinksGFMSupport_Example011() + { + // Example 11 + // Section: Extensions / AutoLinks / GFM Support + // + // The following Markdown: + // Visit www.commonmark.org. + // + // Visit www.commonmark.org/a.b. + // + // Should be rendered as: + //

Visit www.commonmark.org.

+ //

Visit www.commonmark.org/a.b.

+ + Console.WriteLine("Example 11\nSection Extensions / AutoLinks / GFM Support\n"); + TestParser.TestSpec("Visit www.commonmark.org.\n\nVisit www.commonmark.org/a.b.", "

Visit www.commonmark.org.

\n

Visit www.commonmark.org/a.b.

", "autolinks|advanced"); + } + + [Test] + public void ExtensionsAutoLinksGFMSupport_Example012() + { + // Example 12 + // Section: Extensions / AutoLinks / GFM Support + // + // The following Markdown: + // www.google.com/search?q=Markup+(business) + // + // (www.google.com/search?q=Markup+(business)) + // + // Should be rendered as: + //

www.google.com/search?q=Markup+(business)

+ //

(www.google.com/search?q=Markup+(business))

+ + Console.WriteLine("Example 12\nSection Extensions / AutoLinks / GFM Support\n"); + TestParser.TestSpec("www.google.com/search?q=Markup+(business)\n\n(www.google.com/search?q=Markup+(business))", "

www.google.com/search?q=Markup+(business)

\n

(www.google.com/search?q=Markup+(business))

", "autolinks|advanced"); + } + + [Test] + public void ExtensionsAutoLinksGFMSupport_Example013() + { + // Example 13 + // Section: Extensions / AutoLinks / GFM Support + // + // The following Markdown: + // www.google.com/search?q=commonmark&hl=en + // + // www.google.com/search?q=commonmark&hl; + // + // Should be rendered as: + //

www.google.com/search?q=commonmark&hl=en

+ //

www.google.com/search?q=commonmark&hl;

+ + Console.WriteLine("Example 13\nSection Extensions / AutoLinks / GFM Support\n"); + TestParser.TestSpec("www.google.com/search?q=commonmark&hl=en\n\nwww.google.com/search?q=commonmark&hl;", "

www.google.com/search?q=commonmark&hl=en

\n

www.google.com/search?q=commonmark&hl;

", "autolinks|advanced"); + } + + [Test] + public void ExtensionsAutoLinksGFMSupport_Example014() + { + // Example 14 + // Section: Extensions / AutoLinks / GFM Support + // + // The following Markdown: + // www.commonmark.org/hewww.commonmark.org/he<lp

+ + Console.WriteLine("Example 14\nSection Extensions / AutoLinks / GFM Support\n"); + TestParser.TestSpec("www.commonmark.org/hewww.commonmark.org/he<lp

", "autolinks|advanced"); + } + + [Test] + public void ExtensionsAutoLinksGFMSupport_Example015() + { + // Example 15 + // Section: Extensions / AutoLinks / GFM Support + // + // The following Markdown: + // http://commonmark.org + // + // (Visit https://encrypted.google.com/search?q=Markup+(business)) + // + // Anonymous FTP is available at ftp://foo.bar.baz. + // + // Should be rendered as: + //

http://commonmark.org

+ //

(Visit https://encrypted.google.com/search?q=Markup+(business))

+ //

Anonymous FTP is available at ftp://foo.bar.baz.

+ + Console.WriteLine("Example 15\nSection Extensions / AutoLinks / GFM Support\n"); + TestParser.TestSpec("http://commonmark.org\n\n(Visit https://encrypted.google.com/search?q=Markup+(business))\n\nAnonymous FTP is available at ftp://foo.bar.baz.", "

http://commonmark.org

\n

(Visit https://encrypted.google.com/search?q=Markup+(business))

\n

Anonymous FTP is available at ftp://foo.bar.baz.

", "autolinks|advanced"); + } + } + + [TestFixture] + public class TestExtensionsAutoLinksValidDomainTests + { + // ### Valid Domain Tests + // + // Domain names that have empty segments won't be matched + [Test] + public void ExtensionsAutoLinksValidDomainTests_Example016() + { + // Example 16 + // Section: Extensions / AutoLinks / Valid Domain Tests + // + // The following Markdown: + // www.. + // www..com + // http://test. + // http://.test + // http://. + // http://.. + // ftp://test. + // ftp://.test + // mailto:email@test. + // mailto:email@.test + // + // Should be rendered as: + //

www.. + // www..com + // http://test. + // http://.test + // http://. + // http://.. + // ftp://test. + // ftp://.test + // mailto:email@test. + // mailto:email@.test

+ + Console.WriteLine("Example 16\nSection Extensions / AutoLinks / Valid Domain Tests\n"); + TestParser.TestSpec("www..\nwww..com\nhttp://test.\nhttp://.test\nhttp://.\nhttp://..\nftp://test.\nftp://.test\nmailto:email@test.\nmailto:email@.test", "

www..\nwww..com\nhttp://test.\nhttp://.test\nhttp://.\nhttp://..\nftp://test.\nftp://.test\nmailto:email@test.\nmailto:email@.test

", "autolinks|advanced"); + } + + // Domain names with too few segments won't be matched + [Test] + public void ExtensionsAutoLinksValidDomainTests_Example017() + { + // Example 17 + // Section: Extensions / AutoLinks / Valid Domain Tests + // + // The following Markdown: + // www + // www.com + // http://test + // ftp://test + // mailto:email@test + // + // Should be rendered as: + //

www + // www.com + // http://test + // ftp://test + // mailto:email@test

+ + Console.WriteLine("Example 17\nSection Extensions / AutoLinks / Valid Domain Tests\n"); + TestParser.TestSpec("www\nwww.com\nhttp://test\nftp://test\nmailto:email@test", "

www\nwww.com\nhttp://test\nftp://test\nmailto:email@test

", "autolinks|advanced"); + } + + // Domain names that contain an underscores in the last two segments won't be matched + [Test] + public void ExtensionsAutoLinksValidDomainTests_Example018() + { + // Example 18 + // Section: Extensions / AutoLinks / Valid Domain Tests + // + // The following Markdown: + // www._test.foo.bar is okay, but www._test.foo is not + // + // http://te_st.foo.bar is okay, as is http://test.foo_.bar.foo + // + // But http://te_st.foo, http://test.foo_.bar and http://test._foo are not + // + // ftp://test_.foo.bar is okay, but ftp://test.fo_o is not + // + // mailto:email@_test.foo.bar is okay, but mailto:email@_test.foo is not + // + // Should be rendered as: + //

www._test.foo.bar is okay, but www._test.foo is not

+ //

http://te_st.foo.bar is okay, as is http://test.foo_.bar.foo

+ //

But http://te_st.foo, http://test.foo_.bar and http://test._foo are not

+ //

ftp://test_.foo.bar is okay, but ftp://test.fo_o is not

+ //

email@_test.foo.bar is okay, but mailto:email@_test.foo is not

+ + Console.WriteLine("Example 18\nSection Extensions / AutoLinks / Valid Domain Tests\n"); + TestParser.TestSpec("www._test.foo.bar is okay, but www._test.foo is not\n\nhttp://te_st.foo.bar is okay, as is http://test.foo_.bar.foo\n\nBut http://te_st.foo, http://test.foo_.bar and http://test._foo are not\n\nftp://test_.foo.bar is okay, but ftp://test.fo_o is not\n\nmailto:email@_test.foo.bar is okay, but mailto:email@_test.foo is not", "

www._test.foo.bar is okay, but www._test.foo is not

\n

http://te_st.foo.bar is okay, as is http://test.foo_.bar.foo

\n

But http://te_st.foo, http://test.foo_.bar and http://test._foo are not

\n

ftp://test_.foo.bar is okay, but ftp://test.fo_o is not

\n

email@_test.foo.bar is okay, but mailto:email@_test.foo is not

", "autolinks|advanced"); + } + + // Domain names that contain invalid characters (not AlphaNumberic, -, _ or .) won't be matched + [Test] + public void ExtensionsAutoLinksValidDomainTests_Example019() + { + // Example 19 + // Section: Extensions / AutoLinks / Valid Domain Tests + // + // The following Markdown: + // https://[your-domain]/api + // + // Should be rendered as: + //

https://[your-domain]/api

+ + Console.WriteLine("Example 19\nSection Extensions / AutoLinks / Valid Domain Tests\n"); + TestParser.TestSpec("https://[your-domain]/api", "

https://[your-domain]/api

", "autolinks|advanced"); + } + + // Domain names followed by ?, : or # instead of / are matched + [Test] + public void ExtensionsAutoLinksValidDomainTests_Example020() + { + // Example 20 + // Section: Extensions / AutoLinks / Valid Domain Tests + // + // The following Markdown: + // https://github.com? + // + // https://github.com?a + // + // https://github.com#a + // + // https://github.com: + // + // https://github.com:443 + // + // Should be rendered as: + //

https://github.com?

+ //

https://github.com?a

+ //

https://github.com#a

+ //

https://github.com:

+ //

https://github.com:443

+ + Console.WriteLine("Example 20\nSection Extensions / AutoLinks / Valid Domain Tests\n"); + TestParser.TestSpec("https://github.com?\n\nhttps://github.com?a\n\nhttps://github.com#a\n\nhttps://github.com:\n\nhttps://github.com:443", "

https://github.com?

\n

https://github.com?a

\n

https://github.com#a

\n

https://github.com:

\n

https://github.com:443

", "autolinks|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/BootstrapSpecs.cs b/src/Markdig.Tests/Specs/BootstrapSpecs.cs new file mode 100644 index 00000000..519f2958 --- /dev/null +++ b/src/Markdig.Tests/Specs/BootstrapSpecs.cs @@ -0,0 +1,111 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Bootstrap +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.Bootstrap +{ + [TestFixture] + public class TestExtensionsBootstrap + { + // # Extensions + // + // Adds support for outputing bootstrap ready tags: + // + // ## Bootstrap + // + // Adds bootstrap `.table` class to ``: + [Test] + public void ExtensionsBootstrap_Example001() + { + // Example 1 + // Section: Extensions / Bootstrap + // + // The following Markdown: + // Name | Value + // -----| ----- + // Abc | 16 + // + // Should be rendered as: + //
+ // + // + // + // + // + // + // + // + // + // + // + // + //
NameValue
Abc16
+ + Console.WriteLine("Example 1\nSection Extensions / Bootstrap\n"); + TestParser.TestSpec("Name | Value\n-----| -----\nAbc | 16", "\n\n\n\n\n\n\n\n\n\n\n\n\n
NameValue
Abc16
", "bootstrap+pipetables+figures+attributes"); + } + + // Adds bootstrap `.blockquote` class to `
`: + [Test] + public void ExtensionsBootstrap_Example002() + { + // Example 2 + // Section: Extensions / Bootstrap + // + // The following Markdown: + // > This is a blockquote + // + // Should be rendered as: + //
+ //

This is a blockquote

+ //
+ + Console.WriteLine("Example 2\nSection Extensions / Bootstrap\n"); + TestParser.TestSpec("> This is a blockquote", "
\n

This is a blockquote

\n
", "bootstrap+pipetables+figures+attributes"); + } + + // Adds bootstrap `.figure` class to `
` and `.figure-caption` to `
` + [Test] + public void ExtensionsBootstrap_Example003() + { + // Example 3 + // Section: Extensions / Bootstrap + // + // The following Markdown: + // ^^^ + // This is a text in a caption + // ^^^ This is the caption + // + // Should be rendered as: + //
+ //

This is a text in a caption

+ //
This is the caption
+ //
+ + Console.WriteLine("Example 3\nSection Extensions / Bootstrap\n"); + TestParser.TestSpec("^^^\nThis is a text in a caption\n^^^ This is the caption", "
\n

This is a text in a caption

\n
This is the caption
\n
", "bootstrap+pipetables+figures+attributes"); + } + + // Adds the `.img-fluid` class to all image links `` + [Test] + public void ExtensionsBootstrap_Example004() + { + // Example 4 + // Section: Extensions / Bootstrap + // + // The following Markdown: + // ![Image Link](/url) + // + // Should be rendered as: + //

Image Link

+ + Console.WriteLine("Example 4\nSection Extensions / Bootstrap\n"); + TestParser.TestSpec("![Image Link](/url)", "

\"Image

", "bootstrap+pipetables+figures+attributes"); + } + } +} diff --git a/src/Markdig.Tests/Specs/CommonMark.cs b/src/Markdig.Tests/Specs/CommonMark.cs new file mode 100644 index 00000000..ef02f104 --- /dev/null +++ b/src/Markdig.Tests/Specs/CommonMark.cs @@ -0,0 +1,14736 @@ +// Generated: 21. 01. 2019 14:31:55 + +// -------------------------------- +// CommonMark v. 0.28 +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.CommonMarkV_0_28 +{ + [TestFixture] + public class TestPreliminariesTabs + { + // --- + // title: CommonMark Spec + // author: John MacFarlane + // version: 0.28 + // date: '2017-08-01' + // license: '[CC-BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)' + // ... + // + // # Introduction + // + // ## What is Markdown? + // + // Markdown is a plain text format for writing structured documents, + // based on conventions for indicating formatting in email + // and usenet posts. It was developed by John Gruber (with + // help from Aaron Swartz) and released in 2004 in the form of a + // [syntax description](http://daringfireball.net/projects/markdown/syntax) + // and a Perl script (`Markdown.pl`) for converting Markdown to + // HTML. In the next decade, dozens of implementations were + // developed in many languages. Some extended the original + // Markdown syntax with conventions for footnotes, tables, and + // other document elements. Some allowed Markdown documents to be + // rendered in formats other than HTML. Websites like Reddit, + // StackOverflow, and GitHub had millions of people using Markdown. + // And Markdown started to be used beyond the web, to author books, + // articles, slide shows, letters, and lecture notes. + // + // What distinguishes Markdown from many other lightweight markup + // syntaxes, which are often easier to write, is its readability. + // As Gruber writes: + // + // > The overriding design goal for Markdown's formatting syntax is + // > to make it as readable as possible. The idea is that a + // > Markdown-formatted document should be publishable as-is, as + // > plain text, without looking like it's been marked up with tags + // > or formatting instructions. + // > () + // + // The point can be illustrated by comparing a sample of + // [AsciiDoc](http://www.methods.co.nz/asciidoc/) with + // an equivalent sample of Markdown. Here is a sample of + // AsciiDoc from the AsciiDoc manual: + // + // ``` + // 1. List item one. + // + + // List item one continued with a second paragraph followed by an + // Indented block. + // + + // ................. + // $ ls *.sh + // $ mv *.sh ~/tmp + // ................. + // + + // List item continued with a third paragraph. + // + // 2. List item two continued with an open block. + // + + // -- + // This paragraph is part of the preceding list item. + // + // a. This list is nested and does not require explicit item + // continuation. + // + + // This paragraph is part of the preceding list item. + // + // b. List item b. + // + // This paragraph belongs to item two of the outer list. + // -- + // ``` + // + // And here is the equivalent in Markdown: + // ``` + // 1. List item one. + // + // List item one continued with a second paragraph followed by an + // Indented block. + // + // $ ls *.sh + // $ mv *.sh ~/tmp + // + // List item continued with a third paragraph. + // + // 2. List item two continued with an open block. + // + // This paragraph is part of the preceding list item. + // + // 1. This list is nested and does not require explicit item continuation. + // + // This paragraph is part of the preceding list item. + // + // 2. List item b. + // + // This paragraph belongs to item two of the outer list. + // ``` + // + // The AsciiDoc version is, arguably, easier to write. You don't need + // to worry about indentation. But the Markdown version is much easier + // to read. The nesting of list items is apparent to the eye in the + // source, not just in the processed document. + // + // ## Why is a spec needed? + // + // John Gruber's [canonical description of Markdown's + // syntax](http://daringfireball.net/projects/markdown/syntax) + // does not specify the syntax unambiguously. Here are some examples of + // questions it does not answer: + // + // 1. How much indentation is needed for a sublist? The spec says that + // continuation paragraphs need to be indented four spaces, but is + // not fully explicit about sublists. It is natural to think that + // they, too, must be indented four spaces, but `Markdown.pl` does + // not require that. This is hardly a "corner case," and divergences + // between implementations on this issue often lead to surprises for + // users in real documents. (See [this comment by John + // Gruber](http://article.gmane.org/gmane.text.markdown.general/1997).) + // + // 2. Is a blank line needed before a block quote or heading? + // Most implementations do not require the blank line. However, + // this can lead to unexpected results in hard-wrapped text, and + // also to ambiguities in parsing (note that some implementations + // put the heading inside the blockquote, while others do not). + // (John Gruber has also spoken [in favor of requiring the blank + // lines](http://article.gmane.org/gmane.text.markdown.general/2146).) + // + // 3. Is a blank line needed before an indented code block? + // (`Markdown.pl` requires it, but this is not mentioned in the + // documentation, and some implementations do not require it.) + // + // ``` markdown + // paragraph + // code? + // ``` + // + // 4. What is the exact rule for determining when list items get + // wrapped in `

` tags? Can a list be partially "loose" and partially + // "tight"? What should we do with a list like this? + // + // ``` markdown + // 1. one + // + // 2. two + // 3. three + // ``` + // + // Or this? + // + // ``` markdown + // 1. one + // - a + // + // - b + // 2. two + // ``` + // + // (There are some relevant comments by John Gruber + // [here](http://article.gmane.org/gmane.text.markdown.general/2554).) + // + // 5. Can list markers be indented? Can ordered list markers be right-aligned? + // + // ``` markdown + // 8. item 1 + // 9. item 2 + // 10. item 2a + // ``` + // + // 6. Is this one list with a thematic break in its second item, + // or two lists separated by a thematic break? + // + // ``` markdown + // * a + // * * * * * + // * b + // ``` + // + // 7. When list markers change from numbers to bullets, do we have + // two lists or one? (The Markdown syntax description suggests two, + // but the perl scripts and many other implementations produce one.) + // + // ``` markdown + // 1. fee + // 2. fie + // - foe + // - fum + // ``` + // + // 8. What are the precedence rules for the markers of inline structure? + // For example, is the following a valid link, or does the code span + // take precedence ? + // + // ``` markdown + // [a backtick (`)](/url) and [another backtick (`)](/url). + // ``` + // + // 9. What are the precedence rules for markers of emphasis and strong + // emphasis? For example, how should the following be parsed? + // + // ``` markdown + // *foo *bar* baz* + // ``` + // + // 10. What are the precedence rules between block-level and inline-level + // structure? For example, how should the following be parsed? + // + // ``` markdown + // - `a long code span can contain a hyphen like this + // - and it can screw things up` + // ``` + // + // 11. Can list items include section headings? (`Markdown.pl` does not + // allow this, but does allow blockquotes to include headings.) + // + // ``` markdown + // - # Heading + // ``` + // + // 12. Can list items be empty? + // + // ``` markdown + // * a + // * + // * b + // ``` + // + // 13. Can link references be defined inside block quotes or list items? + // + // ``` markdown + // > Blockquote [foo]. + // > + // > [foo]: /url + // ``` + // + // 14. If there are multiple definitions for the same reference, which takes + // precedence? + // + // ``` markdown + // [foo]: /url1 + // [foo]: /url2 + // + // [foo][] + // ``` + // + // In the absence of a spec, early implementers consulted `Markdown.pl` + // to resolve these ambiguities. But `Markdown.pl` was quite buggy, and + // gave manifestly bad results in many cases, so it was not a + // satisfactory replacement for a spec. + // + // Because there is no unambiguous spec, implementations have diverged + // considerably. As a result, users are often surprised to find that + // a document that renders one way on one system (say, a github wiki) + // renders differently on another (say, converting to docbook using + // pandoc). To make matters worse, because nothing in Markdown counts + // as a "syntax error," the divergence often isn't discovered right away. + // + // ## About this document + // + // This document attempts to specify Markdown syntax unambiguously. + // It contains many examples with side-by-side Markdown and + // HTML. These are intended to double as conformance tests. An + // accompanying script `spec_tests.py` can be used to run the tests + // against any Markdown program: + // + // python test/spec_tests.py --spec spec.txt --program PROGRAM + // + // Since this document describes how Markdown is to be parsed into + // an abstract syntax tree, it would have made sense to use an abstract + // representation of the syntax tree instead of HTML. But HTML is capable + // of representing the structural distinctions we need to make, and the + // choice of HTML for the tests makes it possible to run the tests against + // an implementation without writing an abstract syntax tree renderer. + // + // This document is generated from a text file, `spec.txt`, written + // in Markdown with a small extension for the side-by-side tests. + // The script `tools/makespec.py` can be used to convert `spec.txt` into + // HTML or CommonMark (which can then be converted into other formats). + // + // In the examples, the `→` character is used to represent tabs. + // + // # Preliminaries + // + // ## Characters and lines + // + // Any sequence of [characters] is a valid CommonMark + // document. + // + // A [character](@) is a Unicode code point. Although some + // code points (for example, combining accents) do not correspond to + // characters in an intuitive sense, all code points count as characters + // for purposes of this spec. + // + // This spec does not specify an encoding; it thinks of lines as composed + // of [characters] rather than bytes. A conforming parser may be limited + // to a certain encoding. + // + // A [line](@) is a sequence of zero or more [characters] + // other than newline (`U+000A`) or carriage return (`U+000D`), + // followed by a [line ending] or by the end of file. + // + // A [line ending](@) is a newline (`U+000A`), a carriage return + // (`U+000D`) not followed by a newline, or a carriage return and a + // following newline. + // + // A line containing no characters, or a line containing only spaces + // (`U+0020`) or tabs (`U+0009`), is called a [blank line](@). + // + // The following definitions of character classes will be used in this spec: + // + // A [whitespace character](@) is a space + // (`U+0020`), tab (`U+0009`), newline (`U+000A`), line tabulation (`U+000B`), + // form feed (`U+000C`), or carriage return (`U+000D`). + // + // [Whitespace](@) is a sequence of one or more [whitespace + // characters]. + // + // A [Unicode whitespace character](@) is + // any code point in the Unicode `Zs` general category, or a tab (`U+0009`), + // carriage return (`U+000D`), newline (`U+000A`), or form feed + // (`U+000C`). + // + // [Unicode whitespace](@) is a sequence of one + // or more [Unicode whitespace characters]. + // + // A [space](@) is `U+0020`. + // + // A [non-whitespace character](@) is any character + // that is not a [whitespace character]. + // + // An [ASCII punctuation character](@) + // is `!`, `"`, `#`, `$`, `%`, `&`, `'`, `(`, `)`, + // `*`, `+`, `,`, `-`, `.`, `/`, `:`, `;`, `<`, `=`, `>`, `?`, `@`, + // `[`, `\`, `]`, `^`, `_`, `` ` ``, `{`, `|`, `}`, or `~`. + // + // A [punctuation character](@) is an [ASCII + // punctuation character] or anything in + // the general Unicode categories `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, or `Ps`. + // + // ## Tabs + // + // Tabs in lines are not expanded to [spaces]. However, + // in contexts where whitespace helps to define block structure, + // tabs behave as if they were replaced by spaces with a tab stop + // of 4 characters. + // + // Thus, for example, a tab can be used instead of four spaces + // in an indented code block. (Note, however, that internal + // tabs are passed through as literal tabs, not expanded to + // spaces.) + [Test] + public void PreliminariesTabs_Example001() + { + // Example 1 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // →foo→baz→→bim + // + // Should be rendered as: + //

foo→baz→→bim
+            //     
+ + Console.WriteLine("Example 1\nSection Preliminaries / Tabs\n"); + TestParser.TestSpec("\tfoo\tbaz\t\tbim", "
foo\tbaz\t\tbim\n
", ""); + } + + [Test] + public void PreliminariesTabs_Example002() + { + // Example 2 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // →foo→baz→→bim + // + // Should be rendered as: + //
foo→baz→→bim
+            //     
+ + Console.WriteLine("Example 2\nSection Preliminaries / Tabs\n"); + TestParser.TestSpec(" \tfoo\tbaz\t\tbim", "
foo\tbaz\t\tbim\n
", ""); + } + + [Test] + public void PreliminariesTabs_Example003() + { + // Example 3 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // a→a + // ὐ→a + // + // Should be rendered as: + //
a→a
+            //     ὐ→a
+            //     
+ + Console.WriteLine("Example 3\nSection Preliminaries / Tabs\n"); + TestParser.TestSpec(" a\ta\n ὐ\ta", "
a\ta\nὐ\ta\n
", ""); + } + + // In the following example, a continuation paragraph of a list + // item is indented with a tab; this has exactly the same effect + // as indentation with four spaces would: + [Test] + public void PreliminariesTabs_Example004() + { + // Example 4 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // - foo + // + // →bar + // + // Should be rendered as: + //
    + //
  • + //

    foo

    + //

    bar

    + //
  • + //
+ + Console.WriteLine("Example 4\nSection Preliminaries / Tabs\n"); + TestParser.TestSpec(" - foo\n\n\tbar", "
    \n
  • \n

    foo

    \n

    bar

    \n
  • \n
", ""); + } + + [Test] + public void PreliminariesTabs_Example005() + { + // Example 5 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // - foo + // + // →→bar + // + // Should be rendered as: + //
    + //
  • + //

    foo

    + //
      bar
    +            //     
    + //
  • + //
+ + Console.WriteLine("Example 5\nSection Preliminaries / Tabs\n"); + TestParser.TestSpec("- foo\n\n\t\tbar", "
    \n
  • \n

    foo

    \n
      bar\n
    \n
  • \n
", ""); + } + + // Normally the `>` that begins a block quote may be followed + // optionally by a space, which is not considered part of the + // content. In the following case `>` is followed by a tab, + // which is treated as if it were expanded into three spaces. + // Since one of these spaces is considered part of the + // delimiter, `foo` is considered to be indented six spaces + // inside the block quote context, so we get an indented + // code block starting with two spaces. + [Test] + public void PreliminariesTabs_Example006() + { + // Example 6 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // >→→foo + // + // Should be rendered as: + //
+ //
  foo
+            //     
+ //
+ + Console.WriteLine("Example 6\nSection Preliminaries / Tabs\n"); + TestParser.TestSpec(">\t\tfoo", "
\n
  foo\n
\n
", ""); + } + + [Test] + public void PreliminariesTabs_Example007() + { + // Example 7 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // -→→foo + // + // Should be rendered as: + //
    + //
  • + //
      foo
    +            //     
    + //
  • + //
+ + Console.WriteLine("Example 7\nSection Preliminaries / Tabs\n"); + TestParser.TestSpec("-\t\tfoo", "
    \n
  • \n
      foo\n
    \n
  • \n
", ""); + } + + [Test] + public void PreliminariesTabs_Example008() + { + // Example 8 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // foo + // →bar + // + // Should be rendered as: + //
foo
+            //     bar
+            //     
+ + Console.WriteLine("Example 8\nSection Preliminaries / Tabs\n"); + TestParser.TestSpec(" foo\n\tbar", "
foo\nbar\n
", ""); + } + + [Test] + public void PreliminariesTabs_Example009() + { + // Example 9 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // - foo + // - bar + // → - baz + // + // Should be rendered as: + //
    + //
  • foo + //
      + //
    • bar + //
        + //
      • baz
      • + //
      + //
    • + //
    + //
  • + //
+ + Console.WriteLine("Example 9\nSection Preliminaries / Tabs\n"); + TestParser.TestSpec(" - foo\n - bar\n\t - baz", "
    \n
  • foo\n
      \n
    • bar\n
        \n
      • baz
      • \n
      \n
    • \n
    \n
  • \n
", ""); + } + + [Test] + public void PreliminariesTabs_Example010() + { + // Example 10 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // #→Foo + // + // Should be rendered as: + //

Foo

+ + Console.WriteLine("Example 10\nSection Preliminaries / Tabs\n"); + TestParser.TestSpec("#\tFoo", "

Foo

", ""); + } + + [Test] + public void PreliminariesTabs_Example011() + { + // Example 11 + // Section: Preliminaries / Tabs + // + // The following Markdown: + // *→*→*→ + // + // Should be rendered as: + //
+ + Console.WriteLine("Example 11\nSection Preliminaries / Tabs\n"); + TestParser.TestSpec("*\t*\t*\t", "
", ""); + } + } + + [TestFixture] + public class TestBlocksAndInlinesPrecedence + { + // ## Insecure characters + // + // For security reasons, the Unicode character `U+0000` must be replaced + // with the REPLACEMENT CHARACTER (`U+FFFD`). + // + // # Blocks and inlines + // + // We can think of a document as a sequence of + // [blocks](@)---structural elements like paragraphs, block + // quotations, lists, headings, rules, and code blocks. Some blocks (like + // block quotes and list items) contain other blocks; others (like + // headings and paragraphs) contain [inline](@) content---text, + // links, emphasized text, images, code spans, and so on. + // + // ## Precedence + // + // Indicators of block structure always take precedence over indicators + // of inline structure. So, for example, the following is a list with + // two items, not a list with one item containing a code span: + [Test] + public void BlocksAndInlinesPrecedence_Example012() + { + // Example 12 + // Section: Blocks and inlines / Precedence + // + // The following Markdown: + // - `one + // - two` + // + // Should be rendered as: + //
    + //
  • `one
  • + //
  • two`
  • + //
+ + Console.WriteLine("Example 12\nSection Blocks and inlines / Precedence\n"); + TestParser.TestSpec("- `one\n- two`", "
    \n
  • `one
  • \n
  • two`
  • \n
", ""); + } + } + + [TestFixture] + public class TestLeafBlocksThematicBreaks + { + // This means that parsing can proceed in two steps: first, the block + // structure of the document can be discerned; second, text lines inside + // paragraphs, headings, and other block constructs can be parsed for inline + // structure. The second step requires information about link reference + // definitions that will be available only at the end of the first + // step. Note that the first step requires processing lines in sequence, + // but the second can be parallelized, since the inline parsing of + // one block element does not affect the inline parsing of any other. + // + // ## Container blocks and leaf blocks + // + // We can divide blocks into two types: + // [container block](@)s, + // which can contain other blocks, and [leaf block](@)s, + // which cannot. + // + // # Leaf blocks + // + // This section describes the different kinds of leaf block that make up a + // Markdown document. + // + // ## Thematic breaks + // + // A line consisting of 0-3 spaces of indentation, followed by a sequence + // of three or more matching `-`, `_`, or `*` characters, each followed + // optionally by any number of spaces, forms a + // [thematic break](@). + [Test] + public void LeafBlocksThematicBreaks_Example013() + { + // Example 13 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // *** + // --- + // ___ + // + // Should be rendered as: + //
+ //
+ //
+ + Console.WriteLine("Example 13\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("***\n---\n___", "
\n
\n
", ""); + } + + // Wrong characters: + [Test] + public void LeafBlocksThematicBreaks_Example014() + { + // Example 14 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // +++ + // + // Should be rendered as: + //

+++

+ + Console.WriteLine("Example 14\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("+++", "

+++

", ""); + } + + [Test] + public void LeafBlocksThematicBreaks_Example015() + { + // Example 15 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // === + // + // Should be rendered as: + //

===

+ + Console.WriteLine("Example 15\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("===", "

===

", ""); + } + + // Not enough characters: + [Test] + public void LeafBlocksThematicBreaks_Example016() + { + // Example 16 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // -- + // ** + // __ + // + // Should be rendered as: + //

-- + // ** + // __

+ + Console.WriteLine("Example 16\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("--\n**\n__", "

--\n**\n__

", ""); + } + + // One to three spaces indent are allowed: + [Test] + public void LeafBlocksThematicBreaks_Example017() + { + // Example 17 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // *** + // *** + // *** + // + // Should be rendered as: + //
+ //
+ //
+ + Console.WriteLine("Example 17\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec(" ***\n ***\n ***", "
\n
\n
", ""); + } + + // Four spaces is too many: + [Test] + public void LeafBlocksThematicBreaks_Example018() + { + // Example 18 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // *** + // + // Should be rendered as: + //
***
+            //     
+ + Console.WriteLine("Example 18\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec(" ***", "
***\n
", ""); + } + + [Test] + public void LeafBlocksThematicBreaks_Example019() + { + // Example 19 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // Foo + // *** + // + // Should be rendered as: + //

Foo + // ***

+ + Console.WriteLine("Example 19\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("Foo\n ***", "

Foo\n***

", ""); + } + + // More than three characters may be used: + [Test] + public void LeafBlocksThematicBreaks_Example020() + { + // Example 20 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // _____________________________________ + // + // Should be rendered as: + //
+ + Console.WriteLine("Example 20\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("_____________________________________", "
", ""); + } + + // Spaces are allowed between the characters: + [Test] + public void LeafBlocksThematicBreaks_Example021() + { + // Example 21 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // - - - + // + // Should be rendered as: + //
+ + Console.WriteLine("Example 21\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec(" - - -", "
", ""); + } + + [Test] + public void LeafBlocksThematicBreaks_Example022() + { + // Example 22 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // ** * ** * ** * ** + // + // Should be rendered as: + //
+ + Console.WriteLine("Example 22\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec(" ** * ** * ** * **", "
", ""); + } + + [Test] + public void LeafBlocksThematicBreaks_Example023() + { + // Example 23 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // - - - - + // + // Should be rendered as: + //
+ + Console.WriteLine("Example 23\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("- - - -", "
", ""); + } + + // Spaces are allowed at the end: + [Test] + public void LeafBlocksThematicBreaks_Example024() + { + // Example 24 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // - - - - + // + // Should be rendered as: + //
+ + Console.WriteLine("Example 24\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("- - - - ", "
", ""); + } + + // However, no other characters may occur in the line: + [Test] + public void LeafBlocksThematicBreaks_Example025() + { + // Example 25 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // _ _ _ _ a + // + // a------ + // + // ---a--- + // + // Should be rendered as: + //

_ _ _ _ a

+ //

a------

+ //

---a---

+ + Console.WriteLine("Example 25\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("_ _ _ _ a\n\na------\n\n---a---", "

_ _ _ _ a

\n

a------

\n

---a---

", ""); + } + + // It is required that all of the [non-whitespace characters] be the same. + // So, this is not a thematic break: + [Test] + public void LeafBlocksThematicBreaks_Example026() + { + // Example 26 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // *-* + // + // Should be rendered as: + //

-

+ + Console.WriteLine("Example 26\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec(" *-*", "

-

", ""); + } + + // Thematic breaks do not need blank lines before or after: + [Test] + public void LeafBlocksThematicBreaks_Example027() + { + // Example 27 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // - foo + // *** + // - bar + // + // Should be rendered as: + //
    + //
  • foo
  • + //
+ //
+ //
    + //
  • bar
  • + //
+ + Console.WriteLine("Example 27\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("- foo\n***\n- bar", "
    \n
  • foo
  • \n
\n
\n
    \n
  • bar
  • \n
", ""); + } + + // Thematic breaks can interrupt a paragraph: + [Test] + public void LeafBlocksThematicBreaks_Example028() + { + // Example 28 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // Foo + // *** + // bar + // + // Should be rendered as: + //

Foo

+ //
+ //

bar

+ + Console.WriteLine("Example 28\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("Foo\n***\nbar", "

Foo

\n
\n

bar

", ""); + } + + // If a line of dashes that meets the above conditions for being a + // thematic break could also be interpreted as the underline of a [setext + // heading], the interpretation as a + // [setext heading] takes precedence. Thus, for example, + // this is a setext heading, not a paragraph followed by a thematic break: + [Test] + public void LeafBlocksThematicBreaks_Example029() + { + // Example 29 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // Foo + // --- + // bar + // + // Should be rendered as: + //

Foo

+ //

bar

+ + Console.WriteLine("Example 29\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("Foo\n---\nbar", "

Foo

\n

bar

", ""); + } + + // When both a thematic break and a list item are possible + // interpretations of a line, the thematic break takes precedence: + [Test] + public void LeafBlocksThematicBreaks_Example030() + { + // Example 30 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // * Foo + // * * * + // * Bar + // + // Should be rendered as: + //
    + //
  • Foo
  • + //
+ //
+ //
    + //
  • Bar
  • + //
+ + Console.WriteLine("Example 30\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("* Foo\n* * *\n* Bar", "
    \n
  • Foo
  • \n
\n
\n
    \n
  • Bar
  • \n
", ""); + } + + // If you want a thematic break in a list item, use a different bullet: + [Test] + public void LeafBlocksThematicBreaks_Example031() + { + // Example 31 + // Section: Leaf blocks / Thematic breaks + // + // The following Markdown: + // - Foo + // - * * * + // + // Should be rendered as: + //
    + //
  • Foo
  • + //
  • + //
    + //
  • + //
+ + Console.WriteLine("Example 31\nSection Leaf blocks / Thematic breaks\n"); + TestParser.TestSpec("- Foo\n- * * *", "
    \n
  • Foo
  • \n
  • \n
    \n
  • \n
", ""); + } + } + + [TestFixture] + public class TestLeafBlocksATXHeadings + { + // ## ATX headings + // + // An [ATX heading](@) + // consists of a string of characters, parsed as inline content, between an + // opening sequence of 1--6 unescaped `#` characters and an optional + // closing sequence of any number of unescaped `#` characters. + // The opening sequence of `#` characters must be followed by a + // [space] or by the end of line. The optional closing sequence of `#`s must be + // preceded by a [space] and may be followed by spaces only. The opening + // `#` character may be indented 0-3 spaces. The raw contents of the + // heading are stripped of leading and trailing spaces before being parsed + // as inline content. The heading level is equal to the number of `#` + // characters in the opening sequence. + // + // Simple headings: + [Test] + public void LeafBlocksATXHeadings_Example032() + { + // Example 32 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // # foo + // ## foo + // ### foo + // #### foo + // ##### foo + // ###### foo + // + // Should be rendered as: + //

foo

+ //

foo

+ //

foo

+ //

foo

+ //
foo
+ //
foo
+ + Console.WriteLine("Example 32\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("# foo\n## foo\n### foo\n#### foo\n##### foo\n###### foo", "

foo

\n

foo

\n

foo

\n

foo

\n
foo
\n
foo
", ""); + } + + // More than six `#` characters is not a heading: + [Test] + public void LeafBlocksATXHeadings_Example033() + { + // Example 33 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // ####### foo + // + // Should be rendered as: + //

####### foo

+ + Console.WriteLine("Example 33\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("####### foo", "

####### foo

", ""); + } + + // At least one space is required between the `#` characters and the + // heading's contents, unless the heading is empty. Note that many + // implementations currently do not require the space. However, the + // space was required by the + // [original ATX implementation](http://www.aaronsw.com/2002/atx/atx.py), + // and it helps prevent things like the following from being parsed as + // headings: + [Test] + public void LeafBlocksATXHeadings_Example034() + { + // Example 34 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // #5 bolt + // + // #hashtag + // + // Should be rendered as: + //

#5 bolt

+ //

#hashtag

+ + Console.WriteLine("Example 34\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("#5 bolt\n\n#hashtag", "

#5 bolt

\n

#hashtag

", ""); + } + + // This is not a heading, because the first `#` is escaped: + [Test] + public void LeafBlocksATXHeadings_Example035() + { + // Example 35 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // \## foo + // + // Should be rendered as: + //

## foo

+ + Console.WriteLine("Example 35\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("\\## foo", "

## foo

", ""); + } + + // Contents are parsed as inlines: + [Test] + public void LeafBlocksATXHeadings_Example036() + { + // Example 36 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // # foo *bar* \*baz\* + // + // Should be rendered as: + //

foo bar *baz*

+ + Console.WriteLine("Example 36\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("# foo *bar* \\*baz\\*", "

foo bar *baz*

", ""); + } + + // Leading and trailing blanks are ignored in parsing inline content: + [Test] + public void LeafBlocksATXHeadings_Example037() + { + // Example 37 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // # foo + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 37\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("# foo ", "

foo

", ""); + } + + // One to three spaces indentation are allowed: + [Test] + public void LeafBlocksATXHeadings_Example038() + { + // Example 38 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // ### foo + // ## foo + // # foo + // + // Should be rendered as: + //

foo

+ //

foo

+ //

foo

+ + Console.WriteLine("Example 38\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec(" ### foo\n ## foo\n # foo", "

foo

\n

foo

\n

foo

", ""); + } + + // Four spaces are too much: + [Test] + public void LeafBlocksATXHeadings_Example039() + { + // Example 39 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // # foo + // + // Should be rendered as: + //
# foo
+            //     
+ + Console.WriteLine("Example 39\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec(" # foo", "
# foo\n
", ""); + } + + [Test] + public void LeafBlocksATXHeadings_Example040() + { + // Example 40 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // foo + // # bar + // + // Should be rendered as: + //

foo + // # bar

+ + Console.WriteLine("Example 40\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("foo\n # bar", "

foo\n# bar

", ""); + } + + // A closing sequence of `#` characters is optional: + [Test] + public void LeafBlocksATXHeadings_Example041() + { + // Example 41 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // ## foo ## + // ### bar ### + // + // Should be rendered as: + //

foo

+ //

bar

+ + Console.WriteLine("Example 41\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("## foo ##\n ### bar ###", "

foo

\n

bar

", ""); + } + + // It need not be the same length as the opening sequence: + [Test] + public void LeafBlocksATXHeadings_Example042() + { + // Example 42 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // # foo ################################## + // ##### foo ## + // + // Should be rendered as: + //

foo

+ //
foo
+ + Console.WriteLine("Example 42\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("# foo ##################################\n##### foo ##", "

foo

\n
foo
", ""); + } + + // Spaces are allowed after the closing sequence: + [Test] + public void LeafBlocksATXHeadings_Example043() + { + // Example 43 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // ### foo ### + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 43\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("### foo ### ", "

foo

", ""); + } + + // A sequence of `#` characters with anything but [spaces] following it + // is not a closing sequence, but counts as part of the contents of the + // heading: + [Test] + public void LeafBlocksATXHeadings_Example044() + { + // Example 44 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // ### foo ### b + // + // Should be rendered as: + //

foo ### b

+ + Console.WriteLine("Example 44\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("### foo ### b", "

foo ### b

", ""); + } + + // The closing sequence must be preceded by a space: + [Test] + public void LeafBlocksATXHeadings_Example045() + { + // Example 45 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // # foo# + // + // Should be rendered as: + //

foo#

+ + Console.WriteLine("Example 45\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("# foo#", "

foo#

", ""); + } + + // Backslash-escaped `#` characters do not count as part + // of the closing sequence: + [Test] + public void LeafBlocksATXHeadings_Example046() + { + // Example 46 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // ### foo \### + // ## foo #\## + // # foo \# + // + // Should be rendered as: + //

foo ###

+ //

foo ###

+ //

foo #

+ + Console.WriteLine("Example 46\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("### foo \\###\n## foo #\\##\n# foo \\#", "

foo ###

\n

foo ###

\n

foo #

", ""); + } + + // ATX headings need not be separated from surrounding content by blank + // lines, and they can interrupt paragraphs: + [Test] + public void LeafBlocksATXHeadings_Example047() + { + // Example 47 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // **** + // ## foo + // **** + // + // Should be rendered as: + //
+ //

foo

+ //
+ + Console.WriteLine("Example 47\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("****\n## foo\n****", "
\n

foo

\n
", ""); + } + + [Test] + public void LeafBlocksATXHeadings_Example048() + { + // Example 48 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // Foo bar + // # baz + // Bar foo + // + // Should be rendered as: + //

Foo bar

+ //

baz

+ //

Bar foo

+ + Console.WriteLine("Example 48\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("Foo bar\n# baz\nBar foo", "

Foo bar

\n

baz

\n

Bar foo

", ""); + } + + // ATX headings can be empty: + [Test] + public void LeafBlocksATXHeadings_Example049() + { + // Example 49 + // Section: Leaf blocks / ATX headings + // + // The following Markdown: + // ## + // # + // ### ### + // + // Should be rendered as: + //

+ //

+ //

+ + Console.WriteLine("Example 49\nSection Leaf blocks / ATX headings\n"); + TestParser.TestSpec("## \n#\n### ###", "

\n

\n

", ""); + } + } + + [TestFixture] + public class TestLeafBlocksSetextHeadings + { + // ## Setext headings + // + // A [setext heading](@) consists of one or more + // lines of text, each containing at least one [non-whitespace + // character], with no more than 3 spaces indentation, followed by + // a [setext heading underline]. The lines of text must be such + // that, were they not followed by the setext heading underline, + // they would be interpreted as a paragraph: they cannot be + // interpretable as a [code fence], [ATX heading][ATX headings], + // [block quote][block quotes], [thematic break][thematic breaks], + // [list item][list items], or [HTML block][HTML blocks]. + // + // A [setext heading underline](@) is a sequence of + // `=` characters or a sequence of `-` characters, with no more than 3 + // spaces indentation and any number of trailing spaces. If a line + // containing a single `-` can be interpreted as an + // empty [list items], it should be interpreted this way + // and not as a [setext heading underline]. + // + // The heading is a level 1 heading if `=` characters are used in + // the [setext heading underline], and a level 2 heading if `-` + // characters are used. The contents of the heading are the result + // of parsing the preceding lines of text as CommonMark inline + // content. + // + // In general, a setext heading need not be preceded or followed by a + // blank line. However, it cannot interrupt a paragraph, so when a + // setext heading comes after a paragraph, a blank line is needed between + // them. + // + // Simple examples: + [Test] + public void LeafBlocksSetextHeadings_Example050() + { + // Example 50 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo *bar* + // ========= + // + // Foo *bar* + // --------- + // + // Should be rendered as: + //

Foo bar

+ //

Foo bar

+ + Console.WriteLine("Example 50\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo *bar*\n=========\n\nFoo *bar*\n---------", "

Foo bar

\n

Foo bar

", ""); + } + + // The content of the header may span more than one line: + [Test] + public void LeafBlocksSetextHeadings_Example051() + { + // Example 51 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo *bar + // baz* + // ==== + // + // Should be rendered as: + //

Foo bar + // baz

+ + Console.WriteLine("Example 51\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo *bar\nbaz*\n====", "

Foo bar\nbaz

", ""); + } + + // The underlining can be any length: + [Test] + public void LeafBlocksSetextHeadings_Example052() + { + // Example 52 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // ------------------------- + // + // Foo + // = + // + // Should be rendered as: + //

Foo

+ //

Foo

+ + Console.WriteLine("Example 52\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo\n-------------------------\n\nFoo\n=", "

Foo

\n

Foo

", ""); + } + + // The heading content can be indented up to three spaces, and need + // not line up with the underlining: + [Test] + public void LeafBlocksSetextHeadings_Example053() + { + // Example 53 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // --- + // + // Foo + // ----- + // + // Foo + // === + // + // Should be rendered as: + //

Foo

+ //

Foo

+ //

Foo

+ + Console.WriteLine("Example 53\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec(" Foo\n---\n\n Foo\n-----\n\n Foo\n ===", "

Foo

\n

Foo

\n

Foo

", ""); + } + + // Four spaces indent is too much: + [Test] + public void LeafBlocksSetextHeadings_Example054() + { + // Example 54 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // --- + // + // Foo + // --- + // + // Should be rendered as: + //
Foo
+            //     ---
+            //     
+            //     Foo
+            //     
+ //
+ + Console.WriteLine("Example 54\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec(" Foo\n ---\n\n Foo\n---", "
Foo\n---\n\nFoo\n
\n
", ""); + } + + // The setext heading underline can be indented up to three spaces, and + // may have trailing spaces: + [Test] + public void LeafBlocksSetextHeadings_Example055() + { + // Example 55 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // ---- + // + // Should be rendered as: + //

Foo

+ + Console.WriteLine("Example 55\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo\n ---- ", "

Foo

", ""); + } + + // Four spaces is too much: + [Test] + public void LeafBlocksSetextHeadings_Example056() + { + // Example 56 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // --- + // + // Should be rendered as: + //

Foo + // ---

+ + Console.WriteLine("Example 56\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo\n ---", "

Foo\n---

", ""); + } + + // The setext heading underline cannot contain internal spaces: + [Test] + public void LeafBlocksSetextHeadings_Example057() + { + // Example 57 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // = = + // + // Foo + // --- - + // + // Should be rendered as: + //

Foo + // = =

+ //

Foo

+ //
+ + Console.WriteLine("Example 57\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo\n= =\n\nFoo\n--- -", "

Foo\n= =

\n

Foo

\n
", ""); + } + + // Trailing spaces in the content line do not cause a line break: + [Test] + public void LeafBlocksSetextHeadings_Example058() + { + // Example 58 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // ----- + // + // Should be rendered as: + //

Foo

+ + Console.WriteLine("Example 58\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo \n-----", "

Foo

", ""); + } + + // Nor does a backslash at the end: + [Test] + public void LeafBlocksSetextHeadings_Example059() + { + // Example 59 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo\ + // ---- + // + // Should be rendered as: + //

Foo\

+ + Console.WriteLine("Example 59\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo\\\n----", "

Foo\\

", ""); + } + + // Since indicators of block structure take precedence over + // indicators of inline structure, the following are setext headings: + [Test] + public void LeafBlocksSetextHeadings_Example060() + { + // Example 60 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // `Foo + // ---- + // ` + // + // + // + // Should be rendered as: + //

`Foo

+ //

`

+ //

<a title="a lot

+ //

of dashes"/>

+ + Console.WriteLine("Example 60\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("`Foo\n----\n`\n\n
", "

`Foo

\n

`

\n

<a title="a lot

\n

of dashes"/>

", ""); + } + + // The setext heading underline cannot be a [lazy continuation + // line] in a list item or block quote: + [Test] + public void LeafBlocksSetextHeadings_Example061() + { + // Example 61 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // > Foo + // --- + // + // Should be rendered as: + //
+ //

Foo

+ //
+ //
+ + Console.WriteLine("Example 61\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("> Foo\n---", "
\n

Foo

\n
\n
", ""); + } + + [Test] + public void LeafBlocksSetextHeadings_Example062() + { + // Example 62 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // > foo + // bar + // === + // + // Should be rendered as: + //
+ //

foo + // bar + // ===

+ //
+ + Console.WriteLine("Example 62\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("> foo\nbar\n===", "
\n

foo\nbar\n===

\n
", ""); + } + + [Test] + public void LeafBlocksSetextHeadings_Example063() + { + // Example 63 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // - Foo + // --- + // + // Should be rendered as: + //
    + //
  • Foo
  • + //
+ //
+ + Console.WriteLine("Example 63\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("- Foo\n---", "
    \n
  • Foo
  • \n
\n
", ""); + } + + // A blank line is needed between a paragraph and a following + // setext heading, since otherwise the paragraph becomes part + // of the heading's content: + [Test] + public void LeafBlocksSetextHeadings_Example064() + { + // Example 64 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // Bar + // --- + // + // Should be rendered as: + //

Foo + // Bar

+ + Console.WriteLine("Example 64\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo\nBar\n---", "

Foo\nBar

", ""); + } + + // But in general a blank line is not required before or after + // setext headings: + [Test] + public void LeafBlocksSetextHeadings_Example065() + { + // Example 65 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // --- + // Foo + // --- + // Bar + // --- + // Baz + // + // Should be rendered as: + //
+ //

Foo

+ //

Bar

+ //

Baz

+ + Console.WriteLine("Example 65\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("---\nFoo\n---\nBar\n---\nBaz", "
\n

Foo

\n

Bar

\n

Baz

", ""); + } + + // Setext headings cannot be empty: + [Test] + public void LeafBlocksSetextHeadings_Example066() + { + // Example 66 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // + // ==== + // + // Should be rendered as: + //

====

+ + Console.WriteLine("Example 66\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("\n====", "

====

", ""); + } + + // Setext heading text lines must not be interpretable as block + // constructs other than paragraphs. So, the line of dashes + // in these examples gets interpreted as a thematic break: + [Test] + public void LeafBlocksSetextHeadings_Example067() + { + // Example 67 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // --- + // --- + // + // Should be rendered as: + //
+ //
+ + Console.WriteLine("Example 67\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("---\n---", "
\n
", ""); + } + + [Test] + public void LeafBlocksSetextHeadings_Example068() + { + // Example 68 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // - foo + // ----- + // + // Should be rendered as: + //
    + //
  • foo
  • + //
+ //
+ + Console.WriteLine("Example 68\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("- foo\n-----", "
    \n
  • foo
  • \n
\n
", ""); + } + + [Test] + public void LeafBlocksSetextHeadings_Example069() + { + // Example 69 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // foo + // --- + // + // Should be rendered as: + //
foo
+            //     
+ //
+ + Console.WriteLine("Example 69\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec(" foo\n---", "
foo\n
\n
", ""); + } + + [Test] + public void LeafBlocksSetextHeadings_Example070() + { + // Example 70 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // > foo + // ----- + // + // Should be rendered as: + //
+ //

foo

+ //
+ //
+ + Console.WriteLine("Example 70\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("> foo\n-----", "
\n

foo

\n
\n
", ""); + } + + // If you want a heading with `> foo` as its literal text, you can + // use backslash escapes: + [Test] + public void LeafBlocksSetextHeadings_Example071() + { + // Example 71 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // \> foo + // ------ + // + // Should be rendered as: + //

> foo

+ + Console.WriteLine("Example 71\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("\\> foo\n------", "

> foo

", ""); + } + + // **Compatibility note:** Most existing Markdown implementations + // do not allow the text of setext headings to span multiple lines. + // But there is no consensus about how to interpret + // + // ``` markdown + // Foo + // bar + // --- + // baz + // ``` + // + // One can find four different interpretations: + // + // 1. paragraph "Foo", heading "bar", paragraph "baz" + // 2. paragraph "Foo bar", thematic break, paragraph "baz" + // 3. paragraph "Foo bar --- baz" + // 4. heading "Foo bar", paragraph "baz" + // + // We find interpretation 4 most natural, and interpretation 4 + // increases the expressive power of CommonMark, by allowing + // multiline headings. Authors who want interpretation 1 can + // put a blank line after the first paragraph: + [Test] + public void LeafBlocksSetextHeadings_Example072() + { + // Example 72 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // + // bar + // --- + // baz + // + // Should be rendered as: + //

Foo

+ //

bar

+ //

baz

+ + Console.WriteLine("Example 72\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo\n\nbar\n---\nbaz", "

Foo

\n

bar

\n

baz

", ""); + } + + // Authors who want interpretation 2 can put blank lines around + // the thematic break, + [Test] + public void LeafBlocksSetextHeadings_Example073() + { + // Example 73 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // bar + // + // --- + // + // baz + // + // Should be rendered as: + //

Foo + // bar

+ //
+ //

baz

+ + Console.WriteLine("Example 73\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo\nbar\n\n---\n\nbaz", "

Foo\nbar

\n
\n

baz

", ""); + } + + // or use a thematic break that cannot count as a [setext heading + // underline], such as + [Test] + public void LeafBlocksSetextHeadings_Example074() + { + // Example 74 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // bar + // * * * + // baz + // + // Should be rendered as: + //

Foo + // bar

+ //
+ //

baz

+ + Console.WriteLine("Example 74\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo\nbar\n* * *\nbaz", "

Foo\nbar

\n
\n

baz

", ""); + } + + // Authors who want interpretation 3 can use backslash escapes: + [Test] + public void LeafBlocksSetextHeadings_Example075() + { + // Example 75 + // Section: Leaf blocks / Setext headings + // + // The following Markdown: + // Foo + // bar + // \--- + // baz + // + // Should be rendered as: + //

Foo + // bar + // --- + // baz

+ + Console.WriteLine("Example 75\nSection Leaf blocks / Setext headings\n"); + TestParser.TestSpec("Foo\nbar\n\\---\nbaz", "

Foo\nbar\n---\nbaz

", ""); + } + } + + [TestFixture] + public class TestLeafBlocksIndentedCodeBlocks + { + // ## Indented code blocks + // + // An [indented code block](@) is composed of one or more + // [indented chunks] separated by blank lines. + // An [indented chunk](@) is a sequence of non-blank lines, + // each indented four or more spaces. The contents of the code block are + // the literal contents of the lines, including trailing + // [line endings], minus four spaces of indentation. + // An indented code block has no [info string]. + // + // An indented code block cannot interrupt a paragraph, so there must be + // a blank line between a paragraph and a following indented code block. + // (A blank line is not needed, however, between a code block and a following + // paragraph.) + [Test] + public void LeafBlocksIndentedCodeBlocks_Example076() + { + // Example 76 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // a simple + // indented code block + // + // Should be rendered as: + //
a simple
+            //       indented code block
+            //     
+ + Console.WriteLine("Example 76\nSection Leaf blocks / Indented code blocks\n"); + TestParser.TestSpec(" a simple\n indented code block", "
a simple\n  indented code block\n
", ""); + } + + // If there is any ambiguity between an interpretation of indentation + // as a code block and as indicating that material belongs to a [list + // item][list items], the list item interpretation takes precedence: + [Test] + public void LeafBlocksIndentedCodeBlocks_Example077() + { + // Example 77 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // - foo + // + // bar + // + // Should be rendered as: + //
    + //
  • + //

    foo

    + //

    bar

    + //
  • + //
+ + Console.WriteLine("Example 77\nSection Leaf blocks / Indented code blocks\n"); + TestParser.TestSpec(" - foo\n\n bar", "
    \n
  • \n

    foo

    \n

    bar

    \n
  • \n
", ""); + } + + [Test] + public void LeafBlocksIndentedCodeBlocks_Example078() + { + // Example 78 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // 1. foo + // + // - bar + // + // Should be rendered as: + //
    + //
  1. + //

    foo

    + //
      + //
    • bar
    • + //
    + //
  2. + //
+ + Console.WriteLine("Example 78\nSection Leaf blocks / Indented code blocks\n"); + TestParser.TestSpec("1. foo\n\n - bar", "
    \n
  1. \n

    foo

    \n
      \n
    • bar
    • \n
    \n
  2. \n
", ""); + } + + // The contents of a code block are literal text, and do not get parsed + // as Markdown: + [Test] + public void LeafBlocksIndentedCodeBlocks_Example079() + { + // Example 79 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + //
+ // *hi* + // + // - one + // + // Should be rendered as: + //
<a/>
+            //     *hi*
+            //     
+            //     - one
+            //     
+ + Console.WriteLine("Example 79\nSection Leaf blocks / Indented code blocks\n"); + TestParser.TestSpec("
\n *hi*\n\n - one", "
<a/>\n*hi*\n\n- one\n
", ""); + } + + // Here we have three chunks separated by blank lines: + [Test] + public void LeafBlocksIndentedCodeBlocks_Example080() + { + // Example 80 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // chunk1 + // + // chunk2 + // + // + // + // chunk3 + // + // Should be rendered as: + //
chunk1
+            //     
+            //     chunk2
+            //     
+            //     
+            //     
+            //     chunk3
+            //     
+ + Console.WriteLine("Example 80\nSection Leaf blocks / Indented code blocks\n"); + TestParser.TestSpec(" chunk1\n\n chunk2\n \n \n \n chunk3", "
chunk1\n\nchunk2\n\n\n\nchunk3\n
", ""); + } + + // Any initial spaces beyond four will be included in the content, even + // in interior blank lines: + [Test] + public void LeafBlocksIndentedCodeBlocks_Example081() + { + // Example 81 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // chunk1 + // + // chunk2 + // + // Should be rendered as: + //
chunk1
+            //       
+            //       chunk2
+            //     
+ + Console.WriteLine("Example 81\nSection Leaf blocks / Indented code blocks\n"); + TestParser.TestSpec(" chunk1\n \n chunk2", "
chunk1\n  \n  chunk2\n
", ""); + } + + // An indented code block cannot interrupt a paragraph. (This + // allows hanging indents and the like.) + [Test] + public void LeafBlocksIndentedCodeBlocks_Example082() + { + // Example 82 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // Foo + // bar + // + // + // Should be rendered as: + //

Foo + // bar

+ + Console.WriteLine("Example 82\nSection Leaf blocks / Indented code blocks\n"); + TestParser.TestSpec("Foo\n bar\n", "

Foo\nbar

", ""); + } + + // However, any non-blank line with fewer than four leading spaces ends + // the code block immediately. So a paragraph may occur immediately + // after indented code: + [Test] + public void LeafBlocksIndentedCodeBlocks_Example083() + { + // Example 83 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // foo + // bar + // + // Should be rendered as: + //
foo
+            //     
+ //

bar

+ + Console.WriteLine("Example 83\nSection Leaf blocks / Indented code blocks\n"); + TestParser.TestSpec(" foo\nbar", "
foo\n
\n

bar

", ""); + } + + // And indented code can occur immediately before and after other kinds of + // blocks: + [Test] + public void LeafBlocksIndentedCodeBlocks_Example084() + { + // Example 84 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // # Heading + // foo + // Heading + // ------ + // foo + // ---- + // + // Should be rendered as: + //

Heading

+ //
foo
+            //     
+ //

Heading

+ //
foo
+            //     
+ //
+ + Console.WriteLine("Example 84\nSection Leaf blocks / Indented code blocks\n"); + TestParser.TestSpec("# Heading\n foo\nHeading\n------\n foo\n----", "

Heading

\n
foo\n
\n

Heading

\n
foo\n
\n
", ""); + } + + // The first line can be indented more than four spaces: + [Test] + public void LeafBlocksIndentedCodeBlocks_Example085() + { + // Example 85 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // foo + // bar + // + // Should be rendered as: + //
    foo
+            //     bar
+            //     
+ + Console.WriteLine("Example 85\nSection Leaf blocks / Indented code blocks\n"); + TestParser.TestSpec(" foo\n bar", "
    foo\nbar\n
", ""); + } + + // Blank lines preceding or following an indented code block + // are not included in it: + [Test] + public void LeafBlocksIndentedCodeBlocks_Example086() + { + // Example 86 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // + // + // foo + // + // + // + // Should be rendered as: + //
foo
+            //     
+ + Console.WriteLine("Example 86\nSection Leaf blocks / Indented code blocks\n"); + TestParser.TestSpec("\n \n foo\n \n", "
foo\n
", ""); + } + + // Trailing spaces are included in the code block's content: + [Test] + public void LeafBlocksIndentedCodeBlocks_Example087() + { + // Example 87 + // Section: Leaf blocks / Indented code blocks + // + // The following Markdown: + // foo + // + // Should be rendered as: + //
foo  
+            //     
+ + Console.WriteLine("Example 87\nSection Leaf blocks / Indented code blocks\n"); + TestParser.TestSpec(" foo ", "
foo  \n
", ""); + } + } + + [TestFixture] + public class TestLeafBlocksFencedCodeBlocks + { + // ## Fenced code blocks + // + // A [code fence](@) is a sequence + // of at least three consecutive backtick characters (`` ` ``) or + // tildes (`~`). (Tildes and backticks cannot be mixed.) + // A [fenced code block](@) + // begins with a code fence, indented no more than three spaces. + // + // The line with the opening code fence may optionally contain some text + // following the code fence; this is trimmed of leading and trailing + // spaces and called the [info string](@). + // The [info string] may not contain any backtick + // characters. (The reason for this restriction is that otherwise + // some inline code would be incorrectly interpreted as the + // beginning of a fenced code block.) + // + // The content of the code block consists of all subsequent lines, until + // a closing [code fence] of the same type as the code block + // began with (backticks or tildes), and with at least as many backticks + // or tildes as the opening code fence. If the leading code fence is + // indented N spaces, then up to N spaces of indentation are removed from + // each line of the content (if present). (If a content line is not + // indented, it is preserved unchanged. If it is indented less than N + // spaces, all of the indentation is removed.) + // + // The closing code fence may be indented up to three spaces, and may be + // followed only by spaces, which are ignored. If the end of the + // containing block (or document) is reached and no closing code fence + // has been found, the code block contains all of the lines after the + // opening code fence until the end of the containing block (or + // document). (An alternative spec would require backtracking in the + // event that a closing code fence is not found. But this makes parsing + // much less efficient, and there seems to be no real down side to the + // behavior described here.) + // + // A fenced code block may interrupt a paragraph, and does not require + // a blank line either before or after. + // + // The content of a code fence is treated as literal text, not parsed + // as inlines. The first word of the [info string] is typically used to + // specify the language of the code sample, and rendered in the `class` + // attribute of the `code` tag. However, this spec does not mandate any + // particular treatment of the [info string]. + // + // Here is a simple example with backticks: + [Test] + public void LeafBlocksFencedCodeBlocks_Example088() + { + // Example 88 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // < + // > + // ``` + // + // Should be rendered as: + //
<
+            //      >
+            //     
+ + Console.WriteLine("Example 88\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("```\n<\n >\n```", "
<\n >\n
", ""); + } + + // With tildes: + [Test] + public void LeafBlocksFencedCodeBlocks_Example089() + { + // Example 89 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ~~~ + // < + // > + // ~~~ + // + // Should be rendered as: + //
<
+            //      >
+            //     
+ + Console.WriteLine("Example 89\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("~~~\n<\n >\n~~~", "
<\n >\n
", ""); + } + + // Fewer than three backticks is not enough: + [Test] + public void LeafBlocksFencedCodeBlocks_Example090() + { + // Example 90 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // `` + // foo + // `` + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 90\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("``\nfoo\n``", "

foo

", ""); + } + + // The closing code fence must use the same character as the opening + // fence: + [Test] + public void LeafBlocksFencedCodeBlocks_Example091() + { + // Example 91 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // aaa + // ~~~ + // ``` + // + // Should be rendered as: + //
aaa
+            //     ~~~
+            //     
+ + Console.WriteLine("Example 91\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("```\naaa\n~~~\n```", "
aaa\n~~~\n
", ""); + } + + [Test] + public void LeafBlocksFencedCodeBlocks_Example092() + { + // Example 92 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ~~~ + // aaa + // ``` + // ~~~ + // + // Should be rendered as: + //
aaa
+            //     ```
+            //     
+ + Console.WriteLine("Example 92\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("~~~\naaa\n```\n~~~", "
aaa\n```\n
", ""); + } + + // The closing code fence must be at least as long as the opening fence: + [Test] + public void LeafBlocksFencedCodeBlocks_Example093() + { + // Example 93 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ```` + // aaa + // ``` + // `````` + // + // Should be rendered as: + //
aaa
+            //     ```
+            //     
+ + Console.WriteLine("Example 93\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("````\naaa\n```\n``````", "
aaa\n```\n
", ""); + } + + [Test] + public void LeafBlocksFencedCodeBlocks_Example094() + { + // Example 94 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ~~~~ + // aaa + // ~~~ + // ~~~~ + // + // Should be rendered as: + //
aaa
+            //     ~~~
+            //     
+ + Console.WriteLine("Example 94\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("~~~~\naaa\n~~~\n~~~~", "
aaa\n~~~\n
", ""); + } + + // Unclosed code blocks are closed by the end of the document + // (or the enclosing [block quote][block quotes] or [list item][list items]): + [Test] + public void LeafBlocksFencedCodeBlocks_Example095() + { + // Example 95 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // + // Should be rendered as: + //
+ + Console.WriteLine("Example 95\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("```", "
", ""); + } + + [Test] + public void LeafBlocksFencedCodeBlocks_Example096() + { + // Example 96 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ````` + // + // ``` + // aaa + // + // Should be rendered as: + //

+            //     ```
+            //     aaa
+            //     
+ + Console.WriteLine("Example 96\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("`````\n\n```\naaa", "
\n```\naaa\n
", ""); + } + + [Test] + public void LeafBlocksFencedCodeBlocks_Example097() + { + // Example 97 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // > ``` + // > aaa + // + // bbb + // + // Should be rendered as: + //
+ //
aaa
+            //     
+ //
+ //

bbb

+ + Console.WriteLine("Example 97\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("> ```\n> aaa\n\nbbb", "
\n
aaa\n
\n
\n

bbb

", ""); + } + + // A code block can have all empty lines as its content: + [Test] + public void LeafBlocksFencedCodeBlocks_Example098() + { + // Example 98 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // + // + // ``` + // + // Should be rendered as: + //

+            //       
+            //     
+ + Console.WriteLine("Example 98\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("```\n\n \n```", "
\n  \n
", ""); + } + + // A code block can be empty: + [Test] + public void LeafBlocksFencedCodeBlocks_Example099() + { + // Example 99 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // ``` + // + // Should be rendered as: + //
+ + Console.WriteLine("Example 99\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("```\n```", "
", ""); + } + + // Fences can be indented. If the opening fence is indented, + // content lines will have equivalent opening indentation removed, + // if present: + [Test] + public void LeafBlocksFencedCodeBlocks_Example100() + { + // Example 100 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // aaa + // aaa + // ``` + // + // Should be rendered as: + //
aaa
+            //     aaa
+            //     
+ + Console.WriteLine("Example 100\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec(" ```\n aaa\naaa\n```", "
aaa\naaa\n
", ""); + } + + [Test] + public void LeafBlocksFencedCodeBlocks_Example101() + { + // Example 101 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // aaa + // aaa + // aaa + // ``` + // + // Should be rendered as: + //
aaa
+            //     aaa
+            //     aaa
+            //     
+ + Console.WriteLine("Example 101\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec(" ```\naaa\n aaa\naaa\n ```", "
aaa\naaa\naaa\n
", ""); + } + + [Test] + public void LeafBlocksFencedCodeBlocks_Example102() + { + // Example 102 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // aaa + // aaa + // aaa + // ``` + // + // Should be rendered as: + //
aaa
+            //      aaa
+            //     aaa
+            //     
+ + Console.WriteLine("Example 102\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec(" ```\n aaa\n aaa\n aaa\n ```", "
aaa\n aaa\naaa\n
", ""); + } + + // Four spaces indentation produces an indented code block: + [Test] + public void LeafBlocksFencedCodeBlocks_Example103() + { + // Example 103 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // aaa + // ``` + // + // Should be rendered as: + //
```
+            //     aaa
+            //     ```
+            //     
+ + Console.WriteLine("Example 103\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec(" ```\n aaa\n ```", "
```\naaa\n```\n
", ""); + } + + // Closing fences may be indented by 0-3 spaces, and their indentation + // need not match that of the opening fence: + [Test] + public void LeafBlocksFencedCodeBlocks_Example104() + { + // Example 104 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // aaa + // ``` + // + // Should be rendered as: + //
aaa
+            //     
+ + Console.WriteLine("Example 104\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("```\naaa\n ```", "
aaa\n
", ""); + } + + [Test] + public void LeafBlocksFencedCodeBlocks_Example105() + { + // Example 105 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // aaa + // ``` + // + // Should be rendered as: + //
aaa
+            //     
+ + Console.WriteLine("Example 105\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec(" ```\naaa\n ```", "
aaa\n
", ""); + } + + // This is not a closing fence, because it is indented 4 spaces: + [Test] + public void LeafBlocksFencedCodeBlocks_Example106() + { + // Example 106 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // aaa + // ``` + // + // Should be rendered as: + //
aaa
+            //         ```
+            //     
+ + Console.WriteLine("Example 106\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("```\naaa\n ```", "
aaa\n    ```\n
", ""); + } + + // Code fences (opening and closing) cannot contain internal spaces: + [Test] + public void LeafBlocksFencedCodeBlocks_Example107() + { + // Example 107 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` ``` + // aaa + // + // Should be rendered as: + //

+ // aaa

+ + Console.WriteLine("Example 107\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("``` ```\naaa", "

\naaa

", ""); + } + + [Test] + public void LeafBlocksFencedCodeBlocks_Example108() + { + // Example 108 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ~~~~~~ + // aaa + // ~~~ ~~ + // + // Should be rendered as: + //
aaa
+            //     ~~~ ~~
+            //     
+ + Console.WriteLine("Example 108\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("~~~~~~\naaa\n~~~ ~~", "
aaa\n~~~ ~~\n
", ""); + } + + // Fenced code blocks can interrupt paragraphs, and can be followed + // directly by paragraphs, without a blank line between: + [Test] + public void LeafBlocksFencedCodeBlocks_Example109() + { + // Example 109 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // foo + // ``` + // bar + // ``` + // baz + // + // Should be rendered as: + //

foo

+ //
bar
+            //     
+ //

baz

+ + Console.WriteLine("Example 109\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("foo\n```\nbar\n```\nbaz", "

foo

\n
bar\n
\n

baz

", ""); + } + + // Other blocks can also occur before and after fenced code blocks + // without an intervening blank line: + [Test] + public void LeafBlocksFencedCodeBlocks_Example110() + { + // Example 110 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // foo + // --- + // ~~~ + // bar + // ~~~ + // # baz + // + // Should be rendered as: + //

foo

+ //
bar
+            //     
+ //

baz

+ + Console.WriteLine("Example 110\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("foo\n---\n~~~\nbar\n~~~\n# baz", "

foo

\n
bar\n
\n

baz

", ""); + } + + // An [info string] can be provided after the opening code fence. + // Opening and closing spaces will be stripped, and the first word, prefixed + // with `language-`, is used as the value for the `class` attribute of the + // `code` element within the enclosing `pre` element. + [Test] + public void LeafBlocksFencedCodeBlocks_Example111() + { + // Example 111 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ```ruby + // def foo(x) + // return 3 + // end + // ``` + // + // Should be rendered as: + //
def foo(x)
+            //       return 3
+            //     end
+            //     
+ + Console.WriteLine("Example 111\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("```ruby\ndef foo(x)\n return 3\nend\n```", "
def foo(x)\n  return 3\nend\n
", ""); + } + + [Test] + public void LeafBlocksFencedCodeBlocks_Example112() + { + // Example 112 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ~~~~ ruby startline=3 $%@#$ + // def foo(x) + // return 3 + // end + // ~~~~~~~ + // + // Should be rendered as: + //
def foo(x)
+            //       return 3
+            //     end
+            //     
+ + Console.WriteLine("Example 112\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("~~~~ ruby startline=3 $%@#$\ndef foo(x)\n return 3\nend\n~~~~~~~", "
def foo(x)\n  return 3\nend\n
", ""); + } + + [Test] + public void LeafBlocksFencedCodeBlocks_Example113() + { + // Example 113 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ````; + // ```` + // + // Should be rendered as: + //
+ + Console.WriteLine("Example 113\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("````;\n````", "
", ""); + } + + // [Info strings] for backtick code blocks cannot contain backticks: + [Test] + public void LeafBlocksFencedCodeBlocks_Example114() + { + // Example 114 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` aa ``` + // foo + // + // Should be rendered as: + //

aa + // foo

+ + Console.WriteLine("Example 114\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("``` aa ```\nfoo", "

aa\nfoo

", ""); + } + + // Closing code fences cannot have [info strings]: + [Test] + public void LeafBlocksFencedCodeBlocks_Example115() + { + // Example 115 + // Section: Leaf blocks / Fenced code blocks + // + // The following Markdown: + // ``` + // ``` aaa + // ``` + // + // Should be rendered as: + //
``` aaa
+            //     
+ + Console.WriteLine("Example 115\nSection Leaf blocks / Fenced code blocks\n"); + TestParser.TestSpec("```\n``` aaa\n```", "
``` aaa\n
", ""); + } + } + + [TestFixture] + public class TestLeafBlocksHTMLBlocks + { + // ## HTML blocks + // + // An [HTML block](@) is a group of lines that is treated + // as raw HTML (and will not be escaped in HTML output). + // + // There are seven kinds of [HTML block], which can be defined + // by their start and end conditions. The block begins with a line that + // meets a [start condition](@) (after up to three spaces + // optional indentation). It ends with the first subsequent line that + // meets a matching [end condition](@), or the last line of + // the document or other [container block]), if no line is encountered that meets the + // [end condition]. If the first line meets both the [start condition] + // and the [end condition], the block will contain just that line. + // + // 1. **Start condition:** line begins with the string ``, or the end of the line.\ + // **End condition:** line contains an end tag + // ``, ``, or `` (case-insensitive; it + // need not match the start tag). + // + // 2. **Start condition:** line begins with the string ``. + // + // 3. **Start condition:** line begins with the string ``. + // + // 4. **Start condition:** line begins with the string ``. + // + // 5. **Start condition:** line begins with the string + // ``. + // + // 6. **Start condition:** line begins the string `<` or ``, or + // the string `/>`.\ + // **End condition:** line is followed by a [blank line]. + // + // 7. **Start condition:** line begins with a complete [open tag] + // or [closing tag] (with any [tag name] other than `script`, + // `style`, or `pre`) followed only by [whitespace] + // or the end of the line.\ + // **End condition:** line is followed by a [blank line]. + // + // HTML blocks continue until they are closed by their appropriate + // [end condition], or the last line of the document or other [container block]. + // This means any HTML **within an HTML block** that might otherwise be recognised + // as a start condition will be ignored by the parser and passed through as-is, + // without changing the parser's state. + // + // For instance, `
` within a HTML block started by `` will not affect
+        // the parser state; as the HTML block was started in by start condition 6, it
+        // will end at any blank line. This can be surprising:
+        [Test]
+        public void LeafBlocksHTMLBlocks_Example116()
+        {
+            // Example 116
+            // Section: Leaf blocks / HTML blocks
+            //
+            // The following Markdown:
+            //     
+ //
+            //     **Hello**,
+            //     
+            //     _world_.
+            //     
+ //
+ // + // Should be rendered as: + //
+ //
+            //     **Hello**,
+            //     

world. + //

+ //
+ + Console.WriteLine("Example 116\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("
\n
\n**Hello**,\n\n_world_.\n
\n
", "
\n
\n**Hello**,\n

world.\n

\n
", ""); + } + + // In this case, the HTML block is terminated by the newline — the `**hello**` + // text remains verbatim — and regular parsing resumes, with a paragraph, + // emphasised `world` and inline and block HTML following. + // + // All types of [HTML blocks] except type 7 may interrupt + // a paragraph. Blocks of type 7 may not interrupt a paragraph. + // (This restriction is intended to prevent unwanted interpretation + // of long tags inside a wrapped paragraph as starting HTML blocks.) + // + // Some simple examples follow. Here are some basic HTML blocks + // of type 6: + [Test] + public void LeafBlocksHTMLBlocks_Example117() + { + // Example 117 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // + // + // + //
+ // hi + //
+ // + // okay. + // + // Should be rendered as: + // + // + // + // + //
+ // hi + //
+ //

okay.

+ + Console.WriteLine("Example 117\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\n \n \n \n
\n hi\n
\n\nokay.", "\n \n \n \n
\n hi\n
\n

okay.

", ""); + } + + [Test] + public void LeafBlocksHTMLBlocks_Example118() + { + // Example 118 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //
\n*foo*", ""); + } + + // Here we have two HTML blocks with a Markdown paragraph between them: + [Test] + public void LeafBlocksHTMLBlocks_Example120() + { + // Example 120 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //
+ // + // *Markdown* + // + //
+ // + // Should be rendered as: + //
+ //

Markdown

+ //
+ + Console.WriteLine("Example 120\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("
\n\n*Markdown*\n\n
", "
\n

Markdown

\n
", ""); + } + + // The tag on the first line can be partial, as long + // as it is split where there would be whitespace: + [Test] + public void LeafBlocksHTMLBlocks_Example121() + { + // Example 121 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //
+ //
+ // + // Should be rendered as: + //
+ //
+ + Console.WriteLine("Example 121\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("
\n
", "
\n
", ""); + } + + [Test] + public void LeafBlocksHTMLBlocks_Example122() + { + // Example 122 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //
+ //
+ // + // Should be rendered as: + //
+ //
+ + Console.WriteLine("Example 122\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("
\n
", "
\n
", ""); + } + + // An open tag need not be closed: + [Test] + public void LeafBlocksHTMLBlocks_Example123() + { + // Example 123 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //
+ // *foo* + // + // *bar* + // + // Should be rendered as: + //
+ // *foo* + //

bar

+ + Console.WriteLine("Example 123\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("
\n*foo*\n\n*bar*", "
\n*foo*\n

bar

", ""); + } + + // A partial tag need not even be completed (garbage + // in, garbage out): + [Test] + public void LeafBlocksHTMLBlocks_Example124() + { + // Example 124 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //
+ // + // Should be rendered as: + // + + Console.WriteLine("Example 127\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("", "", ""); + } + + [Test] + public void LeafBlocksHTMLBlocks_Example128() + { + // Example 128 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //
+ // foo + //
+ // + // Should be rendered as: + //
+ // foo + //
+ + Console.WriteLine("Example 128\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("
\nfoo\n
", "
\nfoo\n
", ""); + } + + // Everything until the next blank line or end of document + // gets included in the HTML block. So, in the following + // example, what looks like a Markdown code block + // is actually part of the HTML block, which continues until a blank + // line or the end of the document is reached: + [Test] + public void LeafBlocksHTMLBlocks_Example129() + { + // Example 129 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //
+ // ``` c + // int x = 33; + // ``` + // + // Should be rendered as: + //
+ // ``` c + // int x = 33; + // ``` + + Console.WriteLine("Example 129\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("
\n``` c\nint x = 33;\n```", "
\n``` c\nint x = 33;\n```", ""); + } + + // To start an [HTML block] with a tag that is *not* in the + // list of block-level tags in (6), you must put the tag by + // itself on the first line (and it must be complete): + [Test] + public void LeafBlocksHTMLBlocks_Example130() + { + // Example 130 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // *bar* + // + // + // Should be rendered as: + // + // *bar* + // + + Console.WriteLine("Example 130\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\n*bar*\n", "\n*bar*\n", ""); + } + + // In type 7 blocks, the [tag name] can be anything: + [Test] + public void LeafBlocksHTMLBlocks_Example131() + { + // Example 131 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // *bar* + // + // + // Should be rendered as: + // + // *bar* + // + + Console.WriteLine("Example 131\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\n*bar*\n", "\n*bar*\n", ""); + } + + [Test] + public void LeafBlocksHTMLBlocks_Example132() + { + // Example 132 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // *bar* + // + // + // Should be rendered as: + // + // *bar* + // + + Console.WriteLine("Example 132\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\n*bar*\n", "\n*bar*\n", ""); + } + + [Test] + public void LeafBlocksHTMLBlocks_Example133() + { + // Example 133 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // *bar* + // + // Should be rendered as: + // + // *bar* + + Console.WriteLine("Example 133\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\n*bar*", "\n*bar*", ""); + } + + // These rules are designed to allow us to work with tags that + // can function as either block-level or inline-level tags. + // The `` tag is a nice example. We can surround content with + // `` tags in three different ways. In this case, we get a raw + // HTML block, because the `` tag is on a line by itself: + [Test] + public void LeafBlocksHTMLBlocks_Example134() + { + // Example 134 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // *foo* + // + // + // Should be rendered as: + // + // *foo* + // + + Console.WriteLine("Example 134\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\n*foo*\n", "\n*foo*\n", ""); + } + + // In this case, we get a raw HTML block that just includes + // the `` tag (because it ends with the following blank + // line). So the contents get interpreted as CommonMark: + [Test] + public void LeafBlocksHTMLBlocks_Example135() + { + // Example 135 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // + // *foo* + // + // + // + // Should be rendered as: + // + //

foo

+ //
+ + Console.WriteLine("Example 135\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\n\n*foo*\n\n", "\n

foo

\n
", ""); + } + + // Finally, in this case, the `` tags are interpreted + // as [raw HTML] *inside* the CommonMark paragraph. (Because + // the tag is not on a line by itself, we get inline HTML + // rather than an [HTML block].) + [Test] + public void LeafBlocksHTMLBlocks_Example136() + { + // Example 136 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // *foo* + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 136\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("*foo*", "

foo

", ""); + } + + // HTML tags designed to contain literal content + // (`script`, `style`, `pre`), comments, processing instructions, + // and declarations are treated somewhat differently. + // Instead of ending at the first blank line, these blocks + // end at the first line containing a corresponding end tag. + // As a result, these blocks can contain blank lines: + // + // A pre tag (type 1): + [Test] + public void LeafBlocksHTMLBlocks_Example137() + { + // Example 137 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //

+            //     import Text.HTML.TagSoup
+            //     
+            //     main :: IO ()
+            //     main = print $ parseTags tags
+            //     
+ // okay + // + // Should be rendered as: + //

+            //     import Text.HTML.TagSoup
+            //     
+            //     main :: IO ()
+            //     main = print $ parseTags tags
+            //     
+ //

okay

+ + Console.WriteLine("Example 137\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("
\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n
\nokay", "
\nimport Text.HTML.TagSoup\n\nmain :: IO ()\nmain = print $ parseTags tags\n
\n

okay

", ""); + } + + // A script tag (type 1): + [Test] + public void LeafBlocksHTMLBlocks_Example138() + { + // Example 138 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // okay + // + // Should be rendered as: + // + //

okay

+ + Console.WriteLine("Example 138\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\nokay", "\n

okay

", ""); + } + + // A style tag (type 1): + [Test] + public void LeafBlocksHTMLBlocks_Example139() + { + // Example 139 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // okay + // + // Should be rendered as: + // + //

okay

+ + Console.WriteLine("Example 139\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\nh1 {color:red;}\n\np {color:blue;}\n\nokay", "\nh1 {color:red;}\n\np {color:blue;}\n\n

okay

", ""); + } + + // If there is no matching end tag, the block will end at the + // end of the document (or the enclosing [block quote][block quotes] + // or [list item][list items]): + [Test] + public void LeafBlocksHTMLBlocks_Example140() + { + // Example 140 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // *foo* + // + // Should be rendered as: + // + //

foo

+ + Console.WriteLine("Example 143\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\n*foo*", "\n

foo

", ""); + } + + [Test] + public void LeafBlocksHTMLBlocks_Example144() + { + // Example 144 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // *bar* + // *baz* + // + // Should be rendered as: + // *bar* + //

baz

+ + Console.WriteLine("Example 144\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("*bar*\n*baz*", "*bar*\n

baz

", ""); + } + + // Note that anything on the last line after the + // end tag will be included in the [HTML block]: + [Test] + public void LeafBlocksHTMLBlocks_Example145() + { + // Example 145 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // 1. *bar* + // + // Should be rendered as: + // 1. *bar* + + Console.WriteLine("Example 145\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("1. *bar*", "1. *bar*", ""); + } + + // A comment (type 2): + [Test] + public void LeafBlocksHTMLBlocks_Example146() + { + // Example 146 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // okay + // + // Should be rendered as: + // + //

okay

+ + Console.WriteLine("Example 146\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\nokay", "\n

okay

", ""); + } + + // A processing instruction (type 3): + [Test] + public void LeafBlocksHTMLBlocks_Example147() + { + // Example 147 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // '; + // + // ?> + // okay + // + // Should be rendered as: + // '; + // + // ?> + //

okay

+ + Console.WriteLine("Example 147\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("';\n\n?>\nokay", "';\n\n?>\n

okay

", ""); + } + + // A declaration (type 4): + [Test] + public void LeafBlocksHTMLBlocks_Example148() + { + // Example 148 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // + // Should be rendered as: + // + + Console.WriteLine("Example 148\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("", "", ""); + } + + // CDATA (type 5): + [Test] + public void LeafBlocksHTMLBlocks_Example149() + { + // Example 149 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // okay + // + // Should be rendered as: + // + //

okay

+ + Console.WriteLine("Example 149\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\nokay", "\n

okay

", ""); + } + + // The opening tag can be indented 1-3 spaces, but not 4: + [Test] + public void LeafBlocksHTMLBlocks_Example150() + { + // Example 150 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // + // + // + // Should be rendered as: + // + //
<!-- foo -->
+            //     
+ + Console.WriteLine("Example 150\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec(" \n\n ", " \n
<!-- foo -->\n
", ""); + } + + [Test] + public void LeafBlocksHTMLBlocks_Example151() + { + // Example 151 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //
+ // + //
+ // + // Should be rendered as: + //
+ //
<div>
+            //     
+ + Console.WriteLine("Example 151\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("
\n\n
", "
\n
<div>\n
", ""); + } + + // An HTML block of types 1--6 can interrupt a paragraph, and need not be + // preceded by a blank line. + [Test] + public void LeafBlocksHTMLBlocks_Example152() + { + // Example 152 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // Foo + //
+ // bar + //
+ // + // Should be rendered as: + //

Foo

+ //
+ // bar + //
+ + Console.WriteLine("Example 152\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("Foo\n
\nbar\n
", "

Foo

\n
\nbar\n
", ""); + } + + // However, a following blank line is needed, except at the end of + // a document, and except for blocks of types 1--5, above: + [Test] + public void LeafBlocksHTMLBlocks_Example153() + { + // Example 153 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //
+ // bar + //
+ // *foo* + // + // Should be rendered as: + //
+ // bar + //
+ // *foo* + + Console.WriteLine("Example 153\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("
\nbar\n
\n*foo*", "
\nbar\n
\n*foo*", ""); + } + + // HTML blocks of type 7 cannot interrupt a paragraph: + [Test] + public void LeafBlocksHTMLBlocks_Example154() + { + // Example 154 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // Foo + // + // baz + // + // Should be rendered as: + //

Foo + // + // baz

+ + Console.WriteLine("Example 154\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("Foo\n\nbaz", "

Foo\n\nbaz

", ""); + } + + // This rule differs from John Gruber's original Markdown syntax + // specification, which says: + // + // > The only restrictions are that block-level HTML elements — + // > e.g. `
`, ``, `
`, `

`, etc. — must be separated from + // > surrounding content by blank lines, and the start and end tags of the + // > block should not be indented with tabs or spaces. + // + // In some ways Gruber's rule is more restrictive than the one given + // here: + // + // - It requires that an HTML block be preceded by a blank line. + // - It does not allow the start tag to be indented. + // - It requires a matching end tag, which it also does not allow to + // be indented. + // + // Most Markdown implementations (including some of Gruber's own) do not + // respect all of these restrictions. + // + // There is one respect, however, in which Gruber's rule is more liberal + // than the one given here, since it allows blank lines to occur inside + // an HTML block. There are two reasons for disallowing them here. + // First, it removes the need to parse balanced tags, which is + // expensive and can require backtracking from the end of the document + // if no matching end tag is found. Second, it provides a very simple + // and flexible way of including Markdown content inside HTML tags: + // simply separate the Markdown from the HTML using blank lines: + // + // Compare: + [Test] + public void LeafBlocksHTMLBlocks_Example155() + { + // Example 155 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //

+ // + // *Emphasized* text. + // + //
+ // + // Should be rendered as: + //
+ //

Emphasized text.

+ //
+ + Console.WriteLine("Example 155\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("
\n\n*Emphasized* text.\n\n
", "
\n

Emphasized text.

\n
", ""); + } + + [Test] + public void LeafBlocksHTMLBlocks_Example156() + { + // Example 156 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //
+ // *Emphasized* text. + //
+ // + // Should be rendered as: + //
+ // *Emphasized* text. + //
+ + Console.WriteLine("Example 156\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("
\n*Emphasized* text.\n
", "
\n*Emphasized* text.\n
", ""); + } + + // Some Markdown implementations have adopted a convention of + // interpreting content inside tags as text if the open tag has + // the attribute `markdown=1`. The rule given above seems a simpler and + // more elegant way of achieving the same expressive power, which is also + // much simpler to parse. + // + // The main potential drawback is that one can no longer paste HTML + // blocks into Markdown documents with 100% reliability. However, + // *in most cases* this will work fine, because the blank lines in + // HTML are usually followed by HTML block tags. For example: + [Test] + public void LeafBlocksHTMLBlocks_Example157() + { + // Example 157 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + //
+ // + // + // + // + // + // + // + //
+ // Hi + //
+ // + // Should be rendered as: + // + // + // + // + //
+ // Hi + //
+ + Console.WriteLine("Example 157\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\n\n\n\n\n\n\n\n
\nHi\n
", "\n\n\n\n
\nHi\n
", ""); + } + + // There are problems, however, if the inner tags are indented + // *and* separated by spaces, as then they will be interpreted as + // an indented code block: + [Test] + public void LeafBlocksHTMLBlocks_Example158() + { + // Example 158 + // Section: Leaf blocks / HTML blocks + // + // The following Markdown: + // + // + // + // + // + // + // + // + //
+ // Hi + //
+ // + // Should be rendered as: + // + // + //
<td>
+            //       Hi
+            //     </td>
+            //     
+ // + //
+ + Console.WriteLine("Example 158\nSection Leaf blocks / HTML blocks\n"); + TestParser.TestSpec("\n\n \n\n \n\n \n\n
\n Hi\n
", "\n \n
<td>\n  Hi\n</td>\n
\n \n
", ""); + } + } + + [TestFixture] + public class TestLeafBlocksLinkReferenceDefinitions + { + // Fortunately, blank lines are usually not necessary and can be + // deleted. The exception is inside `
` tags, but as described
+        // above, raw HTML blocks starting with `
` *can* contain blank
+        // lines.
+        // 
+        // ## Link reference definitions
+        // 
+        // A [link reference definition](@)
+        // consists of a [link label], indented up to three spaces, followed
+        // by a colon (`:`), optional [whitespace] (including up to one
+        // [line ending]), a [link destination],
+        // optional [whitespace] (including up to one
+        // [line ending]), and an optional [link
+        // title], which if it is present must be separated
+        // from the [link destination] by [whitespace].
+        // No further [non-whitespace characters] may occur on the line.
+        // 
+        // A [link reference definition]
+        // does not correspond to a structural element of a document.  Instead, it
+        // defines a label which can be used in [reference links]
+        // and reference-style [images] elsewhere in the document.  [Link
+        // reference definitions] can come either before or after the links that use
+        // them.
+        [Test]
+        public void LeafBlocksLinkReferenceDefinitions_Example159()
+        {
+            // Example 159
+            // Section: Leaf blocks / Link reference definitions
+            //
+            // The following Markdown:
+            //     [foo]: /url "title"
+            //     
+            //     [foo]
+            //
+            // Should be rendered as:
+            //     

foo

+ + Console.WriteLine("Example 159\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]: /url \"title\"\n\n[foo]", "

foo

", ""); + } + + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example160() + { + // Example 160 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo]: + // /url + // 'the title' + // + // [foo] + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 160\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec(" [foo]: \n /url \n 'the title' \n\n[foo]", "

foo

", ""); + } + + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example161() + { + // Example 161 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [Foo*bar\]]:my_(url) 'title (with parens)' + // + // [Foo*bar\]] + // + // Should be rendered as: + //

Foo*bar]

+ + Console.WriteLine("Example 161\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[Foo*bar\\]]:my_(url) 'title (with parens)'\n\n[Foo*bar\\]]", "

Foo*bar]

", ""); + } + + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example162() + { + // Example 162 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [Foo bar]: + // + // 'title' + // + // [Foo bar] + // + // Should be rendered as: + //

Foo bar

+ + Console.WriteLine("Example 162\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[Foo bar]:\n\n'title'\n\n[Foo bar]", "

Foo bar

", ""); + } + + // The title may extend over multiple lines: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example163() + { + // Example 163 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo]: /url ' + // title + // line1 + // line2 + // ' + // + // [foo] + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 163\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]: /url '\ntitle\nline1\nline2\n'\n\n[foo]", "

foo

", ""); + } + + // However, it may not contain a [blank line]: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example164() + { + // Example 164 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo]: /url 'title + // + // with blank line' + // + // [foo] + // + // Should be rendered as: + //

[foo]: /url 'title

+ //

with blank line'

+ //

[foo]

+ + Console.WriteLine("Example 164\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]: /url 'title\n\nwith blank line'\n\n[foo]", "

[foo]: /url 'title

\n

with blank line'

\n

[foo]

", ""); + } + + // The title may be omitted: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example165() + { + // Example 165 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo]: + // /url + // + // [foo] + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 165\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]:\n/url\n\n[foo]", "

foo

", ""); + } + + // The link destination may not be omitted: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example166() + { + // Example 166 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo]: + // + // [foo] + // + // Should be rendered as: + //

[foo]:

+ //

[foo]

+ + Console.WriteLine("Example 166\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]:\n\n[foo]", "

[foo]:

\n

[foo]

", ""); + } + + // Both title and destination can contain backslash escapes + // and literal backslashes: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example167() + { + // Example 167 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo]: /url\bar\*baz "foo\"bar\baz" + // + // [foo] + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 167\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]: /url\\bar\\*baz \"foo\\\"bar\\baz\"\n\n[foo]", "

foo

", ""); + } + + // A link can come before its corresponding definition: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example168() + { + // Example 168 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo] + // + // [foo]: url + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 168\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]\n\n[foo]: url", "

foo

", ""); + } + + // If there are several matching definitions, the first one takes + // precedence: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example169() + { + // Example 169 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo] + // + // [foo]: first + // [foo]: second + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 169\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]\n\n[foo]: first\n[foo]: second", "

foo

", ""); + } + + // As noted in the section on [Links], matching of labels is + // case-insensitive (see [matches]). + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example170() + { + // Example 170 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [FOO]: /url + // + // [Foo] + // + // Should be rendered as: + //

Foo

+ + Console.WriteLine("Example 170\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[FOO]: /url\n\n[Foo]", "

Foo

", ""); + } + + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example171() + { + // Example 171 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [ΑΓΩ]: /φου + // + // [αγω] + // + // Should be rendered as: + //

αγω

+ + Console.WriteLine("Example 171\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[ΑΓΩ]: /φου\n\n[αγω]", "

αγω

", ""); + } + + // Here is a link reference definition with no corresponding link. + // It contributes nothing to the document. + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example172() + { + // Example 172 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo]: /url + // + // Should be rendered as: + // + Console.WriteLine("Example 172\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]: /url", "", ""); + } + + // Here is another one: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example173() + { + // Example 173 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [ + // foo + // ]: /url + // bar + // + // Should be rendered as: + //

bar

+ + Console.WriteLine("Example 173\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[\nfoo\n]: /url\nbar", "

bar

", ""); + } + + // This is not a link reference definition, because there are + // [non-whitespace characters] after the title: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example174() + { + // Example 174 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo]: /url "title" ok + // + // Should be rendered as: + //

[foo]: /url "title" ok

+ + Console.WriteLine("Example 174\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]: /url \"title\" ok", "

[foo]: /url "title" ok

", ""); + } + + // This is a link reference definition, but it has no title: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example175() + { + // Example 175 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo]: /url + // "title" ok + // + // Should be rendered as: + //

"title" ok

+ + Console.WriteLine("Example 175\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]: /url\n\"title\" ok", "

"title" ok

", ""); + } + + // This is not a link reference definition, because it is indented + // four spaces: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example176() + { + // Example 176 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo]: /url "title" + // + // [foo] + // + // Should be rendered as: + //
[foo]: /url "title"
+            //     
+ //

[foo]

+ + Console.WriteLine("Example 176\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec(" [foo]: /url \"title\"\n\n[foo]", "
[foo]: /url "title"\n
\n

[foo]

", ""); + } + + // This is not a link reference definition, because it occurs inside + // a code block: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example177() + { + // Example 177 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // ``` + // [foo]: /url + // ``` + // + // [foo] + // + // Should be rendered as: + //
[foo]: /url
+            //     
+ //

[foo]

+ + Console.WriteLine("Example 177\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("```\n[foo]: /url\n```\n\n[foo]", "
[foo]: /url\n
\n

[foo]

", ""); + } + + // A [link reference definition] cannot interrupt a paragraph. + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example178() + { + // Example 178 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // Foo + // [bar]: /baz + // + // [bar] + // + // Should be rendered as: + //

Foo + // [bar]: /baz

+ //

[bar]

+ + Console.WriteLine("Example 178\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("Foo\n[bar]: /baz\n\n[bar]", "

Foo\n[bar]: /baz

\n

[bar]

", ""); + } + + // However, it can directly follow other block elements, such as headings + // and thematic breaks, and it need not be followed by a blank line. + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example179() + { + // Example 179 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // # [Foo] + // [foo]: /url + // > bar + // + // Should be rendered as: + //

Foo

+ //
+ //

bar

+ //
+ + Console.WriteLine("Example 179\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("# [Foo]\n[foo]: /url\n> bar", "

Foo

\n
\n

bar

\n
", ""); + } + + // Several [link reference definitions] + // can occur one after another, without intervening blank lines. + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example180() + { + // Example 180 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo]: /foo-url "foo" + // [bar]: /bar-url + // "bar" + // [baz]: /baz-url + // + // [foo], + // [bar], + // [baz] + // + // Should be rendered as: + //

foo, + // bar, + // baz

+ + Console.WriteLine("Example 180\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]: /foo-url \"foo\"\n[bar]: /bar-url\n \"bar\"\n[baz]: /baz-url\n\n[foo],\n[bar],\n[baz]", "

foo,\nbar,\nbaz

", ""); + } + + // [Link reference definitions] can occur + // inside block containers, like lists and block quotations. They + // affect the entire document, not just the container in which they + // are defined: + [Test] + public void LeafBlocksLinkReferenceDefinitions_Example181() + { + // Example 181 + // Section: Leaf blocks / Link reference definitions + // + // The following Markdown: + // [foo] + // + // > [foo]: /url + // + // Should be rendered as: + //

foo

+ //
+ //
+ + Console.WriteLine("Example 181\nSection Leaf blocks / Link reference definitions\n"); + TestParser.TestSpec("[foo]\n\n> [foo]: /url", "

foo

\n
\n
", ""); + } + } + + [TestFixture] + public class TestLeafBlocksParagraphs + { + // ## Paragraphs + // + // A sequence of non-blank lines that cannot be interpreted as other + // kinds of blocks forms a [paragraph](@). + // The contents of the paragraph are the result of parsing the + // paragraph's raw content as inlines. The paragraph's raw content + // is formed by concatenating the lines and removing initial and final + // [whitespace]. + // + // A simple example with two paragraphs: + [Test] + public void LeafBlocksParagraphs_Example182() + { + // Example 182 + // Section: Leaf blocks / Paragraphs + // + // The following Markdown: + // aaa + // + // bbb + // + // Should be rendered as: + //

aaa

+ //

bbb

+ + Console.WriteLine("Example 182\nSection Leaf blocks / Paragraphs\n"); + TestParser.TestSpec("aaa\n\nbbb", "

aaa

\n

bbb

", ""); + } + + // Paragraphs can contain multiple lines, but no blank lines: + [Test] + public void LeafBlocksParagraphs_Example183() + { + // Example 183 + // Section: Leaf blocks / Paragraphs + // + // The following Markdown: + // aaa + // bbb + // + // ccc + // ddd + // + // Should be rendered as: + //

aaa + // bbb

+ //

ccc + // ddd

+ + Console.WriteLine("Example 183\nSection Leaf blocks / Paragraphs\n"); + TestParser.TestSpec("aaa\nbbb\n\nccc\nddd", "

aaa\nbbb

\n

ccc\nddd

", ""); + } + + // Multiple blank lines between paragraph have no effect: + [Test] + public void LeafBlocksParagraphs_Example184() + { + // Example 184 + // Section: Leaf blocks / Paragraphs + // + // The following Markdown: + // aaa + // + // + // bbb + // + // Should be rendered as: + //

aaa

+ //

bbb

+ + Console.WriteLine("Example 184\nSection Leaf blocks / Paragraphs\n"); + TestParser.TestSpec("aaa\n\n\nbbb", "

aaa

\n

bbb

", ""); + } + + // Leading spaces are skipped: + [Test] + public void LeafBlocksParagraphs_Example185() + { + // Example 185 + // Section: Leaf blocks / Paragraphs + // + // The following Markdown: + // aaa + // bbb + // + // Should be rendered as: + //

aaa + // bbb

+ + Console.WriteLine("Example 185\nSection Leaf blocks / Paragraphs\n"); + TestParser.TestSpec(" aaa\n bbb", "

aaa\nbbb

", ""); + } + + // Lines after the first may be indented any amount, since indented + // code blocks cannot interrupt paragraphs. + [Test] + public void LeafBlocksParagraphs_Example186() + { + // Example 186 + // Section: Leaf blocks / Paragraphs + // + // The following Markdown: + // aaa + // bbb + // ccc + // + // Should be rendered as: + //

aaa + // bbb + // ccc

+ + Console.WriteLine("Example 186\nSection Leaf blocks / Paragraphs\n"); + TestParser.TestSpec("aaa\n bbb\n ccc", "

aaa\nbbb\nccc

", ""); + } + + // However, the first line may be indented at most three spaces, + // or an indented code block will be triggered: + [Test] + public void LeafBlocksParagraphs_Example187() + { + // Example 187 + // Section: Leaf blocks / Paragraphs + // + // The following Markdown: + // aaa + // bbb + // + // Should be rendered as: + //

aaa + // bbb

+ + Console.WriteLine("Example 187\nSection Leaf blocks / Paragraphs\n"); + TestParser.TestSpec(" aaa\nbbb", "

aaa\nbbb

", ""); + } + + [Test] + public void LeafBlocksParagraphs_Example188() + { + // Example 188 + // Section: Leaf blocks / Paragraphs + // + // The following Markdown: + // aaa + // bbb + // + // Should be rendered as: + //
aaa
+            //     
+ //

bbb

+ + Console.WriteLine("Example 188\nSection Leaf blocks / Paragraphs\n"); + TestParser.TestSpec(" aaa\nbbb", "
aaa\n
\n

bbb

", ""); + } + + // Final spaces are stripped before inline parsing, so a paragraph + // that ends with two or more spaces will not end with a [hard line + // break]: + [Test] + public void LeafBlocksParagraphs_Example189() + { + // Example 189 + // Section: Leaf blocks / Paragraphs + // + // The following Markdown: + // aaa + // bbb + // + // Should be rendered as: + //

aaa
+ // bbb

+ + Console.WriteLine("Example 189\nSection Leaf blocks / Paragraphs\n"); + TestParser.TestSpec("aaa \nbbb ", "

aaa
\nbbb

", ""); + } + } + + [TestFixture] + public class TestLeafBlocksBlankLines + { + // ## Blank lines + // + // [Blank lines] between block-level elements are ignored, + // except for the role they play in determining whether a [list] + // is [tight] or [loose]. + // + // Blank lines at the beginning and end of the document are also ignored. + [Test] + public void LeafBlocksBlankLines_Example190() + { + // Example 190 + // Section: Leaf blocks / Blank lines + // + // The following Markdown: + // + // + // aaa + // + // + // # aaa + // + // + // + // Should be rendered as: + //

aaa

+ //

aaa

+ + Console.WriteLine("Example 190\nSection Leaf blocks / Blank lines\n"); + TestParser.TestSpec(" \n\naaa\n \n\n# aaa\n\n ", "

aaa

\n

aaa

", ""); + } + } + + [TestFixture] + public class TestContainerBlocksBlockQuotes + { + // # Container blocks + // + // A [container block] is a block that has other + // blocks as its contents. There are two basic kinds of container blocks: + // [block quotes] and [list items]. + // [Lists] are meta-containers for [list items]. + // + // We define the syntax for container blocks recursively. The general + // form of the definition is: + // + // > If X is a sequence of blocks, then the result of + // > transforming X in such-and-such a way is a container of type Y + // > with these blocks as its content. + // + // So, we explain what counts as a block quote or list item by explaining + // how these can be *generated* from their contents. This should suffice + // to define the syntax, although it does not give a recipe for *parsing* + // these constructions. (A recipe is provided below in the section entitled + // [A parsing strategy](#appendix-a-parsing-strategy).) + // + // ## Block quotes + // + // A [block quote marker](@) + // consists of 0-3 spaces of initial indent, plus (a) the character `>` together + // with a following space, or (b) a single character `>` not followed by a space. + // + // The following rules define [block quotes]: + // + // 1. **Basic case.** If a string of lines *Ls* constitute a sequence + // of blocks *Bs*, then the result of prepending a [block quote + // marker] to the beginning of each line in *Ls* + // is a [block quote](#block-quotes) containing *Bs*. + // + // 2. **Laziness.** If a string of lines *Ls* constitute a [block + // quote](#block-quotes) with contents *Bs*, then the result of deleting + // the initial [block quote marker] from one or + // more lines in which the next [non-whitespace character] after the [block + // quote marker] is [paragraph continuation + // text] is a block quote with *Bs* as its content. + // [Paragraph continuation text](@) is text + // that will be parsed as part of the content of a paragraph, but does + // not occur at the beginning of the paragraph. + // + // 3. **Consecutiveness.** A document cannot contain two [block + // quotes] in a row unless there is a [blank line] between them. + // + // Nothing else counts as a [block quote](#block-quotes). + // + // Here is a simple example: + [Test] + public void ContainerBlocksBlockQuotes_Example191() + { + // Example 191 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > # Foo + // > bar + // > baz + // + // Should be rendered as: + //
+ //

Foo

+ //

bar + // baz

+ //
+ + Console.WriteLine("Example 191\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> # Foo\n> bar\n> baz", "
\n

Foo

\n

bar\nbaz

\n
", ""); + } + + // The spaces after the `>` characters can be omitted: + [Test] + public void ContainerBlocksBlockQuotes_Example192() + { + // Example 192 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // ># Foo + // >bar + // > baz + // + // Should be rendered as: + //
+ //

Foo

+ //

bar + // baz

+ //
+ + Console.WriteLine("Example 192\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("># Foo\n>bar\n> baz", "
\n

Foo

\n

bar\nbaz

\n
", ""); + } + + // The `>` characters can be indented 1-3 spaces: + [Test] + public void ContainerBlocksBlockQuotes_Example193() + { + // Example 193 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > # Foo + // > bar + // > baz + // + // Should be rendered as: + //
+ //

Foo

+ //

bar + // baz

+ //
+ + Console.WriteLine("Example 193\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec(" > # Foo\n > bar\n > baz", "
\n

Foo

\n

bar\nbaz

\n
", ""); + } + + // Four spaces gives us a code block: + [Test] + public void ContainerBlocksBlockQuotes_Example194() + { + // Example 194 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > # Foo + // > bar + // > baz + // + // Should be rendered as: + //
> # Foo
+            //     > bar
+            //     > baz
+            //     
+ + Console.WriteLine("Example 194\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec(" > # Foo\n > bar\n > baz", "
> # Foo\n> bar\n> baz\n
", ""); + } + + // The Laziness clause allows us to omit the `>` before + // [paragraph continuation text]: + [Test] + public void ContainerBlocksBlockQuotes_Example195() + { + // Example 195 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > # Foo + // > bar + // baz + // + // Should be rendered as: + //
+ //

Foo

+ //

bar + // baz

+ //
+ + Console.WriteLine("Example 195\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> # Foo\n> bar\nbaz", "
\n

Foo

\n

bar\nbaz

\n
", ""); + } + + // A block quote can contain some lazy and some non-lazy + // continuation lines: + [Test] + public void ContainerBlocksBlockQuotes_Example196() + { + // Example 196 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > bar + // baz + // > foo + // + // Should be rendered as: + //
+ //

bar + // baz + // foo

+ //
+ + Console.WriteLine("Example 196\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> bar\nbaz\n> foo", "
\n

bar\nbaz\nfoo

\n
", ""); + } + + // Laziness only applies to lines that would have been continuations of + // paragraphs had they been prepended with [block quote markers]. + // For example, the `> ` cannot be omitted in the second line of + // + // ``` markdown + // > foo + // > --- + // ``` + // + // without changing the meaning: + [Test] + public void ContainerBlocksBlockQuotes_Example197() + { + // Example 197 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > foo + // --- + // + // Should be rendered as: + //
+ //

foo

+ //
+ //
+ + Console.WriteLine("Example 197\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> foo\n---", "
\n

foo

\n
\n
", ""); + } + + // Similarly, if we omit the `> ` in the second line of + // + // ``` markdown + // > - foo + // > - bar + // ``` + // + // then the block quote ends after the first line: + [Test] + public void ContainerBlocksBlockQuotes_Example198() + { + // Example 198 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > - foo + // - bar + // + // Should be rendered as: + //
+ //
    + //
  • foo
  • + //
+ //
+ //
    + //
  • bar
  • + //
+ + Console.WriteLine("Example 198\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> - foo\n- bar", "
\n
    \n
  • foo
  • \n
\n
\n
    \n
  • bar
  • \n
", ""); + } + + // For the same reason, we can't omit the `> ` in front of + // subsequent lines of an indented or fenced code block: + [Test] + public void ContainerBlocksBlockQuotes_Example199() + { + // Example 199 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > foo + // bar + // + // Should be rendered as: + //
+ //
foo
+            //     
+ //
+ //
bar
+            //     
+ + Console.WriteLine("Example 199\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> foo\n bar", "
\n
foo\n
\n
\n
bar\n
", ""); + } + + [Test] + public void ContainerBlocksBlockQuotes_Example200() + { + // Example 200 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > ``` + // foo + // ``` + // + // Should be rendered as: + //
+ //
+ //
+ //

foo

+ //
+ + Console.WriteLine("Example 200\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> ```\nfoo\n```", "
\n
\n
\n

foo

\n
", ""); + } + + // Note that in the following case, we have a [lazy + // continuation line]: + [Test] + public void ContainerBlocksBlockQuotes_Example201() + { + // Example 201 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > foo + // - bar + // + // Should be rendered as: + //
+ //

foo + // - bar

+ //
+ + Console.WriteLine("Example 201\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> foo\n - bar", "
\n

foo\n- bar

\n
", ""); + } + + // To see why, note that in + // + // ```markdown + // > foo + // > - bar + // ``` + // + // the `- bar` is indented too far to start a list, and can't + // be an indented code block because indented code blocks cannot + // interrupt paragraphs, so it is [paragraph continuation text]. + // + // A block quote can be empty: + [Test] + public void ContainerBlocksBlockQuotes_Example202() + { + // Example 202 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > + // + // Should be rendered as: + //
+ //
+ + Console.WriteLine("Example 202\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec(">", "
\n
", ""); + } + + [Test] + public void ContainerBlocksBlockQuotes_Example203() + { + // Example 203 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > + // > + // > + // + // Should be rendered as: + //
+ //
+ + Console.WriteLine("Example 203\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec(">\n> \n> ", "
\n
", ""); + } + + // A block quote can have initial or final blank lines: + [Test] + public void ContainerBlocksBlockQuotes_Example204() + { + // Example 204 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > + // > foo + // > + // + // Should be rendered as: + //
+ //

foo

+ //
+ + Console.WriteLine("Example 204\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec(">\n> foo\n> ", "
\n

foo

\n
", ""); + } + + // A blank line always separates block quotes: + [Test] + public void ContainerBlocksBlockQuotes_Example205() + { + // Example 205 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > foo + // + // > bar + // + // Should be rendered as: + //
+ //

foo

+ //
+ //
+ //

bar

+ //
+ + Console.WriteLine("Example 205\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> foo\n\n> bar", "
\n

foo

\n
\n
\n

bar

\n
", ""); + } + + // (Most current Markdown implementations, including John Gruber's + // original `Markdown.pl`, will parse this example as a single block quote + // with two paragraphs. But it seems better to allow the author to decide + // whether two block quotes or one are wanted.) + // + // Consecutiveness means that if we put these block quotes together, + // we get a single block quote: + [Test] + public void ContainerBlocksBlockQuotes_Example206() + { + // Example 206 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > foo + // > bar + // + // Should be rendered as: + //
+ //

foo + // bar

+ //
+ + Console.WriteLine("Example 206\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> foo\n> bar", "
\n

foo\nbar

\n
", ""); + } + + // To get a block quote with two paragraphs, use: + [Test] + public void ContainerBlocksBlockQuotes_Example207() + { + // Example 207 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > foo + // > + // > bar + // + // Should be rendered as: + //
+ //

foo

+ //

bar

+ //
+ + Console.WriteLine("Example 207\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> foo\n>\n> bar", "
\n

foo

\n

bar

\n
", ""); + } + + // Block quotes can interrupt paragraphs: + [Test] + public void ContainerBlocksBlockQuotes_Example208() + { + // Example 208 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // foo + // > bar + // + // Should be rendered as: + //

foo

+ //
+ //

bar

+ //
+ + Console.WriteLine("Example 208\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("foo\n> bar", "

foo

\n
\n

bar

\n
", ""); + } + + // In general, blank lines are not needed before or after block + // quotes: + [Test] + public void ContainerBlocksBlockQuotes_Example209() + { + // Example 209 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > aaa + // *** + // > bbb + // + // Should be rendered as: + //
+ //

aaa

+ //
+ //
+ //
+ //

bbb

+ //
+ + Console.WriteLine("Example 209\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> aaa\n***\n> bbb", "
\n

aaa

\n
\n
\n
\n

bbb

\n
", ""); + } + + // However, because of laziness, a blank line is needed between + // a block quote and a following paragraph: + [Test] + public void ContainerBlocksBlockQuotes_Example210() + { + // Example 210 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > bar + // baz + // + // Should be rendered as: + //
+ //

bar + // baz

+ //
+ + Console.WriteLine("Example 210\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> bar\nbaz", "
\n

bar\nbaz

\n
", ""); + } + + [Test] + public void ContainerBlocksBlockQuotes_Example211() + { + // Example 211 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > bar + // + // baz + // + // Should be rendered as: + //
+ //

bar

+ //
+ //

baz

+ + Console.WriteLine("Example 211\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> bar\n\nbaz", "
\n

bar

\n
\n

baz

", ""); + } + + [Test] + public void ContainerBlocksBlockQuotes_Example212() + { + // Example 212 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > bar + // > + // baz + // + // Should be rendered as: + //
+ //

bar

+ //
+ //

baz

+ + Console.WriteLine("Example 212\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> bar\n>\nbaz", "
\n

bar

\n
\n

baz

", ""); + } + + // It is a consequence of the Laziness rule that any number + // of initial `>`s may be omitted on a continuation line of a + // nested block quote: + [Test] + public void ContainerBlocksBlockQuotes_Example213() + { + // Example 213 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > > > foo + // bar + // + // Should be rendered as: + //
+ //
+ //
+ //

foo + // bar

+ //
+ //
+ //
+ + Console.WriteLine("Example 213\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> > > foo\nbar", "
\n
\n
\n

foo\nbar

\n
\n
\n
", ""); + } + + [Test] + public void ContainerBlocksBlockQuotes_Example214() + { + // Example 214 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // >>> foo + // > bar + // >>baz + // + // Should be rendered as: + //
+ //
+ //
+ //

foo + // bar + // baz

+ //
+ //
+ //
+ + Console.WriteLine("Example 214\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec(">>> foo\n> bar\n>>baz", "
\n
\n
\n

foo\nbar\nbaz

\n
\n
\n
", ""); + } + + // When including an indented code block in a block quote, + // remember that the [block quote marker] includes + // both the `>` and a following space. So *five spaces* are needed after + // the `>`: + [Test] + public void ContainerBlocksBlockQuotes_Example215() + { + // Example 215 + // Section: Container blocks / Block quotes + // + // The following Markdown: + // > code + // + // > not code + // + // Should be rendered as: + //
+ //
code
+            //     
+ //
+ //
+ //

not code

+ //
+ + Console.WriteLine("Example 215\nSection Container blocks / Block quotes\n"); + TestParser.TestSpec("> code\n\n> not code", "
\n
code\n
\n
\n
\n

not code

\n
", ""); + } + } + + [TestFixture] + public class TestContainerBlocksListItems + { + // ## List items + // + // A [list marker](@) is a + // [bullet list marker] or an [ordered list marker]. + // + // A [bullet list marker](@) + // is a `-`, `+`, or `*` character. + // + // An [ordered list marker](@) + // is a sequence of 1--9 arabic digits (`0-9`), followed by either a + // `.` character or a `)` character. (The reason for the length + // limit is that with 10 digits we start seeing integer overflows + // in some browsers.) + // + // The following rules define [list items]: + // + // 1. **Basic case.** If a sequence of lines *Ls* constitute a sequence of + // blocks *Bs* starting with a [non-whitespace character] and not separated + // from each other by more than one blank line, and *M* is a list + // marker of width *W* followed by 1 ≤ *N* ≤ 4 spaces, then the result + // of prepending *M* and the following spaces to the first line of + // *Ls*, and indenting subsequent lines of *Ls* by *W + N* spaces, is a + // list item with *Bs* as its contents. The type of the list item + // (bullet or ordered) is determined by the type of its list marker. + // If the list item is ordered, then it is also assigned a start + // number, based on the ordered list marker. + // + // Exceptions: + // + // 1. When the first list item in a [list] interrupts + // a paragraph---that is, when it starts on a line that would + // otherwise count as [paragraph continuation text]---then (a) + // the lines *Ls* must not begin with a blank line, and (b) if + // the list item is ordered, the start number must be 1. + // 2. If any line is a [thematic break][thematic breaks] then + // that line is not a list item. + // + // For example, let *Ls* be the lines + [Test] + public void ContainerBlocksListItems_Example216() + { + // Example 216 + // Section: Container blocks / List items + // + // The following Markdown: + // A paragraph + // with two lines. + // + // indented code + // + // > A block quote. + // + // Should be rendered as: + //

A paragraph + // with two lines.

+ //
indented code
+            //     
+ //
+ //

A block quote.

+ //
+ + Console.WriteLine("Example 216\nSection Container blocks / List items\n"); + TestParser.TestSpec("A paragraph\nwith two lines.\n\n indented code\n\n> A block quote.", "

A paragraph\nwith two lines.

\n
indented code\n
\n
\n

A block quote.

\n
", ""); + } + + // And let *M* be the marker `1.`, and *N* = 2. Then rule #1 says + // that the following is an ordered list item with start number 1, + // and the same contents as *Ls*: + [Test] + public void ContainerBlocksListItems_Example217() + { + // Example 217 + // Section: Container blocks / List items + // + // The following Markdown: + // 1. A paragraph + // with two lines. + // + // indented code + // + // > A block quote. + // + // Should be rendered as: + //
    + //
  1. + //

    A paragraph + // with two lines.

    + //
    indented code
    +            //     
    + //
    + //

    A block quote.

    + //
    + //
  2. + //
+ + Console.WriteLine("Example 217\nSection Container blocks / List items\n"); + TestParser.TestSpec("1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.", "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
", ""); + } + + // The most important thing to notice is that the position of + // the text after the list marker determines how much indentation + // is needed in subsequent blocks in the list item. If the list + // marker takes up two spaces, and there are three spaces between + // the list marker and the next [non-whitespace character], then blocks + // must be indented five spaces in order to fall under the list + // item. + // + // Here are some examples showing how far content must be indented to be + // put under the list item: + [Test] + public void ContainerBlocksListItems_Example218() + { + // Example 218 + // Section: Container blocks / List items + // + // The following Markdown: + // - one + // + // two + // + // Should be rendered as: + //
    + //
  • one
  • + //
+ //

two

+ + Console.WriteLine("Example 218\nSection Container blocks / List items\n"); + TestParser.TestSpec("- one\n\n two", "
    \n
  • one
  • \n
\n

two

", ""); + } + + [Test] + public void ContainerBlocksListItems_Example219() + { + // Example 219 + // Section: Container blocks / List items + // + // The following Markdown: + // - one + // + // two + // + // Should be rendered as: + //
    + //
  • + //

    one

    + //

    two

    + //
  • + //
+ + Console.WriteLine("Example 219\nSection Container blocks / List items\n"); + TestParser.TestSpec("- one\n\n two", "
    \n
  • \n

    one

    \n

    two

    \n
  • \n
", ""); + } + + [Test] + public void ContainerBlocksListItems_Example220() + { + // Example 220 + // Section: Container blocks / List items + // + // The following Markdown: + // - one + // + // two + // + // Should be rendered as: + //
    + //
  • one
  • + //
+ //
 two
+            //     
+ + Console.WriteLine("Example 220\nSection Container blocks / List items\n"); + TestParser.TestSpec(" - one\n\n two", "
    \n
  • one
  • \n
\n
 two\n
", ""); + } + + [Test] + public void ContainerBlocksListItems_Example221() + { + // Example 221 + // Section: Container blocks / List items + // + // The following Markdown: + // - one + // + // two + // + // Should be rendered as: + //
    + //
  • + //

    one

    + //

    two

    + //
  • + //
+ + Console.WriteLine("Example 221\nSection Container blocks / List items\n"); + TestParser.TestSpec(" - one\n\n two", "
    \n
  • \n

    one

    \n

    two

    \n
  • \n
", ""); + } + + // It is tempting to think of this in terms of columns: the continuation + // blocks must be indented at least to the column of the first + // [non-whitespace character] after the list marker. However, that is not quite right. + // The spaces after the list marker determine how much relative indentation + // is needed. Which column this indentation reaches will depend on + // how the list item is embedded in other constructions, as shown by + // this example: + [Test] + public void ContainerBlocksListItems_Example222() + { + // Example 222 + // Section: Container blocks / List items + // + // The following Markdown: + // > > 1. one + // >> + // >> two + // + // Should be rendered as: + //
+ //
+ //
    + //
  1. + //

    one

    + //

    two

    + //
  2. + //
+ //
+ //
+ + Console.WriteLine("Example 222\nSection Container blocks / List items\n"); + TestParser.TestSpec(" > > 1. one\n>>\n>> two", "
\n
\n
    \n
  1. \n

    one

    \n

    two

    \n
  2. \n
\n
\n
", ""); + } + + // Here `two` occurs in the same column as the list marker `1.`, + // but is actually contained in the list item, because there is + // sufficient indentation after the last containing blockquote marker. + // + // The converse is also possible. In the following example, the word `two` + // occurs far to the right of the initial text of the list item, `one`, but + // it is not considered part of the list item, because it is not indented + // far enough past the blockquote marker: + [Test] + public void ContainerBlocksListItems_Example223() + { + // Example 223 + // Section: Container blocks / List items + // + // The following Markdown: + // >>- one + // >> + // > > two + // + // Should be rendered as: + //
+ //
+ //
    + //
  • one
  • + //
+ //

two

+ //
+ //
+ + Console.WriteLine("Example 223\nSection Container blocks / List items\n"); + TestParser.TestSpec(">>- one\n>>\n > > two", "
\n
\n
    \n
  • one
  • \n
\n

two

\n
\n
", ""); + } + + // Note that at least one space is needed between the list marker and + // any following content, so these are not list items: + [Test] + public void ContainerBlocksListItems_Example224() + { + // Example 224 + // Section: Container blocks / List items + // + // The following Markdown: + // -one + // + // 2.two + // + // Should be rendered as: + //

-one

+ //

2.two

+ + Console.WriteLine("Example 224\nSection Container blocks / List items\n"); + TestParser.TestSpec("-one\n\n2.two", "

-one

\n

2.two

", ""); + } + + // A list item may contain blocks that are separated by more than + // one blank line. + [Test] + public void ContainerBlocksListItems_Example225() + { + // Example 225 + // Section: Container blocks / List items + // + // The following Markdown: + // - foo + // + // + // bar + // + // Should be rendered as: + //
    + //
  • + //

    foo

    + //

    bar

    + //
  • + //
+ + Console.WriteLine("Example 225\nSection Container blocks / List items\n"); + TestParser.TestSpec("- foo\n\n\n bar", "
    \n
  • \n

    foo

    \n

    bar

    \n
  • \n
", ""); + } + + // A list item may contain any kind of block: + [Test] + public void ContainerBlocksListItems_Example226() + { + // Example 226 + // Section: Container blocks / List items + // + // The following Markdown: + // 1. foo + // + // ``` + // bar + // ``` + // + // baz + // + // > bam + // + // Should be rendered as: + //
    + //
  1. + //

    foo

    + //
    bar
    +            //     
    + //

    baz

    + //
    + //

    bam

    + //
    + //
  2. + //
+ + Console.WriteLine("Example 226\nSection Container blocks / List items\n"); + TestParser.TestSpec("1. foo\n\n ```\n bar\n ```\n\n baz\n\n > bam", "
    \n
  1. \n

    foo

    \n
    bar\n
    \n

    baz

    \n
    \n

    bam

    \n
    \n
  2. \n
", ""); + } + + // A list item that contains an indented code block will preserve + // empty lines within the code block verbatim. + [Test] + public void ContainerBlocksListItems_Example227() + { + // Example 227 + // Section: Container blocks / List items + // + // The following Markdown: + // - Foo + // + // bar + // + // + // baz + // + // Should be rendered as: + //
    + //
  • + //

    Foo

    + //
    bar
    +            //     
    +            //     
    +            //     baz
    +            //     
    + //
  • + //
+ + Console.WriteLine("Example 227\nSection Container blocks / List items\n"); + TestParser.TestSpec("- Foo\n\n bar\n\n\n baz", "
    \n
  • \n

    Foo

    \n
    bar\n\n\nbaz\n
    \n
  • \n
", ""); + } + + // Note that ordered list start numbers must be nine digits or less: + [Test] + public void ContainerBlocksListItems_Example228() + { + // Example 228 + // Section: Container blocks / List items + // + // The following Markdown: + // 123456789. ok + // + // Should be rendered as: + //
    + //
  1. ok
  2. + //
+ + Console.WriteLine("Example 228\nSection Container blocks / List items\n"); + TestParser.TestSpec("123456789. ok", "
    \n
  1. ok
  2. \n
", ""); + } + + [Test] + public void ContainerBlocksListItems_Example229() + { + // Example 229 + // Section: Container blocks / List items + // + // The following Markdown: + // 1234567890. not ok + // + // Should be rendered as: + //

1234567890. not ok

+ + Console.WriteLine("Example 229\nSection Container blocks / List items\n"); + TestParser.TestSpec("1234567890. not ok", "

1234567890. not ok

", ""); + } + + // A start number may begin with 0s: + [Test] + public void ContainerBlocksListItems_Example230() + { + // Example 230 + // Section: Container blocks / List items + // + // The following Markdown: + // 0. ok + // + // Should be rendered as: + //
    + //
  1. ok
  2. + //
+ + Console.WriteLine("Example 230\nSection Container blocks / List items\n"); + TestParser.TestSpec("0. ok", "
    \n
  1. ok
  2. \n
", ""); + } + + [Test] + public void ContainerBlocksListItems_Example231() + { + // Example 231 + // Section: Container blocks / List items + // + // The following Markdown: + // 003. ok + // + // Should be rendered as: + //
    + //
  1. ok
  2. + //
+ + Console.WriteLine("Example 231\nSection Container blocks / List items\n"); + TestParser.TestSpec("003. ok", "
    \n
  1. ok
  2. \n
", ""); + } + + // A start number may not be negative: + [Test] + public void ContainerBlocksListItems_Example232() + { + // Example 232 + // Section: Container blocks / List items + // + // The following Markdown: + // -1. not ok + // + // Should be rendered as: + //

-1. not ok

+ + Console.WriteLine("Example 232\nSection Container blocks / List items\n"); + TestParser.TestSpec("-1. not ok", "

-1. not ok

", ""); + } + + // 2. **Item starting with indented code.** If a sequence of lines *Ls* + // constitute a sequence of blocks *Bs* starting with an indented code + // block and not separated from each other by more than one blank line, + // and *M* is a list marker of width *W* followed by + // one space, then the result of prepending *M* and the following + // space to the first line of *Ls*, and indenting subsequent lines of + // *Ls* by *W + 1* spaces, is a list item with *Bs* as its contents. + // If a line is empty, then it need not be indented. The type of the + // list item (bullet or ordered) is determined by the type of its list + // marker. If the list item is ordered, then it is also assigned a + // start number, based on the ordered list marker. + // + // An indented code block will have to be indented four spaces beyond + // the edge of the region where text will be included in the list item. + // In the following case that is 6 spaces: + [Test] + public void ContainerBlocksListItems_Example233() + { + // Example 233 + // Section: Container blocks / List items + // + // The following Markdown: + // - foo + // + // bar + // + // Should be rendered as: + //
    + //
  • + //

    foo

    + //
    bar
    +            //     
    + //
  • + //
+ + Console.WriteLine("Example 233\nSection Container blocks / List items\n"); + TestParser.TestSpec("- foo\n\n bar", "
    \n
  • \n

    foo

    \n
    bar\n
    \n
  • \n
", ""); + } + + // And in this case it is 11 spaces: + [Test] + public void ContainerBlocksListItems_Example234() + { + // Example 234 + // Section: Container blocks / List items + // + // The following Markdown: + // 10. foo + // + // bar + // + // Should be rendered as: + //
    + //
  1. + //

    foo

    + //
    bar
    +            //     
    + //
  2. + //
+ + Console.WriteLine("Example 234\nSection Container blocks / List items\n"); + TestParser.TestSpec(" 10. foo\n\n bar", "
    \n
  1. \n

    foo

    \n
    bar\n
    \n
  2. \n
", ""); + } + + // If the *first* block in the list item is an indented code block, + // then by rule #2, the contents must be indented *one* space after the + // list marker: + [Test] + public void ContainerBlocksListItems_Example235() + { + // Example 235 + // Section: Container blocks / List items + // + // The following Markdown: + // indented code + // + // paragraph + // + // more code + // + // Should be rendered as: + //
indented code
+            //     
+ //

paragraph

+ //
more code
+            //     
+ + Console.WriteLine("Example 235\nSection Container blocks / List items\n"); + TestParser.TestSpec(" indented code\n\nparagraph\n\n more code", "
indented code\n
\n

paragraph

\n
more code\n
", ""); + } + + [Test] + public void ContainerBlocksListItems_Example236() + { + // Example 236 + // Section: Container blocks / List items + // + // The following Markdown: + // 1. indented code + // + // paragraph + // + // more code + // + // Should be rendered as: + //
    + //
  1. + //
    indented code
    +            //     
    + //

    paragraph

    + //
    more code
    +            //     
    + //
  2. + //
+ + Console.WriteLine("Example 236\nSection Container blocks / List items\n"); + TestParser.TestSpec("1. indented code\n\n paragraph\n\n more code", "
    \n
  1. \n
    indented code\n
    \n

    paragraph

    \n
    more code\n
    \n
  2. \n
", ""); + } + + // Note that an additional space indent is interpreted as space + // inside the code block: + [Test] + public void ContainerBlocksListItems_Example237() + { + // Example 237 + // Section: Container blocks / List items + // + // The following Markdown: + // 1. indented code + // + // paragraph + // + // more code + // + // Should be rendered as: + //
    + //
  1. + //
     indented code
    +            //     
    + //

    paragraph

    + //
    more code
    +            //     
    + //
  2. + //
+ + Console.WriteLine("Example 237\nSection Container blocks / List items\n"); + TestParser.TestSpec("1. indented code\n\n paragraph\n\n more code", "
    \n
  1. \n
     indented code\n
    \n

    paragraph

    \n
    more code\n
    \n
  2. \n
", ""); + } + + // Note that rules #1 and #2 only apply to two cases: (a) cases + // in which the lines to be included in a list item begin with a + // [non-whitespace character], and (b) cases in which + // they begin with an indented code + // block. In a case like the following, where the first block begins with + // a three-space indent, the rules do not allow us to form a list item by + // indenting the whole thing and prepending a list marker: + [Test] + public void ContainerBlocksListItems_Example238() + { + // Example 238 + // Section: Container blocks / List items + // + // The following Markdown: + // foo + // + // bar + // + // Should be rendered as: + //

foo

+ //

bar

+ + Console.WriteLine("Example 238\nSection Container blocks / List items\n"); + TestParser.TestSpec(" foo\n\nbar", "

foo

\n

bar

", ""); + } + + [Test] + public void ContainerBlocksListItems_Example239() + { + // Example 239 + // Section: Container blocks / List items + // + // The following Markdown: + // - foo + // + // bar + // + // Should be rendered as: + //
    + //
  • foo
  • + //
+ //

bar

+ + Console.WriteLine("Example 239\nSection Container blocks / List items\n"); + TestParser.TestSpec("- foo\n\n bar", "
    \n
  • foo
  • \n
\n

bar

", ""); + } + + // This is not a significant restriction, because when a block begins + // with 1-3 spaces indent, the indentation can always be removed without + // a change in interpretation, allowing rule #1 to be applied. So, in + // the above case: + [Test] + public void ContainerBlocksListItems_Example240() + { + // Example 240 + // Section: Container blocks / List items + // + // The following Markdown: + // - foo + // + // bar + // + // Should be rendered as: + //
    + //
  • + //

    foo

    + //

    bar

    + //
  • + //
+ + Console.WriteLine("Example 240\nSection Container blocks / List items\n"); + TestParser.TestSpec("- foo\n\n bar", "
    \n
  • \n

    foo

    \n

    bar

    \n
  • \n
", ""); + } + + // 3. **Item starting with a blank line.** If a sequence of lines *Ls* + // starting with a single [blank line] constitute a (possibly empty) + // sequence of blocks *Bs*, not separated from each other by more than + // one blank line, and *M* is a list marker of width *W*, + // then the result of prepending *M* to the first line of *Ls*, and + // indenting subsequent lines of *Ls* by *W + 1* spaces, is a list + // item with *Bs* as its contents. + // If a line is empty, then it need not be indented. The type of the + // list item (bullet or ordered) is determined by the type of its list + // marker. If the list item is ordered, then it is also assigned a + // start number, based on the ordered list marker. + // + // Here are some list items that start with a blank line but are not empty: + [Test] + public void ContainerBlocksListItems_Example241() + { + // Example 241 + // Section: Container blocks / List items + // + // The following Markdown: + // - + // foo + // - + // ``` + // bar + // ``` + // - + // baz + // + // Should be rendered as: + //
    + //
  • foo
  • + //
  • + //
    bar
    +            //     
    + //
  • + //
  • + //
    baz
    +            //     
    + //
  • + //
+ + Console.WriteLine("Example 241\nSection Container blocks / List items\n"); + TestParser.TestSpec("-\n foo\n-\n ```\n bar\n ```\n-\n baz", "
    \n
  • foo
  • \n
  • \n
    bar\n
    \n
  • \n
  • \n
    baz\n
    \n
  • \n
", ""); + } + + // When the list item starts with a blank line, the number of spaces + // following the list marker doesn't change the required indentation: + [Test] + public void ContainerBlocksListItems_Example242() + { + // Example 242 + // Section: Container blocks / List items + // + // The following Markdown: + // - + // foo + // + // Should be rendered as: + //
    + //
  • foo
  • + //
+ + Console.WriteLine("Example 242\nSection Container blocks / List items\n"); + TestParser.TestSpec("- \n foo", "
    \n
  • foo
  • \n
", ""); + } + + // A list item can begin with at most one blank line. + // In the following example, `foo` is not part of the list + // item: + [Test] + public void ContainerBlocksListItems_Example243() + { + // Example 243 + // Section: Container blocks / List items + // + // The following Markdown: + // - + // + // foo + // + // Should be rendered as: + //
    + //
  • + //
+ //

foo

+ + Console.WriteLine("Example 243\nSection Container blocks / List items\n"); + TestParser.TestSpec("-\n\n foo", "
    \n
  • \n
\n

foo

", ""); + } + + // Here is an empty bullet list item: + [Test] + public void ContainerBlocksListItems_Example244() + { + // Example 244 + // Section: Container blocks / List items + // + // The following Markdown: + // - foo + // - + // - bar + // + // Should be rendered as: + //
    + //
  • foo
  • + //
  • + //
  • bar
  • + //
+ + Console.WriteLine("Example 244\nSection Container blocks / List items\n"); + TestParser.TestSpec("- foo\n-\n- bar", "
    \n
  • foo
  • \n
  • \n
  • bar
  • \n
", ""); + } + + // It does not matter whether there are spaces following the [list marker]: + [Test] + public void ContainerBlocksListItems_Example245() + { + // Example 245 + // Section: Container blocks / List items + // + // The following Markdown: + // - foo + // - + // - bar + // + // Should be rendered as: + //
    + //
  • foo
  • + //
  • + //
  • bar
  • + //
+ + Console.WriteLine("Example 245\nSection Container blocks / List items\n"); + TestParser.TestSpec("- foo\n- \n- bar", "
    \n
  • foo
  • \n
  • \n
  • bar
  • \n
", ""); + } + + // Here is an empty ordered list item: + [Test] + public void ContainerBlocksListItems_Example246() + { + // Example 246 + // Section: Container blocks / List items + // + // The following Markdown: + // 1. foo + // 2. + // 3. bar + // + // Should be rendered as: + //
    + //
  1. foo
  2. + //
  3. + //
  4. bar
  5. + //
+ + Console.WriteLine("Example 246\nSection Container blocks / List items\n"); + TestParser.TestSpec("1. foo\n2.\n3. bar", "
    \n
  1. foo
  2. \n
  3. \n
  4. bar
  5. \n
", ""); + } + + // A list may start or end with an empty list item: + [Test] + public void ContainerBlocksListItems_Example247() + { + // Example 247 + // Section: Container blocks / List items + // + // The following Markdown: + // * + // + // Should be rendered as: + //
    + //
  • + //
+ + Console.WriteLine("Example 247\nSection Container blocks / List items\n"); + TestParser.TestSpec("*", "
    \n
  • \n
", ""); + } + + // However, an empty list item cannot interrupt a paragraph: + [Test] + public void ContainerBlocksListItems_Example248() + { + // Example 248 + // Section: Container blocks / List items + // + // The following Markdown: + // foo + // * + // + // foo + // 1. + // + // Should be rendered as: + //

foo + // *

+ //

foo + // 1.

+ + Console.WriteLine("Example 248\nSection Container blocks / List items\n"); + TestParser.TestSpec("foo\n*\n\nfoo\n1.", "

foo\n*

\n

foo\n1.

", ""); + } + + // 4. **Indentation.** If a sequence of lines *Ls* constitutes a list item + // according to rule #1, #2, or #3, then the result of indenting each line + // of *Ls* by 1-3 spaces (the same for each line) also constitutes a + // list item with the same contents and attributes. If a line is + // empty, then it need not be indented. + // + // Indented one space: + [Test] + public void ContainerBlocksListItems_Example249() + { + // Example 249 + // Section: Container blocks / List items + // + // The following Markdown: + // 1. A paragraph + // with two lines. + // + // indented code + // + // > A block quote. + // + // Should be rendered as: + //
    + //
  1. + //

    A paragraph + // with two lines.

    + //
    indented code
    +            //     
    + //
    + //

    A block quote.

    + //
    + //
  2. + //
+ + Console.WriteLine("Example 249\nSection Container blocks / List items\n"); + TestParser.TestSpec(" 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.", "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
", ""); + } + + // Indented two spaces: + [Test] + public void ContainerBlocksListItems_Example250() + { + // Example 250 + // Section: Container blocks / List items + // + // The following Markdown: + // 1. A paragraph + // with two lines. + // + // indented code + // + // > A block quote. + // + // Should be rendered as: + //
    + //
  1. + //

    A paragraph + // with two lines.

    + //
    indented code
    +            //     
    + //
    + //

    A block quote.

    + //
    + //
  2. + //
+ + Console.WriteLine("Example 250\nSection Container blocks / List items\n"); + TestParser.TestSpec(" 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.", "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
", ""); + } + + // Indented three spaces: + [Test] + public void ContainerBlocksListItems_Example251() + { + // Example 251 + // Section: Container blocks / List items + // + // The following Markdown: + // 1. A paragraph + // with two lines. + // + // indented code + // + // > A block quote. + // + // Should be rendered as: + //
    + //
  1. + //

    A paragraph + // with two lines.

    + //
    indented code
    +            //     
    + //
    + //

    A block quote.

    + //
    + //
  2. + //
+ + Console.WriteLine("Example 251\nSection Container blocks / List items\n"); + TestParser.TestSpec(" 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.", "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
", ""); + } + + // Four spaces indent gives a code block: + [Test] + public void ContainerBlocksListItems_Example252() + { + // Example 252 + // Section: Container blocks / List items + // + // The following Markdown: + // 1. A paragraph + // with two lines. + // + // indented code + // + // > A block quote. + // + // Should be rendered as: + //
1.  A paragraph
+            //         with two lines.
+            //     
+            //             indented code
+            //     
+            //         > A block quote.
+            //     
+ + Console.WriteLine("Example 252\nSection Container blocks / List items\n"); + TestParser.TestSpec(" 1. A paragraph\n with two lines.\n\n indented code\n\n > A block quote.", "
1.  A paragraph\n    with two lines.\n\n        indented code\n\n    > A block quote.\n
", ""); + } + + // 5. **Laziness.** If a string of lines *Ls* constitute a [list + // item](#list-items) with contents *Bs*, then the result of deleting + // some or all of the indentation from one or more lines in which the + // next [non-whitespace character] after the indentation is + // [paragraph continuation text] is a + // list item with the same contents and attributes. The unindented + // lines are called + // [lazy continuation line](@)s. + // + // Here is an example with [lazy continuation lines]: + [Test] + public void ContainerBlocksListItems_Example253() + { + // Example 253 + // Section: Container blocks / List items + // + // The following Markdown: + // 1. A paragraph + // with two lines. + // + // indented code + // + // > A block quote. + // + // Should be rendered as: + //
    + //
  1. + //

    A paragraph + // with two lines.

    + //
    indented code
    +            //     
    + //
    + //

    A block quote.

    + //
    + //
  2. + //
+ + Console.WriteLine("Example 253\nSection Container blocks / List items\n"); + TestParser.TestSpec(" 1. A paragraph\nwith two lines.\n\n indented code\n\n > A block quote.", "
    \n
  1. \n

    A paragraph\nwith two lines.

    \n
    indented code\n
    \n
    \n

    A block quote.

    \n
    \n
  2. \n
", ""); + } + + // Indentation can be partially deleted: + [Test] + public void ContainerBlocksListItems_Example254() + { + // Example 254 + // Section: Container blocks / List items + // + // The following Markdown: + // 1. A paragraph + // with two lines. + // + // Should be rendered as: + //
    + //
  1. A paragraph + // with two lines.
  2. + //
+ + Console.WriteLine("Example 254\nSection Container blocks / List items\n"); + TestParser.TestSpec(" 1. A paragraph\n with two lines.", "
    \n
  1. A paragraph\nwith two lines.
  2. \n
", ""); + } + + // These examples show how laziness can work in nested structures: + [Test] + public void ContainerBlocksListItems_Example255() + { + // Example 255 + // Section: Container blocks / List items + // + // The following Markdown: + // > 1. > Blockquote + // continued here. + // + // Should be rendered as: + //
+ //
    + //
  1. + //
    + //

    Blockquote + // continued here.

    + //
    + //
  2. + //
+ //
+ + Console.WriteLine("Example 255\nSection Container blocks / List items\n"); + TestParser.TestSpec("> 1. > Blockquote\ncontinued here.", "
\n
    \n
  1. \n
    \n

    Blockquote\ncontinued here.

    \n
    \n
  2. \n
\n
", ""); + } + + [Test] + public void ContainerBlocksListItems_Example256() + { + // Example 256 + // Section: Container blocks / List items + // + // The following Markdown: + // > 1. > Blockquote + // > continued here. + // + // Should be rendered as: + //
+ //
    + //
  1. + //
    + //

    Blockquote + // continued here.

    + //
    + //
  2. + //
+ //
+ + Console.WriteLine("Example 256\nSection Container blocks / List items\n"); + TestParser.TestSpec("> 1. > Blockquote\n> continued here.", "
\n
    \n
  1. \n
    \n

    Blockquote\ncontinued here.

    \n
    \n
  2. \n
\n
", ""); + } + + // 6. **That's all.** Nothing that is not counted as a list item by rules + // #1--5 counts as a [list item](#list-items). + // + // The rules for sublists follow from the general rules above. A sublist + // must be indented the same number of spaces a paragraph would need to be + // in order to be included in the list item. + // + // So, in this case we need two spaces indent: + [Test] + public void ContainerBlocksListItems_Example257() + { + // Example 257 + // Section: Container blocks / List items + // + // The following Markdown: + // - foo + // - bar + // - baz + // - boo + // + // Should be rendered as: + //
    + //
  • foo + //
      + //
    • bar + //
        + //
      • baz + //
          + //
        • boo
        • + //
        + //
      • + //
      + //
    • + //
    + //
  • + //
+ + Console.WriteLine("Example 257\nSection Container blocks / List items\n"); + TestParser.TestSpec("- foo\n - bar\n - baz\n - boo", "
    \n
  • foo\n
      \n
    • bar\n
        \n
      • baz\n
          \n
        • boo
        • \n
        \n
      • \n
      \n
    • \n
    \n
  • \n
", ""); + } + + // One is not enough: + [Test] + public void ContainerBlocksListItems_Example258() + { + // Example 258 + // Section: Container blocks / List items + // + // The following Markdown: + // - foo + // - bar + // - baz + // - boo + // + // Should be rendered as: + //
    + //
  • foo
  • + //
  • bar
  • + //
  • baz
  • + //
  • boo
  • + //
+ + Console.WriteLine("Example 258\nSection Container blocks / List items\n"); + TestParser.TestSpec("- foo\n - bar\n - baz\n - boo", "
    \n
  • foo
  • \n
  • bar
  • \n
  • baz
  • \n
  • boo
  • \n
", ""); + } + + // Here we need four, because the list marker is wider: + [Test] + public void ContainerBlocksListItems_Example259() + { + // Example 259 + // Section: Container blocks / List items + // + // The following Markdown: + // 10) foo + // - bar + // + // Should be rendered as: + //
    + //
  1. foo + //
      + //
    • bar
    • + //
    + //
  2. + //
+ + Console.WriteLine("Example 259\nSection Container blocks / List items\n"); + TestParser.TestSpec("10) foo\n - bar", "
    \n
  1. foo\n
      \n
    • bar
    • \n
    \n
  2. \n
", ""); + } + + // Three is not enough: + [Test] + public void ContainerBlocksListItems_Example260() + { + // Example 260 + // Section: Container blocks / List items + // + // The following Markdown: + // 10) foo + // - bar + // + // Should be rendered as: + //
    + //
  1. foo
  2. + //
+ //
    + //
  • bar
  • + //
+ + Console.WriteLine("Example 260\nSection Container blocks / List items\n"); + TestParser.TestSpec("10) foo\n - bar", "
    \n
  1. foo
  2. \n
\n
    \n
  • bar
  • \n
", ""); + } + + // A list may be the first block in a list item: + [Test] + public void ContainerBlocksListItems_Example261() + { + // Example 261 + // Section: Container blocks / List items + // + // The following Markdown: + // - - foo + // + // Should be rendered as: + //
    + //
  • + //
      + //
    • foo
    • + //
    + //
  • + //
+ + Console.WriteLine("Example 261\nSection Container blocks / List items\n"); + TestParser.TestSpec("- - foo", "
    \n
  • \n
      \n
    • foo
    • \n
    \n
  • \n
", ""); + } + + [Test] + public void ContainerBlocksListItems_Example262() + { + // Example 262 + // Section: Container blocks / List items + // + // The following Markdown: + // 1. - 2. foo + // + // Should be rendered as: + //
    + //
  1. + //
      + //
    • + //
        + //
      1. foo
      2. + //
      + //
    • + //
    + //
  2. + //
+ + Console.WriteLine("Example 262\nSection Container blocks / List items\n"); + TestParser.TestSpec("1. - 2. foo", "
    \n
  1. \n
      \n
    • \n
        \n
      1. foo
      2. \n
      \n
    • \n
    \n
  2. \n
", ""); + } + + // A list item can contain a heading: + [Test] + public void ContainerBlocksListItems_Example263() + { + // Example 263 + // Section: Container blocks / List items + // + // The following Markdown: + // - # Foo + // - Bar + // --- + // baz + // + // Should be rendered as: + //
    + //
  • + //

    Foo

    + //
  • + //
  • + //

    Bar

    + // baz
  • + //
+ + Console.WriteLine("Example 263\nSection Container blocks / List items\n"); + TestParser.TestSpec("- # Foo\n- Bar\n ---\n baz", "
    \n
  • \n

    Foo

    \n
  • \n
  • \n

    Bar

    \nbaz
  • \n
", ""); + } + } + + [TestFixture] + public class TestContainerBlocksLists + { + // ### Motivation + // + // John Gruber's Markdown spec says the following about list items: + // + // 1. "List markers typically start at the left margin, but may be indented + // by up to three spaces. List markers must be followed by one or more + // spaces or a tab." + // + // 2. "To make lists look nice, you can wrap items with hanging indents.... + // But if you don't want to, you don't have to." + // + // 3. "List items may consist of multiple paragraphs. Each subsequent + // paragraph in a list item must be indented by either 4 spaces or one + // tab." + // + // 4. "It looks nice if you indent every line of the subsequent paragraphs, + // but here again, Markdown will allow you to be lazy." + // + // 5. "To put a blockquote within a list item, the blockquote's `>` + // delimiters need to be indented." + // + // 6. "To put a code block within a list item, the code block needs to be + // indented twice — 8 spaces or two tabs." + // + // These rules specify that a paragraph under a list item must be indented + // four spaces (presumably, from the left margin, rather than the start of + // the list marker, but this is not said), and that code under a list item + // must be indented eight spaces instead of the usual four. They also say + // that a block quote must be indented, but not by how much; however, the + // example given has four spaces indentation. Although nothing is said + // about other kinds of block-level content, it is certainly reasonable to + // infer that *all* block elements under a list item, including other + // lists, must be indented four spaces. This principle has been called the + // *four-space rule*. + // + // The four-space rule is clear and principled, and if the reference + // implementation `Markdown.pl` had followed it, it probably would have + // become the standard. However, `Markdown.pl` allowed paragraphs and + // sublists to start with only two spaces indentation, at least on the + // outer level. Worse, its behavior was inconsistent: a sublist of an + // outer-level list needed two spaces indentation, but a sublist of this + // sublist needed three spaces. It is not surprising, then, that different + // implementations of Markdown have developed very different rules for + // determining what comes under a list item. (Pandoc and python-Markdown, + // for example, stuck with Gruber's syntax description and the four-space + // rule, while discount, redcarpet, marked, PHP Markdown, and others + // followed `Markdown.pl`'s behavior more closely.) + // + // Unfortunately, given the divergences between implementations, there + // is no way to give a spec for list items that will be guaranteed not + // to break any existing documents. However, the spec given here should + // correctly handle lists formatted with either the four-space rule or + // the more forgiving `Markdown.pl` behavior, provided they are laid out + // in a way that is natural for a human to read. + // + // The strategy here is to let the width and indentation of the list marker + // determine the indentation necessary for blocks to fall under the list + // item, rather than having a fixed and arbitrary number. The writer can + // think of the body of the list item as a unit which gets indented to the + // right enough to fit the list marker (and any indentation on the list + // marker). (The laziness rule, #5, then allows continuation lines to be + // unindented if needed.) + // + // This rule is superior, we claim, to any rule requiring a fixed level of + // indentation from the margin. The four-space rule is clear but + // unnatural. It is quite unintuitive that + // + // ``` markdown + // - foo + // + // bar + // + // - baz + // ``` + // + // should be parsed as two lists with an intervening paragraph, + // + // ``` html + //
    + //
  • foo
  • + //
+ //

bar

+ //
    + //
  • baz
  • + //
+ // ``` + // + // as the four-space rule demands, rather than a single list, + // + // ``` html + //
    + //
  • + //

    foo

    + //

    bar

    + //
      + //
    • baz
    • + //
    + //
  • + //
+ // ``` + // + // The choice of four spaces is arbitrary. It can be learned, but it is + // not likely to be guessed, and it trips up beginners regularly. + // + // Would it help to adopt a two-space rule? The problem is that such + // a rule, together with the rule allowing 1--3 spaces indentation of the + // initial list marker, allows text that is indented *less than* the + // original list marker to be included in the list item. For example, + // `Markdown.pl` parses + // + // ``` markdown + // - one + // + // two + // ``` + // + // as a single list item, with `two` a continuation paragraph: + // + // ``` html + //
    + //
  • + //

    one

    + //

    two

    + //
  • + //
+ // ``` + // + // and similarly + // + // ``` markdown + // > - one + // > + // > two + // ``` + // + // as + // + // ``` html + //
+ //
    + //
  • + //

    one

    + //

    two

    + //
  • + //
+ //
+ // ``` + // + // This is extremely unintuitive. + // + // Rather than requiring a fixed indent from the margin, we could require + // a fixed indent (say, two spaces, or even one space) from the list marker (which + // may itself be indented). This proposal would remove the last anomaly + // discussed. Unlike the spec presented above, it would count the following + // as a list item with a subparagraph, even though the paragraph `bar` + // is not indented as far as the first paragraph `foo`: + // + // ``` markdown + // 10. foo + // + // bar + // ``` + // + // Arguably this text does read like a list item with `bar` as a subparagraph, + // which may count in favor of the proposal. However, on this proposal indented + // code would have to be indented six spaces after the list marker. And this + // would break a lot of existing Markdown, which has the pattern: + // + // ``` markdown + // 1. foo + // + // indented code + // ``` + // + // where the code is indented eight spaces. The spec above, by contrast, will + // parse this text as expected, since the code block's indentation is measured + // from the beginning of `foo`. + // + // The one case that needs special treatment is a list item that *starts* + // with indented code. How much indentation is required in that case, since + // we don't have a "first paragraph" to measure from? Rule #2 simply stipulates + // that in such cases, we require one space indentation from the list marker + // (and then the normal four spaces for the indented code). This will match the + // four-space rule in cases where the list marker plus its initial indentation + // takes four spaces (a common case), but diverge in other cases. + // + // ## Lists + // + // A [list](@) is a sequence of one or more + // list items [of the same type]. The list items + // may be separated by any number of blank lines. + // + // Two list items are [of the same type](@) + // if they begin with a [list marker] of the same type. + // Two list markers are of the + // same type if (a) they are bullet list markers using the same character + // (`-`, `+`, or `*`) or (b) they are ordered list numbers with the same + // delimiter (either `.` or `)`). + // + // A list is an [ordered list](@) + // if its constituent list items begin with + // [ordered list markers], and a + // [bullet list](@) if its constituent list + // items begin with [bullet list markers]. + // + // The [start number](@) + // of an [ordered list] is determined by the list number of + // its initial list item. The numbers of subsequent list items are + // disregarded. + // + // A list is [loose](@) if any of its constituent + // list items are separated by blank lines, or if any of its constituent + // list items directly contain two block-level elements with a blank line + // between them. Otherwise a list is [tight](@). + // (The difference in HTML output is that paragraphs in a loose list are + // wrapped in `

` tags, while paragraphs in a tight list are not.) + // + // Changing the bullet or ordered list delimiter starts a new list: + [Test] + public void ContainerBlocksLists_Example264() + { + // Example 264 + // Section: Container blocks / Lists + // + // The following Markdown: + // - foo + // - bar + // + baz + // + // Should be rendered as: + //

    + //
  • foo
  • + //
  • bar
  • + //
+ //
    + //
  • baz
  • + //
+ + Console.WriteLine("Example 264\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- foo\n- bar\n+ baz", "
    \n
  • foo
  • \n
  • bar
  • \n
\n
    \n
  • baz
  • \n
", ""); + } + + [Test] + public void ContainerBlocksLists_Example265() + { + // Example 265 + // Section: Container blocks / Lists + // + // The following Markdown: + // 1. foo + // 2. bar + // 3) baz + // + // Should be rendered as: + //
    + //
  1. foo
  2. + //
  3. bar
  4. + //
+ //
    + //
  1. baz
  2. + //
+ + Console.WriteLine("Example 265\nSection Container blocks / Lists\n"); + TestParser.TestSpec("1. foo\n2. bar\n3) baz", "
    \n
  1. foo
  2. \n
  3. bar
  4. \n
\n
    \n
  1. baz
  2. \n
", ""); + } + + // In CommonMark, a list can interrupt a paragraph. That is, + // no blank line is needed to separate a paragraph from a following + // list: + [Test] + public void ContainerBlocksLists_Example266() + { + // Example 266 + // Section: Container blocks / Lists + // + // The following Markdown: + // Foo + // - bar + // - baz + // + // Should be rendered as: + //

Foo

+ //
    + //
  • bar
  • + //
  • baz
  • + //
+ + Console.WriteLine("Example 266\nSection Container blocks / Lists\n"); + TestParser.TestSpec("Foo\n- bar\n- baz", "

Foo

\n
    \n
  • bar
  • \n
  • baz
  • \n
", ""); + } + + // `Markdown.pl` does not allow this, through fear of triggering a list + // via a numeral in a hard-wrapped line: + // + // ``` markdown + // The number of windows in my house is + // 14. The number of doors is 6. + // ``` + // + // Oddly, though, `Markdown.pl` *does* allow a blockquote to + // interrupt a paragraph, even though the same considerations might + // apply. + // + // In CommonMark, we do allow lists to interrupt paragraphs, for + // two reasons. First, it is natural and not uncommon for people + // to start lists without blank lines: + // + // ``` markdown + // I need to buy + // - new shoes + // - a coat + // - a plane ticket + // ``` + // + // Second, we are attracted to a + // + // > [principle of uniformity](@): + // > if a chunk of text has a certain + // > meaning, it will continue to have the same meaning when put into a + // > container block (such as a list item or blockquote). + // + // (Indeed, the spec for [list items] and [block quotes] presupposes + // this principle.) This principle implies that if + // + // ``` markdown + // * I need to buy + // - new shoes + // - a coat + // - a plane ticket + // ``` + // + // is a list item containing a paragraph followed by a nested sublist, + // as all Markdown implementations agree it is (though the paragraph + // may be rendered without `

` tags, since the list is "tight"), + // then + // + // ``` markdown + // I need to buy + // - new shoes + // - a coat + // - a plane ticket + // ``` + // + // by itself should be a paragraph followed by a nested sublist. + // + // Since it is well established Markdown practice to allow lists to + // interrupt paragraphs inside list items, the [principle of + // uniformity] requires us to allow this outside list items as + // well. ([reStructuredText](http://docutils.sourceforge.net/rst.html) + // takes a different approach, requiring blank lines before lists + // even inside other list items.) + // + // In order to solve of unwanted lists in paragraphs with + // hard-wrapped numerals, we allow only lists starting with `1` to + // interrupt paragraphs. Thus, + [Test] + public void ContainerBlocksLists_Example267() + { + // Example 267 + // Section: Container blocks / Lists + // + // The following Markdown: + // The number of windows in my house is + // 14. The number of doors is 6. + // + // Should be rendered as: + //

The number of windows in my house is + // 14. The number of doors is 6.

+ + Console.WriteLine("Example 267\nSection Container blocks / Lists\n"); + TestParser.TestSpec("The number of windows in my house is\n14. The number of doors is 6.", "

The number of windows in my house is\n14. The number of doors is 6.

", ""); + } + + // We may still get an unintended result in cases like + [Test] + public void ContainerBlocksLists_Example268() + { + // Example 268 + // Section: Container blocks / Lists + // + // The following Markdown: + // The number of windows in my house is + // 1. The number of doors is 6. + // + // Should be rendered as: + //

The number of windows in my house is

+ //
    + //
  1. The number of doors is 6.
  2. + //
+ + Console.WriteLine("Example 268\nSection Container blocks / Lists\n"); + TestParser.TestSpec("The number of windows in my house is\n1. The number of doors is 6.", "

The number of windows in my house is

\n
    \n
  1. The number of doors is 6.
  2. \n
", ""); + } + + // but this rule should prevent most spurious list captures. + // + // There can be any number of blank lines between items: + [Test] + public void ContainerBlocksLists_Example269() + { + // Example 269 + // Section: Container blocks / Lists + // + // The following Markdown: + // - foo + // + // - bar + // + // + // - baz + // + // Should be rendered as: + //
    + //
  • + //

    foo

    + //
  • + //
  • + //

    bar

    + //
  • + //
  • + //

    baz

    + //
  • + //
+ + Console.WriteLine("Example 269\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- foo\n\n- bar\n\n\n- baz", "
    \n
  • \n

    foo

    \n
  • \n
  • \n

    bar

    \n
  • \n
  • \n

    baz

    \n
  • \n
", ""); + } + + [Test] + public void ContainerBlocksLists_Example270() + { + // Example 270 + // Section: Container blocks / Lists + // + // The following Markdown: + // - foo + // - bar + // - baz + // + // + // bim + // + // Should be rendered as: + //
    + //
  • foo + //
      + //
    • bar + //
        + //
      • + //

        baz

        + //

        bim

        + //
      • + //
      + //
    • + //
    + //
  • + //
+ + Console.WriteLine("Example 270\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- foo\n - bar\n - baz\n\n\n bim", "
    \n
  • foo\n
      \n
    • bar\n
        \n
      • \n

        baz

        \n

        bim

        \n
      • \n
      \n
    • \n
    \n
  • \n
", ""); + } + + // To separate consecutive lists of the same type, or to separate a + // list from an indented code block that would otherwise be parsed + // as a subparagraph of the final list item, you can insert a blank HTML + // comment: + [Test] + public void ContainerBlocksLists_Example271() + { + // Example 271 + // Section: Container blocks / Lists + // + // The following Markdown: + // - foo + // - bar + // + // + // + // - baz + // - bim + // + // Should be rendered as: + //
    + //
  • foo
  • + //
  • bar
  • + //
+ // + //
    + //
  • baz
  • + //
  • bim
  • + //
+ + Console.WriteLine("Example 271\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- foo\n- bar\n\n\n\n- baz\n- bim", "
    \n
  • foo
  • \n
  • bar
  • \n
\n\n
    \n
  • baz
  • \n
  • bim
  • \n
", ""); + } + + [Test] + public void ContainerBlocksLists_Example272() + { + // Example 272 + // Section: Container blocks / Lists + // + // The following Markdown: + // - foo + // + // notcode + // + // - foo + // + // + // + // code + // + // Should be rendered as: + //
    + //
  • + //

    foo

    + //

    notcode

    + //
  • + //
  • + //

    foo

    + //
  • + //
+ // + //
code
+            //     
+ + Console.WriteLine("Example 272\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- foo\n\n notcode\n\n- foo\n\n\n\n code", "
    \n
  • \n

    foo

    \n

    notcode

    \n
  • \n
  • \n

    foo

    \n
  • \n
\n\n
code\n
", ""); + } + + // List items need not be indented to the same level. The following + // list items will be treated as items at the same list level, + // since none is indented enough to belong to the previous list + // item: + [Test] + public void ContainerBlocksLists_Example273() + { + // Example 273 + // Section: Container blocks / Lists + // + // The following Markdown: + // - a + // - b + // - c + // - d + // - e + // - f + // - g + // - h + // - i + // + // Should be rendered as: + //
    + //
  • a
  • + //
  • b
  • + //
  • c
  • + //
  • d
  • + //
  • e
  • + //
  • f
  • + //
  • g
  • + //
  • h
  • + //
  • i
  • + //
+ + Console.WriteLine("Example 273\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- a\n - b\n - c\n - d\n - e\n - f\n - g\n - h\n- i", "
    \n
  • a
  • \n
  • b
  • \n
  • c
  • \n
  • d
  • \n
  • e
  • \n
  • f
  • \n
  • g
  • \n
  • h
  • \n
  • i
  • \n
", ""); + } + + [Test] + public void ContainerBlocksLists_Example274() + { + // Example 274 + // Section: Container blocks / Lists + // + // The following Markdown: + // 1. a + // + // 2. b + // + // 3. c + // + // Should be rendered as: + //
    + //
  1. + //

    a

    + //
  2. + //
  3. + //

    b

    + //
  4. + //
  5. + //

    c

    + //
  6. + //
+ + Console.WriteLine("Example 274\nSection Container blocks / Lists\n"); + TestParser.TestSpec("1. a\n\n 2. b\n\n 3. c", "
    \n
  1. \n

    a

    \n
  2. \n
  3. \n

    b

    \n
  4. \n
  5. \n

    c

    \n
  6. \n
", ""); + } + + // This is a loose list, because there is a blank line between + // two of the list items: + [Test] + public void ContainerBlocksLists_Example275() + { + // Example 275 + // Section: Container blocks / Lists + // + // The following Markdown: + // - a + // - b + // + // - c + // + // Should be rendered as: + //
    + //
  • + //

    a

    + //
  • + //
  • + //

    b

    + //
  • + //
  • + //

    c

    + //
  • + //
+ + Console.WriteLine("Example 275\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- a\n- b\n\n- c", "
    \n
  • \n

    a

    \n
  • \n
  • \n

    b

    \n
  • \n
  • \n

    c

    \n
  • \n
", ""); + } + + // So is this, with a empty second item: + [Test] + public void ContainerBlocksLists_Example276() + { + // Example 276 + // Section: Container blocks / Lists + // + // The following Markdown: + // * a + // * + // + // * c + // + // Should be rendered as: + //
    + //
  • + //

    a

    + //
  • + //
  • + //
  • + //

    c

    + //
  • + //
+ + Console.WriteLine("Example 276\nSection Container blocks / Lists\n"); + TestParser.TestSpec("* a\n*\n\n* c", "
    \n
  • \n

    a

    \n
  • \n
  • \n
  • \n

    c

    \n
  • \n
", ""); + } + + // These are loose lists, even though there is no space between the items, + // because one of the items directly contains two block-level elements + // with a blank line between them: + [Test] + public void ContainerBlocksLists_Example277() + { + // Example 277 + // Section: Container blocks / Lists + // + // The following Markdown: + // - a + // - b + // + // c + // - d + // + // Should be rendered as: + //
    + //
  • + //

    a

    + //
  • + //
  • + //

    b

    + //

    c

    + //
  • + //
  • + //

    d

    + //
  • + //
+ + Console.WriteLine("Example 277\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- a\n- b\n\n c\n- d", "
    \n
  • \n

    a

    \n
  • \n
  • \n

    b

    \n

    c

    \n
  • \n
  • \n

    d

    \n
  • \n
", ""); + } + + [Test] + public void ContainerBlocksLists_Example278() + { + // Example 278 + // Section: Container blocks / Lists + // + // The following Markdown: + // - a + // - b + // + // [ref]: /url + // - d + // + // Should be rendered as: + //
    + //
  • + //

    a

    + //
  • + //
  • + //

    b

    + //
  • + //
  • + //

    d

    + //
  • + //
+ + Console.WriteLine("Example 278\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- a\n- b\n\n [ref]: /url\n- d", "
    \n
  • \n

    a

    \n
  • \n
  • \n

    b

    \n
  • \n
  • \n

    d

    \n
  • \n
", ""); + } + + // This is a tight list, because the blank lines are in a code block: + [Test] + public void ContainerBlocksLists_Example279() + { + // Example 279 + // Section: Container blocks / Lists + // + // The following Markdown: + // - a + // - ``` + // b + // + // + // ``` + // - c + // + // Should be rendered as: + //
    + //
  • a
  • + //
  • + //
    b
    +            //     
    +            //     
    +            //     
    + //
  • + //
  • c
  • + //
+ + Console.WriteLine("Example 279\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- a\n- ```\n b\n\n\n ```\n- c", "
    \n
  • a
  • \n
  • \n
    b\n\n\n
    \n
  • \n
  • c
  • \n
", ""); + } + + // This is a tight list, because the blank line is between two + // paragraphs of a sublist. So the sublist is loose while + // the outer list is tight: + [Test] + public void ContainerBlocksLists_Example280() + { + // Example 280 + // Section: Container blocks / Lists + // + // The following Markdown: + // - a + // - b + // + // c + // - d + // + // Should be rendered as: + //
    + //
  • a + //
      + //
    • + //

      b

      + //

      c

      + //
    • + //
    + //
  • + //
  • d
  • + //
+ + Console.WriteLine("Example 280\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- a\n - b\n\n c\n- d", "
    \n
  • a\n
      \n
    • \n

      b

      \n

      c

      \n
    • \n
    \n
  • \n
  • d
  • \n
", ""); + } + + // This is a tight list, because the blank line is inside the + // block quote: + [Test] + public void ContainerBlocksLists_Example281() + { + // Example 281 + // Section: Container blocks / Lists + // + // The following Markdown: + // * a + // > b + // > + // * c + // + // Should be rendered as: + //
    + //
  • a + //
    + //

    b

    + //
    + //
  • + //
  • c
  • + //
+ + Console.WriteLine("Example 281\nSection Container blocks / Lists\n"); + TestParser.TestSpec("* a\n > b\n >\n* c", "
    \n
  • a\n
    \n

    b

    \n
    \n
  • \n
  • c
  • \n
", ""); + } + + // This list is tight, because the consecutive block elements + // are not separated by blank lines: + [Test] + public void ContainerBlocksLists_Example282() + { + // Example 282 + // Section: Container blocks / Lists + // + // The following Markdown: + // - a + // > b + // ``` + // c + // ``` + // - d + // + // Should be rendered as: + //
    + //
  • a + //
    + //

    b

    + //
    + //
    c
    +            //     
    + //
  • + //
  • d
  • + //
+ + Console.WriteLine("Example 282\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- a\n > b\n ```\n c\n ```\n- d", "
    \n
  • a\n
    \n

    b

    \n
    \n
    c\n
    \n
  • \n
  • d
  • \n
", ""); + } + + // A single-paragraph list is tight: + [Test] + public void ContainerBlocksLists_Example283() + { + // Example 283 + // Section: Container blocks / Lists + // + // The following Markdown: + // - a + // + // Should be rendered as: + //
    + //
  • a
  • + //
+ + Console.WriteLine("Example 283\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- a", "
    \n
  • a
  • \n
", ""); + } + + [Test] + public void ContainerBlocksLists_Example284() + { + // Example 284 + // Section: Container blocks / Lists + // + // The following Markdown: + // - a + // - b + // + // Should be rendered as: + //
    + //
  • a + //
      + //
    • b
    • + //
    + //
  • + //
+ + Console.WriteLine("Example 284\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- a\n - b", "
    \n
  • a\n
      \n
    • b
    • \n
    \n
  • \n
", ""); + } + + // This list is loose, because of the blank line between the + // two block elements in the list item: + [Test] + public void ContainerBlocksLists_Example285() + { + // Example 285 + // Section: Container blocks / Lists + // + // The following Markdown: + // 1. ``` + // foo + // ``` + // + // bar + // + // Should be rendered as: + //
    + //
  1. + //
    foo
    +            //     
    + //

    bar

    + //
  2. + //
+ + Console.WriteLine("Example 285\nSection Container blocks / Lists\n"); + TestParser.TestSpec("1. ```\n foo\n ```\n\n bar", "
    \n
  1. \n
    foo\n
    \n

    bar

    \n
  2. \n
", ""); + } + + // Here the outer list is loose, the inner list tight: + [Test] + public void ContainerBlocksLists_Example286() + { + // Example 286 + // Section: Container blocks / Lists + // + // The following Markdown: + // * foo + // * bar + // + // baz + // + // Should be rendered as: + //
    + //
  • + //

    foo

    + //
      + //
    • bar
    • + //
    + //

    baz

    + //
  • + //
+ + Console.WriteLine("Example 286\nSection Container blocks / Lists\n"); + TestParser.TestSpec("* foo\n * bar\n\n baz", "
    \n
  • \n

    foo

    \n
      \n
    • bar
    • \n
    \n

    baz

    \n
  • \n
", ""); + } + + [Test] + public void ContainerBlocksLists_Example287() + { + // Example 287 + // Section: Container blocks / Lists + // + // The following Markdown: + // - a + // - b + // - c + // + // - d + // - e + // - f + // + // Should be rendered as: + //
    + //
  • + //

    a

    + //
      + //
    • b
    • + //
    • c
    • + //
    + //
  • + //
  • + //

    d

    + //
      + //
    • e
    • + //
    • f
    • + //
    + //
  • + //
+ + Console.WriteLine("Example 287\nSection Container blocks / Lists\n"); + TestParser.TestSpec("- a\n - b\n - c\n\n- d\n - e\n - f", "
    \n
  • \n

    a

    \n
      \n
    • b
    • \n
    • c
    • \n
    \n
  • \n
  • \n

    d

    \n
      \n
    • e
    • \n
    • f
    • \n
    \n
  • \n
", ""); + } + } + + [TestFixture] + public class TestInlines + { + // # Inlines + // + // Inlines are parsed sequentially from the beginning of the character + // stream to the end (left to right, in left-to-right languages). + // Thus, for example, in + [Test] + public void Inlines_Example288() + { + // Example 288 + // Section: Inlines + // + // The following Markdown: + // `hi`lo` + // + // Should be rendered as: + //

hilo`

+ + Console.WriteLine("Example 288\nSection Inlines\n"); + TestParser.TestSpec("`hi`lo`", "

hilo`

", ""); + } + } + + [TestFixture] + public class TestInlinesBackslashEscapes + { + // `hi` is parsed as code, leaving the backtick at the end as a literal + // backtick. + // + // ## Backslash escapes + // + // Any ASCII punctuation character may be backslash-escaped: + [Test] + public void InlinesBackslashEscapes_Example289() + { + // Example 289 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // \!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ + // + // Should be rendered as: + //

!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

+ + Console.WriteLine("Example 289\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec("\\!\\\"\\#\\$\\%\\&\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^\\_\\`\\{\\|\\}\\~", "

!"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~

", ""); + } + + // Backslashes before other characters are treated as literal + // backslashes: + [Test] + public void InlinesBackslashEscapes_Example290() + { + // Example 290 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // \→\A\a\ \3\φ\« + // + // Should be rendered as: + //

\→\A\a\ \3\φ\«

+ + Console.WriteLine("Example 290\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec("\\\t\\A\\a\\ \\3\\φ\\«", "

\\\t\\A\\a\\ \\3\\φ\\«

", ""); + } + + // Escaped characters are treated as regular characters and do + // not have their usual Markdown meanings: + [Test] + public void InlinesBackslashEscapes_Example291() + { + // Example 291 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // \*not emphasized* + // \
not a tag + // \[not a link](/foo) + // \`not code` + // 1\. not a list + // \* not a list + // \# not a heading + // \[foo]: /url "not a reference" + // + // Should be rendered as: + //

*not emphasized* + // <br/> not a tag + // [not a link](/foo) + // `not code` + // 1. not a list + // * not a list + // # not a heading + // [foo]: /url "not a reference"

+ + Console.WriteLine("Example 291\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec("\\*not emphasized*\n\\
not a tag\n\\[not a link](/foo)\n\\`not code`\n1\\. not a list\n\\* not a list\n\\# not a heading\n\\[foo]: /url \"not a reference\"", "

*not emphasized*\n<br/> not a tag\n[not a link](/foo)\n`not code`\n1. not a list\n* not a list\n# not a heading\n[foo]: /url "not a reference"

", ""); + } + + // If a backslash is itself escaped, the following character is not: + [Test] + public void InlinesBackslashEscapes_Example292() + { + // Example 292 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // \\*emphasis* + // + // Should be rendered as: + //

\emphasis

+ + Console.WriteLine("Example 292\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec("\\\\*emphasis*", "

\\emphasis

", ""); + } + + // A backslash at the end of the line is a [hard line break]: + [Test] + public void InlinesBackslashEscapes_Example293() + { + // Example 293 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // foo\ + // bar + // + // Should be rendered as: + //

foo
+ // bar

+ + Console.WriteLine("Example 293\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec("foo\\\nbar", "

foo
\nbar

", ""); + } + + // Backslash escapes do not work in code blocks, code spans, autolinks, or + // raw HTML: + [Test] + public void InlinesBackslashEscapes_Example294() + { + // Example 294 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // `` \[\` `` + // + // Should be rendered as: + //

\[\`

+ + Console.WriteLine("Example 294\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec("`` \\[\\` ``", "

\\[\\`

", ""); + } + + [Test] + public void InlinesBackslashEscapes_Example295() + { + // Example 295 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // \[\] + // + // Should be rendered as: + //
\[\]
+            //     
+ + Console.WriteLine("Example 295\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec(" \\[\\]", "
\\[\\]\n
", ""); + } + + [Test] + public void InlinesBackslashEscapes_Example296() + { + // Example 296 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // ~~~ + // \[\] + // ~~~ + // + // Should be rendered as: + //
\[\]
+            //     
+ + Console.WriteLine("Example 296\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec("~~~\n\\[\\]\n~~~", "
\\[\\]\n
", ""); + } + + [Test] + public void InlinesBackslashEscapes_Example297() + { + // Example 297 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // + // + // Should be rendered as: + //

http://example.com?find=\*

+ + Console.WriteLine("Example 297\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec("", "

http://example.com?find=\\*

", ""); + } + + [Test] + public void InlinesBackslashEscapes_Example298() + { + // Example 298 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // + // + // Should be rendered as: + // + + Console.WriteLine("Example 298\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec("", "", ""); + } + + // But they work in all other contexts, including URLs and link titles, + // link references, and [info strings] in [fenced code blocks]: + [Test] + public void InlinesBackslashEscapes_Example299() + { + // Example 299 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // [foo](/bar\* "ti\*tle") + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 299\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec("[foo](/bar\\* \"ti\\*tle\")", "

foo

", ""); + } + + [Test] + public void InlinesBackslashEscapes_Example300() + { + // Example 300 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // [foo] + // + // [foo]: /bar\* "ti\*tle" + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 300\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec("[foo]\n\n[foo]: /bar\\* \"ti\\*tle\"", "

foo

", ""); + } + + [Test] + public void InlinesBackslashEscapes_Example301() + { + // Example 301 + // Section: Inlines / Backslash escapes + // + // The following Markdown: + // ``` foo\+bar + // foo + // ``` + // + // Should be rendered as: + //
foo
+            //     
+ + Console.WriteLine("Example 301\nSection Inlines / Backslash escapes\n"); + TestParser.TestSpec("``` foo\\+bar\nfoo\n```", "
foo\n
", ""); + } + } + + [TestFixture] + public class TestInlinesEntityAndNumericCharacterReferences + { + // ## Entity and numeric character references + // + // All valid HTML entity references and numeric character + // references, except those occuring in code blocks and code spans, + // are recognized as such and treated as equivalent to the + // corresponding Unicode characters. Conforming CommonMark parsers + // need not store information about whether a particular character + // was represented in the source using a Unicode character or + // an entity reference. + // + // [Entity references](@) consist of `&` + any of the valid + // HTML5 entity names + `;`. The + // document + // is used as an authoritative source for the valid entity + // references and their corresponding code points. + [Test] + public void InlinesEntityAndNumericCharacterReferences_Example302() + { + // Example 302 + // Section: Inlines / Entity and numeric character references + // + // The following Markdown: + //   & © Æ Ď + // ¾ ℋ ⅆ + // ∲ ≧̸ + // + // Should be rendered as: + //

  & © Æ Ď + // ¾ ℋ ⅆ + // ∲ ≧̸

+ + Console.WriteLine("Example 302\nSection Inlines / Entity and numeric character references\n"); + TestParser.TestSpec("  & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸", "

  & © Æ Ď\n¾ ℋ ⅆ\n∲ ≧̸

", ""); + } + + // [Decimal numeric character + // references](@) + // consist of `&#` + a string of 1--8 arabic digits + `;`. A + // numeric character reference is parsed as the corresponding + // Unicode character. Invalid Unicode code points will be replaced by + // the REPLACEMENT CHARACTER (`U+FFFD`). For security reasons, + // the code point `U+0000` will also be replaced by `U+FFFD`. + [Test] + public void InlinesEntityAndNumericCharacterReferences_Example303() + { + // Example 303 + // Section: Inlines / Entity and numeric character references + // + // The following Markdown: + // # Ӓ Ϡ � � + // + // Should be rendered as: + //

# Ӓ Ϡ � �

+ + Console.WriteLine("Example 303\nSection Inlines / Entity and numeric character references\n"); + TestParser.TestSpec("# Ӓ Ϡ � �", "

# Ӓ Ϡ � �

", ""); + } + + // [Hexadecimal numeric character + // references](@) consist of `&#` + + // either `X` or `x` + a string of 1-8 hexadecimal digits + `;`. + // They too are parsed as the corresponding Unicode character (this + // time specified with a hexadecimal numeral instead of decimal). + [Test] + public void InlinesEntityAndNumericCharacterReferences_Example304() + { + // Example 304 + // Section: Inlines / Entity and numeric character references + // + // The following Markdown: + // " ആ ಫ + // + // Should be rendered as: + //

" ആ ಫ

+ + Console.WriteLine("Example 304\nSection Inlines / Entity and numeric character references\n"); + TestParser.TestSpec("" ആ ಫ", "

" ആ ಫ

", ""); + } + + // Here are some nonentities: + [Test] + public void InlinesEntityAndNumericCharacterReferences_Example305() + { + // Example 305 + // Section: Inlines / Entity and numeric character references + // + // The following Markdown: + //   &x; &#; &#x; + // &ThisIsNotDefined; &hi?; + // + // Should be rendered as: + //

&nbsp &x; &#; &#x; + // &ThisIsNotDefined; &hi?;

+ + Console.WriteLine("Example 305\nSection Inlines / Entity and numeric character references\n"); + TestParser.TestSpec("  &x; &#; &#x;\n&ThisIsNotDefined; &hi?;", "

&nbsp &x; &#; &#x;\n&ThisIsNotDefined; &hi?;

", ""); + } + + // Although HTML5 does accept some entity references + // without a trailing semicolon (such as `©`), these are not + // recognized here, because it makes the grammar too ambiguous: + [Test] + public void InlinesEntityAndNumericCharacterReferences_Example306() + { + // Example 306 + // Section: Inlines / Entity and numeric character references + // + // The following Markdown: + // © + // + // Should be rendered as: + //

&copy

+ + Console.WriteLine("Example 306\nSection Inlines / Entity and numeric character references\n"); + TestParser.TestSpec("©", "

&copy

", ""); + } + + // Strings that are not on the list of HTML5 named entities are not + // recognized as entity references either: + [Test] + public void InlinesEntityAndNumericCharacterReferences_Example307() + { + // Example 307 + // Section: Inlines / Entity and numeric character references + // + // The following Markdown: + // &MadeUpEntity; + // + // Should be rendered as: + //

&MadeUpEntity;

+ + Console.WriteLine("Example 307\nSection Inlines / Entity and numeric character references\n"); + TestParser.TestSpec("&MadeUpEntity;", "

&MadeUpEntity;

", ""); + } + + // Entity and numeric character references are recognized in any + // context besides code spans or code blocks, including + // URLs, [link titles], and [fenced code block][] [info strings]: + [Test] + public void InlinesEntityAndNumericCharacterReferences_Example308() + { + // Example 308 + // Section: Inlines / Entity and numeric character references + // + // The following Markdown: + // + // + // Should be rendered as: + // + + Console.WriteLine("Example 308\nSection Inlines / Entity and numeric character references\n"); + TestParser.TestSpec("", "", ""); + } + + [Test] + public void InlinesEntityAndNumericCharacterReferences_Example309() + { + // Example 309 + // Section: Inlines / Entity and numeric character references + // + // The following Markdown: + // [foo](/föö "föö") + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 309\nSection Inlines / Entity and numeric character references\n"); + TestParser.TestSpec("[foo](/föö \"föö\")", "

foo

", ""); + } + + [Test] + public void InlinesEntityAndNumericCharacterReferences_Example310() + { + // Example 310 + // Section: Inlines / Entity and numeric character references + // + // The following Markdown: + // [foo] + // + // [foo]: /föö "föö" + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 310\nSection Inlines / Entity and numeric character references\n"); + TestParser.TestSpec("[foo]\n\n[foo]: /föö \"föö\"", "

foo

", ""); + } + + [Test] + public void InlinesEntityAndNumericCharacterReferences_Example311() + { + // Example 311 + // Section: Inlines / Entity and numeric character references + // + // The following Markdown: + // ``` föö + // foo + // ``` + // + // Should be rendered as: + //
foo
+            //     
+ + Console.WriteLine("Example 311\nSection Inlines / Entity and numeric character references\n"); + TestParser.TestSpec("``` föö\nfoo\n```", "
foo\n
", ""); + } + + // Entity and numeric character references are treated as literal + // text in code spans and code blocks: + [Test] + public void InlinesEntityAndNumericCharacterReferences_Example312() + { + // Example 312 + // Section: Inlines / Entity and numeric character references + // + // The following Markdown: + // `föö` + // + // Should be rendered as: + //

f&ouml;&ouml;

+ + Console.WriteLine("Example 312\nSection Inlines / Entity and numeric character references\n"); + TestParser.TestSpec("`föö`", "

f&ouml;&ouml;

", ""); + } + + [Test] + public void InlinesEntityAndNumericCharacterReferences_Example313() + { + // Example 313 + // Section: Inlines / Entity and numeric character references + // + // The following Markdown: + // föfö + // + // Should be rendered as: + //
f&ouml;f&ouml;
+            //     
+ + Console.WriteLine("Example 313\nSection Inlines / Entity and numeric character references\n"); + TestParser.TestSpec(" föfö", "
f&ouml;f&ouml;\n
", ""); + } + } + + [TestFixture] + public class TestInlinesCodeSpans + { + // ## Code spans + // + // A [backtick string](@) + // is a string of one or more backtick characters (`` ` ``) that is neither + // preceded nor followed by a backtick. + // + // A [code span](@) begins with a backtick string and ends with + // a backtick string of equal length. The contents of the code span are + // the characters between the two backtick strings, with leading and + // trailing spaces and [line endings] removed, and + // [whitespace] collapsed to single spaces. + // + // This is a simple code span: + [Test] + public void InlinesCodeSpans_Example314() + { + // Example 314 + // Section: Inlines / Code spans + // + // The following Markdown: + // `foo` + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 314\nSection Inlines / Code spans\n"); + TestParser.TestSpec("`foo`", "

foo

", ""); + } + + // Here two backticks are used, because the code contains a backtick. + // This example also illustrates stripping of leading and trailing spaces: + [Test] + public void InlinesCodeSpans_Example315() + { + // Example 315 + // Section: Inlines / Code spans + // + // The following Markdown: + // `` foo ` bar `` + // + // Should be rendered as: + //

foo ` bar

+ + Console.WriteLine("Example 315\nSection Inlines / Code spans\n"); + TestParser.TestSpec("`` foo ` bar ``", "

foo ` bar

", ""); + } + + // This example shows the motivation for stripping leading and trailing + // spaces: + [Test] + public void InlinesCodeSpans_Example316() + { + // Example 316 + // Section: Inlines / Code spans + // + // The following Markdown: + // ` `` ` + // + // Should be rendered as: + //

``

+ + Console.WriteLine("Example 316\nSection Inlines / Code spans\n"); + TestParser.TestSpec("` `` `", "

``

", ""); + } + + // [Line endings] are treated like spaces: + [Test] + public void InlinesCodeSpans_Example317() + { + // Example 317 + // Section: Inlines / Code spans + // + // The following Markdown: + // `` + // foo + // `` + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 317\nSection Inlines / Code spans\n"); + TestParser.TestSpec("``\nfoo\n``", "

foo

", ""); + } + + // Interior spaces and [line endings] are collapsed into + // single spaces, just as they would be by a browser: + [Test] + public void InlinesCodeSpans_Example318() + { + // Example 318 + // Section: Inlines / Code spans + // + // The following Markdown: + // `foo bar + // baz` + // + // Should be rendered as: + //

foo bar baz

+ + Console.WriteLine("Example 318\nSection Inlines / Code spans\n"); + TestParser.TestSpec("`foo bar\n baz`", "

foo bar baz

", ""); + } + + // Not all [Unicode whitespace] (for instance, non-breaking space) is + // collapsed, however: + [Test] + public void InlinesCodeSpans_Example319() + { + // Example 319 + // Section: Inlines / Code spans + // + // The following Markdown: + // `a  b` + // + // Should be rendered as: + //

a  b

+ + Console.WriteLine("Example 319\nSection Inlines / Code spans\n"); + TestParser.TestSpec("`a  b`", "

a  b

", ""); + } + + // Q: Why not just leave the spaces, since browsers will collapse them + // anyway? A: Because we might be targeting a non-HTML format, and we + // shouldn't rely on HTML-specific rendering assumptions. + // + // (Existing implementations differ in their treatment of internal + // spaces and [line endings]. Some, including `Markdown.pl` and + // `showdown`, convert an internal [line ending] into a + // `
` tag. But this makes things difficult for those who like to + // hard-wrap their paragraphs, since a line break in the midst of a code + // span will cause an unintended line break in the output. Others just + // leave internal spaces as they are, which is fine if only HTML is being + // targeted.) + [Test] + public void InlinesCodeSpans_Example320() + { + // Example 320 + // Section: Inlines / Code spans + // + // The following Markdown: + // `foo `` bar` + // + // Should be rendered as: + //

foo `` bar

+ + Console.WriteLine("Example 320\nSection Inlines / Code spans\n"); + TestParser.TestSpec("`foo `` bar`", "

foo `` bar

", ""); + } + + // Note that backslash escapes do not work in code spans. All backslashes + // are treated literally: + [Test] + public void InlinesCodeSpans_Example321() + { + // Example 321 + // Section: Inlines / Code spans + // + // The following Markdown: + // `foo\`bar` + // + // Should be rendered as: + //

foo\bar`

+ + Console.WriteLine("Example 321\nSection Inlines / Code spans\n"); + TestParser.TestSpec("`foo\\`bar`", "

foo\\bar`

", ""); + } + + // Backslash escapes are never needed, because one can always choose a + // string of *n* backtick characters as delimiters, where the code does + // not contain any strings of exactly *n* backtick characters. + // + // Code span backticks have higher precedence than any other inline + // constructs except HTML tags and autolinks. Thus, for example, this is + // not parsed as emphasized text, since the second `*` is part of a code + // span: + [Test] + public void InlinesCodeSpans_Example322() + { + // Example 322 + // Section: Inlines / Code spans + // + // The following Markdown: + // *foo`*` + // + // Should be rendered as: + //

*foo*

+ + Console.WriteLine("Example 322\nSection Inlines / Code spans\n"); + TestParser.TestSpec("*foo`*`", "

*foo*

", ""); + } + + // And this is not parsed as a link: + [Test] + public void InlinesCodeSpans_Example323() + { + // Example 323 + // Section: Inlines / Code spans + // + // The following Markdown: + // [not a `link](/foo`) + // + // Should be rendered as: + //

[not a link](/foo)

+ + Console.WriteLine("Example 323\nSection Inlines / Code spans\n"); + TestParser.TestSpec("[not a `link](/foo`)", "

[not a link](/foo)

", ""); + } + + // Code spans, HTML tags, and autolinks have the same precedence. + // Thus, this is code: + [Test] + public void InlinesCodeSpans_Example324() + { + // Example 324 + // Section: Inlines / Code spans + // + // The following Markdown: + // `` + // + // Should be rendered as: + //

<a href="">`

+ + Console.WriteLine("Example 324\nSection Inlines / Code spans\n"); + TestParser.TestSpec("`
`", "

<a href="">`

", ""); + } + + // But this is an HTML tag: + [Test] + public void InlinesCodeSpans_Example325() + { + // Example 325 + // Section: Inlines / Code spans + // + // The following Markdown: + //
` + // + // Should be rendered as: + //

`

+ + Console.WriteLine("Example 325\nSection Inlines / Code spans\n"); + TestParser.TestSpec("`", "

`

", ""); + } + + // And this is code: + [Test] + public void InlinesCodeSpans_Example326() + { + // Example 326 + // Section: Inlines / Code spans + // + // The following Markdown: + // `` + // + // Should be rendered as: + //

<http://foo.bar.baz>`

+ + Console.WriteLine("Example 326\nSection Inlines / Code spans\n"); + TestParser.TestSpec("``", "

<http://foo.bar.baz>`

", ""); + } + + // But this is an autolink: + [Test] + public void InlinesCodeSpans_Example327() + { + // Example 327 + // Section: Inlines / Code spans + // + // The following Markdown: + // ` + // + // Should be rendered as: + //

http://foo.bar.`baz`

+ + Console.WriteLine("Example 327\nSection Inlines / Code spans\n"); + TestParser.TestSpec("`", "

http://foo.bar.`baz`

", ""); + } + + // When a backtick string is not closed by a matching backtick string, + // we just have literal backticks: + [Test] + public void InlinesCodeSpans_Example328() + { + // Example 328 + // Section: Inlines / Code spans + // + // The following Markdown: + // ```foo`` + // + // Should be rendered as: + //

```foo``

+ + Console.WriteLine("Example 328\nSection Inlines / Code spans\n"); + TestParser.TestSpec("```foo``", "

```foo``

", ""); + } + + [Test] + public void InlinesCodeSpans_Example329() + { + // Example 329 + // Section: Inlines / Code spans + // + // The following Markdown: + // `foo + // + // Should be rendered as: + //

`foo

+ + Console.WriteLine("Example 329\nSection Inlines / Code spans\n"); + TestParser.TestSpec("`foo", "

`foo

", ""); + } + + // The following case also illustrates the need for opening and + // closing backtick strings to be equal in length: + [Test] + public void InlinesCodeSpans_Example330() + { + // Example 330 + // Section: Inlines / Code spans + // + // The following Markdown: + // `foo``bar`` + // + // Should be rendered as: + //

`foobar

+ + Console.WriteLine("Example 330\nSection Inlines / Code spans\n"); + TestParser.TestSpec("`foo``bar``", "

`foobar

", ""); + } + } + + [TestFixture] + public class TestInlinesEmphasisAndStrongEmphasis + { + // ## Emphasis and strong emphasis + // + // John Gruber's original [Markdown syntax + // description](http://daringfireball.net/projects/markdown/syntax#em) says: + // + // > Markdown treats asterisks (`*`) and underscores (`_`) as indicators of + // > emphasis. Text wrapped with one `*` or `_` will be wrapped with an HTML + // > `` tag; double `*`'s or `_`'s will be wrapped with an HTML `` + // > tag. + // + // This is enough for most users, but these rules leave much undecided, + // especially when it comes to nested emphasis. The original + // `Markdown.pl` test suite makes it clear that triple `***` and + // `___` delimiters can be used for strong emphasis, and most + // implementations have also allowed the following patterns: + // + // ``` markdown + // ***strong emph*** + // ***strong** in emph* + // ***emph* in strong** + // **in strong *emph*** + // *in emph **strong*** + // ``` + // + // The following patterns are less widely supported, but the intent + // is clear and they are useful (especially in contexts like bibliography + // entries): + // + // ``` markdown + // *emph *with emph* in it* + // **strong **with strong** in it** + // ``` + // + // Many implementations have also restricted intraword emphasis to + // the `*` forms, to avoid unwanted emphasis in words containing + // internal underscores. (It is best practice to put these in code + // spans, but users often do not.) + // + // ``` markdown + // internal emphasis: foo*bar*baz + // no emphasis: foo_bar_baz + // ``` + // + // The rules given below capture all of these patterns, while allowing + // for efficient parsing strategies that do not backtrack. + // + // First, some definitions. A [delimiter run](@) is either + // a sequence of one or more `*` characters that is not preceded or + // followed by a non-backslash-escaped `*` character, or a sequence + // of one or more `_` characters that is not preceded or followed by + // a non-backslash-escaped `_` character. + // + // A [left-flanking delimiter run](@) is + // a [delimiter run] that is (a) not followed by [Unicode whitespace], + // and (b) not followed by a [punctuation character], or + // preceded by [Unicode whitespace] or a [punctuation character]. + // For purposes of this definition, the beginning and the end of + // the line count as Unicode whitespace. + // + // A [right-flanking delimiter run](@) is + // a [delimiter run] that is (a) not preceded by [Unicode whitespace], + // and (b) not preceded by a [punctuation character], or + // followed by [Unicode whitespace] or a [punctuation character]. + // For purposes of this definition, the beginning and the end of + // the line count as Unicode whitespace. + // + // Here are some examples of delimiter runs. + // + // - left-flanking but not right-flanking: + // + // ``` + // ***abc + // _abc + // **"abc" + // _"abc" + // ``` + // + // - right-flanking but not left-flanking: + // + // ``` + // abc*** + // abc_ + // "abc"** + // "abc"_ + // ``` + // + // - Both left and right-flanking: + // + // ``` + // abc***def + // "abc"_"def" + // ``` + // + // - Neither left nor right-flanking: + // + // ``` + // abc *** def + // a _ b + // ``` + // + // (The idea of distinguishing left-flanking and right-flanking + // delimiter runs based on the character before and the character + // after comes from Roopesh Chander's + // [vfmd](http://www.vfmd.org/vfmd-spec/specification/#procedure-for-identifying-emphasis-tags). + // vfmd uses the terminology "emphasis indicator string" instead of "delimiter + // run," and its rules for distinguishing left- and right-flanking runs + // are a bit more complex than the ones given here.) + // + // The following rules define emphasis and strong emphasis: + // + // 1. A single `*` character [can open emphasis](@) + // iff (if and only if) it is part of a [left-flanking delimiter run]. + // + // 2. A single `_` character [can open emphasis] iff + // it is part of a [left-flanking delimiter run] + // and either (a) not part of a [right-flanking delimiter run] + // or (b) part of a [right-flanking delimiter run] + // preceded by punctuation. + // + // 3. A single `*` character [can close emphasis](@) + // iff it is part of a [right-flanking delimiter run]. + // + // 4. A single `_` character [can close emphasis] iff + // it is part of a [right-flanking delimiter run] + // and either (a) not part of a [left-flanking delimiter run] + // or (b) part of a [left-flanking delimiter run] + // followed by punctuation. + // + // 5. A double `**` [can open strong emphasis](@) + // iff it is part of a [left-flanking delimiter run]. + // + // 6. A double `__` [can open strong emphasis] iff + // it is part of a [left-flanking delimiter run] + // and either (a) not part of a [right-flanking delimiter run] + // or (b) part of a [right-flanking delimiter run] + // preceded by punctuation. + // + // 7. A double `**` [can close strong emphasis](@) + // iff it is part of a [right-flanking delimiter run]. + // + // 8. A double `__` [can close strong emphasis] iff + // it is part of a [right-flanking delimiter run] + // and either (a) not part of a [left-flanking delimiter run] + // or (b) part of a [left-flanking delimiter run] + // followed by punctuation. + // + // 9. Emphasis begins with a delimiter that [can open emphasis] and ends + // with a delimiter that [can close emphasis], and that uses the same + // character (`_` or `*`) as the opening delimiter. The + // opening and closing delimiters must belong to separate + // [delimiter runs]. If one of the delimiters can both + // open and close emphasis, then the sum of the lengths of the + // delimiter runs containing the opening and closing delimiters + // must not be a multiple of 3. + // + // 10. Strong emphasis begins with a delimiter that + // [can open strong emphasis] and ends with a delimiter that + // [can close strong emphasis], and that uses the same character + // (`_` or `*`) as the opening delimiter. The + // opening and closing delimiters must belong to separate + // [delimiter runs]. If one of the delimiters can both open + // and close strong emphasis, then the sum of the lengths of + // the delimiter runs containing the opening and closing + // delimiters must not be a multiple of 3. + // + // 11. A literal `*` character cannot occur at the beginning or end of + // `*`-delimited emphasis or `**`-delimited strong emphasis, unless it + // is backslash-escaped. + // + // 12. A literal `_` character cannot occur at the beginning or end of + // `_`-delimited emphasis or `__`-delimited strong emphasis, unless it + // is backslash-escaped. + // + // Where rules 1--12 above are compatible with multiple parsings, + // the following principles resolve ambiguity: + // + // 13. The number of nestings should be minimized. Thus, for example, + // an interpretation `...` is always preferred to + // `...`. + // + // 14. An interpretation `...` is always + // preferred to `...`. + // + // 15. When two potential emphasis or strong emphasis spans overlap, + // so that the second begins before the first ends and ends after + // the first ends, the first takes precedence. Thus, for example, + // `*foo _bar* baz_` is parsed as `foo _bar baz_` rather + // than `*foo bar* baz`. + // + // 16. When there are two potential emphasis or strong emphasis spans + // with the same closing delimiter, the shorter one (the one that + // opens later) takes precedence. Thus, for example, + // `**foo **bar baz**` is parsed as `**foo bar baz` + // rather than `foo **bar baz`. + // + // 17. Inline code spans, links, images, and HTML tags group more tightly + // than emphasis. So, when there is a choice between an interpretation + // that contains one of these elements and one that does not, the + // former always wins. Thus, for example, `*[foo*](bar)` is + // parsed as `*foo*` rather than as + // `[foo](bar)`. + // + // These rules can be illustrated through a series of examples. + // + // Rule 1: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example331() + { + // Example 331 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo bar* + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 331\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo bar*", "

foo bar

", ""); + } + + // This is not emphasis, because the opening `*` is followed by + // whitespace, and hence not part of a [left-flanking delimiter run]: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example332() + { + // Example 332 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // a * foo bar* + // + // Should be rendered as: + //

a * foo bar*

+ + Console.WriteLine("Example 332\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("a * foo bar*", "

a * foo bar*

", ""); + } + + // This is not emphasis, because the opening `*` is preceded + // by an alphanumeric and followed by punctuation, and hence + // not part of a [left-flanking delimiter run]: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example333() + { + // Example 333 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // a*"foo"* + // + // Should be rendered as: + //

a*"foo"*

+ + Console.WriteLine("Example 333\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("a*\"foo\"*", "

a*"foo"*

", ""); + } + + // Unicode nonbreaking spaces count as whitespace, too: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example334() + { + // Example 334 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // * a * + // + // Should be rendered as: + //

* a *

+ + Console.WriteLine("Example 334\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("* a *", "

* a *

", ""); + } + + // Intraword emphasis with `*` is permitted: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example335() + { + // Example 335 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo*bar* + // + // Should be rendered as: + //

foobar

+ + Console.WriteLine("Example 335\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo*bar*", "

foobar

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example336() + { + // Example 336 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // 5*6*78 + // + // Should be rendered as: + //

5678

+ + Console.WriteLine("Example 336\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("5*6*78", "

5678

", ""); + } + + // Rule 2: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example337() + { + // Example 337 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _foo bar_ + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 337\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_foo bar_", "

foo bar

", ""); + } + + // This is not emphasis, because the opening `_` is followed by + // whitespace: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example338() + { + // Example 338 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _ foo bar_ + // + // Should be rendered as: + //

_ foo bar_

+ + Console.WriteLine("Example 338\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_ foo bar_", "

_ foo bar_

", ""); + } + + // This is not emphasis, because the opening `_` is preceded + // by an alphanumeric and followed by punctuation: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example339() + { + // Example 339 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // a_"foo"_ + // + // Should be rendered as: + //

a_"foo"_

+ + Console.WriteLine("Example 339\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("a_\"foo\"_", "

a_"foo"_

", ""); + } + + // Emphasis with `_` is not allowed inside words: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example340() + { + // Example 340 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo_bar_ + // + // Should be rendered as: + //

foo_bar_

+ + Console.WriteLine("Example 340\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo_bar_", "

foo_bar_

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example341() + { + // Example 341 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // 5_6_78 + // + // Should be rendered as: + //

5_6_78

+ + Console.WriteLine("Example 341\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("5_6_78", "

5_6_78

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example342() + { + // Example 342 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // пристаням_стремятся_ + // + // Should be rendered as: + //

пристаням_стремятся_

+ + Console.WriteLine("Example 342\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("пристаням_стремятся_", "

пристаням_стремятся_

", ""); + } + + // Here `_` does not generate emphasis, because the first delimiter run + // is right-flanking and the second left-flanking: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example343() + { + // Example 343 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // aa_"bb"_cc + // + // Should be rendered as: + //

aa_"bb"_cc

+ + Console.WriteLine("Example 343\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("aa_\"bb\"_cc", "

aa_"bb"_cc

", ""); + } + + // This is emphasis, even though the opening delimiter is + // both left- and right-flanking, because it is preceded by + // punctuation: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example344() + { + // Example 344 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo-_(bar)_ + // + // Should be rendered as: + //

foo-(bar)

+ + Console.WriteLine("Example 344\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo-_(bar)_", "

foo-(bar)

", ""); + } + + // Rule 3: + // + // This is not emphasis, because the closing delimiter does + // not match the opening delimiter: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example345() + { + // Example 345 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _foo* + // + // Should be rendered as: + //

_foo*

+ + Console.WriteLine("Example 345\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_foo*", "

_foo*

", ""); + } + + // This is not emphasis, because the closing `*` is preceded by + // whitespace: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example346() + { + // Example 346 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo bar * + // + // Should be rendered as: + //

*foo bar *

+ + Console.WriteLine("Example 346\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo bar *", "

*foo bar *

", ""); + } + + // A newline also counts as whitespace: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example347() + { + // Example 347 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo bar + // * + // + // Should be rendered as: + //

*foo bar + // *

+ + Console.WriteLine("Example 347\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo bar\n*", "

*foo bar\n*

", ""); + } + + // This is not emphasis, because the second `*` is + // preceded by punctuation and followed by an alphanumeric + // (hence it is not part of a [right-flanking delimiter run]: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example348() + { + // Example 348 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *(*foo) + // + // Should be rendered as: + //

*(*foo)

+ + Console.WriteLine("Example 348\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*(*foo)", "

*(*foo)

", ""); + } + + // The point of this restriction is more easily appreciated + // with this example: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example349() + { + // Example 349 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *(*foo*)* + // + // Should be rendered as: + //

(foo)

+ + Console.WriteLine("Example 349\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*(*foo*)*", "

(foo)

", ""); + } + + // Intraword emphasis with `*` is allowed: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example350() + { + // Example 350 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo*bar + // + // Should be rendered as: + //

foobar

+ + Console.WriteLine("Example 350\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo*bar", "

foobar

", ""); + } + + // Rule 4: + // + // This is not emphasis, because the closing `_` is preceded by + // whitespace: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example351() + { + // Example 351 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _foo bar _ + // + // Should be rendered as: + //

_foo bar _

+ + Console.WriteLine("Example 351\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_foo bar _", "

_foo bar _

", ""); + } + + // This is not emphasis, because the second `_` is + // preceded by punctuation and followed by an alphanumeric: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example352() + { + // Example 352 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _(_foo) + // + // Should be rendered as: + //

_(_foo)

+ + Console.WriteLine("Example 352\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_(_foo)", "

_(_foo)

", ""); + } + + // This is emphasis within emphasis: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example353() + { + // Example 353 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _(_foo_)_ + // + // Should be rendered as: + //

(foo)

+ + Console.WriteLine("Example 353\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_(_foo_)_", "

(foo)

", ""); + } + + // Intraword emphasis is disallowed for `_`: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example354() + { + // Example 354 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _foo_bar + // + // Should be rendered as: + //

_foo_bar

+ + Console.WriteLine("Example 354\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_foo_bar", "

_foo_bar

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example355() + { + // Example 355 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _пристаням_стремятся + // + // Should be rendered as: + //

_пристаням_стремятся

+ + Console.WriteLine("Example 355\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_пристаням_стремятся", "

_пристаням_стремятся

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example356() + { + // Example 356 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _foo_bar_baz_ + // + // Should be rendered as: + //

foo_bar_baz

+ + Console.WriteLine("Example 356\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_foo_bar_baz_", "

foo_bar_baz

", ""); + } + + // This is emphasis, even though the closing delimiter is + // both left- and right-flanking, because it is followed by + // punctuation: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example357() + { + // Example 357 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _(bar)_. + // + // Should be rendered as: + //

(bar).

+ + Console.WriteLine("Example 357\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_(bar)_.", "

(bar).

", ""); + } + + // Rule 5: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example358() + { + // Example 358 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo bar** + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 358\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo bar**", "

foo bar

", ""); + } + + // This is not strong emphasis, because the opening delimiter is + // followed by whitespace: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example359() + { + // Example 359 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ** foo bar** + // + // Should be rendered as: + //

** foo bar**

+ + Console.WriteLine("Example 359\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("** foo bar**", "

** foo bar**

", ""); + } + + // This is not strong emphasis, because the opening `**` is preceded + // by an alphanumeric and followed by punctuation, and hence + // not part of a [left-flanking delimiter run]: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example360() + { + // Example 360 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // a**"foo"** + // + // Should be rendered as: + //

a**"foo"**

+ + Console.WriteLine("Example 360\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("a**\"foo\"**", "

a**"foo"**

", ""); + } + + // Intraword strong emphasis with `**` is permitted: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example361() + { + // Example 361 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo**bar** + // + // Should be rendered as: + //

foobar

+ + Console.WriteLine("Example 361\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo**bar**", "

foobar

", ""); + } + + // Rule 6: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example362() + { + // Example 362 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __foo bar__ + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 362\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__foo bar__", "

foo bar

", ""); + } + + // This is not strong emphasis, because the opening delimiter is + // followed by whitespace: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example363() + { + // Example 363 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __ foo bar__ + // + // Should be rendered as: + //

__ foo bar__

+ + Console.WriteLine("Example 363\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__ foo bar__", "

__ foo bar__

", ""); + } + + // A newline counts as whitespace: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example364() + { + // Example 364 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __ + // foo bar__ + // + // Should be rendered as: + //

__ + // foo bar__

+ + Console.WriteLine("Example 364\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__\nfoo bar__", "

__\nfoo bar__

", ""); + } + + // This is not strong emphasis, because the opening `__` is preceded + // by an alphanumeric and followed by punctuation: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example365() + { + // Example 365 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // a__"foo"__ + // + // Should be rendered as: + //

a__"foo"__

+ + Console.WriteLine("Example 365\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("a__\"foo\"__", "

a__"foo"__

", ""); + } + + // Intraword strong emphasis is forbidden with `__`: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example366() + { + // Example 366 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo__bar__ + // + // Should be rendered as: + //

foo__bar__

+ + Console.WriteLine("Example 366\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo__bar__", "

foo__bar__

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example367() + { + // Example 367 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // 5__6__78 + // + // Should be rendered as: + //

5__6__78

+ + Console.WriteLine("Example 367\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("5__6__78", "

5__6__78

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example368() + { + // Example 368 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // пристаням__стремятся__ + // + // Should be rendered as: + //

пристаням__стремятся__

+ + Console.WriteLine("Example 368\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("пристаням__стремятся__", "

пристаням__стремятся__

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example369() + { + // Example 369 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __foo, __bar__, baz__ + // + // Should be rendered as: + //

foo, bar, baz

+ + Console.WriteLine("Example 369\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__foo, __bar__, baz__", "

foo, bar, baz

", ""); + } + + // This is strong emphasis, even though the opening delimiter is + // both left- and right-flanking, because it is preceded by + // punctuation: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example370() + { + // Example 370 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo-__(bar)__ + // + // Should be rendered as: + //

foo-(bar)

+ + Console.WriteLine("Example 370\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo-__(bar)__", "

foo-(bar)

", ""); + } + + // Rule 7: + // + // This is not strong emphasis, because the closing delimiter is preceded + // by whitespace: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example371() + { + // Example 371 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo bar ** + // + // Should be rendered as: + //

**foo bar **

+ + Console.WriteLine("Example 371\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo bar **", "

**foo bar **

", ""); + } + + // (Nor can it be interpreted as an emphasized `*foo bar *`, because of + // Rule 11.) + // + // This is not strong emphasis, because the second `**` is + // preceded by punctuation and followed by an alphanumeric: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example372() + { + // Example 372 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **(**foo) + // + // Should be rendered as: + //

**(**foo)

+ + Console.WriteLine("Example 372\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**(**foo)", "

**(**foo)

", ""); + } + + // The point of this restriction is more easily appreciated + // with these examples: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example373() + { + // Example 373 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *(**foo**)* + // + // Should be rendered as: + //

(foo)

+ + Console.WriteLine("Example 373\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*(**foo**)*", "

(foo)

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example374() + { + // Example 374 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **Gomphocarpus (*Gomphocarpus physocarpus*, syn. + // *Asclepias physocarpa*)** + // + // Should be rendered as: + //

Gomphocarpus (Gomphocarpus physocarpus, syn. + // Asclepias physocarpa)

+ + Console.WriteLine("Example 374\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**Gomphocarpus (*Gomphocarpus physocarpus*, syn.\n*Asclepias physocarpa*)**", "

Gomphocarpus (Gomphocarpus physocarpus, syn.\nAsclepias physocarpa)

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example375() + { + // Example 375 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo "*bar*" foo** + // + // Should be rendered as: + //

foo "bar" foo

+ + Console.WriteLine("Example 375\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo \"*bar*\" foo**", "

foo "bar" foo

", ""); + } + + // Intraword emphasis: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example376() + { + // Example 376 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo**bar + // + // Should be rendered as: + //

foobar

+ + Console.WriteLine("Example 376\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo**bar", "

foobar

", ""); + } + + // Rule 8: + // + // This is not strong emphasis, because the closing delimiter is + // preceded by whitespace: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example377() + { + // Example 377 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __foo bar __ + // + // Should be rendered as: + //

__foo bar __

+ + Console.WriteLine("Example 377\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__foo bar __", "

__foo bar __

", ""); + } + + // This is not strong emphasis, because the second `__` is + // preceded by punctuation and followed by an alphanumeric: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example378() + { + // Example 378 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __(__foo) + // + // Should be rendered as: + //

__(__foo)

+ + Console.WriteLine("Example 378\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__(__foo)", "

__(__foo)

", ""); + } + + // The point of this restriction is more easily appreciated + // with this example: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example379() + { + // Example 379 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _(__foo__)_ + // + // Should be rendered as: + //

(foo)

+ + Console.WriteLine("Example 379\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_(__foo__)_", "

(foo)

", ""); + } + + // Intraword strong emphasis is forbidden with `__`: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example380() + { + // Example 380 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __foo__bar + // + // Should be rendered as: + //

__foo__bar

+ + Console.WriteLine("Example 380\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__foo__bar", "

__foo__bar

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example381() + { + // Example 381 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __пристаням__стремятся + // + // Should be rendered as: + //

__пристаням__стремятся

+ + Console.WriteLine("Example 381\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__пристаням__стремятся", "

__пристаням__стремятся

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example382() + { + // Example 382 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __foo__bar__baz__ + // + // Should be rendered as: + //

foo__bar__baz

+ + Console.WriteLine("Example 382\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__foo__bar__baz__", "

foo__bar__baz

", ""); + } + + // This is strong emphasis, even though the closing delimiter is + // both left- and right-flanking, because it is followed by + // punctuation: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example383() + { + // Example 383 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __(bar)__. + // + // Should be rendered as: + //

(bar).

+ + Console.WriteLine("Example 383\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__(bar)__.", "

(bar).

", ""); + } + + // Rule 9: + // + // Any nonempty sequence of inline elements can be the contents of an + // emphasized span. + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example384() + { + // Example 384 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo [bar](/url)* + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 384\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo [bar](/url)*", "

foo bar

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example385() + { + // Example 385 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo + // bar* + // + // Should be rendered as: + //

foo + // bar

+ + Console.WriteLine("Example 385\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo\nbar*", "

foo\nbar

", ""); + } + + // In particular, emphasis and strong emphasis can be nested + // inside emphasis: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example386() + { + // Example 386 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _foo __bar__ baz_ + // + // Should be rendered as: + //

foo bar baz

+ + Console.WriteLine("Example 386\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_foo __bar__ baz_", "

foo bar baz

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example387() + { + // Example 387 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _foo _bar_ baz_ + // + // Should be rendered as: + //

foo bar baz

+ + Console.WriteLine("Example 387\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_foo _bar_ baz_", "

foo bar baz

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example388() + { + // Example 388 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __foo_ bar_ + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 388\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__foo_ bar_", "

foo bar

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example389() + { + // Example 389 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo *bar** + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 389\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo *bar**", "

foo bar

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example390() + { + // Example 390 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo **bar** baz* + // + // Should be rendered as: + //

foo bar baz

+ + Console.WriteLine("Example 390\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo **bar** baz*", "

foo bar baz

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example391() + { + // Example 391 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo**bar**baz* + // + // Should be rendered as: + //

foobarbaz

+ + Console.WriteLine("Example 391\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo**bar**baz*", "

foobarbaz

", ""); + } + + // Note that in the preceding case, the interpretation + // + // ``` markdown + //

foobarbaz

+ // ``` + // + // + // is precluded by the condition that a delimiter that + // can both open and close (like the `*` after `foo`) + // cannot form emphasis if the sum of the lengths of + // the delimiter runs containing the opening and + // closing delimiters is a multiple of 3. + // + // The same condition ensures that the following + // cases are all strong emphasis nested inside + // emphasis, even when the interior spaces are + // omitted: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example392() + { + // Example 392 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ***foo** bar* + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 392\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("***foo** bar*", "

foo bar

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example393() + { + // Example 393 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo **bar*** + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 393\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo **bar***", "

foo bar

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example394() + { + // Example 394 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo**bar*** + // + // Should be rendered as: + //

foobar

+ + Console.WriteLine("Example 394\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo**bar***", "

foobar

", ""); + } + + // Indefinite levels of nesting are possible: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example395() + { + // Example 395 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo **bar *baz* bim** bop* + // + // Should be rendered as: + //

foo bar baz bim bop

+ + Console.WriteLine("Example 395\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo **bar *baz* bim** bop*", "

foo bar baz bim bop

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example396() + { + // Example 396 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo [*bar*](/url)* + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 396\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo [*bar*](/url)*", "

foo bar

", ""); + } + + // There can be no empty emphasis or strong emphasis: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example397() + { + // Example 397 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ** is not an empty emphasis + // + // Should be rendered as: + //

** is not an empty emphasis

+ + Console.WriteLine("Example 397\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("** is not an empty emphasis", "

** is not an empty emphasis

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example398() + { + // Example 398 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **** is not an empty strong emphasis + // + // Should be rendered as: + //

**** is not an empty strong emphasis

+ + Console.WriteLine("Example 398\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**** is not an empty strong emphasis", "

**** is not an empty strong emphasis

", ""); + } + + // Rule 10: + // + // Any nonempty sequence of inline elements can be the contents of an + // strongly emphasized span. + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example399() + { + // Example 399 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo [bar](/url)** + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 399\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo [bar](/url)**", "

foo bar

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example400() + { + // Example 400 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo + // bar** + // + // Should be rendered as: + //

foo + // bar

+ + Console.WriteLine("Example 400\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo\nbar**", "

foo\nbar

", ""); + } + + // In particular, emphasis and strong emphasis can be nested + // inside strong emphasis: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example401() + { + // Example 401 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __foo _bar_ baz__ + // + // Should be rendered as: + //

foo bar baz

+ + Console.WriteLine("Example 401\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__foo _bar_ baz__", "

foo bar baz

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example402() + { + // Example 402 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __foo __bar__ baz__ + // + // Should be rendered as: + //

foo bar baz

+ + Console.WriteLine("Example 402\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__foo __bar__ baz__", "

foo bar baz

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example403() + { + // Example 403 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ____foo__ bar__ + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 403\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("____foo__ bar__", "

foo bar

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example404() + { + // Example 404 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo **bar**** + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 404\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo **bar****", "

foo bar

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example405() + { + // Example 405 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo *bar* baz** + // + // Should be rendered as: + //

foo bar baz

+ + Console.WriteLine("Example 405\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo *bar* baz**", "

foo bar baz

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example406() + { + // Example 406 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo*bar*baz** + // + // Should be rendered as: + //

foobarbaz

+ + Console.WriteLine("Example 406\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo*bar*baz**", "

foobarbaz

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example407() + { + // Example 407 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ***foo* bar** + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 407\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("***foo* bar**", "

foo bar

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example408() + { + // Example 408 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo *bar*** + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 408\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo *bar***", "

foo bar

", ""); + } + + // Indefinite levels of nesting are possible: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example409() + { + // Example 409 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo *bar **baz** + // bim* bop** + // + // Should be rendered as: + //

foo bar baz + // bim bop

+ + Console.WriteLine("Example 409\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo *bar **baz**\nbim* bop**", "

foo bar baz\nbim bop

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example410() + { + // Example 410 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo [*bar*](/url)** + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 410\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo [*bar*](/url)**", "

foo bar

", ""); + } + + // There can be no empty emphasis or strong emphasis: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example411() + { + // Example 411 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __ is not an empty emphasis + // + // Should be rendered as: + //

__ is not an empty emphasis

+ + Console.WriteLine("Example 411\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__ is not an empty emphasis", "

__ is not an empty emphasis

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example412() + { + // Example 412 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ____ is not an empty strong emphasis + // + // Should be rendered as: + //

____ is not an empty strong emphasis

+ + Console.WriteLine("Example 412\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("____ is not an empty strong emphasis", "

____ is not an empty strong emphasis

", ""); + } + + // Rule 11: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example413() + { + // Example 413 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo *** + // + // Should be rendered as: + //

foo ***

+ + Console.WriteLine("Example 413\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo ***", "

foo ***

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example414() + { + // Example 414 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo *\** + // + // Should be rendered as: + //

foo *

+ + Console.WriteLine("Example 414\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo *\\**", "

foo *

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example415() + { + // Example 415 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo *_* + // + // Should be rendered as: + //

foo _

+ + Console.WriteLine("Example 415\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo *_*", "

foo _

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example416() + { + // Example 416 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo ***** + // + // Should be rendered as: + //

foo *****

+ + Console.WriteLine("Example 416\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo *****", "

foo *****

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example417() + { + // Example 417 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo **\*** + // + // Should be rendered as: + //

foo *

+ + Console.WriteLine("Example 417\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo **\\***", "

foo *

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example418() + { + // Example 418 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo **_** + // + // Should be rendered as: + //

foo _

+ + Console.WriteLine("Example 418\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo **_**", "

foo _

", ""); + } + + // Note that when delimiters do not match evenly, Rule 11 determines + // that the excess literal `*` characters will appear outside of the + // emphasis, rather than inside it: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example419() + { + // Example 419 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo* + // + // Should be rendered as: + //

*foo

+ + Console.WriteLine("Example 419\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo*", "

*foo

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example420() + { + // Example 420 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo** + // + // Should be rendered as: + //

foo*

+ + Console.WriteLine("Example 420\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo**", "

foo*

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example421() + { + // Example 421 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ***foo** + // + // Should be rendered as: + //

*foo

+ + Console.WriteLine("Example 421\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("***foo**", "

*foo

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example422() + { + // Example 422 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ****foo* + // + // Should be rendered as: + //

***foo

+ + Console.WriteLine("Example 422\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("****foo*", "

***foo

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example423() + { + // Example 423 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo*** + // + // Should be rendered as: + //

foo*

+ + Console.WriteLine("Example 423\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo***", "

foo*

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example424() + { + // Example 424 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo**** + // + // Should be rendered as: + //

foo***

+ + Console.WriteLine("Example 424\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo****", "

foo***

", ""); + } + + // Rule 12: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example425() + { + // Example 425 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo ___ + // + // Should be rendered as: + //

foo ___

+ + Console.WriteLine("Example 425\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo ___", "

foo ___

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example426() + { + // Example 426 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo _\__ + // + // Should be rendered as: + //

foo _

+ + Console.WriteLine("Example 426\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo _\\__", "

foo _

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example427() + { + // Example 427 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo _*_ + // + // Should be rendered as: + //

foo *

+ + Console.WriteLine("Example 427\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo _*_", "

foo *

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example428() + { + // Example 428 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo _____ + // + // Should be rendered as: + //

foo _____

+ + Console.WriteLine("Example 428\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo _____", "

foo _____

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example429() + { + // Example 429 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo __\___ + // + // Should be rendered as: + //

foo _

+ + Console.WriteLine("Example 429\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo __\\___", "

foo _

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example430() + { + // Example 430 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // foo __*__ + // + // Should be rendered as: + //

foo *

+ + Console.WriteLine("Example 430\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("foo __*__", "

foo *

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example431() + { + // Example 431 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __foo_ + // + // Should be rendered as: + //

_foo

+ + Console.WriteLine("Example 431\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__foo_", "

_foo

", ""); + } + + // Note that when delimiters do not match evenly, Rule 12 determines + // that the excess literal `_` characters will appear outside of the + // emphasis, rather than inside it: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example432() + { + // Example 432 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _foo__ + // + // Should be rendered as: + //

foo_

+ + Console.WriteLine("Example 432\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_foo__", "

foo_

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example433() + { + // Example 433 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ___foo__ + // + // Should be rendered as: + //

_foo

+ + Console.WriteLine("Example 433\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("___foo__", "

_foo

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example434() + { + // Example 434 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ____foo_ + // + // Should be rendered as: + //

___foo

+ + Console.WriteLine("Example 434\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("____foo_", "

___foo

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example435() + { + // Example 435 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __foo___ + // + // Should be rendered as: + //

foo_

+ + Console.WriteLine("Example 435\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__foo___", "

foo_

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example436() + { + // Example 436 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _foo____ + // + // Should be rendered as: + //

foo___

+ + Console.WriteLine("Example 436\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_foo____", "

foo___

", ""); + } + + // Rule 13 implies that if you want emphasis nested directly inside + // emphasis, you must use different delimiters: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example437() + { + // Example 437 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo** + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 437\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo**", "

foo

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example438() + { + // Example 438 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *_foo_* + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 438\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*_foo_*", "

foo

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example439() + { + // Example 439 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __foo__ + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 439\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__foo__", "

foo

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example440() + { + // Example 440 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _*foo*_ + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 440\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_*foo*_", "

foo

", ""); + } + + // However, strong emphasis within strong emphasis is possible without + // switching delimiters: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example441() + { + // Example 441 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ****foo**** + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 441\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("****foo****", "

foo

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example442() + { + // Example 442 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ____foo____ + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 442\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("____foo____", "

foo

", ""); + } + + // Rule 13 can be applied to arbitrarily long sequences of + // delimiters: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example443() + { + // Example 443 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ******foo****** + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 443\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("******foo******", "

foo

", ""); + } + + // Rule 14: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example444() + { + // Example 444 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ***foo*** + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 444\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("***foo***", "

foo

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example445() + { + // Example 445 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _____foo_____ + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 445\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_____foo_____", "

foo

", ""); + } + + // Rule 15: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example446() + { + // Example 446 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo _bar* baz_ + // + // Should be rendered as: + //

foo _bar baz_

+ + Console.WriteLine("Example 446\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo _bar* baz_", "

foo _bar baz_

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example447() + { + // Example 447 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo __bar *baz bim__ bam* + // + // Should be rendered as: + //

foo bar *baz bim bam

+ + Console.WriteLine("Example 447\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo __bar *baz bim__ bam*", "

foo bar *baz bim bam

", ""); + } + + // Rule 16: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example448() + { + // Example 448 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **foo **bar baz** + // + // Should be rendered as: + //

**foo bar baz

+ + Console.WriteLine("Example 448\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**foo **bar baz**", "

**foo bar baz

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example449() + { + // Example 449 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *foo *bar baz* + // + // Should be rendered as: + //

*foo bar baz

+ + Console.WriteLine("Example 449\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*foo *bar baz*", "

*foo bar baz

", ""); + } + + // Rule 17: + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example450() + { + // Example 450 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *[bar*](/url) + // + // Should be rendered as: + //

*bar*

+ + Console.WriteLine("Example 450\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*[bar*](/url)", "

*bar*

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example451() + { + // Example 451 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _foo [bar_](/url) + // + // Should be rendered as: + //

_foo bar_

+ + Console.WriteLine("Example 451\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_foo [bar_](/url)", "

_foo bar_

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example452() + { + // Example 452 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // * + // + // Should be rendered as: + //

*

+ + Console.WriteLine("Example 452\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*", "

*

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example453() + { + // Example 453 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // ** + // + // Should be rendered as: + //

**

+ + Console.WriteLine("Example 453\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**", "

**

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example454() + { + // Example 454 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __ + // + // Should be rendered as: + //

__

+ + Console.WriteLine("Example 454\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__", "

__

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example455() + { + // Example 455 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // *a `*`* + // + // Should be rendered as: + //

a *

+ + Console.WriteLine("Example 455\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("*a `*`*", "

a *

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example456() + { + // Example 456 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // _a `_`_ + // + // Should be rendered as: + //

a _

+ + Console.WriteLine("Example 456\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("_a `_`_", "

a _

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example457() + { + // Example 457 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // **a + // + // Should be rendered as: + //

**ahttp://foo.bar/?q=**

+ + Console.WriteLine("Example 457\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("**a", "

**ahttp://foo.bar/?q=**

", ""); + } + + [Test] + public void InlinesEmphasisAndStrongEmphasis_Example458() + { + // Example 458 + // Section: Inlines / Emphasis and strong emphasis + // + // The following Markdown: + // __a + // + // Should be rendered as: + //

__ahttp://foo.bar/?q=__

+ + Console.WriteLine("Example 458\nSection Inlines / Emphasis and strong emphasis\n"); + TestParser.TestSpec("__a", "

__ahttp://foo.bar/?q=__

", ""); + } + } + + [TestFixture] + public class TestInlinesLinks + { + // ## Links + // + // A link contains [link text] (the visible text), a [link destination] + // (the URI that is the link destination), and optionally a [link title]. + // There are two basic kinds of links in Markdown. In [inline links] the + // destination and title are given immediately after the link text. In + // [reference links] the destination and title are defined elsewhere in + // the document. + // + // A [link text](@) consists of a sequence of zero or more + // inline elements enclosed by square brackets (`[` and `]`). The + // following rules apply: + // + // - Links may not contain other links, at any level of nesting. If + // multiple otherwise valid link definitions appear nested inside each + // other, the inner-most definition is used. + // + // - Brackets are allowed in the [link text] only if (a) they + // are backslash-escaped or (b) they appear as a matched pair of brackets, + // with an open bracket `[`, a sequence of zero or more inlines, and + // a close bracket `]`. + // + // - Backtick [code spans], [autolinks], and raw [HTML tags] bind more tightly + // than the brackets in link text. Thus, for example, + // `` [foo`]` `` could not be a link text, since the second `]` + // is part of a code span. + // + // - The brackets in link text bind more tightly than markers for + // [emphasis and strong emphasis]. Thus, for example, `*[foo*](url)` is a link. + // + // A [link destination](@) consists of either + // + // - a sequence of zero or more characters between an opening `<` and a + // closing `>` that contains no spaces, line breaks, or unescaped + // `<` or `>` characters, or + // + // - a nonempty sequence of characters that does not include + // ASCII space or control characters, and includes parentheses + // only if (a) they are backslash-escaped or (b) they are part of + // a balanced pair of unescaped parentheses. (Implementations + // may impose limits on parentheses nesting to avoid performance + // issues, but at least three levels of nesting should be supported.) + // + // A [link title](@) consists of either + // + // - a sequence of zero or more characters between straight double-quote + // characters (`"`), including a `"` character only if it is + // backslash-escaped, or + // + // - a sequence of zero or more characters between straight single-quote + // characters (`'`), including a `'` character only if it is + // backslash-escaped, or + // + // - a sequence of zero or more characters between matching parentheses + // (`(...)`), including a `)` character only if it is backslash-escaped. + // + // Although [link titles] may span multiple lines, they may not contain + // a [blank line]. + // + // An [inline link](@) consists of a [link text] followed immediately + // by a left parenthesis `(`, optional [whitespace], an optional + // [link destination], an optional [link title] separated from the link + // destination by [whitespace], optional [whitespace], and a right + // parenthesis `)`. The link's text consists of the inlines contained + // in the [link text] (excluding the enclosing square brackets). + // The link's URI consists of the link destination, excluding enclosing + // `<...>` if present, with backslash-escapes in effect as described + // above. The link's title consists of the link title, excluding its + // enclosing delimiters, with backslash-escapes in effect as described + // above. + // + // Here is a simple inline link: + [Test] + public void InlinesLinks_Example459() + { + // Example 459 + // Section: Inlines / Links + // + // The following Markdown: + // [link](/uri "title") + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 459\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](/uri \"title\")", "

link

", ""); + } + + // The title may be omitted: + [Test] + public void InlinesLinks_Example460() + { + // Example 460 + // Section: Inlines / Links + // + // The following Markdown: + // [link](/uri) + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 460\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](/uri)", "

link

", ""); + } + + // Both the title and the destination may be omitted: + [Test] + public void InlinesLinks_Example461() + { + // Example 461 + // Section: Inlines / Links + // + // The following Markdown: + // [link]() + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 461\nSection Inlines / Links\n"); + TestParser.TestSpec("[link]()", "

link

", ""); + } + + [Test] + public void InlinesLinks_Example462() + { + // Example 462 + // Section: Inlines / Links + // + // The following Markdown: + // [link](<>) + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 462\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](<>)", "

link

", ""); + } + + // The destination cannot contain spaces or line breaks, + // even if enclosed in pointy brackets: + [Test] + public void InlinesLinks_Example463() + { + // Example 463 + // Section: Inlines / Links + // + // The following Markdown: + // [link](/my uri) + // + // Should be rendered as: + //

[link](/my uri)

+ + Console.WriteLine("Example 463\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](/my uri)", "

[link](/my uri)

", ""); + } + + [Test] + public void InlinesLinks_Example464() + { + // Example 464 + // Section: Inlines / Links + // + // The following Markdown: + // [link]() + // + // Should be rendered as: + //

[link](</my uri>)

+ + Console.WriteLine("Example 464\nSection Inlines / Links\n"); + TestParser.TestSpec("[link]()", "

[link](</my uri>)

", ""); + } + + [Test] + public void InlinesLinks_Example465() + { + // Example 465 + // Section: Inlines / Links + // + // The following Markdown: + // [link](foo + // bar) + // + // Should be rendered as: + //

[link](foo + // bar)

+ + Console.WriteLine("Example 465\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](foo\nbar)", "

[link](foo\nbar)

", ""); + } + + [Test] + public void InlinesLinks_Example466() + { + // Example 466 + // Section: Inlines / Links + // + // The following Markdown: + // [link]() + // + // Should be rendered as: + //

[link]()

+ + Console.WriteLine("Example 466\nSection Inlines / Links\n"); + TestParser.TestSpec("[link]()", "

[link]()

", ""); + } + + // Parentheses inside the link destination may be escaped: + [Test] + public void InlinesLinks_Example467() + { + // Example 467 + // Section: Inlines / Links + // + // The following Markdown: + // [link](\(foo\)) + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 467\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](\\(foo\\))", "

link

", ""); + } + + // Any number of parentheses are allowed without escaping, as long as they are + // balanced: + [Test] + public void InlinesLinks_Example468() + { + // Example 468 + // Section: Inlines / Links + // + // The following Markdown: + // [link](foo(and(bar))) + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 468\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](foo(and(bar)))", "

link

", ""); + } + + // However, if you have unbalanced parentheses, you need to escape or use the + // `<...>` form: + [Test] + public void InlinesLinks_Example469() + { + // Example 469 + // Section: Inlines / Links + // + // The following Markdown: + // [link](foo\(and\(bar\)) + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 469\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](foo\\(and\\(bar\\))", "

link

", ""); + } + + [Test] + public void InlinesLinks_Example470() + { + // Example 470 + // Section: Inlines / Links + // + // The following Markdown: + // [link]() + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 470\nSection Inlines / Links\n"); + TestParser.TestSpec("[link]()", "

link

", ""); + } + + // Parentheses and other symbols can also be escaped, as usual + // in Markdown: + [Test] + public void InlinesLinks_Example471() + { + // Example 471 + // Section: Inlines / Links + // + // The following Markdown: + // [link](foo\)\:) + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 471\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](foo\\)\\:)", "

link

", ""); + } + + // A link can contain fragment identifiers and queries: + [Test] + public void InlinesLinks_Example472() + { + // Example 472 + // Section: Inlines / Links + // + // The following Markdown: + // [link](#fragment) + // + // [link](http://example.com#fragment) + // + // [link](http://example.com?foo=3#frag) + // + // Should be rendered as: + //

link

+ //

link

+ //

link

+ + Console.WriteLine("Example 472\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](#fragment)\n\n[link](http://example.com#fragment)\n\n[link](http://example.com?foo=3#frag)", "

link

\n

link

\n

link

", ""); + } + + // Note that a backslash before a non-escapable character is + // just a backslash: + [Test] + public void InlinesLinks_Example473() + { + // Example 473 + // Section: Inlines / Links + // + // The following Markdown: + // [link](foo\bar) + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 473\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](foo\\bar)", "

link

", ""); + } + + // URL-escaping should be left alone inside the destination, as all + // URL-escaped characters are also valid URL characters. Entity and + // numerical character references in the destination will be parsed + // into the corresponding Unicode code points, as usual. These may + // be optionally URL-escaped when written as HTML, but this spec + // does not enforce any particular policy for rendering URLs in + // HTML or other formats. Renderers may make different decisions + // about how to escape or normalize URLs in the output. + [Test] + public void InlinesLinks_Example474() + { + // Example 474 + // Section: Inlines / Links + // + // The following Markdown: + // [link](foo%20bä) + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 474\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](foo%20bä)", "

link

", ""); + } + + // Note that, because titles can often be parsed as destinations, + // if you try to omit the destination and keep the title, you'll + // get unexpected results: + [Test] + public void InlinesLinks_Example475() + { + // Example 475 + // Section: Inlines / Links + // + // The following Markdown: + // [link]("title") + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 475\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](\"title\")", "

link

", ""); + } + + // Titles may be in single quotes, double quotes, or parentheses: + [Test] + public void InlinesLinks_Example476() + { + // Example 476 + // Section: Inlines / Links + // + // The following Markdown: + // [link](/url "title") + // [link](/url 'title') + // [link](/url (title)) + // + // Should be rendered as: + //

link + // link + // link

+ + Console.WriteLine("Example 476\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](/url \"title\")\n[link](/url 'title')\n[link](/url (title))", "

link\nlink\nlink

", ""); + } + + // Backslash escapes and entity and numeric character references + // may be used in titles: + [Test] + public void InlinesLinks_Example477() + { + // Example 477 + // Section: Inlines / Links + // + // The following Markdown: + // [link](/url "title \""") + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 477\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](/url \"title \\\""\")", "

link

", ""); + } + + // Titles must be separated from the link using a [whitespace]. + // Other [Unicode whitespace] like non-breaking space doesn't work. + [Test] + public void InlinesLinks_Example478() + { + // Example 478 + // Section: Inlines / Links + // + // The following Markdown: + // [link](/url "title") + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 478\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](/url \"title\")", "

link

", ""); + } + + // Nested balanced quotes are not allowed without escaping: + [Test] + public void InlinesLinks_Example479() + { + // Example 479 + // Section: Inlines / Links + // + // The following Markdown: + // [link](/url "title "and" title") + // + // Should be rendered as: + //

[link](/url "title "and" title")

+ + Console.WriteLine("Example 479\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](/url \"title \"and\" title\")", "

[link](/url "title "and" title")

", ""); + } + + // But it is easy to work around this by using a different quote type: + [Test] + public void InlinesLinks_Example480() + { + // Example 480 + // Section: Inlines / Links + // + // The following Markdown: + // [link](/url 'title "and" title') + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 480\nSection Inlines / Links\n"); + TestParser.TestSpec("[link](/url 'title \"and\" title')", "

link

", ""); + } + + // (Note: `Markdown.pl` did allow double quotes inside a double-quoted + // title, and its test suite included a test demonstrating this. + // But it is hard to see a good rationale for the extra complexity this + // brings, since there are already many ways---backslash escaping, + // entity and numeric character references, or using a different + // quote type for the enclosing title---to write titles containing + // double quotes. `Markdown.pl`'s handling of titles has a number + // of other strange features. For example, it allows single-quoted + // titles in inline links, but not reference links. And, in + // reference links but not inline links, it allows a title to begin + // with `"` and end with `)`. `Markdown.pl` 1.0.1 even allows + // titles with no closing quotation mark, though 1.0.2b8 does not. + // It seems preferable to adopt a simple, rational rule that works + // the same way in inline links and link reference definitions.) + // + // [Whitespace] is allowed around the destination and title: + [Test] + public void InlinesLinks_Example481() + { + // Example 481 + // Section: Inlines / Links + // + // The following Markdown: + // [link]( /uri + // "title" ) + // + // Should be rendered as: + //

link

+ + Console.WriteLine("Example 481\nSection Inlines / Links\n"); + TestParser.TestSpec("[link]( /uri\n \"title\" )", "

link

", ""); + } + + // But it is not allowed between the link text and the + // following parenthesis: + [Test] + public void InlinesLinks_Example482() + { + // Example 482 + // Section: Inlines / Links + // + // The following Markdown: + // [link] (/uri) + // + // Should be rendered as: + //

[link] (/uri)

+ + Console.WriteLine("Example 482\nSection Inlines / Links\n"); + TestParser.TestSpec("[link] (/uri)", "

[link] (/uri)

", ""); + } + + // The link text may contain balanced brackets, but not unbalanced ones, + // unless they are escaped: + [Test] + public void InlinesLinks_Example483() + { + // Example 483 + // Section: Inlines / Links + // + // The following Markdown: + // [link [foo [bar]]](/uri) + // + // Should be rendered as: + //

link [foo [bar]]

+ + Console.WriteLine("Example 483\nSection Inlines / Links\n"); + TestParser.TestSpec("[link [foo [bar]]](/uri)", "

link [foo [bar]]

", ""); + } + + [Test] + public void InlinesLinks_Example484() + { + // Example 484 + // Section: Inlines / Links + // + // The following Markdown: + // [link] bar](/uri) + // + // Should be rendered as: + //

[link] bar](/uri)

+ + Console.WriteLine("Example 484\nSection Inlines / Links\n"); + TestParser.TestSpec("[link] bar](/uri)", "

[link] bar](/uri)

", ""); + } + + [Test] + public void InlinesLinks_Example485() + { + // Example 485 + // Section: Inlines / Links + // + // The following Markdown: + // [link [bar](/uri) + // + // Should be rendered as: + //

[link bar

+ + Console.WriteLine("Example 485\nSection Inlines / Links\n"); + TestParser.TestSpec("[link [bar](/uri)", "

[link bar

", ""); + } + + [Test] + public void InlinesLinks_Example486() + { + // Example 486 + // Section: Inlines / Links + // + // The following Markdown: + // [link \[bar](/uri) + // + // Should be rendered as: + //

link [bar

+ + Console.WriteLine("Example 486\nSection Inlines / Links\n"); + TestParser.TestSpec("[link \\[bar](/uri)", "

link [bar

", ""); + } + + // The link text may contain inline content: + [Test] + public void InlinesLinks_Example487() + { + // Example 487 + // Section: Inlines / Links + // + // The following Markdown: + // [link *foo **bar** `#`*](/uri) + // + // Should be rendered as: + //

link foo bar #

+ + Console.WriteLine("Example 487\nSection Inlines / Links\n"); + TestParser.TestSpec("[link *foo **bar** `#`*](/uri)", "

link foo bar #

", ""); + } + + [Test] + public void InlinesLinks_Example488() + { + // Example 488 + // Section: Inlines / Links + // + // The following Markdown: + // [![moon](moon.jpg)](/uri) + // + // Should be rendered as: + //

moon

+ + Console.WriteLine("Example 488\nSection Inlines / Links\n"); + TestParser.TestSpec("[![moon](moon.jpg)](/uri)", "

\"moon\"

", ""); + } + + // However, links may not contain other links, at any level of nesting. + [Test] + public void InlinesLinks_Example489() + { + // Example 489 + // Section: Inlines / Links + // + // The following Markdown: + // [foo [bar](/uri)](/uri) + // + // Should be rendered as: + //

[foo bar](/uri)

+ + Console.WriteLine("Example 489\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo [bar](/uri)](/uri)", "

[foo bar](/uri)

", ""); + } + + [Test] + public void InlinesLinks_Example490() + { + // Example 490 + // Section: Inlines / Links + // + // The following Markdown: + // [foo *[bar [baz](/uri)](/uri)*](/uri) + // + // Should be rendered as: + //

[foo [bar baz](/uri)](/uri)

+ + Console.WriteLine("Example 490\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo *[bar [baz](/uri)](/uri)*](/uri)", "

[foo [bar baz](/uri)](/uri)

", ""); + } + + [Test] + public void InlinesLinks_Example491() + { + // Example 491 + // Section: Inlines / Links + // + // The following Markdown: + // ![[[foo](uri1)](uri2)](uri3) + // + // Should be rendered as: + //

[foo](uri2)

+ + Console.WriteLine("Example 491\nSection Inlines / Links\n"); + TestParser.TestSpec("![[[foo](uri1)](uri2)](uri3)", "

\"[foo](uri2)\"

", ""); + } + + // These cases illustrate the precedence of link text grouping over + // emphasis grouping: + [Test] + public void InlinesLinks_Example492() + { + // Example 492 + // Section: Inlines / Links + // + // The following Markdown: + // *[foo*](/uri) + // + // Should be rendered as: + //

*foo*

+ + Console.WriteLine("Example 492\nSection Inlines / Links\n"); + TestParser.TestSpec("*[foo*](/uri)", "

*foo*

", ""); + } + + [Test] + public void InlinesLinks_Example493() + { + // Example 493 + // Section: Inlines / Links + // + // The following Markdown: + // [foo *bar](baz*) + // + // Should be rendered as: + //

foo *bar

+ + Console.WriteLine("Example 493\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo *bar](baz*)", "

foo *bar

", ""); + } + + // Note that brackets that *aren't* part of links do not take + // precedence: + [Test] + public void InlinesLinks_Example494() + { + // Example 494 + // Section: Inlines / Links + // + // The following Markdown: + // *foo [bar* baz] + // + // Should be rendered as: + //

foo [bar baz]

+ + Console.WriteLine("Example 494\nSection Inlines / Links\n"); + TestParser.TestSpec("*foo [bar* baz]", "

foo [bar baz]

", ""); + } + + // These cases illustrate the precedence of HTML tags, code spans, + // and autolinks over link grouping: + [Test] + public void InlinesLinks_Example495() + { + // Example 495 + // Section: Inlines / Links + // + // The following Markdown: + // [foo + // + // Should be rendered as: + //

[foo

+ + Console.WriteLine("Example 495\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo ", "

[foo

", ""); + } + + [Test] + public void InlinesLinks_Example496() + { + // Example 496 + // Section: Inlines / Links + // + // The following Markdown: + // [foo`](/uri)` + // + // Should be rendered as: + //

[foo](/uri)

+ + Console.WriteLine("Example 496\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo`](/uri)`", "

[foo](/uri)

", ""); + } + + [Test] + public void InlinesLinks_Example497() + { + // Example 497 + // Section: Inlines / Links + // + // The following Markdown: + // [foo + // + // Should be rendered as: + //

[foohttp://example.com/?search=](uri)

+ + Console.WriteLine("Example 497\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo", "

[foohttp://example.com/?search=](uri)

", ""); + } + + // There are three kinds of [reference link](@)s: + // [full](#full-reference-link), [collapsed](#collapsed-reference-link), + // and [shortcut](#shortcut-reference-link). + // + // A [full reference link](@) + // consists of a [link text] immediately followed by a [link label] + // that [matches] a [link reference definition] elsewhere in the document. + // + // A [link label](@) begins with a left bracket (`[`) and ends + // with the first right bracket (`]`) that is not backslash-escaped. + // Between these brackets there must be at least one [non-whitespace character]. + // Unescaped square bracket characters are not allowed inside the + // opening and closing square brackets of [link labels]. A link + // label can have at most 999 characters inside the square + // brackets. + // + // One label [matches](@) + // another just in case their normalized forms are equal. To normalize a + // label, strip off the opening and closing brackets, + // perform the *Unicode case fold*, strip leading and trailing + // [whitespace] and collapse consecutive internal + // [whitespace] to a single space. If there are multiple + // matching reference link definitions, the one that comes first in the + // document is used. (It is desirable in such cases to emit a warning.) + // + // The contents of the first link label are parsed as inlines, which are + // used as the link's text. The link's URI and title are provided by the + // matching [link reference definition]. + // + // Here is a simple example: + [Test] + public void InlinesLinks_Example498() + { + // Example 498 + // Section: Inlines / Links + // + // The following Markdown: + // [foo][bar] + // + // [bar]: /url "title" + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 498\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo][bar]\n\n[bar]: /url \"title\"", "

foo

", ""); + } + + // The rules for the [link text] are the same as with + // [inline links]. Thus: + // + // The link text may contain balanced brackets, but not unbalanced ones, + // unless they are escaped: + [Test] + public void InlinesLinks_Example499() + { + // Example 499 + // Section: Inlines / Links + // + // The following Markdown: + // [link [foo [bar]]][ref] + // + // [ref]: /uri + // + // Should be rendered as: + //

link [foo [bar]]

+ + Console.WriteLine("Example 499\nSection Inlines / Links\n"); + TestParser.TestSpec("[link [foo [bar]]][ref]\n\n[ref]: /uri", "

link [foo [bar]]

", ""); + } + + [Test] + public void InlinesLinks_Example500() + { + // Example 500 + // Section: Inlines / Links + // + // The following Markdown: + // [link \[bar][ref] + // + // [ref]: /uri + // + // Should be rendered as: + //

link [bar

+ + Console.WriteLine("Example 500\nSection Inlines / Links\n"); + TestParser.TestSpec("[link \\[bar][ref]\n\n[ref]: /uri", "

link [bar

", ""); + } + + // The link text may contain inline content: + [Test] + public void InlinesLinks_Example501() + { + // Example 501 + // Section: Inlines / Links + // + // The following Markdown: + // [link *foo **bar** `#`*][ref] + // + // [ref]: /uri + // + // Should be rendered as: + //

link foo bar #

+ + Console.WriteLine("Example 501\nSection Inlines / Links\n"); + TestParser.TestSpec("[link *foo **bar** `#`*][ref]\n\n[ref]: /uri", "

link foo bar #

", ""); + } + + [Test] + public void InlinesLinks_Example502() + { + // Example 502 + // Section: Inlines / Links + // + // The following Markdown: + // [![moon](moon.jpg)][ref] + // + // [ref]: /uri + // + // Should be rendered as: + //

moon

+ + Console.WriteLine("Example 502\nSection Inlines / Links\n"); + TestParser.TestSpec("[![moon](moon.jpg)][ref]\n\n[ref]: /uri", "

\"moon\"

", ""); + } + + // However, links may not contain other links, at any level of nesting. + [Test] + public void InlinesLinks_Example503() + { + // Example 503 + // Section: Inlines / Links + // + // The following Markdown: + // [foo [bar](/uri)][ref] + // + // [ref]: /uri + // + // Should be rendered as: + //

[foo bar]ref

+ + Console.WriteLine("Example 503\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo [bar](/uri)][ref]\n\n[ref]: /uri", "

[foo bar]ref

", ""); + } + + [Test] + public void InlinesLinks_Example504() + { + // Example 504 + // Section: Inlines / Links + // + // The following Markdown: + // [foo *bar [baz][ref]*][ref] + // + // [ref]: /uri + // + // Should be rendered as: + //

[foo bar baz]ref

+ + Console.WriteLine("Example 504\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo *bar [baz][ref]*][ref]\n\n[ref]: /uri", "

[foo bar baz]ref

", ""); + } + + // (In the examples above, we have two [shortcut reference links] + // instead of one [full reference link].) + // + // The following cases illustrate the precedence of link text grouping over + // emphasis grouping: + [Test] + public void InlinesLinks_Example505() + { + // Example 505 + // Section: Inlines / Links + // + // The following Markdown: + // *[foo*][ref] + // + // [ref]: /uri + // + // Should be rendered as: + //

*foo*

+ + Console.WriteLine("Example 505\nSection Inlines / Links\n"); + TestParser.TestSpec("*[foo*][ref]\n\n[ref]: /uri", "

*foo*

", ""); + } + + [Test] + public void InlinesLinks_Example506() + { + // Example 506 + // Section: Inlines / Links + // + // The following Markdown: + // [foo *bar][ref] + // + // [ref]: /uri + // + // Should be rendered as: + //

foo *bar

+ + Console.WriteLine("Example 506\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo *bar][ref]\n\n[ref]: /uri", "

foo *bar

", ""); + } + + // These cases illustrate the precedence of HTML tags, code spans, + // and autolinks over link grouping: + [Test] + public void InlinesLinks_Example507() + { + // Example 507 + // Section: Inlines / Links + // + // The following Markdown: + // [foo + // + // [ref]: /uri + // + // Should be rendered as: + //

[foo

+ + Console.WriteLine("Example 507\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo \n\n[ref]: /uri", "

[foo

", ""); + } + + [Test] + public void InlinesLinks_Example508() + { + // Example 508 + // Section: Inlines / Links + // + // The following Markdown: + // [foo`][ref]` + // + // [ref]: /uri + // + // Should be rendered as: + //

[foo][ref]

+ + Console.WriteLine("Example 508\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo`][ref]`\n\n[ref]: /uri", "

[foo][ref]

", ""); + } + + [Test] + public void InlinesLinks_Example509() + { + // Example 509 + // Section: Inlines / Links + // + // The following Markdown: + // [foo + // + // [ref]: /uri + // + // Should be rendered as: + //

[foohttp://example.com/?search=][ref]

+ + Console.WriteLine("Example 509\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo\n\n[ref]: /uri", "

[foohttp://example.com/?search=][ref]

", ""); + } + + // Matching is case-insensitive: + [Test] + public void InlinesLinks_Example510() + { + // Example 510 + // Section: Inlines / Links + // + // The following Markdown: + // [foo][BaR] + // + // [bar]: /url "title" + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 510\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo][BaR]\n\n[bar]: /url \"title\"", "

foo

", ""); + } + + // Unicode case fold is used: + [Test] + public void InlinesLinks_Example511() + { + // Example 511 + // Section: Inlines / Links + // + // The following Markdown: + // [Толпой][Толпой] is a Russian word. + // + // [ТОЛПОЙ]: /url + // + // Should be rendered as: + //

Толпой is a Russian word.

+ + Console.WriteLine("Example 511\nSection Inlines / Links\n"); + TestParser.TestSpec("[Толпой][Толпой] is a Russian word.\n\n[ТОЛПОЙ]: /url", "

Толпой is a Russian word.

", ""); + } + + // Consecutive internal [whitespace] is treated as one space for + // purposes of determining matching: + [Test] + public void InlinesLinks_Example512() + { + // Example 512 + // Section: Inlines / Links + // + // The following Markdown: + // [Foo + // bar]: /url + // + // [Baz][Foo bar] + // + // Should be rendered as: + //

Baz

+ + Console.WriteLine("Example 512\nSection Inlines / Links\n"); + TestParser.TestSpec("[Foo\n bar]: /url\n\n[Baz][Foo bar]", "

Baz

", ""); + } + + // No [whitespace] is allowed between the [link text] and the + // [link label]: + [Test] + public void InlinesLinks_Example513() + { + // Example 513 + // Section: Inlines / Links + // + // The following Markdown: + // [foo] [bar] + // + // [bar]: /url "title" + // + // Should be rendered as: + //

[foo] bar

+ + Console.WriteLine("Example 513\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo] [bar]\n\n[bar]: /url \"title\"", "

[foo] bar

", ""); + } + + [Test] + public void InlinesLinks_Example514() + { + // Example 514 + // Section: Inlines / Links + // + // The following Markdown: + // [foo] + // [bar] + // + // [bar]: /url "title" + // + // Should be rendered as: + //

[foo] + // bar

+ + Console.WriteLine("Example 514\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo]\n[bar]\n\n[bar]: /url \"title\"", "

[foo]\nbar

", ""); + } + + // This is a departure from John Gruber's original Markdown syntax + // description, which explicitly allows whitespace between the link + // text and the link label. It brings reference links in line with + // [inline links], which (according to both original Markdown and + // this spec) cannot have whitespace after the link text. More + // importantly, it prevents inadvertent capture of consecutive + // [shortcut reference links]. If whitespace is allowed between the + // link text and the link label, then in the following we will have + // a single reference link, not two shortcut reference links, as + // intended: + // + // ``` markdown + // [foo] + // [bar] + // + // [foo]: /url1 + // [bar]: /url2 + // ``` + // + // (Note that [shortcut reference links] were introduced by Gruber + // himself in a beta version of `Markdown.pl`, but never included + // in the official syntax description. Without shortcut reference + // links, it is harmless to allow space between the link text and + // link label; but once shortcut references are introduced, it is + // too dangerous to allow this, as it frequently leads to + // unintended results.) + // + // When there are multiple matching [link reference definitions], + // the first is used: + [Test] + public void InlinesLinks_Example515() + { + // Example 515 + // Section: Inlines / Links + // + // The following Markdown: + // [foo]: /url1 + // + // [foo]: /url2 + // + // [bar][foo] + // + // Should be rendered as: + //

bar

+ + Console.WriteLine("Example 515\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo]: /url1\n\n[foo]: /url2\n\n[bar][foo]", "

bar

", ""); + } + + // Note that matching is performed on normalized strings, not parsed + // inline content. So the following does not match, even though the + // labels define equivalent inline content: + [Test] + public void InlinesLinks_Example516() + { + // Example 516 + // Section: Inlines / Links + // + // The following Markdown: + // [bar][foo\!] + // + // [foo!]: /url + // + // Should be rendered as: + //

[bar][foo!]

+ + Console.WriteLine("Example 516\nSection Inlines / Links\n"); + TestParser.TestSpec("[bar][foo\\!]\n\n[foo!]: /url", "

[bar][foo!]

", ""); + } + + // [Link labels] cannot contain brackets, unless they are + // backslash-escaped: + [Test] + public void InlinesLinks_Example517() + { + // Example 517 + // Section: Inlines / Links + // + // The following Markdown: + // [foo][ref[] + // + // [ref[]: /uri + // + // Should be rendered as: + //

[foo][ref[]

+ //

[ref[]: /uri

+ + Console.WriteLine("Example 517\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo][ref[]\n\n[ref[]: /uri", "

[foo][ref[]

\n

[ref[]: /uri

", ""); + } + + [Test] + public void InlinesLinks_Example518() + { + // Example 518 + // Section: Inlines / Links + // + // The following Markdown: + // [foo][ref[bar]] + // + // [ref[bar]]: /uri + // + // Should be rendered as: + //

[foo][ref[bar]]

+ //

[ref[bar]]: /uri

+ + Console.WriteLine("Example 518\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo][ref[bar]]\n\n[ref[bar]]: /uri", "

[foo][ref[bar]]

\n

[ref[bar]]: /uri

", ""); + } + + [Test] + public void InlinesLinks_Example519() + { + // Example 519 + // Section: Inlines / Links + // + // The following Markdown: + // [[[foo]]] + // + // [[[foo]]]: /url + // + // Should be rendered as: + //

[[[foo]]]

+ //

[[[foo]]]: /url

+ + Console.WriteLine("Example 519\nSection Inlines / Links\n"); + TestParser.TestSpec("[[[foo]]]\n\n[[[foo]]]: /url", "

[[[foo]]]

\n

[[[foo]]]: /url

", ""); + } + + [Test] + public void InlinesLinks_Example520() + { + // Example 520 + // Section: Inlines / Links + // + // The following Markdown: + // [foo][ref\[] + // + // [ref\[]: /uri + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 520\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo][ref\\[]\n\n[ref\\[]: /uri", "

foo

", ""); + } + + // Note that in this example `]` is not backslash-escaped: + [Test] + public void InlinesLinks_Example521() + { + // Example 521 + // Section: Inlines / Links + // + // The following Markdown: + // [bar\\]: /uri + // + // [bar\\] + // + // Should be rendered as: + //

bar\

+ + Console.WriteLine("Example 521\nSection Inlines / Links\n"); + TestParser.TestSpec("[bar\\\\]: /uri\n\n[bar\\\\]", "

bar\\

", ""); + } + + // A [link label] must contain at least one [non-whitespace character]: + [Test] + public void InlinesLinks_Example522() + { + // Example 522 + // Section: Inlines / Links + // + // The following Markdown: + // [] + // + // []: /uri + // + // Should be rendered as: + //

[]

+ //

[]: /uri

+ + Console.WriteLine("Example 522\nSection Inlines / Links\n"); + TestParser.TestSpec("[]\n\n[]: /uri", "

[]

\n

[]: /uri

", ""); + } + + [Test] + public void InlinesLinks_Example523() + { + // Example 523 + // Section: Inlines / Links + // + // The following Markdown: + // [ + // ] + // + // [ + // ]: /uri + // + // Should be rendered as: + //

[ + // ]

+ //

[ + // ]: /uri

+ + Console.WriteLine("Example 523\nSection Inlines / Links\n"); + TestParser.TestSpec("[\n ]\n\n[\n ]: /uri", "

[\n]

\n

[\n]: /uri

", ""); + } + + // A [collapsed reference link](@) + // consists of a [link label] that [matches] a + // [link reference definition] elsewhere in the + // document, followed by the string `[]`. + // The contents of the first link label are parsed as inlines, + // which are used as the link's text. The link's URI and title are + // provided by the matching reference link definition. Thus, + // `[foo][]` is equivalent to `[foo][foo]`. + [Test] + public void InlinesLinks_Example524() + { + // Example 524 + // Section: Inlines / Links + // + // The following Markdown: + // [foo][] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 524\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo][]\n\n[foo]: /url \"title\"", "

foo

", ""); + } + + [Test] + public void InlinesLinks_Example525() + { + // Example 525 + // Section: Inlines / Links + // + // The following Markdown: + // [*foo* bar][] + // + // [*foo* bar]: /url "title" + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 525\nSection Inlines / Links\n"); + TestParser.TestSpec("[*foo* bar][]\n\n[*foo* bar]: /url \"title\"", "

foo bar

", ""); + } + + // The link labels are case-insensitive: + [Test] + public void InlinesLinks_Example526() + { + // Example 526 + // Section: Inlines / Links + // + // The following Markdown: + // [Foo][] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

Foo

+ + Console.WriteLine("Example 526\nSection Inlines / Links\n"); + TestParser.TestSpec("[Foo][]\n\n[foo]: /url \"title\"", "

Foo

", ""); + } + + // As with full reference links, [whitespace] is not + // allowed between the two sets of brackets: + [Test] + public void InlinesLinks_Example527() + { + // Example 527 + // Section: Inlines / Links + // + // The following Markdown: + // [foo] + // [] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

foo + // []

+ + Console.WriteLine("Example 527\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo] \n[]\n\n[foo]: /url \"title\"", "

foo\n[]

", ""); + } + + // A [shortcut reference link](@) + // consists of a [link label] that [matches] a + // [link reference definition] elsewhere in the + // document and is not followed by `[]` or a link label. + // The contents of the first link label are parsed as inlines, + // which are used as the link's text. The link's URI and title + // are provided by the matching link reference definition. + // Thus, `[foo]` is equivalent to `[foo][]`. + [Test] + public void InlinesLinks_Example528() + { + // Example 528 + // Section: Inlines / Links + // + // The following Markdown: + // [foo] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 528\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo]\n\n[foo]: /url \"title\"", "

foo

", ""); + } + + [Test] + public void InlinesLinks_Example529() + { + // Example 529 + // Section: Inlines / Links + // + // The following Markdown: + // [*foo* bar] + // + // [*foo* bar]: /url "title" + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 529\nSection Inlines / Links\n"); + TestParser.TestSpec("[*foo* bar]\n\n[*foo* bar]: /url \"title\"", "

foo bar

", ""); + } + + [Test] + public void InlinesLinks_Example530() + { + // Example 530 + // Section: Inlines / Links + // + // The following Markdown: + // [[*foo* bar]] + // + // [*foo* bar]: /url "title" + // + // Should be rendered as: + //

[foo bar]

+ + Console.WriteLine("Example 530\nSection Inlines / Links\n"); + TestParser.TestSpec("[[*foo* bar]]\n\n[*foo* bar]: /url \"title\"", "

[foo bar]

", ""); + } + + [Test] + public void InlinesLinks_Example531() + { + // Example 531 + // Section: Inlines / Links + // + // The following Markdown: + // [[bar [foo] + // + // [foo]: /url + // + // Should be rendered as: + //

[[bar foo

+ + Console.WriteLine("Example 531\nSection Inlines / Links\n"); + TestParser.TestSpec("[[bar [foo]\n\n[foo]: /url", "

[[bar foo

", ""); + } + + // The link labels are case-insensitive: + [Test] + public void InlinesLinks_Example532() + { + // Example 532 + // Section: Inlines / Links + // + // The following Markdown: + // [Foo] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

Foo

+ + Console.WriteLine("Example 532\nSection Inlines / Links\n"); + TestParser.TestSpec("[Foo]\n\n[foo]: /url \"title\"", "

Foo

", ""); + } + + // A space after the link text should be preserved: + [Test] + public void InlinesLinks_Example533() + { + // Example 533 + // Section: Inlines / Links + // + // The following Markdown: + // [foo] bar + // + // [foo]: /url + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 533\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo] bar\n\n[foo]: /url", "

foo bar

", ""); + } + + // If you just want bracketed text, you can backslash-escape the + // opening bracket to avoid links: + [Test] + public void InlinesLinks_Example534() + { + // Example 534 + // Section: Inlines / Links + // + // The following Markdown: + // \[foo] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

[foo]

+ + Console.WriteLine("Example 534\nSection Inlines / Links\n"); + TestParser.TestSpec("\\[foo]\n\n[foo]: /url \"title\"", "

[foo]

", ""); + } + + // Note that this is a link, because a link label ends with the first + // following closing bracket: + [Test] + public void InlinesLinks_Example535() + { + // Example 535 + // Section: Inlines / Links + // + // The following Markdown: + // [foo*]: /url + // + // *[foo*] + // + // Should be rendered as: + //

*foo*

+ + Console.WriteLine("Example 535\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo*]: /url\n\n*[foo*]", "

*foo*

", ""); + } + + // Full and compact references take precedence over shortcut + // references: + [Test] + public void InlinesLinks_Example536() + { + // Example 536 + // Section: Inlines / Links + // + // The following Markdown: + // [foo][bar] + // + // [foo]: /url1 + // [bar]: /url2 + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 536\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo][bar]\n\n[foo]: /url1\n[bar]: /url2", "

foo

", ""); + } + + [Test] + public void InlinesLinks_Example537() + { + // Example 537 + // Section: Inlines / Links + // + // The following Markdown: + // [foo][] + // + // [foo]: /url1 + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 537\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo][]\n\n[foo]: /url1", "

foo

", ""); + } + + // Inline links also take precedence: + [Test] + public void InlinesLinks_Example538() + { + // Example 538 + // Section: Inlines / Links + // + // The following Markdown: + // [foo]() + // + // [foo]: /url1 + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 538\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo]()\n\n[foo]: /url1", "

foo

", ""); + } + + [Test] + public void InlinesLinks_Example539() + { + // Example 539 + // Section: Inlines / Links + // + // The following Markdown: + // [foo](not a link) + // + // [foo]: /url1 + // + // Should be rendered as: + //

foo(not a link)

+ + Console.WriteLine("Example 539\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo](not a link)\n\n[foo]: /url1", "

foo(not a link)

", ""); + } + + // In the following case `[bar][baz]` is parsed as a reference, + // `[foo]` as normal text: + [Test] + public void InlinesLinks_Example540() + { + // Example 540 + // Section: Inlines / Links + // + // The following Markdown: + // [foo][bar][baz] + // + // [baz]: /url + // + // Should be rendered as: + //

[foo]bar

+ + Console.WriteLine("Example 540\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo][bar][baz]\n\n[baz]: /url", "

[foo]bar

", ""); + } + + // Here, though, `[foo][bar]` is parsed as a reference, since + // `[bar]` is defined: + [Test] + public void InlinesLinks_Example541() + { + // Example 541 + // Section: Inlines / Links + // + // The following Markdown: + // [foo][bar][baz] + // + // [baz]: /url1 + // [bar]: /url2 + // + // Should be rendered as: + //

foobaz

+ + Console.WriteLine("Example 541\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo][bar][baz]\n\n[baz]: /url1\n[bar]: /url2", "

foobaz

", ""); + } + + // Here `[foo]` is not parsed as a shortcut reference, because it + // is followed by a link label (even though `[bar]` is not defined): + [Test] + public void InlinesLinks_Example542() + { + // Example 542 + // Section: Inlines / Links + // + // The following Markdown: + // [foo][bar][baz] + // + // [baz]: /url1 + // [foo]: /url2 + // + // Should be rendered as: + //

[foo]bar

+ + Console.WriteLine("Example 542\nSection Inlines / Links\n"); + TestParser.TestSpec("[foo][bar][baz]\n\n[baz]: /url1\n[foo]: /url2", "

[foo]bar

", ""); + } + } + + [TestFixture] + public class TestInlinesImages + { + // ## Images + // + // Syntax for images is like the syntax for links, with one + // difference. Instead of [link text], we have an + // [image description](@). The rules for this are the + // same as for [link text], except that (a) an + // image description starts with `![` rather than `[`, and + // (b) an image description may contain links. + // An image description has inline elements + // as its contents. When an image is rendered to HTML, + // this is standardly used as the image's `alt` attribute. + [Test] + public void InlinesImages_Example543() + { + // Example 543 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo](/url "title") + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 543\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo](/url \"title\")", "

\"foo\"

", ""); + } + + [Test] + public void InlinesImages_Example544() + { + // Example 544 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo *bar*] + // + // [foo *bar*]: train.jpg "train & tracks" + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 544\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo *bar*]\n\n[foo *bar*]: train.jpg \"train & tracks\"", "

\"foo

", ""); + } + + [Test] + public void InlinesImages_Example545() + { + // Example 545 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo ![bar](/url)](/url2) + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 545\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo ![bar](/url)](/url2)", "

\"foo

", ""); + } + + [Test] + public void InlinesImages_Example546() + { + // Example 546 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo [bar](/url)](/url2) + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 546\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo [bar](/url)](/url2)", "

\"foo

", ""); + } + + // Though this spec is concerned with parsing, not rendering, it is + // recommended that in rendering to HTML, only the plain string content + // of the [image description] be used. Note that in + // the above example, the alt attribute's value is `foo bar`, not `foo + // [bar](/url)` or `foo bar`. Only the plain string + // content is rendered, without formatting. + [Test] + public void InlinesImages_Example547() + { + // Example 547 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo *bar*][] + // + // [foo *bar*]: train.jpg "train & tracks" + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 547\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo *bar*][]\n\n[foo *bar*]: train.jpg \"train & tracks\"", "

\"foo

", ""); + } + + [Test] + public void InlinesImages_Example548() + { + // Example 548 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo *bar*][foobar] + // + // [FOOBAR]: train.jpg "train & tracks" + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 548\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo *bar*][foobar]\n\n[FOOBAR]: train.jpg \"train & tracks\"", "

\"foo

", ""); + } + + [Test] + public void InlinesImages_Example549() + { + // Example 549 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo](train.jpg) + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 549\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo](train.jpg)", "

\"foo\"

", ""); + } + + [Test] + public void InlinesImages_Example550() + { + // Example 550 + // Section: Inlines / Images + // + // The following Markdown: + // My ![foo bar](/path/to/train.jpg "title" ) + // + // Should be rendered as: + //

My foo bar

+ + Console.WriteLine("Example 550\nSection Inlines / Images\n"); + TestParser.TestSpec("My ![foo bar](/path/to/train.jpg \"title\" )", "

My \"foo

", ""); + } + + [Test] + public void InlinesImages_Example551() + { + // Example 551 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo]() + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 551\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo]()", "

\"foo\"

", ""); + } + + [Test] + public void InlinesImages_Example552() + { + // Example 552 + // Section: Inlines / Images + // + // The following Markdown: + // ![](/url) + // + // Should be rendered as: + //

+ + Console.WriteLine("Example 552\nSection Inlines / Images\n"); + TestParser.TestSpec("![](/url)", "

\"\"

", ""); + } + + // Reference-style: + [Test] + public void InlinesImages_Example553() + { + // Example 553 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo][bar] + // + // [bar]: /url + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 553\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo][bar]\n\n[bar]: /url", "

\"foo\"

", ""); + } + + [Test] + public void InlinesImages_Example554() + { + // Example 554 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo][bar] + // + // [BAR]: /url + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 554\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo][bar]\n\n[BAR]: /url", "

\"foo\"

", ""); + } + + // Collapsed: + [Test] + public void InlinesImages_Example555() + { + // Example 555 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo][] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 555\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo][]\n\n[foo]: /url \"title\"", "

\"foo\"

", ""); + } + + [Test] + public void InlinesImages_Example556() + { + // Example 556 + // Section: Inlines / Images + // + // The following Markdown: + // ![*foo* bar][] + // + // [*foo* bar]: /url "title" + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 556\nSection Inlines / Images\n"); + TestParser.TestSpec("![*foo* bar][]\n\n[*foo* bar]: /url \"title\"", "

\"foo

", ""); + } + + // The labels are case-insensitive: + [Test] + public void InlinesImages_Example557() + { + // Example 557 + // Section: Inlines / Images + // + // The following Markdown: + // ![Foo][] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

Foo

+ + Console.WriteLine("Example 557\nSection Inlines / Images\n"); + TestParser.TestSpec("![Foo][]\n\n[foo]: /url \"title\"", "

\"Foo\"

", ""); + } + + // As with reference links, [whitespace] is not allowed + // between the two sets of brackets: + [Test] + public void InlinesImages_Example558() + { + // Example 558 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo] + // [] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

foo + // []

+ + Console.WriteLine("Example 558\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo] \n[]\n\n[foo]: /url \"title\"", "

\"foo\"\n[]

", ""); + } + + // Shortcut: + [Test] + public void InlinesImages_Example559() + { + // Example 559 + // Section: Inlines / Images + // + // The following Markdown: + // ![foo] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 559\nSection Inlines / Images\n"); + TestParser.TestSpec("![foo]\n\n[foo]: /url \"title\"", "

\"foo\"

", ""); + } + + [Test] + public void InlinesImages_Example560() + { + // Example 560 + // Section: Inlines / Images + // + // The following Markdown: + // ![*foo* bar] + // + // [*foo* bar]: /url "title" + // + // Should be rendered as: + //

foo bar

+ + Console.WriteLine("Example 560\nSection Inlines / Images\n"); + TestParser.TestSpec("![*foo* bar]\n\n[*foo* bar]: /url \"title\"", "

\"foo

", ""); + } + + // Note that link labels cannot contain unescaped brackets: + [Test] + public void InlinesImages_Example561() + { + // Example 561 + // Section: Inlines / Images + // + // The following Markdown: + // ![[foo]] + // + // [[foo]]: /url "title" + // + // Should be rendered as: + //

![[foo]]

+ //

[[foo]]: /url "title"

+ + Console.WriteLine("Example 561\nSection Inlines / Images\n"); + TestParser.TestSpec("![[foo]]\n\n[[foo]]: /url \"title\"", "

![[foo]]

\n

[[foo]]: /url "title"

", ""); + } + + // The link labels are case-insensitive: + [Test] + public void InlinesImages_Example562() + { + // Example 562 + // Section: Inlines / Images + // + // The following Markdown: + // ![Foo] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

Foo

+ + Console.WriteLine("Example 562\nSection Inlines / Images\n"); + TestParser.TestSpec("![Foo]\n\n[foo]: /url \"title\"", "

\"Foo\"

", ""); + } + + // If you just want a literal `!` followed by bracketed text, you can + // backslash-escape the opening `[`: + [Test] + public void InlinesImages_Example563() + { + // Example 563 + // Section: Inlines / Images + // + // The following Markdown: + // !\[foo] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

![foo]

+ + Console.WriteLine("Example 563\nSection Inlines / Images\n"); + TestParser.TestSpec("!\\[foo]\n\n[foo]: /url \"title\"", "

![foo]

", ""); + } + + // If you want a link after a literal `!`, backslash-escape the + // `!`: + [Test] + public void InlinesImages_Example564() + { + // Example 564 + // Section: Inlines / Images + // + // The following Markdown: + // \![foo] + // + // [foo]: /url "title" + // + // Should be rendered as: + //

!foo

+ + Console.WriteLine("Example 564\nSection Inlines / Images\n"); + TestParser.TestSpec("\\![foo]\n\n[foo]: /url \"title\"", "

!foo

", ""); + } + } + + [TestFixture] + public class TestInlinesAutolinks + { + // ## Autolinks + // + // [Autolink](@)s are absolute URIs and email addresses inside + // `<` and `>`. They are parsed as links, with the URL or email address + // as the link label. + // + // A [URI autolink](@) consists of `<`, followed by an + // [absolute URI] not containing `<`, followed by `>`. It is parsed as + // a link to the URI, with the URI as the link's label. + // + // An [absolute URI](@), + // for these purposes, consists of a [scheme] followed by a colon (`:`) + // followed by zero or more characters other than ASCII + // [whitespace] and control characters, `<`, and `>`. If + // the URI includes these characters, they must be percent-encoded + // (e.g. `%20` for a space). + // + // For purposes of this spec, a [scheme](@) is any sequence + // of 2--32 characters beginning with an ASCII letter and followed + // by any combination of ASCII letters, digits, or the symbols plus + // ("+"), period ("."), or hyphen ("-"). + // + // Here are some valid autolinks: + [Test] + public void InlinesAutolinks_Example565() + { + // Example 565 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

http://foo.bar.baz

+ + Console.WriteLine("Example 565\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

http://foo.bar.baz

", ""); + } + + [Test] + public void InlinesAutolinks_Example566() + { + // Example 566 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

http://foo.bar.baz/test?q=hello&id=22&boolean

+ + Console.WriteLine("Example 566\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

http://foo.bar.baz/test?q=hello&id=22&boolean

", ""); + } + + [Test] + public void InlinesAutolinks_Example567() + { + // Example 567 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

irc://foo.bar:2233/baz

+ + Console.WriteLine("Example 567\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

irc://foo.bar:2233/baz

", ""); + } + + // Uppercase is also fine: + [Test] + public void InlinesAutolinks_Example568() + { + // Example 568 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

MAILTO:FOO@BAR.BAZ

+ + Console.WriteLine("Example 568\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

MAILTO:FOO@BAR.BAZ

", ""); + } + + // Note that many strings that count as [absolute URIs] for + // purposes of this spec are not valid URIs, because their + // schemes are not registered or because of other problems + // with their syntax: + [Test] + public void InlinesAutolinks_Example569() + { + // Example 569 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

a+b+c:d

+ + Console.WriteLine("Example 569\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

a+b+c:d

", ""); + } + + [Test] + public void InlinesAutolinks_Example570() + { + // Example 570 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

made-up-scheme://foo,bar

+ + Console.WriteLine("Example 570\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

made-up-scheme://foo,bar

", ""); + } + + [Test] + public void InlinesAutolinks_Example571() + { + // Example 571 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

http://../

+ + Console.WriteLine("Example 571\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

http://../

", ""); + } + + [Test] + public void InlinesAutolinks_Example572() + { + // Example 572 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

localhost:5001/foo

+ + Console.WriteLine("Example 572\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

localhost:5001/foo

", ""); + } + + // Spaces are not allowed in autolinks: + [Test] + public void InlinesAutolinks_Example573() + { + // Example 573 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

<http://foo.bar/baz bim>

+ + Console.WriteLine("Example 573\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

<http://foo.bar/baz bim>

", ""); + } + + // Backslash-escapes do not work inside autolinks: + [Test] + public void InlinesAutolinks_Example574() + { + // Example 574 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

http://example.com/\[\

+ + Console.WriteLine("Example 574\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

http://example.com/\\[\\

", ""); + } + + // An [email autolink](@) + // consists of `<`, followed by an [email address], + // followed by `>`. The link's label is the email address, + // and the URL is `mailto:` followed by the email address. + // + // An [email address](@), + // for these purposes, is anything that matches + // the [non-normative regex from the HTML5 + // spec](https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email)): + // + // /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])? + // (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ + // + // Examples of email autolinks: + [Test] + public void InlinesAutolinks_Example575() + { + // Example 575 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

foo@bar.example.com

+ + Console.WriteLine("Example 575\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

foo@bar.example.com

", ""); + } + + [Test] + public void InlinesAutolinks_Example576() + { + // Example 576 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

foo+special@Bar.baz-bar0.com

+ + Console.WriteLine("Example 576\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

foo+special@Bar.baz-bar0.com

", ""); + } + + // Backslash-escapes do not work inside email autolinks: + [Test] + public void InlinesAutolinks_Example577() + { + // Example 577 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

<foo+@bar.example.com>

+ + Console.WriteLine("Example 577\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

<foo+@bar.example.com>

", ""); + } + + // These are not autolinks: + [Test] + public void InlinesAutolinks_Example578() + { + // Example 578 + // Section: Inlines / Autolinks + // + // The following Markdown: + // <> + // + // Should be rendered as: + //

<>

+ + Console.WriteLine("Example 578\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("<>", "

<>

", ""); + } + + [Test] + public void InlinesAutolinks_Example579() + { + // Example 579 + // Section: Inlines / Autolinks + // + // The following Markdown: + // < http://foo.bar > + // + // Should be rendered as: + //

< http://foo.bar >

+ + Console.WriteLine("Example 579\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("< http://foo.bar >", "

< http://foo.bar >

", ""); + } + + [Test] + public void InlinesAutolinks_Example580() + { + // Example 580 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

<m:abc>

+ + Console.WriteLine("Example 580\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

<m:abc>

", ""); + } + + [Test] + public void InlinesAutolinks_Example581() + { + // Example 581 + // Section: Inlines / Autolinks + // + // The following Markdown: + // + // + // Should be rendered as: + //

<foo.bar.baz>

+ + Console.WriteLine("Example 581\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("", "

<foo.bar.baz>

", ""); + } + + [Test] + public void InlinesAutolinks_Example582() + { + // Example 582 + // Section: Inlines / Autolinks + // + // The following Markdown: + // http://example.com + // + // Should be rendered as: + //

http://example.com

+ + Console.WriteLine("Example 582\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("http://example.com", "

http://example.com

", ""); + } + + [Test] + public void InlinesAutolinks_Example583() + { + // Example 583 + // Section: Inlines / Autolinks + // + // The following Markdown: + // foo@bar.example.com + // + // Should be rendered as: + //

foo@bar.example.com

+ + Console.WriteLine("Example 583\nSection Inlines / Autolinks\n"); + TestParser.TestSpec("foo@bar.example.com", "

foo@bar.example.com

", ""); + } + } + + [TestFixture] + public class TestInlinesRawHTML + { + // ## Raw HTML + // + // Text between `<` and `>` that looks like an HTML tag is parsed as a + // raw HTML tag and will be rendered in HTML without escaping. + // Tag and attribute names are not limited to current HTML tags, + // so custom tags (and even, say, DocBook tags) may be used. + // + // Here is the grammar for tags: + // + // A [tag name](@) consists of an ASCII letter + // followed by zero or more ASCII letters, digits, or + // hyphens (`-`). + // + // An [attribute](@) consists of [whitespace], + // an [attribute name], and an optional + // [attribute value specification]. + // + // An [attribute name](@) + // consists of an ASCII letter, `_`, or `:`, followed by zero or more ASCII + // letters, digits, `_`, `.`, `:`, or `-`. (Note: This is the XML + // specification restricted to ASCII. HTML5 is laxer.) + // + // An [attribute value specification](@) + // consists of optional [whitespace], + // a `=` character, optional [whitespace], and an [attribute + // value]. + // + // An [attribute value](@) + // consists of an [unquoted attribute value], + // a [single-quoted attribute value], or a [double-quoted attribute value]. + // + // An [unquoted attribute value](@) + // is a nonempty string of characters not + // including spaces, `"`, `'`, `=`, `<`, `>`, or `` ` ``. + // + // A [single-quoted attribute value](@) + // consists of `'`, zero or more + // characters not including `'`, and a final `'`. + // + // A [double-quoted attribute value](@) + // consists of `"`, zero or more + // characters not including `"`, and a final `"`. + // + // An [open tag](@) consists of a `<` character, a [tag name], + // zero or more [attributes], optional [whitespace], an optional `/` + // character, and a `>` character. + // + // A [closing tag](@) consists of the string ``. + // + // An [HTML comment](@) consists of ``, + // where *text* does not start with `>` or `->`, does not end with `-`, + // and does not contain `--`. (See the + // [HTML5 spec](http://www.w3.org/TR/html5/syntax.html#comments).) + // + // A [processing instruction](@) + // consists of the string ``, and the string + // `?>`. + // + // A [declaration](@) consists of the + // string ``, and the character `>`. + // + // A [CDATA section](@) consists of + // the string ``, and the string `]]>`. + // + // An [HTML tag](@) consists of an [open tag], a [closing tag], + // an [HTML comment], a [processing instruction], a [declaration], + // or a [CDATA section]. + // + // Here are some simple open tags: + [Test] + public void InlinesRawHTML_Example584() + { + // Example 584 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // + // + // Should be rendered as: + //

+ + Console.WriteLine("Example 584\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("", "

", ""); + } + + // Empty elements: + [Test] + public void InlinesRawHTML_Example585() + { + // Example 585 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // + // + // Should be rendered as: + //

+ + Console.WriteLine("Example 585\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("", "

", ""); + } + + // [Whitespace] is allowed: + [Test] + public void InlinesRawHTML_Example586() + { + // Example 586 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // + // + // Should be rendered as: + //

+ + Console.WriteLine("Example 586\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("", "

", ""); + } + + // With attributes: + [Test] + public void InlinesRawHTML_Example587() + { + // Example 587 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // + // + // Should be rendered as: + //

+ + Console.WriteLine("Example 587\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("", "

", ""); + } + + // Custom tag names can be used: + [Test] + public void InlinesRawHTML_Example588() + { + // Example 588 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // Foo + // + // Should be rendered as: + //

Foo

+ + Console.WriteLine("Example 588\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("Foo ", "

Foo

", ""); + } + + // Illegal tag names, not parsed as HTML: + [Test] + public void InlinesRawHTML_Example589() + { + // Example 589 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // <33> <__> + // + // Should be rendered as: + //

<33> <__>

+ + Console.WriteLine("Example 589\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("<33> <__>", "

<33> <__>

", ""); + } + + // Illegal attribute names: + [Test] + public void InlinesRawHTML_Example590() + { + // Example 590 + // Section: Inlines / Raw HTML + // + // The following Markdown: + //
+ // + // Should be rendered as: + //

<a h*#ref="hi">

+ + Console.WriteLine("Example 590\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("
", "

<a h*#ref="hi">

", ""); + } + + // Illegal attribute values: + [Test] + public void InlinesRawHTML_Example591() + { + // Example 591 + // Section: Inlines / Raw HTML + // + // The following Markdown: + //
", "

<a href="hi'> <a href=hi'>

", ""); + } + + // Illegal [whitespace]: + [Test] + public void InlinesRawHTML_Example592() + { + // Example 592 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // < a>< + // foo> + // + // Should be rendered as: + //

< a>< + // foo><bar/ >

+ + Console.WriteLine("Example 592\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("< a><\nfoo>", "

< a><\nfoo><bar/ >

", ""); + } + + // Missing [whitespace]: + [Test] + public void InlinesRawHTML_Example593() + { + // Example 593 + // Section: Inlines / Raw HTML + // + // The following Markdown: + //
+ // + // Should be rendered as: + //

<a href='bar'title=title>

+ + Console.WriteLine("Example 593\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("
", "

<a href='bar'title=title>

", ""); + } + + // Closing tags: + [Test] + public void InlinesRawHTML_Example594() + { + // Example 594 + // Section: Inlines / Raw HTML + // + // The following Markdown: + //
+ // + // Should be rendered as: + //

+ + Console.WriteLine("Example 594\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("", "

", ""); + } + + // Illegal attributes in closing tag: + [Test] + public void InlinesRawHTML_Example595() + { + // Example 595 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // + // + // Should be rendered as: + //

</a href="foo">

+ + Console.WriteLine("Example 595\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("", "

</a href="foo">

", ""); + } + + // Comments: + [Test] + public void InlinesRawHTML_Example596() + { + // Example 596 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // foo + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 596\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("foo ", "

foo

", ""); + } + + [Test] + public void InlinesRawHTML_Example597() + { + // Example 597 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // foo + // + // Should be rendered as: + //

foo <!-- not a comment -- two hyphens -->

+ + Console.WriteLine("Example 597\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("foo ", "

foo <!-- not a comment -- two hyphens -->

", ""); + } + + // Not comments: + [Test] + public void InlinesRawHTML_Example598() + { + // Example 598 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // foo foo --> + // + // foo + // + // Should be rendered as: + //

foo <!--> foo -->

+ //

foo <!-- foo--->

+ + Console.WriteLine("Example 598\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("foo foo -->\n\nfoo ", "

foo <!--> foo -->

\n

foo <!-- foo--->

", ""); + } + + // Processing instructions: + [Test] + public void InlinesRawHTML_Example599() + { + // Example 599 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // foo + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 599\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("foo ", "

foo

", ""); + } + + // Declarations: + [Test] + public void InlinesRawHTML_Example600() + { + // Example 600 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // foo + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 600\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("foo ", "

foo

", ""); + } + + // CDATA sections: + [Test] + public void InlinesRawHTML_Example601() + { + // Example 601 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // foo &<]]> + // + // Should be rendered as: + //

foo &<]]>

+ + Console.WriteLine("Example 601\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("foo &<]]>", "

foo &<]]>

", ""); + } + + // Entity and numeric character references are preserved in HTML + // attributes: + [Test] + public void InlinesRawHTML_Example602() + { + // Example 602 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // foo + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 602\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("foo ", "

foo

", ""); + } + + // Backslash escapes do not work in HTML attributes: + [Test] + public void InlinesRawHTML_Example603() + { + // Example 603 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // foo + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 603\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("foo ", "

foo

", ""); + } + + [Test] + public void InlinesRawHTML_Example604() + { + // Example 604 + // Section: Inlines / Raw HTML + // + // The following Markdown: + // + // + // Should be rendered as: + //

<a href=""">

+ + Console.WriteLine("Example 604\nSection Inlines / Raw HTML\n"); + TestParser.TestSpec("
", "

<a href=""">

", ""); + } + } + + [TestFixture] + public class TestInlinesHardLineBreaks + { + // ## Hard line breaks + // + // A line break (not in a code span or HTML tag) that is preceded + // by two or more spaces and does not occur at the end of a block + // is parsed as a [hard line break](@) (rendered + // in HTML as a `
` tag): + [Test] + public void InlinesHardLineBreaks_Example605() + { + // Example 605 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // foo + // baz + // + // Should be rendered as: + //

foo
+ // baz

+ + Console.WriteLine("Example 605\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("foo \nbaz", "

foo
\nbaz

", ""); + } + + // For a more visible alternative, a backslash before the + // [line ending] may be used instead of two spaces: + [Test] + public void InlinesHardLineBreaks_Example606() + { + // Example 606 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // foo\ + // baz + // + // Should be rendered as: + //

foo
+ // baz

+ + Console.WriteLine("Example 606\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("foo\\\nbaz", "

foo
\nbaz

", ""); + } + + // More than two spaces can be used: + [Test] + public void InlinesHardLineBreaks_Example607() + { + // Example 607 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // foo + // baz + // + // Should be rendered as: + //

foo
+ // baz

+ + Console.WriteLine("Example 607\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("foo \nbaz", "

foo
\nbaz

", ""); + } + + // Leading spaces at the beginning of the next line are ignored: + [Test] + public void InlinesHardLineBreaks_Example608() + { + // Example 608 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // foo + // bar + // + // Should be rendered as: + //

foo
+ // bar

+ + Console.WriteLine("Example 608\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("foo \n bar", "

foo
\nbar

", ""); + } + + [Test] + public void InlinesHardLineBreaks_Example609() + { + // Example 609 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // foo\ + // bar + // + // Should be rendered as: + //

foo
+ // bar

+ + Console.WriteLine("Example 609\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("foo\\\n bar", "

foo
\nbar

", ""); + } + + // Line breaks can occur inside emphasis, links, and other constructs + // that allow inline content: + [Test] + public void InlinesHardLineBreaks_Example610() + { + // Example 610 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // *foo + // bar* + // + // Should be rendered as: + //

foo
+ // bar

+ + Console.WriteLine("Example 610\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("*foo \nbar*", "

foo
\nbar

", ""); + } + + [Test] + public void InlinesHardLineBreaks_Example611() + { + // Example 611 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // *foo\ + // bar* + // + // Should be rendered as: + //

foo
+ // bar

+ + Console.WriteLine("Example 611\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("*foo\\\nbar*", "

foo
\nbar

", ""); + } + + // Line breaks do not occur inside code spans + [Test] + public void InlinesHardLineBreaks_Example612() + { + // Example 612 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // `code + // span` + // + // Should be rendered as: + //

code span

+ + Console.WriteLine("Example 612\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("`code \nspan`", "

code span

", ""); + } + + [Test] + public void InlinesHardLineBreaks_Example613() + { + // Example 613 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // `code\ + // span` + // + // Should be rendered as: + //

code\ span

+ + Console.WriteLine("Example 613\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("`code\\\nspan`", "

code\\ span

", ""); + } + + // or HTML tags: + [Test] + public void InlinesHardLineBreaks_Example614() + { + // Example 614 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + //
+ // + // Should be rendered as: + //

+ + Console.WriteLine("Example 614\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("", "

", ""); + } + + [Test] + public void InlinesHardLineBreaks_Example615() + { + // Example 615 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // + // + // Should be rendered as: + //

+ + Console.WriteLine("Example 615\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("", "

", ""); + } + + // Hard line breaks are for separating inline content within a block. + // Neither syntax for hard line breaks works at the end of a paragraph or + // other block element: + [Test] + public void InlinesHardLineBreaks_Example616() + { + // Example 616 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // foo\ + // + // Should be rendered as: + //

foo\

+ + Console.WriteLine("Example 616\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("foo\\", "

foo\\

", ""); + } + + [Test] + public void InlinesHardLineBreaks_Example617() + { + // Example 617 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // foo + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 617\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("foo ", "

foo

", ""); + } + + [Test] + public void InlinesHardLineBreaks_Example618() + { + // Example 618 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // ### foo\ + // + // Should be rendered as: + //

foo\

+ + Console.WriteLine("Example 618\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("### foo\\", "

foo\\

", ""); + } + + [Test] + public void InlinesHardLineBreaks_Example619() + { + // Example 619 + // Section: Inlines / Hard line breaks + // + // The following Markdown: + // ### foo + // + // Should be rendered as: + //

foo

+ + Console.WriteLine("Example 619\nSection Inlines / Hard line breaks\n"); + TestParser.TestSpec("### foo ", "

foo

", ""); + } + } + + [TestFixture] + public class TestInlinesSoftLineBreaks + { + // ## Soft line breaks + // + // A regular line break (not in a code span or HTML tag) that is not + // preceded by two or more spaces or a backslash is parsed as a + // [softbreak](@). (A softbreak may be rendered in HTML either as a + // [line ending] or as a space. The result will be the same in + // browsers. In the examples here, a [line ending] will be used.) + [Test] + public void InlinesSoftLineBreaks_Example620() + { + // Example 620 + // Section: Inlines / Soft line breaks + // + // The following Markdown: + // foo + // baz + // + // Should be rendered as: + //

foo + // baz

+ + Console.WriteLine("Example 620\nSection Inlines / Soft line breaks\n"); + TestParser.TestSpec("foo\nbaz", "

foo\nbaz

", ""); + } + + // Spaces at the end of the line and beginning of the next line are + // removed: + [Test] + public void InlinesSoftLineBreaks_Example621() + { + // Example 621 + // Section: Inlines / Soft line breaks + // + // The following Markdown: + // foo + // baz + // + // Should be rendered as: + //

foo + // baz

+ + Console.WriteLine("Example 621\nSection Inlines / Soft line breaks\n"); + TestParser.TestSpec("foo \n baz", "

foo\nbaz

", ""); + } + } + + [TestFixture] + public class TestInlinesTextualContent + { + // A conforming parser may render a soft line break in HTML either as a + // line break or as a space. + // + // A renderer may also provide an option to render soft line breaks + // as hard line breaks. + // + // ## Textual content + // + // Any characters not given an interpretation by the above rules will + // be parsed as plain textual content. + [Test] + public void InlinesTextualContent_Example622() + { + // Example 622 + // Section: Inlines / Textual content + // + // The following Markdown: + // hello $.;'there + // + // Should be rendered as: + //

hello $.;'there

+ + Console.WriteLine("Example 622\nSection Inlines / Textual content\n"); + TestParser.TestSpec("hello $.;'there", "

hello $.;'there

", ""); + } + + [Test] + public void InlinesTextualContent_Example623() + { + // Example 623 + // Section: Inlines / Textual content + // + // The following Markdown: + // Foo χρῆν + // + // Should be rendered as: + //

Foo χρῆν

+ + Console.WriteLine("Example 623\nSection Inlines / Textual content\n"); + TestParser.TestSpec("Foo χρῆν", "

Foo χρῆν

", ""); + } + + // Internal spaces are preserved verbatim: + [Test] + public void InlinesTextualContent_Example624() + { + // Example 624 + // Section: Inlines / Textual content + // + // The following Markdown: + // Multiple spaces + // + // Should be rendered as: + //

Multiple spaces

+ + Console.WriteLine("Example 624\nSection Inlines / Textual content\n"); + TestParser.TestSpec("Multiple spaces", "

Multiple spaces

", ""); + } + // + // + // # Appendix: A parsing strategy + // + // In this appendix we describe some features of the parsing strategy + // used in the CommonMark reference implementations. + // + // ## Overview + // + // Parsing has two phases: + // + // 1. In the first phase, lines of input are consumed and the block + // structure of the document---its division into paragraphs, block quotes, + // list items, and so on---is constructed. Text is assigned to these + // blocks but not parsed. Link reference definitions are parsed and a + // map of links is constructed. + // + // 2. In the second phase, the raw text contents of paragraphs and headings + // are parsed into sequences of Markdown inline elements (strings, + // code spans, links, emphasis, and so on), using the map of link + // references constructed in phase 1. + // + // At each point in processing, the document is represented as a tree of + // **blocks**. The root of the tree is a `document` block. The `document` + // may have any number of other blocks as **children**. These children + // may, in turn, have other blocks as children. The last child of a block + // is normally considered **open**, meaning that subsequent lines of input + // can alter its contents. (Blocks that are not open are **closed**.) + // Here, for example, is a possible document tree, with the open blocks + // marked by arrows: + // + // ``` tree + // -> document + // -> block_quote + // paragraph + // "Lorem ipsum dolor\nsit amet." + // -> list (type=bullet tight=true bullet_char=-) + // list_item + // paragraph + // "Qui *quodsi iracundia*" + // -> list_item + // -> paragraph + // "aliquando id" + // ``` + // + // ## Phase 1: block structure + // + // Each line that is processed has an effect on this tree. The line is + // analyzed and, depending on its contents, the document may be altered + // in one or more of the following ways: + // + // 1. One or more open blocks may be closed. + // 2. One or more new blocks may be created as children of the + // last open block. + // 3. Text may be added to the last (deepest) open block remaining + // on the tree. + // + // Once a line has been incorporated into the tree in this way, + // it can be discarded, so input can be read in a stream. + // + // For each line, we follow this procedure: + // + // 1. First we iterate through the open blocks, starting with the + // root document, and descending through last children down to the last + // open block. Each block imposes a condition that the line must satisfy + // if the block is to remain open. For example, a block quote requires a + // `>` character. A paragraph requires a non-blank line. + // In this phase we may match all or just some of the open + // blocks. But we cannot close unmatched blocks yet, because we may have a + // [lazy continuation line]. + // + // 2. Next, after consuming the continuation markers for existing + // blocks, we look for new block starts (e.g. `>` for a block quote). + // If we encounter a new block start, we close any blocks unmatched + // in step 1 before creating the new block as a child of the last + // matched block. + // + // 3. Finally, we look at the remainder of the line (after block + // markers like `>`, list markers, and indentation have been consumed). + // This is text that can be incorporated into the last open + // block (a paragraph, code block, heading, or raw HTML). + // + // Setext headings are formed when we see a line of a paragraph + // that is a [setext heading underline]. + // + // Reference link definitions are detected when a paragraph is closed; + // the accumulated text lines are parsed to see if they begin with + // one or more reference link definitions. Any remainder becomes a + // normal paragraph. + // + // We can see how this works by considering how the tree above is + // generated by four lines of Markdown: + // + // ``` markdown + // > Lorem ipsum dolor + // sit amet. + // > - Qui *quodsi iracundia* + // > - aliquando id + // ``` + // + // At the outset, our document model is just + // + // ``` tree + // -> document + // ``` + // + // The first line of our text, + // + // ``` markdown + // > Lorem ipsum dolor + // ``` + // + // causes a `block_quote` block to be created as a child of our + // open `document` block, and a `paragraph` block as a child of + // the `block_quote`. Then the text is added to the last open + // block, the `paragraph`: + // + // ``` tree + // -> document + // -> block_quote + // -> paragraph + // "Lorem ipsum dolor" + // ``` + // + // The next line, + // + // ``` markdown + // sit amet. + // ``` + // + // is a "lazy continuation" of the open `paragraph`, so it gets added + // to the paragraph's text: + // + // ``` tree + // -> document + // -> block_quote + // -> paragraph + // "Lorem ipsum dolor\nsit amet." + // ``` + // + // The third line, + // + // ``` markdown + // > - Qui *quodsi iracundia* + // ``` + // + // causes the `paragraph` block to be closed, and a new `list` block + // opened as a child of the `block_quote`. A `list_item` is also + // added as a child of the `list`, and a `paragraph` as a child of + // the `list_item`. The text is then added to the new `paragraph`: + // + // ``` tree + // -> document + // -> block_quote + // paragraph + // "Lorem ipsum dolor\nsit amet." + // -> list (type=bullet tight=true bullet_char=-) + // -> list_item + // -> paragraph + // "Qui *quodsi iracundia*" + // ``` + // + // The fourth line, + // + // ``` markdown + // > - aliquando id + // ``` + // + // causes the `list_item` (and its child the `paragraph`) to be closed, + // and a new `list_item` opened up as child of the `list`. A `paragraph` + // is added as a child of the new `list_item`, to contain the text. + // We thus obtain the final tree: + // + // ``` tree + // -> document + // -> block_quote + // paragraph + // "Lorem ipsum dolor\nsit amet." + // -> list (type=bullet tight=true bullet_char=-) + // list_item + // paragraph + // "Qui *quodsi iracundia*" + // -> list_item + // -> paragraph + // "aliquando id" + // ``` + // + // ## Phase 2: inline structure + // + // Once all of the input has been parsed, all open blocks are closed. + // + // We then "walk the tree," visiting every node, and parse raw + // string contents of paragraphs and headings as inlines. At this + // point we have seen all the link reference definitions, so we can + // resolve reference links as we go. + // + // ``` tree + // document + // block_quote + // paragraph + // str "Lorem ipsum dolor" + // softbreak + // str "sit amet." + // list (type=bullet tight=true bullet_char=-) + // list_item + // paragraph + // str "Qui " + // emph + // str "quodsi iracundia" + // list_item + // paragraph + // str "aliquando id" + // ``` + // + // Notice how the [line ending] in the first paragraph has + // been parsed as a `softbreak`, and the asterisks in the first list item + // have become an `emph`. + // + // ### An algorithm for parsing nested emphasis and links + // + // By far the trickiest part of inline parsing is handling emphasis, + // strong emphasis, links, and images. This is done using the following + // algorithm. + // + // When we're parsing inlines and we hit either + // + // - a run of `*` or `_` characters, or + // - a `[` or `![` + // + // we insert a text node with these symbols as its literal content, and we + // add a pointer to this text node to the [delimiter stack](@). + // + // The [delimiter stack] is a doubly linked list. Each + // element contains a pointer to a text node, plus information about + // + // - the type of delimiter (`[`, `![`, `*`, `_`) + // - the number of delimiters, + // - whether the delimiter is "active" (all are active to start), and + // - whether the delimiter is a potential opener, a potential closer, + // or both (which depends on what sort of characters precede + // and follow the delimiters). + // + // When we hit a `]` character, we call the *look for link or image* + // procedure (see below). + // + // When we hit the end of the input, we call the *process emphasis* + // procedure (see below), with `stack_bottom` = NULL. + // + // #### *look for link or image* + // + // Starting at the top of the delimiter stack, we look backwards + // through the stack for an opening `[` or `![` delimiter. + // + // - If we don't find one, we return a literal text node `]`. + // + // - If we do find one, but it's not *active*, we remove the inactive + // delimiter from the stack, and return a literal text node `]`. + // + // - If we find one and it's active, then we parse ahead to see if + // we have an inline link/image, reference link/image, compact reference + // link/image, or shortcut reference link/image. + // + // + If we don't, then we remove the opening delimiter from the + // delimiter stack and return a literal text node `]`. + // + // + If we do, then + // + // * We return a link or image node whose children are the inlines + // after the text node pointed to by the opening delimiter. + // + // * We run *process emphasis* on these inlines, with the `[` opener + // as `stack_bottom`. + // + // * We remove the opening delimiter. + // + // * If we have a link (and not an image), we also set all + // `[` delimiters before the opening delimiter to *inactive*. (This + // will prevent us from getting links within links.) + // + // #### *process emphasis* + // + // Parameter `stack_bottom` sets a lower bound to how far we + // descend in the [delimiter stack]. If it is NULL, we can + // go all the way to the bottom. Otherwise, we stop before + // visiting `stack_bottom`. + // + // Let `current_position` point to the element on the [delimiter stack] + // just above `stack_bottom` (or the first element if `stack_bottom` + // is NULL). + // + // We keep track of the `openers_bottom` for each delimiter + // type (`*`, `_`). Initialize this to `stack_bottom`. + // + // Then we repeat the following until we run out of potential + // closers: + // + // - Move `current_position` forward in the delimiter stack (if needed) + // until we find the first potential closer with delimiter `*` or `_`. + // (This will be the potential closer closest + // to the beginning of the input -- the first one in parse order.) + // + // - Now, look back in the stack (staying above `stack_bottom` and + // the `openers_bottom` for this delimiter type) for the + // first matching potential opener ("matching" means same delimiter). + // + // - If one is found: + // + // + Figure out whether we have emphasis or strong emphasis: + // if both closer and opener spans have length >= 2, we have + // strong, otherwise regular. + // + // + Insert an emph or strong emph node accordingly, after + // the text node corresponding to the opener. + // + // + Remove any delimiters between the opener and closer from + // the delimiter stack. + // + // + Remove 1 (for regular emph) or 2 (for strong emph) delimiters + // from the opening and closing text nodes. If they become empty + // as a result, remove them and remove the corresponding element + // of the delimiter stack. If the closing node is removed, reset + // `current_position` to the next element in the stack. + // + // - If none in found: + // + // + Set `openers_bottom` to the element before `current_position`. + // (We know that there are no openers for this kind of closer up to and + // including this point, so this puts a lower bound on future searches.) + // + // + If the closer at `current_position` is not a potential opener, + // remove it from the delimiter stack (since we know it can't + // be a closer either). + // + // + Advance `current_position` to the next element in the stack. + // + // After we're done, we remove all delimiters above `stack_bottom` from the + // delimiter stack. + } +} diff --git a/src/Markdig.Tests/Specs/CommonMark.md b/src/Markdig.Tests/Specs/CommonMark.md new file mode 100644 index 00000000..9fd58413 --- /dev/null +++ b/src/Markdig.Tests/Specs/CommonMark.md @@ -0,0 +1,9414 @@ +--- +title: CommonMark Spec +author: John MacFarlane +version: 0.28 +date: '2017-08-01' +license: '[CC-BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)' +... + +# Introduction + +## What is Markdown? + +Markdown is a plain text format for writing structured documents, +based on conventions for indicating formatting in email +and usenet posts. It was developed by John Gruber (with +help from Aaron Swartz) and released in 2004 in the form of a +[syntax description](http://daringfireball.net/projects/markdown/syntax) +and a Perl script (`Markdown.pl`) for converting Markdown to +HTML. In the next decade, dozens of implementations were +developed in many languages. Some extended the original +Markdown syntax with conventions for footnotes, tables, and +other document elements. Some allowed Markdown documents to be +rendered in formats other than HTML. Websites like Reddit, +StackOverflow, and GitHub had millions of people using Markdown. +And Markdown started to be used beyond the web, to author books, +articles, slide shows, letters, and lecture notes. + +What distinguishes Markdown from many other lightweight markup +syntaxes, which are often easier to write, is its readability. +As Gruber writes: + +> The overriding design goal for Markdown's formatting syntax is +> to make it as readable as possible. The idea is that a +> Markdown-formatted document should be publishable as-is, as +> plain text, without looking like it's been marked up with tags +> or formatting instructions. +> () + +The point can be illustrated by comparing a sample of +[AsciiDoc](http://www.methods.co.nz/asciidoc/) with +an equivalent sample of Markdown. Here is a sample of +AsciiDoc from the AsciiDoc manual: + +``` +1. List item one. ++ +List item one continued with a second paragraph followed by an +Indented block. ++ +................. +$ ls *.sh +$ mv *.sh ~/tmp +................. ++ +List item continued with a third paragraph. + +2. List item two continued with an open block. ++ +-- +This paragraph is part of the preceding list item. + +a. This list is nested and does not require explicit item +continuation. ++ +This paragraph is part of the preceding list item. + +b. List item b. + +This paragraph belongs to item two of the outer list. +-- +``` + +And here is the equivalent in Markdown: +``` +1. List item one. + + List item one continued with a second paragraph followed by an + Indented block. + + $ ls *.sh + $ mv *.sh ~/tmp + + List item continued with a third paragraph. + +2. List item two continued with an open block. + + This paragraph is part of the preceding list item. + + 1. This list is nested and does not require explicit item continuation. + + This paragraph is part of the preceding list item. + + 2. List item b. + + This paragraph belongs to item two of the outer list. +``` + +The AsciiDoc version is, arguably, easier to write. You don't need +to worry about indentation. But the Markdown version is much easier +to read. The nesting of list items is apparent to the eye in the +source, not just in the processed document. + +## Why is a spec needed? + +John Gruber's [canonical description of Markdown's +syntax](http://daringfireball.net/projects/markdown/syntax) +does not specify the syntax unambiguously. Here are some examples of +questions it does not answer: + +1. How much indentation is needed for a sublist? The spec says that + continuation paragraphs need to be indented four spaces, but is + not fully explicit about sublists. It is natural to think that + they, too, must be indented four spaces, but `Markdown.pl` does + not require that. This is hardly a "corner case," and divergences + between implementations on this issue often lead to surprises for + users in real documents. (See [this comment by John + Gruber](http://article.gmane.org/gmane.text.markdown.general/1997).) + +2. Is a blank line needed before a block quote or heading? + Most implementations do not require the blank line. However, + this can lead to unexpected results in hard-wrapped text, and + also to ambiguities in parsing (note that some implementations + put the heading inside the blockquote, while others do not). + (John Gruber has also spoken [in favor of requiring the blank + lines](http://article.gmane.org/gmane.text.markdown.general/2146).) + +3. Is a blank line needed before an indented code block? + (`Markdown.pl` requires it, but this is not mentioned in the + documentation, and some implementations do not require it.) + + ``` markdown + paragraph + code? + ``` + +4. What is the exact rule for determining when list items get + wrapped in `

` tags? Can a list be partially "loose" and partially + "tight"? What should we do with a list like this? + + ``` markdown + 1. one + + 2. two + 3. three + ``` + + Or this? + + ``` markdown + 1. one + - a + + - b + 2. two + ``` + + (There are some relevant comments by John Gruber + [here](http://article.gmane.org/gmane.text.markdown.general/2554).) + +5. Can list markers be indented? Can ordered list markers be right-aligned? + + ``` markdown + 8. item 1 + 9. item 2 + 10. item 2a + ``` + +6. Is this one list with a thematic break in its second item, + or two lists separated by a thematic break? + + ``` markdown + * a + * * * * * + * b + ``` + +7. When list markers change from numbers to bullets, do we have + two lists or one? (The Markdown syntax description suggests two, + but the perl scripts and many other implementations produce one.) + + ``` markdown + 1. fee + 2. fie + - foe + - fum + ``` + +8. What are the precedence rules for the markers of inline structure? + For example, is the following a valid link, or does the code span + take precedence ? + + ``` markdown + [a backtick (`)](/url) and [another backtick (`)](/url). + ``` + +9. What are the precedence rules for markers of emphasis and strong + emphasis? For example, how should the following be parsed? + + ``` markdown + *foo *bar* baz* + ``` + +10. What are the precedence rules between block-level and inline-level + structure? For example, how should the following be parsed? + + ``` markdown + - `a long code span can contain a hyphen like this + - and it can screw things up` + ``` + +11. Can list items include section headings? (`Markdown.pl` does not + allow this, but does allow blockquotes to include headings.) + + ``` markdown + - # Heading + ``` + +12. Can list items be empty? + + ``` markdown + * a + * + * b + ``` + +13. Can link references be defined inside block quotes or list items? + + ``` markdown + > Blockquote [foo]. + > + > [foo]: /url + ``` + +14. If there are multiple definitions for the same reference, which takes + precedence? + + ``` markdown + [foo]: /url1 + [foo]: /url2 + + [foo][] + ``` + +In the absence of a spec, early implementers consulted `Markdown.pl` +to resolve these ambiguities. But `Markdown.pl` was quite buggy, and +gave manifestly bad results in many cases, so it was not a +satisfactory replacement for a spec. + +Because there is no unambiguous spec, implementations have diverged +considerably. As a result, users are often surprised to find that +a document that renders one way on one system (say, a github wiki) +renders differently on another (say, converting to docbook using +pandoc). To make matters worse, because nothing in Markdown counts +as a "syntax error," the divergence often isn't discovered right away. + +## About this document + +This document attempts to specify Markdown syntax unambiguously. +It contains many examples with side-by-side Markdown and +HTML. These are intended to double as conformance tests. An +accompanying script `spec_tests.py` can be used to run the tests +against any Markdown program: + + python test/spec_tests.py --spec spec.txt --program PROGRAM + +Since this document describes how Markdown is to be parsed into +an abstract syntax tree, it would have made sense to use an abstract +representation of the syntax tree instead of HTML. But HTML is capable +of representing the structural distinctions we need to make, and the +choice of HTML for the tests makes it possible to run the tests against +an implementation without writing an abstract syntax tree renderer. + +This document is generated from a text file, `spec.txt`, written +in Markdown with a small extension for the side-by-side tests. +The script `tools/makespec.py` can be used to convert `spec.txt` into +HTML or CommonMark (which can then be converted into other formats). + +In the examples, the `→` character is used to represent tabs. + +# Preliminaries + +## Characters and lines + +Any sequence of [characters] is a valid CommonMark +document. + +A [character](@) is a Unicode code point. Although some +code points (for example, combining accents) do not correspond to +characters in an intuitive sense, all code points count as characters +for purposes of this spec. + +This spec does not specify an encoding; it thinks of lines as composed +of [characters] rather than bytes. A conforming parser may be limited +to a certain encoding. + +A [line](@) is a sequence of zero or more [characters] +other than newline (`U+000A`) or carriage return (`U+000D`), +followed by a [line ending] or by the end of file. + +A [line ending](@) is a newline (`U+000A`), a carriage return +(`U+000D`) not followed by a newline, or a carriage return and a +following newline. + +A line containing no characters, or a line containing only spaces +(`U+0020`) or tabs (`U+0009`), is called a [blank line](@). + +The following definitions of character classes will be used in this spec: + +A [whitespace character](@) is a space +(`U+0020`), tab (`U+0009`), newline (`U+000A`), line tabulation (`U+000B`), +form feed (`U+000C`), or carriage return (`U+000D`). + +[Whitespace](@) is a sequence of one or more [whitespace +characters]. + +A [Unicode whitespace character](@) is +any code point in the Unicode `Zs` general category, or a tab (`U+0009`), +carriage return (`U+000D`), newline (`U+000A`), or form feed +(`U+000C`). + +[Unicode whitespace](@) is a sequence of one +or more [Unicode whitespace characters]. + +A [space](@) is `U+0020`. + +A [non-whitespace character](@) is any character +that is not a [whitespace character]. + +An [ASCII punctuation character](@) +is `!`, `"`, `#`, `$`, `%`, `&`, `'`, `(`, `)`, +`*`, `+`, `,`, `-`, `.`, `/`, `:`, `;`, `<`, `=`, `>`, `?`, `@`, +`[`, `\`, `]`, `^`, `_`, `` ` ``, `{`, `|`, `}`, or `~`. + +A [punctuation character](@) is an [ASCII +punctuation character] or anything in +the general Unicode categories `Pc`, `Pd`, `Pe`, `Pf`, `Pi`, `Po`, or `Ps`. + +## Tabs + +Tabs in lines are not expanded to [spaces]. However, +in contexts where whitespace helps to define block structure, +tabs behave as if they were replaced by spaces with a tab stop +of 4 characters. + +Thus, for example, a tab can be used instead of four spaces +in an indented code block. (Note, however, that internal +tabs are passed through as literal tabs, not expanded to +spaces.) + +```````````````````````````````` example +→foo→baz→→bim +. +

foo→baz→→bim
+
+```````````````````````````````` + +```````````````````````````````` example + →foo→baz→→bim +. +
foo→baz→→bim
+
+```````````````````````````````` + +```````````````````````````````` example + a→a + ὐ→a +. +
a→a
+ὐ→a
+
+```````````````````````````````` + +In the following example, a continuation paragraph of a list +item is indented with a tab; this has exactly the same effect +as indentation with four spaces would: + +```````````````````````````````` example + - foo + +→bar +. +
    +
  • +

    foo

    +

    bar

    +
  • +
+```````````````````````````````` + +```````````````````````````````` example +- foo + +→→bar +. +
    +
  • +

    foo

    +
      bar
    +
    +
  • +
+```````````````````````````````` + +Normally the `>` that begins a block quote may be followed +optionally by a space, which is not considered part of the +content. In the following case `>` is followed by a tab, +which is treated as if it were expanded into three spaces. +Since one of these spaces is considered part of the +delimiter, `foo` is considered to be indented six spaces +inside the block quote context, so we get an indented +code block starting with two spaces. + +```````````````````````````````` example +>→→foo +. +
+
  foo
+
+
+```````````````````````````````` + +```````````````````````````````` example +-→→foo +. +
    +
  • +
      foo
    +
    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example + foo +→bar +. +
foo
+bar
+
+```````````````````````````````` + +```````````````````````````````` example + - foo + - bar +→ - baz +. +
    +
  • foo +
      +
    • bar +
        +
      • baz
      • +
      +
    • +
    +
  • +
+```````````````````````````````` + +```````````````````````````````` example +#→Foo +. +

Foo

+```````````````````````````````` + +```````````````````````````````` example +*→*→*→ +. +
+```````````````````````````````` + + +## Insecure characters + +For security reasons, the Unicode character `U+0000` must be replaced +with the REPLACEMENT CHARACTER (`U+FFFD`). + +# Blocks and inlines + +We can think of a document as a sequence of +[blocks](@)---structural elements like paragraphs, block +quotations, lists, headings, rules, and code blocks. Some blocks (like +block quotes and list items) contain other blocks; others (like +headings and paragraphs) contain [inline](@) content---text, +links, emphasized text, images, code spans, and so on. + +## Precedence + +Indicators of block structure always take precedence over indicators +of inline structure. So, for example, the following is a list with +two items, not a list with one item containing a code span: + +```````````````````````````````` example +- `one +- two` +. +
    +
  • `one
  • +
  • two`
  • +
+```````````````````````````````` + + +This means that parsing can proceed in two steps: first, the block +structure of the document can be discerned; second, text lines inside +paragraphs, headings, and other block constructs can be parsed for inline +structure. The second step requires information about link reference +definitions that will be available only at the end of the first +step. Note that the first step requires processing lines in sequence, +but the second can be parallelized, since the inline parsing of +one block element does not affect the inline parsing of any other. + +## Container blocks and leaf blocks + +We can divide blocks into two types: +[container block](@)s, +which can contain other blocks, and [leaf block](@)s, +which cannot. + +# Leaf blocks + +This section describes the different kinds of leaf block that make up a +Markdown document. + +## Thematic breaks + +A line consisting of 0-3 spaces of indentation, followed by a sequence +of three or more matching `-`, `_`, or `*` characters, each followed +optionally by any number of spaces, forms a +[thematic break](@). + +```````````````````````````````` example +*** +--- +___ +. +
+
+
+```````````````````````````````` + + +Wrong characters: + +```````````````````````````````` example ++++ +. +

+++

+```````````````````````````````` + + +```````````````````````````````` example +=== +. +

===

+```````````````````````````````` + + +Not enough characters: + +```````````````````````````````` example +-- +** +__ +. +

-- +** +__

+```````````````````````````````` + + +One to three spaces indent are allowed: + +```````````````````````````````` example + *** + *** + *** +. +
+
+
+```````````````````````````````` + + +Four spaces is too many: + +```````````````````````````````` example + *** +. +
***
+
+```````````````````````````````` + + +```````````````````````````````` example +Foo + *** +. +

Foo +***

+```````````````````````````````` + + +More than three characters may be used: + +```````````````````````````````` example +_____________________________________ +. +
+```````````````````````````````` + + +Spaces are allowed between the characters: + +```````````````````````````````` example + - - - +. +
+```````````````````````````````` + + +```````````````````````````````` example + ** * ** * ** * ** +. +
+```````````````````````````````` + + +```````````````````````````````` example +- - - - +. +
+```````````````````````````````` + + +Spaces are allowed at the end: + +```````````````````````````````` example +- - - - +. +
+```````````````````````````````` + + +However, no other characters may occur in the line: + +```````````````````````````````` example +_ _ _ _ a + +a------ + +---a--- +. +

_ _ _ _ a

+

a------

+

---a---

+```````````````````````````````` + + +It is required that all of the [non-whitespace characters] be the same. +So, this is not a thematic break: + +```````````````````````````````` example + *-* +. +

-

+```````````````````````````````` + + +Thematic breaks do not need blank lines before or after: + +```````````````````````````````` example +- foo +*** +- bar +. +
    +
  • foo
  • +
+
+
    +
  • bar
  • +
+```````````````````````````````` + + +Thematic breaks can interrupt a paragraph: + +```````````````````````````````` example +Foo +*** +bar +. +

Foo

+
+

bar

+```````````````````````````````` + + +If a line of dashes that meets the above conditions for being a +thematic break could also be interpreted as the underline of a [setext +heading], the interpretation as a +[setext heading] takes precedence. Thus, for example, +this is a setext heading, not a paragraph followed by a thematic break: + +```````````````````````````````` example +Foo +--- +bar +. +

Foo

+

bar

+```````````````````````````````` + + +When both a thematic break and a list item are possible +interpretations of a line, the thematic break takes precedence: + +```````````````````````````````` example +* Foo +* * * +* Bar +. +
    +
  • Foo
  • +
+
+
    +
  • Bar
  • +
+```````````````````````````````` + + +If you want a thematic break in a list item, use a different bullet: + +```````````````````````````````` example +- Foo +- * * * +. +
    +
  • Foo
  • +
  • +
    +
  • +
+```````````````````````````````` + + +## ATX headings + +An [ATX heading](@) +consists of a string of characters, parsed as inline content, between an +opening sequence of 1--6 unescaped `#` characters and an optional +closing sequence of any number of unescaped `#` characters. +The opening sequence of `#` characters must be followed by a +[space] or by the end of line. The optional closing sequence of `#`s must be +preceded by a [space] and may be followed by spaces only. The opening +`#` character may be indented 0-3 spaces. The raw contents of the +heading are stripped of leading and trailing spaces before being parsed +as inline content. The heading level is equal to the number of `#` +characters in the opening sequence. + +Simple headings: + +```````````````````````````````` example +# foo +## foo +### foo +#### foo +##### foo +###### foo +. +

foo

+

foo

+

foo

+

foo

+
foo
+
foo
+```````````````````````````````` + + +More than six `#` characters is not a heading: + +```````````````````````````````` example +####### foo +. +

####### foo

+```````````````````````````````` + + +At least one space is required between the `#` characters and the +heading's contents, unless the heading is empty. Note that many +implementations currently do not require the space. However, the +space was required by the +[original ATX implementation](http://www.aaronsw.com/2002/atx/atx.py), +and it helps prevent things like the following from being parsed as +headings: + +```````````````````````````````` example +#5 bolt + +#hashtag +. +

#5 bolt

+

#hashtag

+```````````````````````````````` + + +This is not a heading, because the first `#` is escaped: + +```````````````````````````````` example +\## foo +. +

## foo

+```````````````````````````````` + + +Contents are parsed as inlines: + +```````````````````````````````` example +# foo *bar* \*baz\* +. +

foo bar *baz*

+```````````````````````````````` + + +Leading and trailing blanks are ignored in parsing inline content: + +```````````````````````````````` example +# foo +. +

foo

+```````````````````````````````` + + +One to three spaces indentation are allowed: + +```````````````````````````````` example + ### foo + ## foo + # foo +. +

foo

+

foo

+

foo

+```````````````````````````````` + + +Four spaces are too much: + +```````````````````````````````` example + # foo +. +
# foo
+
+```````````````````````````````` + + +```````````````````````````````` example +foo + # bar +. +

foo +# bar

+```````````````````````````````` + + +A closing sequence of `#` characters is optional: + +```````````````````````````````` example +## foo ## + ### bar ### +. +

foo

+

bar

+```````````````````````````````` + + +It need not be the same length as the opening sequence: + +```````````````````````````````` example +# foo ################################## +##### foo ## +. +

foo

+
foo
+```````````````````````````````` + + +Spaces are allowed after the closing sequence: + +```````````````````````````````` example +### foo ### +. +

foo

+```````````````````````````````` + + +A sequence of `#` characters with anything but [spaces] following it +is not a closing sequence, but counts as part of the contents of the +heading: + +```````````````````````````````` example +### foo ### b +. +

foo ### b

+```````````````````````````````` + + +The closing sequence must be preceded by a space: + +```````````````````````````````` example +# foo# +. +

foo#

+```````````````````````````````` + + +Backslash-escaped `#` characters do not count as part +of the closing sequence: + +```````````````````````````````` example +### foo \### +## foo #\## +# foo \# +. +

foo ###

+

foo ###

+

foo #

+```````````````````````````````` + + +ATX headings need not be separated from surrounding content by blank +lines, and they can interrupt paragraphs: + +```````````````````````````````` example +**** +## foo +**** +. +
+

foo

+
+```````````````````````````````` + + +```````````````````````````````` example +Foo bar +# baz +Bar foo +. +

Foo bar

+

baz

+

Bar foo

+```````````````````````````````` + + +ATX headings can be empty: + +```````````````````````````````` example +## +# +### ### +. +

+

+

+```````````````````````````````` + + +## Setext headings + +A [setext heading](@) consists of one or more +lines of text, each containing at least one [non-whitespace +character], with no more than 3 spaces indentation, followed by +a [setext heading underline]. The lines of text must be such +that, were they not followed by the setext heading underline, +they would be interpreted as a paragraph: they cannot be +interpretable as a [code fence], [ATX heading][ATX headings], +[block quote][block quotes], [thematic break][thematic breaks], +[list item][list items], or [HTML block][HTML blocks]. + +A [setext heading underline](@) is a sequence of +`=` characters or a sequence of `-` characters, with no more than 3 +spaces indentation and any number of trailing spaces. If a line +containing a single `-` can be interpreted as an +empty [list items], it should be interpreted this way +and not as a [setext heading underline]. + +The heading is a level 1 heading if `=` characters are used in +the [setext heading underline], and a level 2 heading if `-` +characters are used. The contents of the heading are the result +of parsing the preceding lines of text as CommonMark inline +content. + +In general, a setext heading need not be preceded or followed by a +blank line. However, it cannot interrupt a paragraph, so when a +setext heading comes after a paragraph, a blank line is needed between +them. + +Simple examples: + +```````````````````````````````` example +Foo *bar* +========= + +Foo *bar* +--------- +. +

Foo bar

+

Foo bar

+```````````````````````````````` + + +The content of the header may span more than one line: + +```````````````````````````````` example +Foo *bar +baz* +==== +. +

Foo bar +baz

+```````````````````````````````` + + +The underlining can be any length: + +```````````````````````````````` example +Foo +------------------------- + +Foo += +. +

Foo

+

Foo

+```````````````````````````````` + + +The heading content can be indented up to three spaces, and need +not line up with the underlining: + +```````````````````````````````` example + Foo +--- + + Foo +----- + + Foo + === +. +

Foo

+

Foo

+

Foo

+```````````````````````````````` + + +Four spaces indent is too much: + +```````````````````````````````` example + Foo + --- + + Foo +--- +. +
Foo
+---
+
+Foo
+
+
+```````````````````````````````` + + +The setext heading underline can be indented up to three spaces, and +may have trailing spaces: + +```````````````````````````````` example +Foo + ---- +. +

Foo

+```````````````````````````````` + + +Four spaces is too much: + +```````````````````````````````` example +Foo + --- +. +

Foo +---

+```````````````````````````````` + + +The setext heading underline cannot contain internal spaces: + +```````````````````````````````` example +Foo += = + +Foo +--- - +. +

Foo += =

+

Foo

+
+```````````````````````````````` + + +Trailing spaces in the content line do not cause a line break: + +```````````````````````````````` example +Foo +----- +. +

Foo

+```````````````````````````````` + + +Nor does a backslash at the end: + +```````````````````````````````` example +Foo\ +---- +. +

Foo\

+```````````````````````````````` + + +Since indicators of block structure take precedence over +indicators of inline structure, the following are setext headings: + +```````````````````````````````` example +`Foo +---- +` + +
+. +

`Foo

+

`

+

<a title="a lot

+

of dashes"/>

+```````````````````````````````` + + +The setext heading underline cannot be a [lazy continuation +line] in a list item or block quote: + +```````````````````````````````` example +> Foo +--- +. +
+

Foo

+
+
+```````````````````````````````` + + +```````````````````````````````` example +> foo +bar +=== +. +
+

foo +bar +===

+
+```````````````````````````````` + + +```````````````````````````````` example +- Foo +--- +. +
    +
  • Foo
  • +
+
+```````````````````````````````` + + +A blank line is needed between a paragraph and a following +setext heading, since otherwise the paragraph becomes part +of the heading's content: + +```````````````````````````````` example +Foo +Bar +--- +. +

Foo +Bar

+```````````````````````````````` + + +But in general a blank line is not required before or after +setext headings: + +```````````````````````````````` example +--- +Foo +--- +Bar +--- +Baz +. +
+

Foo

+

Bar

+

Baz

+```````````````````````````````` + + +Setext headings cannot be empty: + +```````````````````````````````` example + +==== +. +

====

+```````````````````````````````` + + +Setext heading text lines must not be interpretable as block +constructs other than paragraphs. So, the line of dashes +in these examples gets interpreted as a thematic break: + +```````````````````````````````` example +--- +--- +. +
+
+```````````````````````````````` + + +```````````````````````````````` example +- foo +----- +. +
    +
  • foo
  • +
+
+```````````````````````````````` + + +```````````````````````````````` example + foo +--- +. +
foo
+
+
+```````````````````````````````` + + +```````````````````````````````` example +> foo +----- +. +
+

foo

+
+
+```````````````````````````````` + + +If you want a heading with `> foo` as its literal text, you can +use backslash escapes: + +```````````````````````````````` example +\> foo +------ +. +

> foo

+```````````````````````````````` + + +**Compatibility note:** Most existing Markdown implementations +do not allow the text of setext headings to span multiple lines. +But there is no consensus about how to interpret + +``` markdown +Foo +bar +--- +baz +``` + +One can find four different interpretations: + +1. paragraph "Foo", heading "bar", paragraph "baz" +2. paragraph "Foo bar", thematic break, paragraph "baz" +3. paragraph "Foo bar --- baz" +4. heading "Foo bar", paragraph "baz" + +We find interpretation 4 most natural, and interpretation 4 +increases the expressive power of CommonMark, by allowing +multiline headings. Authors who want interpretation 1 can +put a blank line after the first paragraph: + +```````````````````````````````` example +Foo + +bar +--- +baz +. +

Foo

+

bar

+

baz

+```````````````````````````````` + + +Authors who want interpretation 2 can put blank lines around +the thematic break, + +```````````````````````````````` example +Foo +bar + +--- + +baz +. +

Foo +bar

+
+

baz

+```````````````````````````````` + + +or use a thematic break that cannot count as a [setext heading +underline], such as + +```````````````````````````````` example +Foo +bar +* * * +baz +. +

Foo +bar

+
+

baz

+```````````````````````````````` + + +Authors who want interpretation 3 can use backslash escapes: + +```````````````````````````````` example +Foo +bar +\--- +baz +. +

Foo +bar +--- +baz

+```````````````````````````````` + + +## Indented code blocks + +An [indented code block](@) is composed of one or more +[indented chunks] separated by blank lines. +An [indented chunk](@) is a sequence of non-blank lines, +each indented four or more spaces. The contents of the code block are +the literal contents of the lines, including trailing +[line endings], minus four spaces of indentation. +An indented code block has no [info string]. + +An indented code block cannot interrupt a paragraph, so there must be +a blank line between a paragraph and a following indented code block. +(A blank line is not needed, however, between a code block and a following +paragraph.) + +```````````````````````````````` example + a simple + indented code block +. +
a simple
+  indented code block
+
+```````````````````````````````` + + +If there is any ambiguity between an interpretation of indentation +as a code block and as indicating that material belongs to a [list +item][list items], the list item interpretation takes precedence: + +```````````````````````````````` example + - foo + + bar +. +
    +
  • +

    foo

    +

    bar

    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +1. foo + + - bar +. +
    +
  1. +

    foo

    +
      +
    • bar
    • +
    +
  2. +
+```````````````````````````````` + + + +The contents of a code block are literal text, and do not get parsed +as Markdown: + +```````````````````````````````` example +
+ *hi* + + - one +. +
<a/>
+*hi*
+
+- one
+
+```````````````````````````````` + + +Here we have three chunks separated by blank lines: + +```````````````````````````````` example + chunk1 + + chunk2 + + + + chunk3 +. +
chunk1
+
+chunk2
+
+
+
+chunk3
+
+```````````````````````````````` + + +Any initial spaces beyond four will be included in the content, even +in interior blank lines: + +```````````````````````````````` example + chunk1 + + chunk2 +. +
chunk1
+  
+  chunk2
+
+```````````````````````````````` + + +An indented code block cannot interrupt a paragraph. (This +allows hanging indents and the like.) + +```````````````````````````````` example +Foo + bar + +. +

Foo +bar

+```````````````````````````````` + + +However, any non-blank line with fewer than four leading spaces ends +the code block immediately. So a paragraph may occur immediately +after indented code: + +```````````````````````````````` example + foo +bar +. +
foo
+
+

bar

+```````````````````````````````` + + +And indented code can occur immediately before and after other kinds of +blocks: + +```````````````````````````````` example +# Heading + foo +Heading +------ + foo +---- +. +

Heading

+
foo
+
+

Heading

+
foo
+
+
+```````````````````````````````` + + +The first line can be indented more than four spaces: + +```````````````````````````````` example + foo + bar +. +
    foo
+bar
+
+```````````````````````````````` + + +Blank lines preceding or following an indented code block +are not included in it: + +```````````````````````````````` example + + + foo + + +. +
foo
+
+```````````````````````````````` + + +Trailing spaces are included in the code block's content: + +```````````````````````````````` example + foo +. +
foo  
+
+```````````````````````````````` + + + +## Fenced code blocks + +A [code fence](@) is a sequence +of at least three consecutive backtick characters (`` ` ``) or +tildes (`~`). (Tildes and backticks cannot be mixed.) +A [fenced code block](@) +begins with a code fence, indented no more than three spaces. + +The line with the opening code fence may optionally contain some text +following the code fence; this is trimmed of leading and trailing +spaces and called the [info string](@). +The [info string] may not contain any backtick +characters. (The reason for this restriction is that otherwise +some inline code would be incorrectly interpreted as the +beginning of a fenced code block.) + +The content of the code block consists of all subsequent lines, until +a closing [code fence] of the same type as the code block +began with (backticks or tildes), and with at least as many backticks +or tildes as the opening code fence. If the leading code fence is +indented N spaces, then up to N spaces of indentation are removed from +each line of the content (if present). (If a content line is not +indented, it is preserved unchanged. If it is indented less than N +spaces, all of the indentation is removed.) + +The closing code fence may be indented up to three spaces, and may be +followed only by spaces, which are ignored. If the end of the +containing block (or document) is reached and no closing code fence +has been found, the code block contains all of the lines after the +opening code fence until the end of the containing block (or +document). (An alternative spec would require backtracking in the +event that a closing code fence is not found. But this makes parsing +much less efficient, and there seems to be no real down side to the +behavior described here.) + +A fenced code block may interrupt a paragraph, and does not require +a blank line either before or after. + +The content of a code fence is treated as literal text, not parsed +as inlines. The first word of the [info string] is typically used to +specify the language of the code sample, and rendered in the `class` +attribute of the `code` tag. However, this spec does not mandate any +particular treatment of the [info string]. + +Here is a simple example with backticks: + +```````````````````````````````` example +``` +< + > +``` +. +
<
+ >
+
+```````````````````````````````` + + +With tildes: + +```````````````````````````````` example +~~~ +< + > +~~~ +. +
<
+ >
+
+```````````````````````````````` + +Fewer than three backticks is not enough: + +```````````````````````````````` example +`` +foo +`` +. +

foo

+```````````````````````````````` + +The closing code fence must use the same character as the opening +fence: + +```````````````````````````````` example +``` +aaa +~~~ +``` +. +
aaa
+~~~
+
+```````````````````````````````` + + +```````````````````````````````` example +~~~ +aaa +``` +~~~ +. +
aaa
+```
+
+```````````````````````````````` + + +The closing code fence must be at least as long as the opening fence: + +```````````````````````````````` example +```` +aaa +``` +`````` +. +
aaa
+```
+
+```````````````````````````````` + + +```````````````````````````````` example +~~~~ +aaa +~~~ +~~~~ +. +
aaa
+~~~
+
+```````````````````````````````` + + +Unclosed code blocks are closed by the end of the document +(or the enclosing [block quote][block quotes] or [list item][list items]): + +```````````````````````````````` example +``` +. +
+```````````````````````````````` + + +```````````````````````````````` example +````` + +``` +aaa +. +

+```
+aaa
+
+```````````````````````````````` + + +```````````````````````````````` example +> ``` +> aaa + +bbb +. +
+
aaa
+
+
+

bbb

+```````````````````````````````` + + +A code block can have all empty lines as its content: + +```````````````````````````````` example +``` + + +``` +. +

+  
+
+```````````````````````````````` + + +A code block can be empty: + +```````````````````````````````` example +``` +``` +. +
+```````````````````````````````` + + +Fences can be indented. If the opening fence is indented, +content lines will have equivalent opening indentation removed, +if present: + +```````````````````````````````` example + ``` + aaa +aaa +``` +. +
aaa
+aaa
+
+```````````````````````````````` + + +```````````````````````````````` example + ``` +aaa + aaa +aaa + ``` +. +
aaa
+aaa
+aaa
+
+```````````````````````````````` + + +```````````````````````````````` example + ``` + aaa + aaa + aaa + ``` +. +
aaa
+ aaa
+aaa
+
+```````````````````````````````` + + +Four spaces indentation produces an indented code block: + +```````````````````````````````` example + ``` + aaa + ``` +. +
```
+aaa
+```
+
+```````````````````````````````` + + +Closing fences may be indented by 0-3 spaces, and their indentation +need not match that of the opening fence: + +```````````````````````````````` example +``` +aaa + ``` +. +
aaa
+
+```````````````````````````````` + + +```````````````````````````````` example + ``` +aaa + ``` +. +
aaa
+
+```````````````````````````````` + + +This is not a closing fence, because it is indented 4 spaces: + +```````````````````````````````` example +``` +aaa + ``` +. +
aaa
+    ```
+
+```````````````````````````````` + + + +Code fences (opening and closing) cannot contain internal spaces: + +```````````````````````````````` example +``` ``` +aaa +. +

+aaa

+```````````````````````````````` + + +```````````````````````````````` example +~~~~~~ +aaa +~~~ ~~ +. +
aaa
+~~~ ~~
+
+```````````````````````````````` + + +Fenced code blocks can interrupt paragraphs, and can be followed +directly by paragraphs, without a blank line between: + +```````````````````````````````` example +foo +``` +bar +``` +baz +. +

foo

+
bar
+
+

baz

+```````````````````````````````` + + +Other blocks can also occur before and after fenced code blocks +without an intervening blank line: + +```````````````````````````````` example +foo +--- +~~~ +bar +~~~ +# baz +. +

foo

+
bar
+
+

baz

+```````````````````````````````` + + +An [info string] can be provided after the opening code fence. +Opening and closing spaces will be stripped, and the first word, prefixed +with `language-`, is used as the value for the `class` attribute of the +`code` element within the enclosing `pre` element. + +```````````````````````````````` example +```ruby +def foo(x) + return 3 +end +``` +. +
def foo(x)
+  return 3
+end
+
+```````````````````````````````` + + +```````````````````````````````` example +~~~~ ruby startline=3 $%@#$ +def foo(x) + return 3 +end +~~~~~~~ +. +
def foo(x)
+  return 3
+end
+
+```````````````````````````````` + + +```````````````````````````````` example +````; +```` +. +
+```````````````````````````````` + + +[Info strings] for backtick code blocks cannot contain backticks: + +```````````````````````````````` example +``` aa ``` +foo +. +

aa +foo

+```````````````````````````````` + + +Closing code fences cannot have [info strings]: + +```````````````````````````````` example +``` +``` aaa +``` +. +
``` aaa
+
+```````````````````````````````` + + + +## HTML blocks + +An [HTML block](@) is a group of lines that is treated +as raw HTML (and will not be escaped in HTML output). + +There are seven kinds of [HTML block], which can be defined +by their start and end conditions. The block begins with a line that +meets a [start condition](@) (after up to three spaces +optional indentation). It ends with the first subsequent line that +meets a matching [end condition](@), or the last line of +the document or other [container block]), if no line is encountered that meets the +[end condition]. If the first line meets both the [start condition] +and the [end condition], the block will contain just that line. + +1. **Start condition:** line begins with the string ``, or the end of the line.\ +**End condition:** line contains an end tag +``, `
`, or `` (case-insensitive; it +need not match the start tag). + +2. **Start condition:** line begins with the string ``. + +3. **Start condition:** line begins with the string ``. + +4. **Start condition:** line begins with the string ``. + +5. **Start condition:** line begins with the string +``. + +6. **Start condition:** line begins the string `<` or ``, or +the string `/>`.\ +**End condition:** line is followed by a [blank line]. + +7. **Start condition:** line begins with a complete [open tag] +or [closing tag] (with any [tag name] other than `script`, +`style`, or `pre`) followed only by [whitespace] +or the end of the line.\ +**End condition:** line is followed by a [blank line]. + +HTML blocks continue until they are closed by their appropriate +[end condition], or the last line of the document or other [container block]. +This means any HTML **within an HTML block** that might otherwise be recognised +as a start condition will be ignored by the parser and passed through as-is, +without changing the parser's state. + +For instance, `
` within a HTML block started by `` will not affect
+the parser state; as the HTML block was started in by start condition 6, it
+will end at any blank line. This can be surprising:
+
+```````````````````````````````` example
+
+
+**Hello**,
+
+_world_.
+
+
+. +
+
+**Hello**,
+

world. +

+
+```````````````````````````````` + +In this case, the HTML block is terminated by the newline — the `**hello**` +text remains verbatim — and regular parsing resumes, with a paragraph, +emphasised `world` and inline and block HTML following. + +All types of [HTML blocks] except type 7 may interrupt +a paragraph. Blocks of type 7 may not interrupt a paragraph. +(This restriction is intended to prevent unwanted interpretation +of long tags inside a wrapped paragraph as starting HTML blocks.) + +Some simple examples follow. Here are some basic HTML blocks +of type 6: + +```````````````````````````````` example + + + + +
+ hi +
+ +okay. +. + + + + +
+ hi +
+

okay.

+```````````````````````````````` + + +```````````````````````````````` example +
+*foo* +```````````````````````````````` + + +Here we have two HTML blocks with a Markdown paragraph between them: + +```````````````````````````````` example +
+ +*Markdown* + +
+. +
+

Markdown

+
+```````````````````````````````` + + +The tag on the first line can be partial, as long +as it is split where there would be whitespace: + +```````````````````````````````` example +
+
+. +
+
+```````````````````````````````` + + +```````````````````````````````` example +
+
+. +
+
+```````````````````````````````` + + +An open tag need not be closed: +```````````````````````````````` example +
+*foo* + +*bar* +. +
+*foo* +

bar

+```````````````````````````````` + + + +A partial tag need not even be completed (garbage +in, garbage out): + +```````````````````````````````` example +
+. + +```````````````````````````````` + + +```````````````````````````````` example +
+foo +
+. +
+foo +
+```````````````````````````````` + + +Everything until the next blank line or end of document +gets included in the HTML block. So, in the following +example, what looks like a Markdown code block +is actually part of the HTML block, which continues until a blank +line or the end of the document is reached: + +```````````````````````````````` example +
+``` c +int x = 33; +``` +. +
+``` c +int x = 33; +``` +```````````````````````````````` + + +To start an [HTML block] with a tag that is *not* in the +list of block-level tags in (6), you must put the tag by +itself on the first line (and it must be complete): + +```````````````````````````````` example + +*bar* + +. + +*bar* + +```````````````````````````````` + + +In type 7 blocks, the [tag name] can be anything: + +```````````````````````````````` example + +*bar* + +. + +*bar* + +```````````````````````````````` + + +```````````````````````````````` example + +*bar* + +. + +*bar* + +```````````````````````````````` + + +```````````````````````````````` example + +*bar* +. + +*bar* +```````````````````````````````` + + +These rules are designed to allow us to work with tags that +can function as either block-level or inline-level tags. +The `` tag is a nice example. We can surround content with +`` tags in three different ways. In this case, we get a raw +HTML block, because the `` tag is on a line by itself: + +```````````````````````````````` example + +*foo* + +. + +*foo* + +```````````````````````````````` + + +In this case, we get a raw HTML block that just includes +the `` tag (because it ends with the following blank +line). So the contents get interpreted as CommonMark: + +```````````````````````````````` example + + +*foo* + + +. + +

foo

+
+```````````````````````````````` + + +Finally, in this case, the `` tags are interpreted +as [raw HTML] *inside* the CommonMark paragraph. (Because +the tag is not on a line by itself, we get inline HTML +rather than an [HTML block].) + +```````````````````````````````` example +*foo* +. +

foo

+```````````````````````````````` + + +HTML tags designed to contain literal content +(`script`, `style`, `pre`), comments, processing instructions, +and declarations are treated somewhat differently. +Instead of ending at the first blank line, these blocks +end at the first line containing a corresponding end tag. +As a result, these blocks can contain blank lines: + +A pre tag (type 1): + +```````````````````````````````` example +

+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+
+okay +. +

+import Text.HTML.TagSoup
+
+main :: IO ()
+main = print $ parseTags tags
+
+

okay

+```````````````````````````````` + + +A script tag (type 1): + +```````````````````````````````` example + +okay +. + +

okay

+```````````````````````````````` + + +A style tag (type 1): + +```````````````````````````````` example + +okay +. + +

okay

+```````````````````````````````` + + +If there is no matching end tag, the block will end at the +end of the document (or the enclosing [block quote][block quotes] +or [list item][list items]): + +```````````````````````````````` example + +*foo* +. + +

foo

+```````````````````````````````` + + +```````````````````````````````` example +*bar* +*baz* +. +*bar* +

baz

+```````````````````````````````` + + +Note that anything on the last line after the +end tag will be included in the [HTML block]: + +```````````````````````````````` example +1. *bar* +. +1. *bar* +```````````````````````````````` + + +A comment (type 2): + +```````````````````````````````` example + +okay +. + +

okay

+```````````````````````````````` + + + +A processing instruction (type 3): + +```````````````````````````````` example +'; + +?> +okay +. +'; + +?> +

okay

+```````````````````````````````` + + +A declaration (type 4): + +```````````````````````````````` example + +. + +```````````````````````````````` + + +CDATA (type 5): + +```````````````````````````````` example + +okay +. + +

okay

+```````````````````````````````` + + +The opening tag can be indented 1-3 spaces, but not 4: + +```````````````````````````````` example + + + +. + +
<!-- foo -->
+
+```````````````````````````````` + + +```````````````````````````````` example +
+ +
+. +
+
<div>
+
+```````````````````````````````` + + +An HTML block of types 1--6 can interrupt a paragraph, and need not be +preceded by a blank line. + +```````````````````````````````` example +Foo +
+bar +
+. +

Foo

+
+bar +
+```````````````````````````````` + + +However, a following blank line is needed, except at the end of +a document, and except for blocks of types 1--5, above: + +```````````````````````````````` example +
+bar +
+*foo* +. +
+bar +
+*foo* +```````````````````````````````` + + +HTML blocks of type 7 cannot interrupt a paragraph: + +```````````````````````````````` example +Foo + +baz +. +

Foo + +baz

+```````````````````````````````` + + +This rule differs from John Gruber's original Markdown syntax +specification, which says: + +> The only restrictions are that block-level HTML elements — +> e.g. `
`, ``, `
`, `

`, etc. — must be separated from +> surrounding content by blank lines, and the start and end tags of the +> block should not be indented with tabs or spaces. + +In some ways Gruber's rule is more restrictive than the one given +here: + +- It requires that an HTML block be preceded by a blank line. +- It does not allow the start tag to be indented. +- It requires a matching end tag, which it also does not allow to + be indented. + +Most Markdown implementations (including some of Gruber's own) do not +respect all of these restrictions. + +There is one respect, however, in which Gruber's rule is more liberal +than the one given here, since it allows blank lines to occur inside +an HTML block. There are two reasons for disallowing them here. +First, it removes the need to parse balanced tags, which is +expensive and can require backtracking from the end of the document +if no matching end tag is found. Second, it provides a very simple +and flexible way of including Markdown content inside HTML tags: +simply separate the Markdown from the HTML using blank lines: + +Compare: + +```````````````````````````````` example +

+ +*Emphasized* text. + +
+. +
+

Emphasized text.

+
+```````````````````````````````` + + +```````````````````````````````` example +
+*Emphasized* text. +
+. +
+*Emphasized* text. +
+```````````````````````````````` + + +Some Markdown implementations have adopted a convention of +interpreting content inside tags as text if the open tag has +the attribute `markdown=1`. The rule given above seems a simpler and +more elegant way of achieving the same expressive power, which is also +much simpler to parse. + +The main potential drawback is that one can no longer paste HTML +blocks into Markdown documents with 100% reliability. However, +*in most cases* this will work fine, because the blank lines in +HTML are usually followed by HTML block tags. For example: + +```````````````````````````````` example +
+ + + + + + + +
+Hi +
+. + + + + +
+Hi +
+```````````````````````````````` + + +There are problems, however, if the inner tags are indented +*and* separated by spaces, as then they will be interpreted as +an indented code block: + +```````````````````````````````` example + + + + + + + + +
+ Hi +
+. + + +
<td>
+  Hi
+</td>
+
+ +
+```````````````````````````````` + + +Fortunately, blank lines are usually not necessary and can be +deleted. The exception is inside `
` tags, but as described
+above, raw HTML blocks starting with `
` *can* contain blank
+lines.
+
+## Link reference definitions
+
+A [link reference definition](@)
+consists of a [link label], indented up to three spaces, followed
+by a colon (`:`), optional [whitespace] (including up to one
+[line ending]), a [link destination],
+optional [whitespace] (including up to one
+[line ending]), and an optional [link
+title], which if it is present must be separated
+from the [link destination] by [whitespace].
+No further [non-whitespace characters] may occur on the line.
+
+A [link reference definition]
+does not correspond to a structural element of a document.  Instead, it
+defines a label which can be used in [reference links]
+and reference-style [images] elsewhere in the document.  [Link
+reference definitions] can come either before or after the links that use
+them.
+
+```````````````````````````````` example
+[foo]: /url "title"
+
+[foo]
+.
+

foo

+```````````````````````````````` + + +```````````````````````````````` example + [foo]: + /url + 'the title' + +[foo] +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[Foo*bar\]]:my_(url) 'title (with parens)' + +[Foo*bar\]] +. +

Foo*bar]

+```````````````````````````````` + + +```````````````````````````````` example +[Foo bar]: + +'title' + +[Foo bar] +. +

Foo bar

+```````````````````````````````` + + +The title may extend over multiple lines: + +```````````````````````````````` example +[foo]: /url ' +title +line1 +line2 +' + +[foo] +. +

foo

+```````````````````````````````` + + +However, it may not contain a [blank line]: + +```````````````````````````````` example +[foo]: /url 'title + +with blank line' + +[foo] +. +

[foo]: /url 'title

+

with blank line'

+

[foo]

+```````````````````````````````` + + +The title may be omitted: + +```````````````````````````````` example +[foo]: +/url + +[foo] +. +

foo

+```````````````````````````````` + + +The link destination may not be omitted: + +```````````````````````````````` example +[foo]: + +[foo] +. +

[foo]:

+

[foo]

+```````````````````````````````` + + +Both title and destination can contain backslash escapes +and literal backslashes: + +```````````````````````````````` example +[foo]: /url\bar\*baz "foo\"bar\baz" + +[foo] +. +

foo

+```````````````````````````````` + + +A link can come before its corresponding definition: + +```````````````````````````````` example +[foo] + +[foo]: url +. +

foo

+```````````````````````````````` + + +If there are several matching definitions, the first one takes +precedence: + +```````````````````````````````` example +[foo] + +[foo]: first +[foo]: second +. +

foo

+```````````````````````````````` + + +As noted in the section on [Links], matching of labels is +case-insensitive (see [matches]). + +```````````````````````````````` example +[FOO]: /url + +[Foo] +. +

Foo

+```````````````````````````````` + + +```````````````````````````````` example +[ΑΓΩ]: /φου + +[αγω] +. +

αγω

+```````````````````````````````` + + +Here is a link reference definition with no corresponding link. +It contributes nothing to the document. + +```````````````````````````````` example +[foo]: /url +. +```````````````````````````````` + + +Here is another one: + +```````````````````````````````` example +[ +foo +]: /url +bar +. +

bar

+```````````````````````````````` + + +This is not a link reference definition, because there are +[non-whitespace characters] after the title: + +```````````````````````````````` example +[foo]: /url "title" ok +. +

[foo]: /url "title" ok

+```````````````````````````````` + + +This is a link reference definition, but it has no title: + +```````````````````````````````` example +[foo]: /url +"title" ok +. +

"title" ok

+```````````````````````````````` + + +This is not a link reference definition, because it is indented +four spaces: + +```````````````````````````````` example + [foo]: /url "title" + +[foo] +. +
[foo]: /url "title"
+
+

[foo]

+```````````````````````````````` + + +This is not a link reference definition, because it occurs inside +a code block: + +```````````````````````````````` example +``` +[foo]: /url +``` + +[foo] +. +
[foo]: /url
+
+

[foo]

+```````````````````````````````` + + +A [link reference definition] cannot interrupt a paragraph. + +```````````````````````````````` example +Foo +[bar]: /baz + +[bar] +. +

Foo +[bar]: /baz

+

[bar]

+```````````````````````````````` + + +However, it can directly follow other block elements, such as headings +and thematic breaks, and it need not be followed by a blank line. + +```````````````````````````````` example +# [Foo] +[foo]: /url +> bar +. +

Foo

+
+

bar

+
+```````````````````````````````` + + +Several [link reference definitions] +can occur one after another, without intervening blank lines. + +```````````````````````````````` example +[foo]: /foo-url "foo" +[bar]: /bar-url + "bar" +[baz]: /baz-url + +[foo], +[bar], +[baz] +. +

foo, +bar, +baz

+```````````````````````````````` + + +[Link reference definitions] can occur +inside block containers, like lists and block quotations. They +affect the entire document, not just the container in which they +are defined: + +```````````````````````````````` example +[foo] + +> [foo]: /url +. +

foo

+
+
+```````````````````````````````` + + + +## Paragraphs + +A sequence of non-blank lines that cannot be interpreted as other +kinds of blocks forms a [paragraph](@). +The contents of the paragraph are the result of parsing the +paragraph's raw content as inlines. The paragraph's raw content +is formed by concatenating the lines and removing initial and final +[whitespace]. + +A simple example with two paragraphs: + +```````````````````````````````` example +aaa + +bbb +. +

aaa

+

bbb

+```````````````````````````````` + + +Paragraphs can contain multiple lines, but no blank lines: + +```````````````````````````````` example +aaa +bbb + +ccc +ddd +. +

aaa +bbb

+

ccc +ddd

+```````````````````````````````` + + +Multiple blank lines between paragraph have no effect: + +```````````````````````````````` example +aaa + + +bbb +. +

aaa

+

bbb

+```````````````````````````````` + + +Leading spaces are skipped: + +```````````````````````````````` example + aaa + bbb +. +

aaa +bbb

+```````````````````````````````` + + +Lines after the first may be indented any amount, since indented +code blocks cannot interrupt paragraphs. + +```````````````````````````````` example +aaa + bbb + ccc +. +

aaa +bbb +ccc

+```````````````````````````````` + + +However, the first line may be indented at most three spaces, +or an indented code block will be triggered: + +```````````````````````````````` example + aaa +bbb +. +

aaa +bbb

+```````````````````````````````` + + +```````````````````````````````` example + aaa +bbb +. +
aaa
+
+

bbb

+```````````````````````````````` + + +Final spaces are stripped before inline parsing, so a paragraph +that ends with two or more spaces will not end with a [hard line +break]: + +```````````````````````````````` example +aaa +bbb +. +

aaa
+bbb

+```````````````````````````````` + + +## Blank lines + +[Blank lines] between block-level elements are ignored, +except for the role they play in determining whether a [list] +is [tight] or [loose]. + +Blank lines at the beginning and end of the document are also ignored. + +```````````````````````````````` example + + +aaa + + +# aaa + + +. +

aaa

+

aaa

+```````````````````````````````` + + + +# Container blocks + +A [container block] is a block that has other +blocks as its contents. There are two basic kinds of container blocks: +[block quotes] and [list items]. +[Lists] are meta-containers for [list items]. + +We define the syntax for container blocks recursively. The general +form of the definition is: + +> If X is a sequence of blocks, then the result of +> transforming X in such-and-such a way is a container of type Y +> with these blocks as its content. + +So, we explain what counts as a block quote or list item by explaining +how these can be *generated* from their contents. This should suffice +to define the syntax, although it does not give a recipe for *parsing* +these constructions. (A recipe is provided below in the section entitled +[A parsing strategy](#appendix-a-parsing-strategy).) + +## Block quotes + +A [block quote marker](@) +consists of 0-3 spaces of initial indent, plus (a) the character `>` together +with a following space, or (b) a single character `>` not followed by a space. + +The following rules define [block quotes]: + +1. **Basic case.** If a string of lines *Ls* constitute a sequence + of blocks *Bs*, then the result of prepending a [block quote + marker] to the beginning of each line in *Ls* + is a [block quote](#block-quotes) containing *Bs*. + +2. **Laziness.** If a string of lines *Ls* constitute a [block + quote](#block-quotes) with contents *Bs*, then the result of deleting + the initial [block quote marker] from one or + more lines in which the next [non-whitespace character] after the [block + quote marker] is [paragraph continuation + text] is a block quote with *Bs* as its content. + [Paragraph continuation text](@) is text + that will be parsed as part of the content of a paragraph, but does + not occur at the beginning of the paragraph. + +3. **Consecutiveness.** A document cannot contain two [block + quotes] in a row unless there is a [blank line] between them. + +Nothing else counts as a [block quote](#block-quotes). + +Here is a simple example: + +```````````````````````````````` example +> # Foo +> bar +> baz +. +
+

Foo

+

bar +baz

+
+```````````````````````````````` + + +The spaces after the `>` characters can be omitted: + +```````````````````````````````` example +># Foo +>bar +> baz +. +
+

Foo

+

bar +baz

+
+```````````````````````````````` + + +The `>` characters can be indented 1-3 spaces: + +```````````````````````````````` example + > # Foo + > bar + > baz +. +
+

Foo

+

bar +baz

+
+```````````````````````````````` + + +Four spaces gives us a code block: + +```````````````````````````````` example + > # Foo + > bar + > baz +. +
> # Foo
+> bar
+> baz
+
+```````````````````````````````` + + +The Laziness clause allows us to omit the `>` before +[paragraph continuation text]: + +```````````````````````````````` example +> # Foo +> bar +baz +. +
+

Foo

+

bar +baz

+
+```````````````````````````````` + + +A block quote can contain some lazy and some non-lazy +continuation lines: + +```````````````````````````````` example +> bar +baz +> foo +. +
+

bar +baz +foo

+
+```````````````````````````````` + + +Laziness only applies to lines that would have been continuations of +paragraphs had they been prepended with [block quote markers]. +For example, the `> ` cannot be omitted in the second line of + +``` markdown +> foo +> --- +``` + +without changing the meaning: + +```````````````````````````````` example +> foo +--- +. +
+

foo

+
+
+```````````````````````````````` + + +Similarly, if we omit the `> ` in the second line of + +``` markdown +> - foo +> - bar +``` + +then the block quote ends after the first line: + +```````````````````````````````` example +> - foo +- bar +. +
+
    +
  • foo
  • +
+
+
    +
  • bar
  • +
+```````````````````````````````` + + +For the same reason, we can't omit the `> ` in front of +subsequent lines of an indented or fenced code block: + +```````````````````````````````` example +> foo + bar +. +
+
foo
+
+
+
bar
+
+```````````````````````````````` + + +```````````````````````````````` example +> ``` +foo +``` +. +
+
+
+

foo

+
+```````````````````````````````` + + +Note that in the following case, we have a [lazy +continuation line]: + +```````````````````````````````` example +> foo + - bar +. +
+

foo +- bar

+
+```````````````````````````````` + + +To see why, note that in + +```markdown +> foo +> - bar +``` + +the `- bar` is indented too far to start a list, and can't +be an indented code block because indented code blocks cannot +interrupt paragraphs, so it is [paragraph continuation text]. + +A block quote can be empty: + +```````````````````````````````` example +> +. +
+
+```````````````````````````````` + + +```````````````````````````````` example +> +> +> +. +
+
+```````````````````````````````` + + +A block quote can have initial or final blank lines: + +```````````````````````````````` example +> +> foo +> +. +
+

foo

+
+```````````````````````````````` + + +A blank line always separates block quotes: + +```````````````````````````````` example +> foo + +> bar +. +
+

foo

+
+
+

bar

+
+```````````````````````````````` + + +(Most current Markdown implementations, including John Gruber's +original `Markdown.pl`, will parse this example as a single block quote +with two paragraphs. But it seems better to allow the author to decide +whether two block quotes or one are wanted.) + +Consecutiveness means that if we put these block quotes together, +we get a single block quote: + +```````````````````````````````` example +> foo +> bar +. +
+

foo +bar

+
+```````````````````````````````` + + +To get a block quote with two paragraphs, use: + +```````````````````````````````` example +> foo +> +> bar +. +
+

foo

+

bar

+
+```````````````````````````````` + + +Block quotes can interrupt paragraphs: + +```````````````````````````````` example +foo +> bar +. +

foo

+
+

bar

+
+```````````````````````````````` + + +In general, blank lines are not needed before or after block +quotes: + +```````````````````````````````` example +> aaa +*** +> bbb +. +
+

aaa

+
+
+
+

bbb

+
+```````````````````````````````` + + +However, because of laziness, a blank line is needed between +a block quote and a following paragraph: + +```````````````````````````````` example +> bar +baz +. +
+

bar +baz

+
+```````````````````````````````` + + +```````````````````````````````` example +> bar + +baz +. +
+

bar

+
+

baz

+```````````````````````````````` + + +```````````````````````````````` example +> bar +> +baz +. +
+

bar

+
+

baz

+```````````````````````````````` + + +It is a consequence of the Laziness rule that any number +of initial `>`s may be omitted on a continuation line of a +nested block quote: + +```````````````````````````````` example +> > > foo +bar +. +
+
+
+

foo +bar

+
+
+
+```````````````````````````````` + + +```````````````````````````````` example +>>> foo +> bar +>>baz +. +
+
+
+

foo +bar +baz

+
+
+
+```````````````````````````````` + + +When including an indented code block in a block quote, +remember that the [block quote marker] includes +both the `>` and a following space. So *five spaces* are needed after +the `>`: + +```````````````````````````````` example +> code + +> not code +. +
+
code
+
+
+
+

not code

+
+```````````````````````````````` + + + +## List items + +A [list marker](@) is a +[bullet list marker] or an [ordered list marker]. + +A [bullet list marker](@) +is a `-`, `+`, or `*` character. + +An [ordered list marker](@) +is a sequence of 1--9 arabic digits (`0-9`), followed by either a +`.` character or a `)` character. (The reason for the length +limit is that with 10 digits we start seeing integer overflows +in some browsers.) + +The following rules define [list items]: + +1. **Basic case.** If a sequence of lines *Ls* constitute a sequence of + blocks *Bs* starting with a [non-whitespace character] and not separated + from each other by more than one blank line, and *M* is a list + marker of width *W* followed by 1 ≤ *N* ≤ 4 spaces, then the result + of prepending *M* and the following spaces to the first line of + *Ls*, and indenting subsequent lines of *Ls* by *W + N* spaces, is a + list item with *Bs* as its contents. The type of the list item + (bullet or ordered) is determined by the type of its list marker. + If the list item is ordered, then it is also assigned a start + number, based on the ordered list marker. + + Exceptions: + + 1. When the first list item in a [list] interrupts + a paragraph---that is, when it starts on a line that would + otherwise count as [paragraph continuation text]---then (a) + the lines *Ls* must not begin with a blank line, and (b) if + the list item is ordered, the start number must be 1. + 2. If any line is a [thematic break][thematic breaks] then + that line is not a list item. + +For example, let *Ls* be the lines + +```````````````````````````````` example +A paragraph +with two lines. + + indented code + +> A block quote. +. +

A paragraph +with two lines.

+
indented code
+
+
+

A block quote.

+
+```````````````````````````````` + + +And let *M* be the marker `1.`, and *N* = 2. Then rule #1 says +that the following is an ordered list item with start number 1, +and the same contents as *Ls*: + +```````````````````````````````` example +1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +The most important thing to notice is that the position of +the text after the list marker determines how much indentation +is needed in subsequent blocks in the list item. If the list +marker takes up two spaces, and there are three spaces between +the list marker and the next [non-whitespace character], then blocks +must be indented five spaces in order to fall under the list +item. + +Here are some examples showing how far content must be indented to be +put under the list item: + +```````````````````````````````` example +- one + + two +. +
    +
  • one
  • +
+

two

+```````````````````````````````` + + +```````````````````````````````` example +- one + + two +. +
    +
  • +

    one

    +

    two

    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example + - one + + two +. +
    +
  • one
  • +
+
 two
+
+```````````````````````````````` + + +```````````````````````````````` example + - one + + two +. +
    +
  • +

    one

    +

    two

    +
  • +
+```````````````````````````````` + + +It is tempting to think of this in terms of columns: the continuation +blocks must be indented at least to the column of the first +[non-whitespace character] after the list marker. However, that is not quite right. +The spaces after the list marker determine how much relative indentation +is needed. Which column this indentation reaches will depend on +how the list item is embedded in other constructions, as shown by +this example: + +```````````````````````````````` example + > > 1. one +>> +>> two +. +
+
+
    +
  1. +

    one

    +

    two

    +
  2. +
+
+
+```````````````````````````````` + + +Here `two` occurs in the same column as the list marker `1.`, +but is actually contained in the list item, because there is +sufficient indentation after the last containing blockquote marker. + +The converse is also possible. In the following example, the word `two` +occurs far to the right of the initial text of the list item, `one`, but +it is not considered part of the list item, because it is not indented +far enough past the blockquote marker: + +```````````````````````````````` example +>>- one +>> + > > two +. +
+
+
    +
  • one
  • +
+

two

+
+
+```````````````````````````````` + + +Note that at least one space is needed between the list marker and +any following content, so these are not list items: + +```````````````````````````````` example +-one + +2.two +. +

-one

+

2.two

+```````````````````````````````` + + +A list item may contain blocks that are separated by more than +one blank line. + +```````````````````````````````` example +- foo + + + bar +. +
    +
  • +

    foo

    +

    bar

    +
  • +
+```````````````````````````````` + + +A list item may contain any kind of block: + +```````````````````````````````` example +1. foo + + ``` + bar + ``` + + baz + + > bam +. +
    +
  1. +

    foo

    +
    bar
    +
    +

    baz

    +
    +

    bam

    +
    +
  2. +
+```````````````````````````````` + + +A list item that contains an indented code block will preserve +empty lines within the code block verbatim. + +```````````````````````````````` example +- Foo + + bar + + + baz +. +
    +
  • +

    Foo

    +
    bar
    +
    +
    +baz
    +
    +
  • +
+```````````````````````````````` + +Note that ordered list start numbers must be nine digits or less: + +```````````````````````````````` example +123456789. ok +. +
    +
  1. ok
  2. +
+```````````````````````````````` + + +```````````````````````````````` example +1234567890. not ok +. +

1234567890. not ok

+```````````````````````````````` + + +A start number may begin with 0s: + +```````````````````````````````` example +0. ok +. +
    +
  1. ok
  2. +
+```````````````````````````````` + + +```````````````````````````````` example +003. ok +. +
    +
  1. ok
  2. +
+```````````````````````````````` + + +A start number may not be negative: + +```````````````````````````````` example +-1. not ok +. +

-1. not ok

+```````````````````````````````` + + + +2. **Item starting with indented code.** If a sequence of lines *Ls* + constitute a sequence of blocks *Bs* starting with an indented code + block and not separated from each other by more than one blank line, + and *M* is a list marker of width *W* followed by + one space, then the result of prepending *M* and the following + space to the first line of *Ls*, and indenting subsequent lines of + *Ls* by *W + 1* spaces, is a list item with *Bs* as its contents. + If a line is empty, then it need not be indented. The type of the + list item (bullet or ordered) is determined by the type of its list + marker. If the list item is ordered, then it is also assigned a + start number, based on the ordered list marker. + +An indented code block will have to be indented four spaces beyond +the edge of the region where text will be included in the list item. +In the following case that is 6 spaces: + +```````````````````````````````` example +- foo + + bar +. +
    +
  • +

    foo

    +
    bar
    +
    +
  • +
+```````````````````````````````` + + +And in this case it is 11 spaces: + +```````````````````````````````` example + 10. foo + + bar +. +
    +
  1. +

    foo

    +
    bar
    +
    +
  2. +
+```````````````````````````````` + + +If the *first* block in the list item is an indented code block, +then by rule #2, the contents must be indented *one* space after the +list marker: + +```````````````````````````````` example + indented code + +paragraph + + more code +. +
indented code
+
+

paragraph

+
more code
+
+```````````````````````````````` + + +```````````````````````````````` example +1. indented code + + paragraph + + more code +. +
    +
  1. +
    indented code
    +
    +

    paragraph

    +
    more code
    +
    +
  2. +
+```````````````````````````````` + + +Note that an additional space indent is interpreted as space +inside the code block: + +```````````````````````````````` example +1. indented code + + paragraph + + more code +. +
    +
  1. +
     indented code
    +
    +

    paragraph

    +
    more code
    +
    +
  2. +
+```````````````````````````````` + + +Note that rules #1 and #2 only apply to two cases: (a) cases +in which the lines to be included in a list item begin with a +[non-whitespace character], and (b) cases in which +they begin with an indented code +block. In a case like the following, where the first block begins with +a three-space indent, the rules do not allow us to form a list item by +indenting the whole thing and prepending a list marker: + +```````````````````````````````` example + foo + +bar +. +

foo

+

bar

+```````````````````````````````` + + +```````````````````````````````` example +- foo + + bar +. +
    +
  • foo
  • +
+

bar

+```````````````````````````````` + + +This is not a significant restriction, because when a block begins +with 1-3 spaces indent, the indentation can always be removed without +a change in interpretation, allowing rule #1 to be applied. So, in +the above case: + +```````````````````````````````` example +- foo + + bar +. +
    +
  • +

    foo

    +

    bar

    +
  • +
+```````````````````````````````` + + +3. **Item starting with a blank line.** If a sequence of lines *Ls* + starting with a single [blank line] constitute a (possibly empty) + sequence of blocks *Bs*, not separated from each other by more than + one blank line, and *M* is a list marker of width *W*, + then the result of prepending *M* to the first line of *Ls*, and + indenting subsequent lines of *Ls* by *W + 1* spaces, is a list + item with *Bs* as its contents. + If a line is empty, then it need not be indented. The type of the + list item (bullet or ordered) is determined by the type of its list + marker. If the list item is ordered, then it is also assigned a + start number, based on the ordered list marker. + +Here are some list items that start with a blank line but are not empty: + +```````````````````````````````` example +- + foo +- + ``` + bar + ``` +- + baz +. +
    +
  • foo
  • +
  • +
    bar
    +
    +
  • +
  • +
    baz
    +
    +
  • +
+```````````````````````````````` + +When the list item starts with a blank line, the number of spaces +following the list marker doesn't change the required indentation: + +```````````````````````````````` example +- + foo +. +
    +
  • foo
  • +
+```````````````````````````````` + + +A list item can begin with at most one blank line. +In the following example, `foo` is not part of the list +item: + +```````````````````````````````` example +- + + foo +. +
    +
  • +
+

foo

+```````````````````````````````` + + +Here is an empty bullet list item: + +```````````````````````````````` example +- foo +- +- bar +. +
    +
  • foo
  • +
  • +
  • bar
  • +
+```````````````````````````````` + + +It does not matter whether there are spaces following the [list marker]: + +```````````````````````````````` example +- foo +- +- bar +. +
    +
  • foo
  • +
  • +
  • bar
  • +
+```````````````````````````````` + + +Here is an empty ordered list item: + +```````````````````````````````` example +1. foo +2. +3. bar +. +
    +
  1. foo
  2. +
  3. +
  4. bar
  5. +
+```````````````````````````````` + + +A list may start or end with an empty list item: + +```````````````````````````````` example +* +. +
    +
  • +
+```````````````````````````````` + +However, an empty list item cannot interrupt a paragraph: + +```````````````````````````````` example +foo +* + +foo +1. +. +

foo +*

+

foo +1.

+```````````````````````````````` + + +4. **Indentation.** If a sequence of lines *Ls* constitutes a list item + according to rule #1, #2, or #3, then the result of indenting each line + of *Ls* by 1-3 spaces (the same for each line) also constitutes a + list item with the same contents and attributes. If a line is + empty, then it need not be indented. + +Indented one space: + +```````````````````````````````` example + 1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +Indented two spaces: + +```````````````````````````````` example + 1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +Indented three spaces: + +```````````````````````````````` example + 1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +Four spaces indent gives a code block: + +```````````````````````````````` example + 1. A paragraph + with two lines. + + indented code + + > A block quote. +. +
1.  A paragraph
+    with two lines.
+
+        indented code
+
+    > A block quote.
+
+```````````````````````````````` + + + +5. **Laziness.** If a string of lines *Ls* constitute a [list + item](#list-items) with contents *Bs*, then the result of deleting + some or all of the indentation from one or more lines in which the + next [non-whitespace character] after the indentation is + [paragraph continuation text] is a + list item with the same contents and attributes. The unindented + lines are called + [lazy continuation line](@)s. + +Here is an example with [lazy continuation lines]: + +```````````````````````````````` example + 1. A paragraph +with two lines. + + indented code + + > A block quote. +. +
    +
  1. +

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +
  2. +
+```````````````````````````````` + + +Indentation can be partially deleted: + +```````````````````````````````` example + 1. A paragraph + with two lines. +. +
    +
  1. A paragraph +with two lines.
  2. +
+```````````````````````````````` + + +These examples show how laziness can work in nested structures: + +```````````````````````````````` example +> 1. > Blockquote +continued here. +. +
+
    +
  1. +
    +

    Blockquote +continued here.

    +
    +
  2. +
+
+```````````````````````````````` + + +```````````````````````````````` example +> 1. > Blockquote +> continued here. +. +
+
    +
  1. +
    +

    Blockquote +continued here.

    +
    +
  2. +
+
+```````````````````````````````` + + + +6. **That's all.** Nothing that is not counted as a list item by rules + #1--5 counts as a [list item](#list-items). + +The rules for sublists follow from the general rules above. A sublist +must be indented the same number of spaces a paragraph would need to be +in order to be included in the list item. + +So, in this case we need two spaces indent: + +```````````````````````````````` example +- foo + - bar + - baz + - boo +. +
    +
  • foo +
      +
    • bar +
        +
      • baz +
          +
        • boo
        • +
        +
      • +
      +
    • +
    +
  • +
+```````````````````````````````` + + +One is not enough: + +```````````````````````````````` example +- foo + - bar + - baz + - boo +. +
    +
  • foo
  • +
  • bar
  • +
  • baz
  • +
  • boo
  • +
+```````````````````````````````` + + +Here we need four, because the list marker is wider: + +```````````````````````````````` example +10) foo + - bar +. +
    +
  1. foo +
      +
    • bar
    • +
    +
  2. +
+```````````````````````````````` + + +Three is not enough: + +```````````````````````````````` example +10) foo + - bar +. +
    +
  1. foo
  2. +
+
    +
  • bar
  • +
+```````````````````````````````` + + +A list may be the first block in a list item: + +```````````````````````````````` example +- - foo +. +
    +
  • +
      +
    • foo
    • +
    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +1. - 2. foo +. +
    +
  1. +
      +
    • +
        +
      1. foo
      2. +
      +
    • +
    +
  2. +
+```````````````````````````````` + + +A list item can contain a heading: + +```````````````````````````````` example +- # Foo +- Bar + --- + baz +. +
    +
  • +

    Foo

    +
  • +
  • +

    Bar

    +baz
  • +
+```````````````````````````````` + + +### Motivation + +John Gruber's Markdown spec says the following about list items: + +1. "List markers typically start at the left margin, but may be indented + by up to three spaces. List markers must be followed by one or more + spaces or a tab." + +2. "To make lists look nice, you can wrap items with hanging indents.... + But if you don't want to, you don't have to." + +3. "List items may consist of multiple paragraphs. Each subsequent + paragraph in a list item must be indented by either 4 spaces or one + tab." + +4. "It looks nice if you indent every line of the subsequent paragraphs, + but here again, Markdown will allow you to be lazy." + +5. "To put a blockquote within a list item, the blockquote's `>` + delimiters need to be indented." + +6. "To put a code block within a list item, the code block needs to be + indented twice — 8 spaces or two tabs." + +These rules specify that a paragraph under a list item must be indented +four spaces (presumably, from the left margin, rather than the start of +the list marker, but this is not said), and that code under a list item +must be indented eight spaces instead of the usual four. They also say +that a block quote must be indented, but not by how much; however, the +example given has four spaces indentation. Although nothing is said +about other kinds of block-level content, it is certainly reasonable to +infer that *all* block elements under a list item, including other +lists, must be indented four spaces. This principle has been called the +*four-space rule*. + +The four-space rule is clear and principled, and if the reference +implementation `Markdown.pl` had followed it, it probably would have +become the standard. However, `Markdown.pl` allowed paragraphs and +sublists to start with only two spaces indentation, at least on the +outer level. Worse, its behavior was inconsistent: a sublist of an +outer-level list needed two spaces indentation, but a sublist of this +sublist needed three spaces. It is not surprising, then, that different +implementations of Markdown have developed very different rules for +determining what comes under a list item. (Pandoc and python-Markdown, +for example, stuck with Gruber's syntax description and the four-space +rule, while discount, redcarpet, marked, PHP Markdown, and others +followed `Markdown.pl`'s behavior more closely.) + +Unfortunately, given the divergences between implementations, there +is no way to give a spec for list items that will be guaranteed not +to break any existing documents. However, the spec given here should +correctly handle lists formatted with either the four-space rule or +the more forgiving `Markdown.pl` behavior, provided they are laid out +in a way that is natural for a human to read. + +The strategy here is to let the width and indentation of the list marker +determine the indentation necessary for blocks to fall under the list +item, rather than having a fixed and arbitrary number. The writer can +think of the body of the list item as a unit which gets indented to the +right enough to fit the list marker (and any indentation on the list +marker). (The laziness rule, #5, then allows continuation lines to be +unindented if needed.) + +This rule is superior, we claim, to any rule requiring a fixed level of +indentation from the margin. The four-space rule is clear but +unnatural. It is quite unintuitive that + +``` markdown +- foo + + bar + + - baz +``` + +should be parsed as two lists with an intervening paragraph, + +``` html +
    +
  • foo
  • +
+

bar

+
    +
  • baz
  • +
+``` + +as the four-space rule demands, rather than a single list, + +``` html +
    +
  • +

    foo

    +

    bar

    +
      +
    • baz
    • +
    +
  • +
+``` + +The choice of four spaces is arbitrary. It can be learned, but it is +not likely to be guessed, and it trips up beginners regularly. + +Would it help to adopt a two-space rule? The problem is that such +a rule, together with the rule allowing 1--3 spaces indentation of the +initial list marker, allows text that is indented *less than* the +original list marker to be included in the list item. For example, +`Markdown.pl` parses + +``` markdown + - one + + two +``` + +as a single list item, with `two` a continuation paragraph: + +``` html +
    +
  • +

    one

    +

    two

    +
  • +
+``` + +and similarly + +``` markdown +> - one +> +> two +``` + +as + +``` html +
+
    +
  • +

    one

    +

    two

    +
  • +
+
+``` + +This is extremely unintuitive. + +Rather than requiring a fixed indent from the margin, we could require +a fixed indent (say, two spaces, or even one space) from the list marker (which +may itself be indented). This proposal would remove the last anomaly +discussed. Unlike the spec presented above, it would count the following +as a list item with a subparagraph, even though the paragraph `bar` +is not indented as far as the first paragraph `foo`: + +``` markdown + 10. foo + + bar +``` + +Arguably this text does read like a list item with `bar` as a subparagraph, +which may count in favor of the proposal. However, on this proposal indented +code would have to be indented six spaces after the list marker. And this +would break a lot of existing Markdown, which has the pattern: + +``` markdown +1. foo + + indented code +``` + +where the code is indented eight spaces. The spec above, by contrast, will +parse this text as expected, since the code block's indentation is measured +from the beginning of `foo`. + +The one case that needs special treatment is a list item that *starts* +with indented code. How much indentation is required in that case, since +we don't have a "first paragraph" to measure from? Rule #2 simply stipulates +that in such cases, we require one space indentation from the list marker +(and then the normal four spaces for the indented code). This will match the +four-space rule in cases where the list marker plus its initial indentation +takes four spaces (a common case), but diverge in other cases. + +## Lists + +A [list](@) is a sequence of one or more +list items [of the same type]. The list items +may be separated by any number of blank lines. + +Two list items are [of the same type](@) +if they begin with a [list marker] of the same type. +Two list markers are of the +same type if (a) they are bullet list markers using the same character +(`-`, `+`, or `*`) or (b) they are ordered list numbers with the same +delimiter (either `.` or `)`). + +A list is an [ordered list](@) +if its constituent list items begin with +[ordered list markers], and a +[bullet list](@) if its constituent list +items begin with [bullet list markers]. + +The [start number](@) +of an [ordered list] is determined by the list number of +its initial list item. The numbers of subsequent list items are +disregarded. + +A list is [loose](@) if any of its constituent +list items are separated by blank lines, or if any of its constituent +list items directly contain two block-level elements with a blank line +between them. Otherwise a list is [tight](@). +(The difference in HTML output is that paragraphs in a loose list are +wrapped in `

` tags, while paragraphs in a tight list are not.) + +Changing the bullet or ordered list delimiter starts a new list: + +```````````````````````````````` example +- foo +- bar ++ baz +. +

    +
  • foo
  • +
  • bar
  • +
+
    +
  • baz
  • +
+```````````````````````````````` + + +```````````````````````````````` example +1. foo +2. bar +3) baz +. +
    +
  1. foo
  2. +
  3. bar
  4. +
+
    +
  1. baz
  2. +
+```````````````````````````````` + + +In CommonMark, a list can interrupt a paragraph. That is, +no blank line is needed to separate a paragraph from a following +list: + +```````````````````````````````` example +Foo +- bar +- baz +. +

Foo

+
    +
  • bar
  • +
  • baz
  • +
+```````````````````````````````` + +`Markdown.pl` does not allow this, through fear of triggering a list +via a numeral in a hard-wrapped line: + +``` markdown +The number of windows in my house is +14. The number of doors is 6. +``` + +Oddly, though, `Markdown.pl` *does* allow a blockquote to +interrupt a paragraph, even though the same considerations might +apply. + +In CommonMark, we do allow lists to interrupt paragraphs, for +two reasons. First, it is natural and not uncommon for people +to start lists without blank lines: + +``` markdown +I need to buy +- new shoes +- a coat +- a plane ticket +``` + +Second, we are attracted to a + +> [principle of uniformity](@): +> if a chunk of text has a certain +> meaning, it will continue to have the same meaning when put into a +> container block (such as a list item or blockquote). + +(Indeed, the spec for [list items] and [block quotes] presupposes +this principle.) This principle implies that if + +``` markdown + * I need to buy + - new shoes + - a coat + - a plane ticket +``` + +is a list item containing a paragraph followed by a nested sublist, +as all Markdown implementations agree it is (though the paragraph +may be rendered without `

` tags, since the list is "tight"), +then + +``` markdown +I need to buy +- new shoes +- a coat +- a plane ticket +``` + +by itself should be a paragraph followed by a nested sublist. + +Since it is well established Markdown practice to allow lists to +interrupt paragraphs inside list items, the [principle of +uniformity] requires us to allow this outside list items as +well. ([reStructuredText](http://docutils.sourceforge.net/rst.html) +takes a different approach, requiring blank lines before lists +even inside other list items.) + +In order to solve of unwanted lists in paragraphs with +hard-wrapped numerals, we allow only lists starting with `1` to +interrupt paragraphs. Thus, + +```````````````````````````````` example +The number of windows in my house is +14. The number of doors is 6. +. +

The number of windows in my house is +14. The number of doors is 6.

+```````````````````````````````` + +We may still get an unintended result in cases like + +```````````````````````````````` example +The number of windows in my house is +1. The number of doors is 6. +. +

The number of windows in my house is

+
    +
  1. The number of doors is 6.
  2. +
+```````````````````````````````` + +but this rule should prevent most spurious list captures. + +There can be any number of blank lines between items: + +```````````````````````````````` example +- foo + +- bar + + +- baz +. +
    +
  • +

    foo

    +
  • +
  • +

    bar

    +
  • +
  • +

    baz

    +
  • +
+```````````````````````````````` + +```````````````````````````````` example +- foo + - bar + - baz + + + bim +. +
    +
  • foo +
      +
    • bar +
        +
      • +

        baz

        +

        bim

        +
      • +
      +
    • +
    +
  • +
+```````````````````````````````` + + +To separate consecutive lists of the same type, or to separate a +list from an indented code block that would otherwise be parsed +as a subparagraph of the final list item, you can insert a blank HTML +comment: + +```````````````````````````````` example +- foo +- bar + + + +- baz +- bim +. +
    +
  • foo
  • +
  • bar
  • +
+ +
    +
  • baz
  • +
  • bim
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- foo + + notcode + +- foo + + + + code +. +
    +
  • +

    foo

    +

    notcode

    +
  • +
  • +

    foo

    +
  • +
+ +
code
+
+```````````````````````````````` + + +List items need not be indented to the same level. The following +list items will be treated as items at the same list level, +since none is indented enough to belong to the previous list +item: + +```````````````````````````````` example +- a + - b + - c + - d + - e + - f + - g + - h +- i +. +
    +
  • a
  • +
  • b
  • +
  • c
  • +
  • d
  • +
  • e
  • +
  • f
  • +
  • g
  • +
  • h
  • +
  • i
  • +
+```````````````````````````````` + + +```````````````````````````````` example +1. a + + 2. b + + 3. c +. +
    +
  1. +

    a

    +
  2. +
  3. +

    b

    +
  4. +
  5. +

    c

    +
  6. +
+```````````````````````````````` + + +This is a loose list, because there is a blank line between +two of the list items: + +```````````````````````````````` example +- a +- b + +- c +. +
    +
  • +

    a

    +
  • +
  • +

    b

    +
  • +
  • +

    c

    +
  • +
+```````````````````````````````` + + +So is this, with a empty second item: + +```````````````````````````````` example +* a +* + +* c +. +
    +
  • +

    a

    +
  • +
  • +
  • +

    c

    +
  • +
+```````````````````````````````` + + +These are loose lists, even though there is no space between the items, +because one of the items directly contains two block-level elements +with a blank line between them: + +```````````````````````````````` example +- a +- b + + c +- d +. +
    +
  • +

    a

    +
  • +
  • +

    b

    +

    c

    +
  • +
  • +

    d

    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- a +- b + + [ref]: /url +- d +. +
    +
  • +

    a

    +
  • +
  • +

    b

    +
  • +
  • +

    d

    +
  • +
+```````````````````````````````` + + +This is a tight list, because the blank lines are in a code block: + +```````````````````````````````` example +- a +- ``` + b + + + ``` +- c +. +
    +
  • a
  • +
  • +
    b
    +
    +
    +
    +
  • +
  • c
  • +
+```````````````````````````````` + + +This is a tight list, because the blank line is between two +paragraphs of a sublist. So the sublist is loose while +the outer list is tight: + +```````````````````````````````` example +- a + - b + + c +- d +. +
    +
  • a +
      +
    • +

      b

      +

      c

      +
    • +
    +
  • +
  • d
  • +
+```````````````````````````````` + + +This is a tight list, because the blank line is inside the +block quote: + +```````````````````````````````` example +* a + > b + > +* c +. +
    +
  • a +
    +

    b

    +
    +
  • +
  • c
  • +
+```````````````````````````````` + + +This list is tight, because the consecutive block elements +are not separated by blank lines: + +```````````````````````````````` example +- a + > b + ``` + c + ``` +- d +. +
    +
  • a +
    +

    b

    +
    +
    c
    +
    +
  • +
  • d
  • +
+```````````````````````````````` + + +A single-paragraph list is tight: + +```````````````````````````````` example +- a +. +
    +
  • a
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- a + - b +. +
    +
  • a +
      +
    • b
    • +
    +
  • +
+```````````````````````````````` + + +This list is loose, because of the blank line between the +two block elements in the list item: + +```````````````````````````````` example +1. ``` + foo + ``` + + bar +. +
    +
  1. +
    foo
    +
    +

    bar

    +
  2. +
+```````````````````````````````` + + +Here the outer list is loose, the inner list tight: + +```````````````````````````````` example +* foo + * bar + + baz +. +
    +
  • +

    foo

    +
      +
    • bar
    • +
    +

    baz

    +
  • +
+```````````````````````````````` + + +```````````````````````````````` example +- a + - b + - c + +- d + - e + - f +. +
    +
  • +

    a

    +
      +
    • b
    • +
    • c
    • +
    +
  • +
  • +

    d

    +
      +
    • e
    • +
    • f
    • +
    +
  • +
+```````````````````````````````` + + +# Inlines + +Inlines are parsed sequentially from the beginning of the character +stream to the end (left to right, in left-to-right languages). +Thus, for example, in + +```````````````````````````````` example +`hi`lo` +. +

hilo`

+```````````````````````````````` + + +`hi` is parsed as code, leaving the backtick at the end as a literal +backtick. + +## Backslash escapes + +Any ASCII punctuation character may be backslash-escaped: + +```````````````````````````````` example +\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ +. +

!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

+```````````````````````````````` + + +Backslashes before other characters are treated as literal +backslashes: + +```````````````````````````````` example +\→\A\a\ \3\φ\« +. +

\→\A\a\ \3\φ\«

+```````````````````````````````` + + +Escaped characters are treated as regular characters and do +not have their usual Markdown meanings: + +```````````````````````````````` example +\*not emphasized* +\
not a tag +\[not a link](/foo) +\`not code` +1\. not a list +\* not a list +\# not a heading +\[foo]: /url "not a reference" +. +

*not emphasized* +<br/> not a tag +[not a link](/foo) +`not code` +1. not a list +* not a list +# not a heading +[foo]: /url "not a reference"

+```````````````````````````````` + + +If a backslash is itself escaped, the following character is not: + +```````````````````````````````` example +\\*emphasis* +. +

\emphasis

+```````````````````````````````` + + +A backslash at the end of the line is a [hard line break]: + +```````````````````````````````` example +foo\ +bar +. +

foo
+bar

+```````````````````````````````` + + +Backslash escapes do not work in code blocks, code spans, autolinks, or +raw HTML: + +```````````````````````````````` example +`` \[\` `` +. +

\[\`

+```````````````````````````````` + + +```````````````````````````````` example + \[\] +. +
\[\]
+
+```````````````````````````````` + + +```````````````````````````````` example +~~~ +\[\] +~~~ +. +
\[\]
+
+```````````````````````````````` + + +```````````````````````````````` example + +. +

http://example.com?find=\*

+```````````````````````````````` + + +```````````````````````````````` example + +. + +```````````````````````````````` + + +But they work in all other contexts, including URLs and link titles, +link references, and [info strings] in [fenced code blocks]: + +```````````````````````````````` example +[foo](/bar\* "ti\*tle") +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[foo] + +[foo]: /bar\* "ti\*tle" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +``` foo\+bar +foo +``` +. +
foo
+
+```````````````````````````````` + + + +## Entity and numeric character references + +All valid HTML entity references and numeric character +references, except those occuring in code blocks and code spans, +are recognized as such and treated as equivalent to the +corresponding Unicode characters. Conforming CommonMark parsers +need not store information about whether a particular character +was represented in the source using a Unicode character or +an entity reference. + +[Entity references](@) consist of `&` + any of the valid +HTML5 entity names + `;`. The +document +is used as an authoritative source for the valid entity +references and their corresponding code points. + +```````````````````````````````` example +  & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸ +. +

  & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸

+```````````````````````````````` + + +[Decimal numeric character +references](@) +consist of `&#` + a string of 1--8 arabic digits + `;`. A +numeric character reference is parsed as the corresponding +Unicode character. Invalid Unicode code points will be replaced by +the REPLACEMENT CHARACTER (`U+FFFD`). For security reasons, +the code point `U+0000` will also be replaced by `U+FFFD`. + +```````````````````````````````` example +# Ӓ Ϡ � � +. +

# Ӓ Ϡ � �

+```````````````````````````````` + + +[Hexadecimal numeric character +references](@) consist of `&#` + +either `X` or `x` + a string of 1-8 hexadecimal digits + `;`. +They too are parsed as the corresponding Unicode character (this +time specified with a hexadecimal numeral instead of decimal). + +```````````````````````````````` example +" ആ ಫ +. +

" ആ ಫ

+```````````````````````````````` + + +Here are some nonentities: + +```````````````````````````````` example +  &x; &#; &#x; +&ThisIsNotDefined; &hi?; +. +

&nbsp &x; &#; &#x; +&ThisIsNotDefined; &hi?;

+```````````````````````````````` + + +Although HTML5 does accept some entity references +without a trailing semicolon (such as `©`), these are not +recognized here, because it makes the grammar too ambiguous: + +```````````````````````````````` example +© +. +

&copy

+```````````````````````````````` + + +Strings that are not on the list of HTML5 named entities are not +recognized as entity references either: + +```````````````````````````````` example +&MadeUpEntity; +. +

&MadeUpEntity;

+```````````````````````````````` + + +Entity and numeric character references are recognized in any +context besides code spans or code blocks, including +URLs, [link titles], and [fenced code block][] [info strings]: + +```````````````````````````````` example + +. + +```````````````````````````````` + + +```````````````````````````````` example +[foo](/föö "föö") +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[foo] + +[foo]: /föö "föö" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +``` föö +foo +``` +. +
foo
+
+```````````````````````````````` + + +Entity and numeric character references are treated as literal +text in code spans and code blocks: + +```````````````````````````````` example +`föö` +. +

f&ouml;&ouml;

+```````````````````````````````` + + +```````````````````````````````` example + föfö +. +
f&ouml;f&ouml;
+
+```````````````````````````````` + + +## Code spans + +A [backtick string](@) +is a string of one or more backtick characters (`` ` ``) that is neither +preceded nor followed by a backtick. + +A [code span](@) begins with a backtick string and ends with +a backtick string of equal length. The contents of the code span are +the characters between the two backtick strings, with leading and +trailing spaces and [line endings] removed, and +[whitespace] collapsed to single spaces. + +This is a simple code span: + +```````````````````````````````` example +`foo` +. +

foo

+```````````````````````````````` + + +Here two backticks are used, because the code contains a backtick. +This example also illustrates stripping of leading and trailing spaces: + +```````````````````````````````` example +`` foo ` bar `` +. +

foo ` bar

+```````````````````````````````` + + +This example shows the motivation for stripping leading and trailing +spaces: + +```````````````````````````````` example +` `` ` +. +

``

+```````````````````````````````` + + +[Line endings] are treated like spaces: + +```````````````````````````````` example +`` +foo +`` +. +

foo

+```````````````````````````````` + + +Interior spaces and [line endings] are collapsed into +single spaces, just as they would be by a browser: + +```````````````````````````````` example +`foo bar + baz` +. +

foo bar baz

+```````````````````````````````` + + +Not all [Unicode whitespace] (for instance, non-breaking space) is +collapsed, however: + +```````````````````````````````` example +`a  b` +. +

a  b

+```````````````````````````````` + + +Q: Why not just leave the spaces, since browsers will collapse them +anyway? A: Because we might be targeting a non-HTML format, and we +shouldn't rely on HTML-specific rendering assumptions. + +(Existing implementations differ in their treatment of internal +spaces and [line endings]. Some, including `Markdown.pl` and +`showdown`, convert an internal [line ending] into a +`
` tag. But this makes things difficult for those who like to +hard-wrap their paragraphs, since a line break in the midst of a code +span will cause an unintended line break in the output. Others just +leave internal spaces as they are, which is fine if only HTML is being +targeted.) + +```````````````````````````````` example +`foo `` bar` +. +

foo `` bar

+```````````````````````````````` + + +Note that backslash escapes do not work in code spans. All backslashes +are treated literally: + +```````````````````````````````` example +`foo\`bar` +. +

foo\bar`

+```````````````````````````````` + + +Backslash escapes are never needed, because one can always choose a +string of *n* backtick characters as delimiters, where the code does +not contain any strings of exactly *n* backtick characters. + +Code span backticks have higher precedence than any other inline +constructs except HTML tags and autolinks. Thus, for example, this is +not parsed as emphasized text, since the second `*` is part of a code +span: + +```````````````````````````````` example +*foo`*` +. +

*foo*

+```````````````````````````````` + + +And this is not parsed as a link: + +```````````````````````````````` example +[not a `link](/foo`) +. +

[not a link](/foo)

+```````````````````````````````` + + +Code spans, HTML tags, and autolinks have the same precedence. +Thus, this is code: + +```````````````````````````````` example +`` +. +

<a href="">`

+```````````````````````````````` + + +But this is an HTML tag: + +```````````````````````````````` example +
` +. +

`

+```````````````````````````````` + + +And this is code: + +```````````````````````````````` example +`` +. +

<http://foo.bar.baz>`

+```````````````````````````````` + + +But this is an autolink: + +```````````````````````````````` example +` +. +

http://foo.bar.`baz`

+```````````````````````````````` + + +When a backtick string is not closed by a matching backtick string, +we just have literal backticks: + +```````````````````````````````` example +```foo`` +. +

```foo``

+```````````````````````````````` + + +```````````````````````````````` example +`foo +. +

`foo

+```````````````````````````````` + +The following case also illustrates the need for opening and +closing backtick strings to be equal in length: + +```````````````````````````````` example +`foo``bar`` +. +

`foobar

+```````````````````````````````` + + +## Emphasis and strong emphasis + +John Gruber's original [Markdown syntax +description](http://daringfireball.net/projects/markdown/syntax#em) says: + +> Markdown treats asterisks (`*`) and underscores (`_`) as indicators of +> emphasis. Text wrapped with one `*` or `_` will be wrapped with an HTML +> `` tag; double `*`'s or `_`'s will be wrapped with an HTML `` +> tag. + +This is enough for most users, but these rules leave much undecided, +especially when it comes to nested emphasis. The original +`Markdown.pl` test suite makes it clear that triple `***` and +`___` delimiters can be used for strong emphasis, and most +implementations have also allowed the following patterns: + +``` markdown +***strong emph*** +***strong** in emph* +***emph* in strong** +**in strong *emph*** +*in emph **strong*** +``` + +The following patterns are less widely supported, but the intent +is clear and they are useful (especially in contexts like bibliography +entries): + +``` markdown +*emph *with emph* in it* +**strong **with strong** in it** +``` + +Many implementations have also restricted intraword emphasis to +the `*` forms, to avoid unwanted emphasis in words containing +internal underscores. (It is best practice to put these in code +spans, but users often do not.) + +``` markdown +internal emphasis: foo*bar*baz +no emphasis: foo_bar_baz +``` + +The rules given below capture all of these patterns, while allowing +for efficient parsing strategies that do not backtrack. + +First, some definitions. A [delimiter run](@) is either +a sequence of one or more `*` characters that is not preceded or +followed by a non-backslash-escaped `*` character, or a sequence +of one or more `_` characters that is not preceded or followed by +a non-backslash-escaped `_` character. + +A [left-flanking delimiter run](@) is +a [delimiter run] that is (a) not followed by [Unicode whitespace], +and (b) not followed by a [punctuation character], or +preceded by [Unicode whitespace] or a [punctuation character]. +For purposes of this definition, the beginning and the end of +the line count as Unicode whitespace. + +A [right-flanking delimiter run](@) is +a [delimiter run] that is (a) not preceded by [Unicode whitespace], +and (b) not preceded by a [punctuation character], or +followed by [Unicode whitespace] or a [punctuation character]. +For purposes of this definition, the beginning and the end of +the line count as Unicode whitespace. + +Here are some examples of delimiter runs. + + - left-flanking but not right-flanking: + + ``` + ***abc + _abc + **"abc" + _"abc" + ``` + + - right-flanking but not left-flanking: + + ``` + abc*** + abc_ + "abc"** + "abc"_ + ``` + + - Both left and right-flanking: + + ``` + abc***def + "abc"_"def" + ``` + + - Neither left nor right-flanking: + + ``` + abc *** def + a _ b + ``` + +(The idea of distinguishing left-flanking and right-flanking +delimiter runs based on the character before and the character +after comes from Roopesh Chander's +[vfmd](http://www.vfmd.org/vfmd-spec/specification/#procedure-for-identifying-emphasis-tags). +vfmd uses the terminology "emphasis indicator string" instead of "delimiter +run," and its rules for distinguishing left- and right-flanking runs +are a bit more complex than the ones given here.) + +The following rules define emphasis and strong emphasis: + +1. A single `*` character [can open emphasis](@) + iff (if and only if) it is part of a [left-flanking delimiter run]. + +2. A single `_` character [can open emphasis] iff + it is part of a [left-flanking delimiter run] + and either (a) not part of a [right-flanking delimiter run] + or (b) part of a [right-flanking delimiter run] + preceded by punctuation. + +3. A single `*` character [can close emphasis](@) + iff it is part of a [right-flanking delimiter run]. + +4. A single `_` character [can close emphasis] iff + it is part of a [right-flanking delimiter run] + and either (a) not part of a [left-flanking delimiter run] + or (b) part of a [left-flanking delimiter run] + followed by punctuation. + +5. A double `**` [can open strong emphasis](@) + iff it is part of a [left-flanking delimiter run]. + +6. A double `__` [can open strong emphasis] iff + it is part of a [left-flanking delimiter run] + and either (a) not part of a [right-flanking delimiter run] + or (b) part of a [right-flanking delimiter run] + preceded by punctuation. + +7. A double `**` [can close strong emphasis](@) + iff it is part of a [right-flanking delimiter run]. + +8. A double `__` [can close strong emphasis] iff + it is part of a [right-flanking delimiter run] + and either (a) not part of a [left-flanking delimiter run] + or (b) part of a [left-flanking delimiter run] + followed by punctuation. + +9. Emphasis begins with a delimiter that [can open emphasis] and ends + with a delimiter that [can close emphasis], and that uses the same + character (`_` or `*`) as the opening delimiter. The + opening and closing delimiters must belong to separate + [delimiter runs]. If one of the delimiters can both + open and close emphasis, then the sum of the lengths of the + delimiter runs containing the opening and closing delimiters + must not be a multiple of 3. + +10. Strong emphasis begins with a delimiter that + [can open strong emphasis] and ends with a delimiter that + [can close strong emphasis], and that uses the same character + (`_` or `*`) as the opening delimiter. The + opening and closing delimiters must belong to separate + [delimiter runs]. If one of the delimiters can both open + and close strong emphasis, then the sum of the lengths of + the delimiter runs containing the opening and closing + delimiters must not be a multiple of 3. + +11. A literal `*` character cannot occur at the beginning or end of + `*`-delimited emphasis or `**`-delimited strong emphasis, unless it + is backslash-escaped. + +12. A literal `_` character cannot occur at the beginning or end of + `_`-delimited emphasis or `__`-delimited strong emphasis, unless it + is backslash-escaped. + +Where rules 1--12 above are compatible with multiple parsings, +the following principles resolve ambiguity: + +13. The number of nestings should be minimized. Thus, for example, + an interpretation `...` is always preferred to + `...`. + +14. An interpretation `...` is always + preferred to `...`. + +15. When two potential emphasis or strong emphasis spans overlap, + so that the second begins before the first ends and ends after + the first ends, the first takes precedence. Thus, for example, + `*foo _bar* baz_` is parsed as `foo _bar baz_` rather + than `*foo bar* baz`. + +16. When there are two potential emphasis or strong emphasis spans + with the same closing delimiter, the shorter one (the one that + opens later) takes precedence. Thus, for example, + `**foo **bar baz**` is parsed as `**foo bar baz` + rather than `foo **bar baz`. + +17. Inline code spans, links, images, and HTML tags group more tightly + than emphasis. So, when there is a choice between an interpretation + that contains one of these elements and one that does not, the + former always wins. Thus, for example, `*[foo*](bar)` is + parsed as `*foo*` rather than as + `[foo](bar)`. + +These rules can be illustrated through a series of examples. + +Rule 1: + +```````````````````````````````` example +*foo bar* +. +

foo bar

+```````````````````````````````` + + +This is not emphasis, because the opening `*` is followed by +whitespace, and hence not part of a [left-flanking delimiter run]: + +```````````````````````````````` example +a * foo bar* +. +

a * foo bar*

+```````````````````````````````` + + +This is not emphasis, because the opening `*` is preceded +by an alphanumeric and followed by punctuation, and hence +not part of a [left-flanking delimiter run]: + +```````````````````````````````` example +a*"foo"* +. +

a*"foo"*

+```````````````````````````````` + + +Unicode nonbreaking spaces count as whitespace, too: + +```````````````````````````````` example +* a * +. +

* a *

+```````````````````````````````` + + +Intraword emphasis with `*` is permitted: + +```````````````````````````````` example +foo*bar* +. +

foobar

+```````````````````````````````` + + +```````````````````````````````` example +5*6*78 +. +

5678

+```````````````````````````````` + + +Rule 2: + +```````````````````````````````` example +_foo bar_ +. +

foo bar

+```````````````````````````````` + + +This is not emphasis, because the opening `_` is followed by +whitespace: + +```````````````````````````````` example +_ foo bar_ +. +

_ foo bar_

+```````````````````````````````` + + +This is not emphasis, because the opening `_` is preceded +by an alphanumeric and followed by punctuation: + +```````````````````````````````` example +a_"foo"_ +. +

a_"foo"_

+```````````````````````````````` + + +Emphasis with `_` is not allowed inside words: + +```````````````````````````````` example +foo_bar_ +. +

foo_bar_

+```````````````````````````````` + + +```````````````````````````````` example +5_6_78 +. +

5_6_78

+```````````````````````````````` + + +```````````````````````````````` example +пристаням_стремятся_ +. +

пристаням_стремятся_

+```````````````````````````````` + + +Here `_` does not generate emphasis, because the first delimiter run +is right-flanking and the second left-flanking: + +```````````````````````````````` example +aa_"bb"_cc +. +

aa_"bb"_cc

+```````````````````````````````` + + +This is emphasis, even though the opening delimiter is +both left- and right-flanking, because it is preceded by +punctuation: + +```````````````````````````````` example +foo-_(bar)_ +. +

foo-(bar)

+```````````````````````````````` + + +Rule 3: + +This is not emphasis, because the closing delimiter does +not match the opening delimiter: + +```````````````````````````````` example +_foo* +. +

_foo*

+```````````````````````````````` + + +This is not emphasis, because the closing `*` is preceded by +whitespace: + +```````````````````````````````` example +*foo bar * +. +

*foo bar *

+```````````````````````````````` + + +A newline also counts as whitespace: + +```````````````````````````````` example +*foo bar +* +. +

*foo bar +*

+```````````````````````````````` + + +This is not emphasis, because the second `*` is +preceded by punctuation and followed by an alphanumeric +(hence it is not part of a [right-flanking delimiter run]: + +```````````````````````````````` example +*(*foo) +. +

*(*foo)

+```````````````````````````````` + + +The point of this restriction is more easily appreciated +with this example: + +```````````````````````````````` example +*(*foo*)* +. +

(foo)

+```````````````````````````````` + + +Intraword emphasis with `*` is allowed: + +```````````````````````````````` example +*foo*bar +. +

foobar

+```````````````````````````````` + + + +Rule 4: + +This is not emphasis, because the closing `_` is preceded by +whitespace: + +```````````````````````````````` example +_foo bar _ +. +

_foo bar _

+```````````````````````````````` + + +This is not emphasis, because the second `_` is +preceded by punctuation and followed by an alphanumeric: + +```````````````````````````````` example +_(_foo) +. +

_(_foo)

+```````````````````````````````` + + +This is emphasis within emphasis: + +```````````````````````````````` example +_(_foo_)_ +. +

(foo)

+```````````````````````````````` + + +Intraword emphasis is disallowed for `_`: + +```````````````````````````````` example +_foo_bar +. +

_foo_bar

+```````````````````````````````` + + +```````````````````````````````` example +_пристаням_стремятся +. +

_пристаням_стремятся

+```````````````````````````````` + + +```````````````````````````````` example +_foo_bar_baz_ +. +

foo_bar_baz

+```````````````````````````````` + + +This is emphasis, even though the closing delimiter is +both left- and right-flanking, because it is followed by +punctuation: + +```````````````````````````````` example +_(bar)_. +. +

(bar).

+```````````````````````````````` + + +Rule 5: + +```````````````````````````````` example +**foo bar** +. +

foo bar

+```````````````````````````````` + + +This is not strong emphasis, because the opening delimiter is +followed by whitespace: + +```````````````````````````````` example +** foo bar** +. +

** foo bar**

+```````````````````````````````` + + +This is not strong emphasis, because the opening `**` is preceded +by an alphanumeric and followed by punctuation, and hence +not part of a [left-flanking delimiter run]: + +```````````````````````````````` example +a**"foo"** +. +

a**"foo"**

+```````````````````````````````` + + +Intraword strong emphasis with `**` is permitted: + +```````````````````````````````` example +foo**bar** +. +

foobar

+```````````````````````````````` + + +Rule 6: + +```````````````````````````````` example +__foo bar__ +. +

foo bar

+```````````````````````````````` + + +This is not strong emphasis, because the opening delimiter is +followed by whitespace: + +```````````````````````````````` example +__ foo bar__ +. +

__ foo bar__

+```````````````````````````````` + + +A newline counts as whitespace: +```````````````````````````````` example +__ +foo bar__ +. +

__ +foo bar__

+```````````````````````````````` + + +This is not strong emphasis, because the opening `__` is preceded +by an alphanumeric and followed by punctuation: + +```````````````````````````````` example +a__"foo"__ +. +

a__"foo"__

+```````````````````````````````` + + +Intraword strong emphasis is forbidden with `__`: + +```````````````````````````````` example +foo__bar__ +. +

foo__bar__

+```````````````````````````````` + + +```````````````````````````````` example +5__6__78 +. +

5__6__78

+```````````````````````````````` + + +```````````````````````````````` example +пристаням__стремятся__ +. +

пристаням__стремятся__

+```````````````````````````````` + + +```````````````````````````````` example +__foo, __bar__, baz__ +. +

foo, bar, baz

+```````````````````````````````` + + +This is strong emphasis, even though the opening delimiter is +both left- and right-flanking, because it is preceded by +punctuation: + +```````````````````````````````` example +foo-__(bar)__ +. +

foo-(bar)

+```````````````````````````````` + + + +Rule 7: + +This is not strong emphasis, because the closing delimiter is preceded +by whitespace: + +```````````````````````````````` example +**foo bar ** +. +

**foo bar **

+```````````````````````````````` + + +(Nor can it be interpreted as an emphasized `*foo bar *`, because of +Rule 11.) + +This is not strong emphasis, because the second `**` is +preceded by punctuation and followed by an alphanumeric: + +```````````````````````````````` example +**(**foo) +. +

**(**foo)

+```````````````````````````````` + + +The point of this restriction is more easily appreciated +with these examples: + +```````````````````````````````` example +*(**foo**)* +. +

(foo)

+```````````````````````````````` + + +```````````````````````````````` example +**Gomphocarpus (*Gomphocarpus physocarpus*, syn. +*Asclepias physocarpa*)** +. +

Gomphocarpus (Gomphocarpus physocarpus, syn. +Asclepias physocarpa)

+```````````````````````````````` + + +```````````````````````````````` example +**foo "*bar*" foo** +. +

foo "bar" foo

+```````````````````````````````` + + +Intraword emphasis: + +```````````````````````````````` example +**foo**bar +. +

foobar

+```````````````````````````````` + + +Rule 8: + +This is not strong emphasis, because the closing delimiter is +preceded by whitespace: + +```````````````````````````````` example +__foo bar __ +. +

__foo bar __

+```````````````````````````````` + + +This is not strong emphasis, because the second `__` is +preceded by punctuation and followed by an alphanumeric: + +```````````````````````````````` example +__(__foo) +. +

__(__foo)

+```````````````````````````````` + + +The point of this restriction is more easily appreciated +with this example: + +```````````````````````````````` example +_(__foo__)_ +. +

(foo)

+```````````````````````````````` + + +Intraword strong emphasis is forbidden with `__`: + +```````````````````````````````` example +__foo__bar +. +

__foo__bar

+```````````````````````````````` + + +```````````````````````````````` example +__пристаням__стремятся +. +

__пристаням__стремятся

+```````````````````````````````` + + +```````````````````````````````` example +__foo__bar__baz__ +. +

foo__bar__baz

+```````````````````````````````` + + +This is strong emphasis, even though the closing delimiter is +both left- and right-flanking, because it is followed by +punctuation: + +```````````````````````````````` example +__(bar)__. +. +

(bar).

+```````````````````````````````` + + +Rule 9: + +Any nonempty sequence of inline elements can be the contents of an +emphasized span. + +```````````````````````````````` example +*foo [bar](/url)* +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo +bar* +. +

foo +bar

+```````````````````````````````` + + +In particular, emphasis and strong emphasis can be nested +inside emphasis: + +```````````````````````````````` example +_foo __bar__ baz_ +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +_foo _bar_ baz_ +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +__foo_ bar_ +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo *bar** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo **bar** baz* +. +

foo bar baz

+```````````````````````````````` + +```````````````````````````````` example +*foo**bar**baz* +. +

foobarbaz

+```````````````````````````````` + +Note that in the preceding case, the interpretation + +``` markdown +

foobarbaz

+``` + + +is precluded by the condition that a delimiter that +can both open and close (like the `*` after `foo`) +cannot form emphasis if the sum of the lengths of +the delimiter runs containing the opening and +closing delimiters is a multiple of 3. + +The same condition ensures that the following +cases are all strong emphasis nested inside +emphasis, even when the interior spaces are +omitted: + + +```````````````````````````````` example +***foo** bar* +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo **bar*** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo**bar*** +. +

foobar

+```````````````````````````````` + + +Indefinite levels of nesting are possible: + +```````````````````````````````` example +*foo **bar *baz* bim** bop* +. +

foo bar baz bim bop

+```````````````````````````````` + + +```````````````````````````````` example +*foo [*bar*](/url)* +. +

foo bar

+```````````````````````````````` + + +There can be no empty emphasis or strong emphasis: + +```````````````````````````````` example +** is not an empty emphasis +. +

** is not an empty emphasis

+```````````````````````````````` + + +```````````````````````````````` example +**** is not an empty strong emphasis +. +

**** is not an empty strong emphasis

+```````````````````````````````` + + + +Rule 10: + +Any nonempty sequence of inline elements can be the contents of an +strongly emphasized span. + +```````````````````````````````` example +**foo [bar](/url)** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +**foo +bar** +. +

foo +bar

+```````````````````````````````` + + +In particular, emphasis and strong emphasis can be nested +inside strong emphasis: + +```````````````````````````````` example +__foo _bar_ baz__ +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +__foo __bar__ baz__ +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +____foo__ bar__ +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +**foo **bar**** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +**foo *bar* baz** +. +

foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +**foo*bar*baz** +. +

foobarbaz

+```````````````````````````````` + + +```````````````````````````````` example +***foo* bar** +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +**foo *bar*** +. +

foo bar

+```````````````````````````````` + + +Indefinite levels of nesting are possible: + +```````````````````````````````` example +**foo *bar **baz** +bim* bop** +. +

foo bar baz +bim bop

+```````````````````````````````` + + +```````````````````````````````` example +**foo [*bar*](/url)** +. +

foo bar

+```````````````````````````````` + + +There can be no empty emphasis or strong emphasis: + +```````````````````````````````` example +__ is not an empty emphasis +. +

__ is not an empty emphasis

+```````````````````````````````` + + +```````````````````````````````` example +____ is not an empty strong emphasis +. +

____ is not an empty strong emphasis

+```````````````````````````````` + + + +Rule 11: + +```````````````````````````````` example +foo *** +. +

foo ***

+```````````````````````````````` + + +```````````````````````````````` example +foo *\** +. +

foo *

+```````````````````````````````` + + +```````````````````````````````` example +foo *_* +. +

foo _

+```````````````````````````````` + + +```````````````````````````````` example +foo ***** +. +

foo *****

+```````````````````````````````` + + +```````````````````````````````` example +foo **\*** +. +

foo *

+```````````````````````````````` + + +```````````````````````````````` example +foo **_** +. +

foo _

+```````````````````````````````` + + +Note that when delimiters do not match evenly, Rule 11 determines +that the excess literal `*` characters will appear outside of the +emphasis, rather than inside it: + +```````````````````````````````` example +**foo* +. +

*foo

+```````````````````````````````` + + +```````````````````````````````` example +*foo** +. +

foo*

+```````````````````````````````` + + +```````````````````````````````` example +***foo** +. +

*foo

+```````````````````````````````` + + +```````````````````````````````` example +****foo* +. +

***foo

+```````````````````````````````` + + +```````````````````````````````` example +**foo*** +. +

foo*

+```````````````````````````````` + + +```````````````````````````````` example +*foo**** +. +

foo***

+```````````````````````````````` + + + +Rule 12: + +```````````````````````````````` example +foo ___ +. +

foo ___

+```````````````````````````````` + + +```````````````````````````````` example +foo _\__ +. +

foo _

+```````````````````````````````` + + +```````````````````````````````` example +foo _*_ +. +

foo *

+```````````````````````````````` + + +```````````````````````````````` example +foo _____ +. +

foo _____

+```````````````````````````````` + + +```````````````````````````````` example +foo __\___ +. +

foo _

+```````````````````````````````` + + +```````````````````````````````` example +foo __*__ +. +

foo *

+```````````````````````````````` + + +```````````````````````````````` example +__foo_ +. +

_foo

+```````````````````````````````` + + +Note that when delimiters do not match evenly, Rule 12 determines +that the excess literal `_` characters will appear outside of the +emphasis, rather than inside it: + +```````````````````````````````` example +_foo__ +. +

foo_

+```````````````````````````````` + + +```````````````````````````````` example +___foo__ +. +

_foo

+```````````````````````````````` + + +```````````````````````````````` example +____foo_ +. +

___foo

+```````````````````````````````` + + +```````````````````````````````` example +__foo___ +. +

foo_

+```````````````````````````````` + + +```````````````````````````````` example +_foo____ +. +

foo___

+```````````````````````````````` + + +Rule 13 implies that if you want emphasis nested directly inside +emphasis, you must use different delimiters: + +```````````````````````````````` example +**foo** +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +*_foo_* +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +__foo__ +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +_*foo*_ +. +

foo

+```````````````````````````````` + + +However, strong emphasis within strong emphasis is possible without +switching delimiters: + +```````````````````````````````` example +****foo**** +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +____foo____ +. +

foo

+```````````````````````````````` + + + +Rule 13 can be applied to arbitrarily long sequences of +delimiters: + +```````````````````````````````` example +******foo****** +. +

foo

+```````````````````````````````` + + +Rule 14: + +```````````````````````````````` example +***foo*** +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +_____foo_____ +. +

foo

+```````````````````````````````` + + +Rule 15: + +```````````````````````````````` example +*foo _bar* baz_ +. +

foo _bar baz_

+```````````````````````````````` + + +```````````````````````````````` example +*foo __bar *baz bim__ bam* +. +

foo bar *baz bim bam

+```````````````````````````````` + + +Rule 16: + +```````````````````````````````` example +**foo **bar baz** +. +

**foo bar baz

+```````````````````````````````` + + +```````````````````````````````` example +*foo *bar baz* +. +

*foo bar baz

+```````````````````````````````` + + +Rule 17: + +```````````````````````````````` example +*[bar*](/url) +. +

*bar*

+```````````````````````````````` + + +```````````````````````````````` example +_foo [bar_](/url) +. +

_foo bar_

+```````````````````````````````` + + +```````````````````````````````` example +* +. +

*

+```````````````````````````````` + + +```````````````````````````````` example +** +. +

**

+```````````````````````````````` + + +```````````````````````````````` example +__ +. +

__

+```````````````````````````````` + + +```````````````````````````````` example +*a `*`* +. +

a *

+```````````````````````````````` + + +```````````````````````````````` example +_a `_`_ +. +

a _

+```````````````````````````````` + + +```````````````````````````````` example +**a +. +

**ahttp://foo.bar/?q=**

+```````````````````````````````` + + +```````````````````````````````` example +__a +. +

__ahttp://foo.bar/?q=__

+```````````````````````````````` + + + +## Links + +A link contains [link text] (the visible text), a [link destination] +(the URI that is the link destination), and optionally a [link title]. +There are two basic kinds of links in Markdown. In [inline links] the +destination and title are given immediately after the link text. In +[reference links] the destination and title are defined elsewhere in +the document. + +A [link text](@) consists of a sequence of zero or more +inline elements enclosed by square brackets (`[` and `]`). The +following rules apply: + +- Links may not contain other links, at any level of nesting. If + multiple otherwise valid link definitions appear nested inside each + other, the inner-most definition is used. + +- Brackets are allowed in the [link text] only if (a) they + are backslash-escaped or (b) they appear as a matched pair of brackets, + with an open bracket `[`, a sequence of zero or more inlines, and + a close bracket `]`. + +- Backtick [code spans], [autolinks], and raw [HTML tags] bind more tightly + than the brackets in link text. Thus, for example, + `` [foo`]` `` could not be a link text, since the second `]` + is part of a code span. + +- The brackets in link text bind more tightly than markers for + [emphasis and strong emphasis]. Thus, for example, `*[foo*](url)` is a link. + +A [link destination](@) consists of either + +- a sequence of zero or more characters between an opening `<` and a + closing `>` that contains no spaces, line breaks, or unescaped + `<` or `>` characters, or + +- a nonempty sequence of characters that does not include + ASCII space or control characters, and includes parentheses + only if (a) they are backslash-escaped or (b) they are part of + a balanced pair of unescaped parentheses. (Implementations + may impose limits on parentheses nesting to avoid performance + issues, but at least three levels of nesting should be supported.) + +A [link title](@) consists of either + +- a sequence of zero or more characters between straight double-quote + characters (`"`), including a `"` character only if it is + backslash-escaped, or + +- a sequence of zero or more characters between straight single-quote + characters (`'`), including a `'` character only if it is + backslash-escaped, or + +- a sequence of zero or more characters between matching parentheses + (`(...)`), including a `)` character only if it is backslash-escaped. + +Although [link titles] may span multiple lines, they may not contain +a [blank line]. + +An [inline link](@) consists of a [link text] followed immediately +by a left parenthesis `(`, optional [whitespace], an optional +[link destination], an optional [link title] separated from the link +destination by [whitespace], optional [whitespace], and a right +parenthesis `)`. The link's text consists of the inlines contained +in the [link text] (excluding the enclosing square brackets). +The link's URI consists of the link destination, excluding enclosing +`<...>` if present, with backslash-escapes in effect as described +above. The link's title consists of the link title, excluding its +enclosing delimiters, with backslash-escapes in effect as described +above. + +Here is a simple inline link: + +```````````````````````````````` example +[link](/uri "title") +. +

link

+```````````````````````````````` + + +The title may be omitted: + +```````````````````````````````` example +[link](/uri) +. +

link

+```````````````````````````````` + + +Both the title and the destination may be omitted: + +```````````````````````````````` example +[link]() +. +

link

+```````````````````````````````` + + +```````````````````````````````` example +[link](<>) +. +

link

+```````````````````````````````` + + +The destination cannot contain spaces or line breaks, +even if enclosed in pointy brackets: + +```````````````````````````````` example +[link](/my uri) +. +

[link](/my uri)

+```````````````````````````````` + + +```````````````````````````````` example +[link]() +. +

[link](</my uri>)

+```````````````````````````````` + + +```````````````````````````````` example +[link](foo +bar) +. +

[link](foo +bar)

+```````````````````````````````` + + +```````````````````````````````` example +[link]() +. +

[link]()

+```````````````````````````````` + +Parentheses inside the link destination may be escaped: + +```````````````````````````````` example +[link](\(foo\)) +. +

link

+```````````````````````````````` + +Any number of parentheses are allowed without escaping, as long as they are +balanced: + +```````````````````````````````` example +[link](foo(and(bar))) +. +

link

+```````````````````````````````` + +However, if you have unbalanced parentheses, you need to escape or use the +`<...>` form: + +```````````````````````````````` example +[link](foo\(and\(bar\)) +. +

link

+```````````````````````````````` + + +```````````````````````````````` example +[link]() +. +

link

+```````````````````````````````` + + +Parentheses and other symbols can also be escaped, as usual +in Markdown: + +```````````````````````````````` example +[link](foo\)\:) +. +

link

+```````````````````````````````` + + +A link can contain fragment identifiers and queries: + +```````````````````````````````` example +[link](#fragment) + +[link](http://example.com#fragment) + +[link](http://example.com?foo=3#frag) +. +

link

+

link

+

link

+```````````````````````````````` + + +Note that a backslash before a non-escapable character is +just a backslash: + +```````````````````````````````` example +[link](foo\bar) +. +

link

+```````````````````````````````` + + +URL-escaping should be left alone inside the destination, as all +URL-escaped characters are also valid URL characters. Entity and +numerical character references in the destination will be parsed +into the corresponding Unicode code points, as usual. These may +be optionally URL-escaped when written as HTML, but this spec +does not enforce any particular policy for rendering URLs in +HTML or other formats. Renderers may make different decisions +about how to escape or normalize URLs in the output. + +```````````````````````````````` example +[link](foo%20bä) +. +

link

+```````````````````````````````` + + +Note that, because titles can often be parsed as destinations, +if you try to omit the destination and keep the title, you'll +get unexpected results: + +```````````````````````````````` example +[link]("title") +. +

link

+```````````````````````````````` + + +Titles may be in single quotes, double quotes, or parentheses: + +```````````````````````````````` example +[link](/url "title") +[link](/url 'title') +[link](/url (title)) +. +

link +link +link

+```````````````````````````````` + + +Backslash escapes and entity and numeric character references +may be used in titles: + +```````````````````````````````` example +[link](/url "title \""") +. +

link

+```````````````````````````````` + + +Titles must be separated from the link using a [whitespace]. +Other [Unicode whitespace] like non-breaking space doesn't work. + +```````````````````````````````` example +[link](/url "title") +. +

link

+```````````````````````````````` + + +Nested balanced quotes are not allowed without escaping: + +```````````````````````````````` example +[link](/url "title "and" title") +. +

[link](/url "title "and" title")

+```````````````````````````````` + + +But it is easy to work around this by using a different quote type: + +```````````````````````````````` example +[link](/url 'title "and" title') +. +

link

+```````````````````````````````` + + +(Note: `Markdown.pl` did allow double quotes inside a double-quoted +title, and its test suite included a test demonstrating this. +But it is hard to see a good rationale for the extra complexity this +brings, since there are already many ways---backslash escaping, +entity and numeric character references, or using a different +quote type for the enclosing title---to write titles containing +double quotes. `Markdown.pl`'s handling of titles has a number +of other strange features. For example, it allows single-quoted +titles in inline links, but not reference links. And, in +reference links but not inline links, it allows a title to begin +with `"` and end with `)`. `Markdown.pl` 1.0.1 even allows +titles with no closing quotation mark, though 1.0.2b8 does not. +It seems preferable to adopt a simple, rational rule that works +the same way in inline links and link reference definitions.) + +[Whitespace] is allowed around the destination and title: + +```````````````````````````````` example +[link]( /uri + "title" ) +. +

link

+```````````````````````````````` + + +But it is not allowed between the link text and the +following parenthesis: + +```````````````````````````````` example +[link] (/uri) +. +

[link] (/uri)

+```````````````````````````````` + + +The link text may contain balanced brackets, but not unbalanced ones, +unless they are escaped: + +```````````````````````````````` example +[link [foo [bar]]](/uri) +. +

link [foo [bar]]

+```````````````````````````````` + + +```````````````````````````````` example +[link] bar](/uri) +. +

[link] bar](/uri)

+```````````````````````````````` + + +```````````````````````````````` example +[link [bar](/uri) +. +

[link bar

+```````````````````````````````` + + +```````````````````````````````` example +[link \[bar](/uri) +. +

link [bar

+```````````````````````````````` + + +The link text may contain inline content: + +```````````````````````````````` example +[link *foo **bar** `#`*](/uri) +. +

link foo bar #

+```````````````````````````````` + + +```````````````````````````````` example +[![moon](moon.jpg)](/uri) +. +

moon

+```````````````````````````````` + + +However, links may not contain other links, at any level of nesting. + +```````````````````````````````` example +[foo [bar](/uri)](/uri) +. +

[foo bar](/uri)

+```````````````````````````````` + + +```````````````````````````````` example +[foo *[bar [baz](/uri)](/uri)*](/uri) +. +

[foo [bar baz](/uri)](/uri)

+```````````````````````````````` + + +```````````````````````````````` example +![[[foo](uri1)](uri2)](uri3) +. +

[foo](uri2)

+```````````````````````````````` + + +These cases illustrate the precedence of link text grouping over +emphasis grouping: + +```````````````````````````````` example +*[foo*](/uri) +. +

*foo*

+```````````````````````````````` + + +```````````````````````````````` example +[foo *bar](baz*) +. +

foo *bar

+```````````````````````````````` + + +Note that brackets that *aren't* part of links do not take +precedence: + +```````````````````````````````` example +*foo [bar* baz] +. +

foo [bar baz]

+```````````````````````````````` + + +These cases illustrate the precedence of HTML tags, code spans, +and autolinks over link grouping: + +```````````````````````````````` example +[foo +. +

[foo

+```````````````````````````````` + + +```````````````````````````````` example +[foo`](/uri)` +. +

[foo](/uri)

+```````````````````````````````` + + +```````````````````````````````` example +[foo +. +

[foohttp://example.com/?search=](uri)

+```````````````````````````````` + + +There are three kinds of [reference link](@)s: +[full](#full-reference-link), [collapsed](#collapsed-reference-link), +and [shortcut](#shortcut-reference-link). + +A [full reference link](@) +consists of a [link text] immediately followed by a [link label] +that [matches] a [link reference definition] elsewhere in the document. + +A [link label](@) begins with a left bracket (`[`) and ends +with the first right bracket (`]`) that is not backslash-escaped. +Between these brackets there must be at least one [non-whitespace character]. +Unescaped square bracket characters are not allowed inside the +opening and closing square brackets of [link labels]. A link +label can have at most 999 characters inside the square +brackets. + +One label [matches](@) +another just in case their normalized forms are equal. To normalize a +label, strip off the opening and closing brackets, +perform the *Unicode case fold*, strip leading and trailing +[whitespace] and collapse consecutive internal +[whitespace] to a single space. If there are multiple +matching reference link definitions, the one that comes first in the +document is used. (It is desirable in such cases to emit a warning.) + +The contents of the first link label are parsed as inlines, which are +used as the link's text. The link's URI and title are provided by the +matching [link reference definition]. + +Here is a simple example: + +```````````````````````````````` example +[foo][bar] + +[bar]: /url "title" +. +

foo

+```````````````````````````````` + + +The rules for the [link text] are the same as with +[inline links]. Thus: + +The link text may contain balanced brackets, but not unbalanced ones, +unless they are escaped: + +```````````````````````````````` example +[link [foo [bar]]][ref] + +[ref]: /uri +. +

link [foo [bar]]

+```````````````````````````````` + + +```````````````````````````````` example +[link \[bar][ref] + +[ref]: /uri +. +

link [bar

+```````````````````````````````` + + +The link text may contain inline content: + +```````````````````````````````` example +[link *foo **bar** `#`*][ref] + +[ref]: /uri +. +

link foo bar #

+```````````````````````````````` + + +```````````````````````````````` example +[![moon](moon.jpg)][ref] + +[ref]: /uri +. +

moon

+```````````````````````````````` + + +However, links may not contain other links, at any level of nesting. + +```````````````````````````````` example +[foo [bar](/uri)][ref] + +[ref]: /uri +. +

[foo bar]ref

+```````````````````````````````` + + +```````````````````````````````` example +[foo *bar [baz][ref]*][ref] + +[ref]: /uri +. +

[foo bar baz]ref

+```````````````````````````````` + + +(In the examples above, we have two [shortcut reference links] +instead of one [full reference link].) + +The following cases illustrate the precedence of link text grouping over +emphasis grouping: + +```````````````````````````````` example +*[foo*][ref] + +[ref]: /uri +. +

*foo*

+```````````````````````````````` + + +```````````````````````````````` example +[foo *bar][ref] + +[ref]: /uri +. +

foo *bar

+```````````````````````````````` + + +These cases illustrate the precedence of HTML tags, code spans, +and autolinks over link grouping: + +```````````````````````````````` example +[foo + +[ref]: /uri +. +

[foo

+```````````````````````````````` + + +```````````````````````````````` example +[foo`][ref]` + +[ref]: /uri +. +

[foo][ref]

+```````````````````````````````` + + +```````````````````````````````` example +[foo + +[ref]: /uri +. +

[foohttp://example.com/?search=][ref]

+```````````````````````````````` + + +Matching is case-insensitive: + +```````````````````````````````` example +[foo][BaR] + +[bar]: /url "title" +. +

foo

+```````````````````````````````` + + +Unicode case fold is used: + +```````````````````````````````` example +[Толпой][Толпой] is a Russian word. + +[ТОЛПОЙ]: /url +. +

Толпой is a Russian word.

+```````````````````````````````` + + +Consecutive internal [whitespace] is treated as one space for +purposes of determining matching: + +```````````````````````````````` example +[Foo + bar]: /url + +[Baz][Foo bar] +. +

Baz

+```````````````````````````````` + + +No [whitespace] is allowed between the [link text] and the +[link label]: + +```````````````````````````````` example +[foo] [bar] + +[bar]: /url "title" +. +

[foo] bar

+```````````````````````````````` + + +```````````````````````````````` example +[foo] +[bar] + +[bar]: /url "title" +. +

[foo] +bar

+```````````````````````````````` + + +This is a departure from John Gruber's original Markdown syntax +description, which explicitly allows whitespace between the link +text and the link label. It brings reference links in line with +[inline links], which (according to both original Markdown and +this spec) cannot have whitespace after the link text. More +importantly, it prevents inadvertent capture of consecutive +[shortcut reference links]. If whitespace is allowed between the +link text and the link label, then in the following we will have +a single reference link, not two shortcut reference links, as +intended: + +``` markdown +[foo] +[bar] + +[foo]: /url1 +[bar]: /url2 +``` + +(Note that [shortcut reference links] were introduced by Gruber +himself in a beta version of `Markdown.pl`, but never included +in the official syntax description. Without shortcut reference +links, it is harmless to allow space between the link text and +link label; but once shortcut references are introduced, it is +too dangerous to allow this, as it frequently leads to +unintended results.) + +When there are multiple matching [link reference definitions], +the first is used: + +```````````````````````````````` example +[foo]: /url1 + +[foo]: /url2 + +[bar][foo] +. +

bar

+```````````````````````````````` + + +Note that matching is performed on normalized strings, not parsed +inline content. So the following does not match, even though the +labels define equivalent inline content: + +```````````````````````````````` example +[bar][foo\!] + +[foo!]: /url +. +

[bar][foo!]

+```````````````````````````````` + + +[Link labels] cannot contain brackets, unless they are +backslash-escaped: + +```````````````````````````````` example +[foo][ref[] + +[ref[]: /uri +. +

[foo][ref[]

+

[ref[]: /uri

+```````````````````````````````` + + +```````````````````````````````` example +[foo][ref[bar]] + +[ref[bar]]: /uri +. +

[foo][ref[bar]]

+

[ref[bar]]: /uri

+```````````````````````````````` + + +```````````````````````````````` example +[[[foo]]] + +[[[foo]]]: /url +. +

[[[foo]]]

+

[[[foo]]]: /url

+```````````````````````````````` + + +```````````````````````````````` example +[foo][ref\[] + +[ref\[]: /uri +. +

foo

+```````````````````````````````` + + +Note that in this example `]` is not backslash-escaped: + +```````````````````````````````` example +[bar\\]: /uri + +[bar\\] +. +

bar\

+```````````````````````````````` + + +A [link label] must contain at least one [non-whitespace character]: + +```````````````````````````````` example +[] + +[]: /uri +. +

[]

+

[]: /uri

+```````````````````````````````` + + +```````````````````````````````` example +[ + ] + +[ + ]: /uri +. +

[ +]

+

[ +]: /uri

+```````````````````````````````` + + +A [collapsed reference link](@) +consists of a [link label] that [matches] a +[link reference definition] elsewhere in the +document, followed by the string `[]`. +The contents of the first link label are parsed as inlines, +which are used as the link's text. The link's URI and title are +provided by the matching reference link definition. Thus, +`[foo][]` is equivalent to `[foo][foo]`. + +```````````````````````````````` example +[foo][] + +[foo]: /url "title" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[*foo* bar][] + +[*foo* bar]: /url "title" +. +

foo bar

+```````````````````````````````` + + +The link labels are case-insensitive: + +```````````````````````````````` example +[Foo][] + +[foo]: /url "title" +. +

Foo

+```````````````````````````````` + + + +As with full reference links, [whitespace] is not +allowed between the two sets of brackets: + +```````````````````````````````` example +[foo] +[] + +[foo]: /url "title" +. +

foo +[]

+```````````````````````````````` + + +A [shortcut reference link](@) +consists of a [link label] that [matches] a +[link reference definition] elsewhere in the +document and is not followed by `[]` or a link label. +The contents of the first link label are parsed as inlines, +which are used as the link's text. The link's URI and title +are provided by the matching link reference definition. +Thus, `[foo]` is equivalent to `[foo][]`. + +```````````````````````````````` example +[foo] + +[foo]: /url "title" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +[*foo* bar] + +[*foo* bar]: /url "title" +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +[[*foo* bar]] + +[*foo* bar]: /url "title" +. +

[foo bar]

+```````````````````````````````` + + +```````````````````````````````` example +[[bar [foo] + +[foo]: /url +. +

[[bar foo

+```````````````````````````````` + + +The link labels are case-insensitive: + +```````````````````````````````` example +[Foo] + +[foo]: /url "title" +. +

Foo

+```````````````````````````````` + + +A space after the link text should be preserved: + +```````````````````````````````` example +[foo] bar + +[foo]: /url +. +

foo bar

+```````````````````````````````` + + +If you just want bracketed text, you can backslash-escape the +opening bracket to avoid links: + +```````````````````````````````` example +\[foo] + +[foo]: /url "title" +. +

[foo]

+```````````````````````````````` + + +Note that this is a link, because a link label ends with the first +following closing bracket: + +```````````````````````````````` example +[foo*]: /url + +*[foo*] +. +

*foo*

+```````````````````````````````` + + +Full and compact references take precedence over shortcut +references: + +```````````````````````````````` example +[foo][bar] + +[foo]: /url1 +[bar]: /url2 +. +

foo

+```````````````````````````````` + +```````````````````````````````` example +[foo][] + +[foo]: /url1 +. +

foo

+```````````````````````````````` + +Inline links also take precedence: + +```````````````````````````````` example +[foo]() + +[foo]: /url1 +. +

foo

+```````````````````````````````` + +```````````````````````````````` example +[foo](not a link) + +[foo]: /url1 +. +

foo(not a link)

+```````````````````````````````` + +In the following case `[bar][baz]` is parsed as a reference, +`[foo]` as normal text: + +```````````````````````````````` example +[foo][bar][baz] + +[baz]: /url +. +

[foo]bar

+```````````````````````````````` + + +Here, though, `[foo][bar]` is parsed as a reference, since +`[bar]` is defined: + +```````````````````````````````` example +[foo][bar][baz] + +[baz]: /url1 +[bar]: /url2 +. +

foobaz

+```````````````````````````````` + + +Here `[foo]` is not parsed as a shortcut reference, because it +is followed by a link label (even though `[bar]` is not defined): + +```````````````````````````````` example +[foo][bar][baz] + +[baz]: /url1 +[foo]: /url2 +. +

[foo]bar

+```````````````````````````````` + + + +## Images + +Syntax for images is like the syntax for links, with one +difference. Instead of [link text], we have an +[image description](@). The rules for this are the +same as for [link text], except that (a) an +image description starts with `![` rather than `[`, and +(b) an image description may contain links. +An image description has inline elements +as its contents. When an image is rendered to HTML, +this is standardly used as the image's `alt` attribute. + +```````````````````````````````` example +![foo](/url "title") +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![foo *bar*] + +[foo *bar*]: train.jpg "train & tracks" +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo ![bar](/url)](/url2) +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo [bar](/url)](/url2) +. +

foo bar

+```````````````````````````````` + + +Though this spec is concerned with parsing, not rendering, it is +recommended that in rendering to HTML, only the plain string content +of the [image description] be used. Note that in +the above example, the alt attribute's value is `foo bar`, not `foo +[bar](/url)` or `foo bar`. Only the plain string +content is rendered, without formatting. + +```````````````````````````````` example +![foo *bar*][] + +[foo *bar*]: train.jpg "train & tracks" +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo *bar*][foobar] + +[FOOBAR]: train.jpg "train & tracks" +. +

foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo](train.jpg) +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +My ![foo bar](/path/to/train.jpg "title" ) +. +

My foo bar

+```````````````````````````````` + + +```````````````````````````````` example +![foo]() +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![](/url) +. +

+```````````````````````````````` + + +Reference-style: + +```````````````````````````````` example +![foo][bar] + +[bar]: /url +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![foo][bar] + +[BAR]: /url +. +

foo

+```````````````````````````````` + + +Collapsed: + +```````````````````````````````` example +![foo][] + +[foo]: /url "title" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![*foo* bar][] + +[*foo* bar]: /url "title" +. +

foo bar

+```````````````````````````````` + + +The labels are case-insensitive: + +```````````````````````````````` example +![Foo][] + +[foo]: /url "title" +. +

Foo

+```````````````````````````````` + + +As with reference links, [whitespace] is not allowed +between the two sets of brackets: + +```````````````````````````````` example +![foo] +[] + +[foo]: /url "title" +. +

foo +[]

+```````````````````````````````` + + +Shortcut: + +```````````````````````````````` example +![foo] + +[foo]: /url "title" +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +![*foo* bar] + +[*foo* bar]: /url "title" +. +

foo bar

+```````````````````````````````` + + +Note that link labels cannot contain unescaped brackets: + +```````````````````````````````` example +![[foo]] + +[[foo]]: /url "title" +. +

![[foo]]

+

[[foo]]: /url "title"

+```````````````````````````````` + + +The link labels are case-insensitive: + +```````````````````````````````` example +![Foo] + +[foo]: /url "title" +. +

Foo

+```````````````````````````````` + + +If you just want a literal `!` followed by bracketed text, you can +backslash-escape the opening `[`: + +```````````````````````````````` example +!\[foo] + +[foo]: /url "title" +. +

![foo]

+```````````````````````````````` + + +If you want a link after a literal `!`, backslash-escape the +`!`: + +```````````````````````````````` example +\![foo] + +[foo]: /url "title" +. +

!foo

+```````````````````````````````` + + +## Autolinks + +[Autolink](@)s are absolute URIs and email addresses inside +`<` and `>`. They are parsed as links, with the URL or email address +as the link label. + +A [URI autolink](@) consists of `<`, followed by an +[absolute URI] not containing `<`, followed by `>`. It is parsed as +a link to the URI, with the URI as the link's label. + +An [absolute URI](@), +for these purposes, consists of a [scheme] followed by a colon (`:`) +followed by zero or more characters other than ASCII +[whitespace] and control characters, `<`, and `>`. If +the URI includes these characters, they must be percent-encoded +(e.g. `%20` for a space). + +For purposes of this spec, a [scheme](@) is any sequence +of 2--32 characters beginning with an ASCII letter and followed +by any combination of ASCII letters, digits, or the symbols plus +("+"), period ("."), or hyphen ("-"). + +Here are some valid autolinks: + +```````````````````````````````` example + +. +

http://foo.bar.baz

+```````````````````````````````` + + +```````````````````````````````` example + +. +

http://foo.bar.baz/test?q=hello&id=22&boolean

+```````````````````````````````` + + +```````````````````````````````` example + +. +

irc://foo.bar:2233/baz

+```````````````````````````````` + + +Uppercase is also fine: + +```````````````````````````````` example + +. +

MAILTO:FOO@BAR.BAZ

+```````````````````````````````` + + +Note that many strings that count as [absolute URIs] for +purposes of this spec are not valid URIs, because their +schemes are not registered or because of other problems +with their syntax: + +```````````````````````````````` example + +. +

a+b+c:d

+```````````````````````````````` + + +```````````````````````````````` example + +. +

made-up-scheme://foo,bar

+```````````````````````````````` + + +```````````````````````````````` example + +. +

http://../

+```````````````````````````````` + + +```````````````````````````````` example + +. +

localhost:5001/foo

+```````````````````````````````` + + +Spaces are not allowed in autolinks: + +```````````````````````````````` example + +. +

<http://foo.bar/baz bim>

+```````````````````````````````` + + +Backslash-escapes do not work inside autolinks: + +```````````````````````````````` example + +. +

http://example.com/\[\

+```````````````````````````````` + + +An [email autolink](@) +consists of `<`, followed by an [email address], +followed by `>`. The link's label is the email address, +and the URL is `mailto:` followed by the email address. + +An [email address](@), +for these purposes, is anything that matches +the [non-normative regex from the HTML5 +spec](https://html.spec.whatwg.org/multipage/forms.html#e-mail-state-(type=email)): + + /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])? + (?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/ + +Examples of email autolinks: + +```````````````````````````````` example + +. +

foo@bar.example.com

+```````````````````````````````` + + +```````````````````````````````` example + +. +

foo+special@Bar.baz-bar0.com

+```````````````````````````````` + + +Backslash-escapes do not work inside email autolinks: + +```````````````````````````````` example + +. +

<foo+@bar.example.com>

+```````````````````````````````` + + +These are not autolinks: + +```````````````````````````````` example +<> +. +

<>

+```````````````````````````````` + + +```````````````````````````````` example +< http://foo.bar > +. +

< http://foo.bar >

+```````````````````````````````` + + +```````````````````````````````` example + +. +

<m:abc>

+```````````````````````````````` + + +```````````````````````````````` example + +. +

<foo.bar.baz>

+```````````````````````````````` + + +```````````````````````````````` example +http://example.com +. +

http://example.com

+```````````````````````````````` + + +```````````````````````````````` example +foo@bar.example.com +. +

foo@bar.example.com

+```````````````````````````````` + + +## Raw HTML + +Text between `<` and `>` that looks like an HTML tag is parsed as a +raw HTML tag and will be rendered in HTML without escaping. +Tag and attribute names are not limited to current HTML tags, +so custom tags (and even, say, DocBook tags) may be used. + +Here is the grammar for tags: + +A [tag name](@) consists of an ASCII letter +followed by zero or more ASCII letters, digits, or +hyphens (`-`). + +An [attribute](@) consists of [whitespace], +an [attribute name], and an optional +[attribute value specification]. + +An [attribute name](@) +consists of an ASCII letter, `_`, or `:`, followed by zero or more ASCII +letters, digits, `_`, `.`, `:`, or `-`. (Note: This is the XML +specification restricted to ASCII. HTML5 is laxer.) + +An [attribute value specification](@) +consists of optional [whitespace], +a `=` character, optional [whitespace], and an [attribute +value]. + +An [attribute value](@) +consists of an [unquoted attribute value], +a [single-quoted attribute value], or a [double-quoted attribute value]. + +An [unquoted attribute value](@) +is a nonempty string of characters not +including spaces, `"`, `'`, `=`, `<`, `>`, or `` ` ``. + +A [single-quoted attribute value](@) +consists of `'`, zero or more +characters not including `'`, and a final `'`. + +A [double-quoted attribute value](@) +consists of `"`, zero or more +characters not including `"`, and a final `"`. + +An [open tag](@) consists of a `<` character, a [tag name], +zero or more [attributes], optional [whitespace], an optional `/` +character, and a `>` character. + +A [closing tag](@) consists of the string ``. + +An [HTML comment](@) consists of ``, +where *text* does not start with `>` or `->`, does not end with `-`, +and does not contain `--`. (See the +[HTML5 spec](http://www.w3.org/TR/html5/syntax.html#comments).) + +A [processing instruction](@) +consists of the string ``, and the string +`?>`. + +A [declaration](@) consists of the +string ``, and the character `>`. + +A [CDATA section](@) consists of +the string ``, and the string `]]>`. + +An [HTML tag](@) consists of an [open tag], a [closing tag], +an [HTML comment], a [processing instruction], a [declaration], +or a [CDATA section]. + +Here are some simple open tags: + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +Empty elements: + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +[Whitespace] is allowed: + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +With attributes: + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +Custom tag names can be used: + +```````````````````````````````` example +Foo +. +

Foo

+```````````````````````````````` + + +Illegal tag names, not parsed as HTML: + +```````````````````````````````` example +<33> <__> +. +

<33> <__>

+```````````````````````````````` + + +Illegal attribute names: + +```````````````````````````````` example +
+. +

<a h*#ref="hi">

+```````````````````````````````` + + +Illegal attribute values: + +```````````````````````````````` example +
+. +

</a href="foo">

+```````````````````````````````` + + +Comments: + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +foo +. +

foo <!-- not a comment -- two hyphens -->

+```````````````````````````````` + + +Not comments: + +```````````````````````````````` example +foo foo --> + +foo +. +

foo <!--> foo -->

+

foo <!-- foo--->

+```````````````````````````````` + + +Processing instructions: + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +Declarations: + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +CDATA sections: + +```````````````````````````````` example +foo &<]]> +. +

foo &<]]>

+```````````````````````````````` + + +Entity and numeric character references are preserved in HTML +attributes: + +```````````````````````````````` example +foo
+. +

foo

+```````````````````````````````` + + +Backslash escapes do not work in HTML attributes: + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example + +. +

<a href=""">

+```````````````````````````````` + + +## Hard line breaks + +A line break (not in a code span or HTML tag) that is preceded +by two or more spaces and does not occur at the end of a block +is parsed as a [hard line break](@) (rendered +in HTML as a `
` tag): + +```````````````````````````````` example +foo +baz +. +

foo
+baz

+```````````````````````````````` + + +For a more visible alternative, a backslash before the +[line ending] may be used instead of two spaces: + +```````````````````````````````` example +foo\ +baz +. +

foo
+baz

+```````````````````````````````` + + +More than two spaces can be used: + +```````````````````````````````` example +foo +baz +. +

foo
+baz

+```````````````````````````````` + + +Leading spaces at the beginning of the next line are ignored: + +```````````````````````````````` example +foo + bar +. +

foo
+bar

+```````````````````````````````` + + +```````````````````````````````` example +foo\ + bar +. +

foo
+bar

+```````````````````````````````` + + +Line breaks can occur inside emphasis, links, and other constructs +that allow inline content: + +```````````````````````````````` example +*foo +bar* +. +

foo
+bar

+```````````````````````````````` + + +```````````````````````````````` example +*foo\ +bar* +. +

foo
+bar

+```````````````````````````````` + + +Line breaks do not occur inside code spans + +```````````````````````````````` example +`code +span` +. +

code span

+```````````````````````````````` + + +```````````````````````````````` example +`code\ +span` +. +

code\ span

+```````````````````````````````` + + +or HTML tags: + +```````````````````````````````` example +
+. +

+```````````````````````````````` + + +```````````````````````````````` example + +. +

+```````````````````````````````` + + +Hard line breaks are for separating inline content within a block. +Neither syntax for hard line breaks works at the end of a paragraph or +other block element: + +```````````````````````````````` example +foo\ +. +

foo\

+```````````````````````````````` + + +```````````````````````````````` example +foo +. +

foo

+```````````````````````````````` + + +```````````````````````````````` example +### foo\ +. +

foo\

+```````````````````````````````` + + +```````````````````````````````` example +### foo +. +

foo

+```````````````````````````````` + + +## Soft line breaks + +A regular line break (not in a code span or HTML tag) that is not +preceded by two or more spaces or a backslash is parsed as a +[softbreak](@). (A softbreak may be rendered in HTML either as a +[line ending] or as a space. The result will be the same in +browsers. In the examples here, a [line ending] will be used.) + +```````````````````````````````` example +foo +baz +. +

foo +baz

+```````````````````````````````` + + +Spaces at the end of the line and beginning of the next line are +removed: + +```````````````````````````````` example +foo + baz +. +

foo +baz

+```````````````````````````````` + + +A conforming parser may render a soft line break in HTML either as a +line break or as a space. + +A renderer may also provide an option to render soft line breaks +as hard line breaks. + +## Textual content + +Any characters not given an interpretation by the above rules will +be parsed as plain textual content. + +```````````````````````````````` example +hello $.;'there +. +

hello $.;'there

+```````````````````````````````` + + +```````````````````````````````` example +Foo χρῆν +. +

Foo χρῆν

+```````````````````````````````` + + +Internal spaces are preserved verbatim: + +```````````````````````````````` example +Multiple spaces +. +

Multiple spaces

+```````````````````````````````` + + + + +# Appendix: A parsing strategy + +In this appendix we describe some features of the parsing strategy +used in the CommonMark reference implementations. + +## Overview + +Parsing has two phases: + +1. In the first phase, lines of input are consumed and the block +structure of the document---its division into paragraphs, block quotes, +list items, and so on---is constructed. Text is assigned to these +blocks but not parsed. Link reference definitions are parsed and a +map of links is constructed. + +2. In the second phase, the raw text contents of paragraphs and headings +are parsed into sequences of Markdown inline elements (strings, +code spans, links, emphasis, and so on), using the map of link +references constructed in phase 1. + +At each point in processing, the document is represented as a tree of +**blocks**. The root of the tree is a `document` block. The `document` +may have any number of other blocks as **children**. These children +may, in turn, have other blocks as children. The last child of a block +is normally considered **open**, meaning that subsequent lines of input +can alter its contents. (Blocks that are not open are **closed**.) +Here, for example, is a possible document tree, with the open blocks +marked by arrows: + +``` tree +-> document + -> block_quote + paragraph + "Lorem ipsum dolor\nsit amet." + -> list (type=bullet tight=true bullet_char=-) + list_item + paragraph + "Qui *quodsi iracundia*" + -> list_item + -> paragraph + "aliquando id" +``` + +## Phase 1: block structure + +Each line that is processed has an effect on this tree. The line is +analyzed and, depending on its contents, the document may be altered +in one or more of the following ways: + +1. One or more open blocks may be closed. +2. One or more new blocks may be created as children of the + last open block. +3. Text may be added to the last (deepest) open block remaining + on the tree. + +Once a line has been incorporated into the tree in this way, +it can be discarded, so input can be read in a stream. + +For each line, we follow this procedure: + +1. First we iterate through the open blocks, starting with the +root document, and descending through last children down to the last +open block. Each block imposes a condition that the line must satisfy +if the block is to remain open. For example, a block quote requires a +`>` character. A paragraph requires a non-blank line. +In this phase we may match all or just some of the open +blocks. But we cannot close unmatched blocks yet, because we may have a +[lazy continuation line]. + +2. Next, after consuming the continuation markers for existing +blocks, we look for new block starts (e.g. `>` for a block quote). +If we encounter a new block start, we close any blocks unmatched +in step 1 before creating the new block as a child of the last +matched block. + +3. Finally, we look at the remainder of the line (after block +markers like `>`, list markers, and indentation have been consumed). +This is text that can be incorporated into the last open +block (a paragraph, code block, heading, or raw HTML). + +Setext headings are formed when we see a line of a paragraph +that is a [setext heading underline]. + +Reference link definitions are detected when a paragraph is closed; +the accumulated text lines are parsed to see if they begin with +one or more reference link definitions. Any remainder becomes a +normal paragraph. + +We can see how this works by considering how the tree above is +generated by four lines of Markdown: + +``` markdown +> Lorem ipsum dolor +sit amet. +> - Qui *quodsi iracundia* +> - aliquando id +``` + +At the outset, our document model is just + +``` tree +-> document +``` + +The first line of our text, + +``` markdown +> Lorem ipsum dolor +``` + +causes a `block_quote` block to be created as a child of our +open `document` block, and a `paragraph` block as a child of +the `block_quote`. Then the text is added to the last open +block, the `paragraph`: + +``` tree +-> document + -> block_quote + -> paragraph + "Lorem ipsum dolor" +``` + +The next line, + +``` markdown +sit amet. +``` + +is a "lazy continuation" of the open `paragraph`, so it gets added +to the paragraph's text: + +``` tree +-> document + -> block_quote + -> paragraph + "Lorem ipsum dolor\nsit amet." +``` + +The third line, + +``` markdown +> - Qui *quodsi iracundia* +``` + +causes the `paragraph` block to be closed, and a new `list` block +opened as a child of the `block_quote`. A `list_item` is also +added as a child of the `list`, and a `paragraph` as a child of +the `list_item`. The text is then added to the new `paragraph`: + +``` tree +-> document + -> block_quote + paragraph + "Lorem ipsum dolor\nsit amet." + -> list (type=bullet tight=true bullet_char=-) + -> list_item + -> paragraph + "Qui *quodsi iracundia*" +``` + +The fourth line, + +``` markdown +> - aliquando id +``` + +causes the `list_item` (and its child the `paragraph`) to be closed, +and a new `list_item` opened up as child of the `list`. A `paragraph` +is added as a child of the new `list_item`, to contain the text. +We thus obtain the final tree: + +``` tree +-> document + -> block_quote + paragraph + "Lorem ipsum dolor\nsit amet." + -> list (type=bullet tight=true bullet_char=-) + list_item + paragraph + "Qui *quodsi iracundia*" + -> list_item + -> paragraph + "aliquando id" +``` + +## Phase 2: inline structure + +Once all of the input has been parsed, all open blocks are closed. + +We then "walk the tree," visiting every node, and parse raw +string contents of paragraphs and headings as inlines. At this +point we have seen all the link reference definitions, so we can +resolve reference links as we go. + +``` tree +document + block_quote + paragraph + str "Lorem ipsum dolor" + softbreak + str "sit amet." + list (type=bullet tight=true bullet_char=-) + list_item + paragraph + str "Qui " + emph + str "quodsi iracundia" + list_item + paragraph + str "aliquando id" +``` + +Notice how the [line ending] in the first paragraph has +been parsed as a `softbreak`, and the asterisks in the first list item +have become an `emph`. + +### An algorithm for parsing nested emphasis and links + +By far the trickiest part of inline parsing is handling emphasis, +strong emphasis, links, and images. This is done using the following +algorithm. + +When we're parsing inlines and we hit either + +- a run of `*` or `_` characters, or +- a `[` or `![` + +we insert a text node with these symbols as its literal content, and we +add a pointer to this text node to the [delimiter stack](@). + +The [delimiter stack] is a doubly linked list. Each +element contains a pointer to a text node, plus information about + +- the type of delimiter (`[`, `![`, `*`, `_`) +- the number of delimiters, +- whether the delimiter is "active" (all are active to start), and +- whether the delimiter is a potential opener, a potential closer, + or both (which depends on what sort of characters precede + and follow the delimiters). + +When we hit a `]` character, we call the *look for link or image* +procedure (see below). + +When we hit the end of the input, we call the *process emphasis* +procedure (see below), with `stack_bottom` = NULL. + +#### *look for link or image* + +Starting at the top of the delimiter stack, we look backwards +through the stack for an opening `[` or `![` delimiter. + +- If we don't find one, we return a literal text node `]`. + +- If we do find one, but it's not *active*, we remove the inactive + delimiter from the stack, and return a literal text node `]`. + +- If we find one and it's active, then we parse ahead to see if + we have an inline link/image, reference link/image, compact reference + link/image, or shortcut reference link/image. + + + If we don't, then we remove the opening delimiter from the + delimiter stack and return a literal text node `]`. + + + If we do, then + + * We return a link or image node whose children are the inlines + after the text node pointed to by the opening delimiter. + + * We run *process emphasis* on these inlines, with the `[` opener + as `stack_bottom`. + + * We remove the opening delimiter. + + * If we have a link (and not an image), we also set all + `[` delimiters before the opening delimiter to *inactive*. (This + will prevent us from getting links within links.) + +#### *process emphasis* + +Parameter `stack_bottom` sets a lower bound to how far we +descend in the [delimiter stack]. If it is NULL, we can +go all the way to the bottom. Otherwise, we stop before +visiting `stack_bottom`. + +Let `current_position` point to the element on the [delimiter stack] +just above `stack_bottom` (or the first element if `stack_bottom` +is NULL). + +We keep track of the `openers_bottom` for each delimiter +type (`*`, `_`). Initialize this to `stack_bottom`. + +Then we repeat the following until we run out of potential +closers: + +- Move `current_position` forward in the delimiter stack (if needed) + until we find the first potential closer with delimiter `*` or `_`. + (This will be the potential closer closest + to the beginning of the input -- the first one in parse order.) + +- Now, look back in the stack (staying above `stack_bottom` and + the `openers_bottom` for this delimiter type) for the + first matching potential opener ("matching" means same delimiter). + +- If one is found: + + + Figure out whether we have emphasis or strong emphasis: + if both closer and opener spans have length >= 2, we have + strong, otherwise regular. + + + Insert an emph or strong emph node accordingly, after + the text node corresponding to the opener. + + + Remove any delimiters between the opener and closer from + the delimiter stack. + + + Remove 1 (for regular emph) or 2 (for strong emph) delimiters + from the opening and closing text nodes. If they become empty + as a result, remove them and remove the corresponding element + of the delimiter stack. If the closing node is removed, reset + `current_position` to the next element in the stack. + +- If none in found: + + + Set `openers_bottom` to the element before `current_position`. + (We know that there are no openers for this kind of closer up to and + including this point, so this puts a lower bound on future searches.) + + + If the closer at `current_position` is not a potential opener, + remove it from the delimiter stack (since we know it can't + be a closer either). + + + Advance `current_position` to the next element in the stack. + +After we're done, we remove all delimiters above `stack_bottom` from the +delimiter stack. + diff --git a/src/Markdig.Tests/Specs/CustomContainerSpecs.cs b/src/Markdig.Tests/Specs/CustomContainerSpecs.cs new file mode 100644 index 00000000..ac3399e0 --- /dev/null +++ b/src/Markdig.Tests/Specs/CustomContainerSpecs.cs @@ -0,0 +1,211 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Custom Containers +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.CustomContainers +{ + [TestFixture] + public class TestExtensionsCustomContainer + { + // # Extensions + // + // This section describes the different extensions supported: + // + // ## Custom Container + // + // A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `
...
` it will generate a `
...
` block. + [Test] + public void ExtensionsCustomContainer_Example001() + { + // Example 1 + // Section: Extensions / Custom Container + // + // The following Markdown: + // :::spoiler + // This is a *spoiler* + // ::: + // + // Should be rendered as: + //

This is a spoiler

+ //
+ + Console.WriteLine("Example 1\nSection Extensions / Custom Container\n"); + TestParser.TestSpec(":::spoiler\nThis is a *spoiler*\n:::", "

This is a spoiler

\n
", "customcontainers+attributes|advanced"); + } + + // The text following the opened custom container is optional: + [Test] + public void ExtensionsCustomContainer_Example002() + { + // Example 2 + // Section: Extensions / Custom Container + // + // The following Markdown: + // ::: + // This is a regular div + // ::: + // + // Should be rendered as: + //

This is a regular div

+ //
+ + Console.WriteLine("Example 2\nSection Extensions / Custom Container\n"); + TestParser.TestSpec(":::\nThis is a regular div\n:::", "

This is a regular div

\n
", "customcontainers+attributes|advanced"); + } + + // Like for fenced code block, you can use more than 3 `:` characters as long as the closing has the same number of characters: + [Test] + public void ExtensionsCustomContainer_Example003() + { + // Example 3 + // Section: Extensions / Custom Container + // + // The following Markdown: + // ::::::::::::spoiler + // This is a spoiler + // :::::::::::: + // + // Should be rendered as: + //

This is a spoiler

+ //
+ + Console.WriteLine("Example 3\nSection Extensions / Custom Container\n"); + TestParser.TestSpec("::::::::::::spoiler\nThis is a spoiler\n::::::::::::", "

This is a spoiler

\n
", "customcontainers+attributes|advanced"); + } + + // Like for fenced code block, a custom container can span over multiple empty lines in a list block: + [Test] + public void ExtensionsCustomContainer_Example004() + { + // Example 4 + // Section: Extensions / Custom Container + // + // The following Markdown: + // - This is a list + // :::spoiler + // This is a spoiler + // - item1 + // - item2 + // ::: + // - A second item in the list + // + // Should be rendered as: + //
    + //
  • This is a list + //
    This is a spoiler + //
      + //
    • item1
    • + //
    • item2
    • + //
    + //
    + //
  • + //
  • A second item in the list
  • + //
+ + Console.WriteLine("Example 4\nSection Extensions / Custom Container\n"); + TestParser.TestSpec("- This is a list\n :::spoiler\n This is a spoiler\n - item1\n - item2\n :::\n- A second item in the list", "
    \n
  • This is a list\n
    This is a spoiler\n
      \n
    • item1
    • \n
    • item2
    • \n
    \n
    \n
  • \n
  • A second item in the list
  • \n
", "customcontainers+attributes|advanced"); + } + + // Attributes extension is also supported for Custom Container, as long as the Attributes extension is activated after the CustomContainer extension (`.UseCustomContainer().UseAttributes()`) + [Test] + public void ExtensionsCustomContainer_Example005() + { + // Example 5 + // Section: Extensions / Custom Container + // + // The following Markdown: + // :::spoiler {#myspoiler myprop=yes} + // This is a spoiler + // ::: + // + // Should be rendered as: + //

This is a spoiler

+ //
+ + Console.WriteLine("Example 5\nSection Extensions / Custom Container\n"); + TestParser.TestSpec(":::spoiler {#myspoiler myprop=yes}\nThis is a spoiler\n:::", "

This is a spoiler

\n
", "customcontainers+attributes|advanced"); + } + + // The content of a custom container can contain any blocks: + [Test] + public void ExtensionsCustomContainer_Example006() + { + // Example 6 + // Section: Extensions / Custom Container + // + // The following Markdown: + // :::mycontainer + //

This is a raw spoiler

+ // ::: + // + // Should be rendered as: + //

This is a raw spoiler

+ //
+ + Console.WriteLine("Example 6\nSection Extensions / Custom Container\n"); + TestParser.TestSpec(":::mycontainer\n

This is a raw spoiler

\n:::", "

This is a raw spoiler

\n
", "customcontainers+attributes|advanced"); + } + } + + [TestFixture] + public class TestExtensionsInlineCustomContainer + { + // ## Inline Custom Container + // + // A custom container can also be used within an inline container (e.g: paragraph, heading...) by enclosing a text by a new emphasis `::` + [Test] + public void ExtensionsInlineCustomContainer_Example007() + { + // Example 7 + // Section: Extensions / Inline Custom Container + // + // The following Markdown: + // This is a text ::with special emphasis:: + // + // Should be rendered as: + //

This is a text with special emphasis

+ + Console.WriteLine("Example 7\nSection Extensions / Inline Custom Container \n"); + TestParser.TestSpec("This is a text ::with special emphasis::", "

This is a text with special emphasis

", "customcontainers+attributes|advanced"); + } + + // Any other emphasis inline can be used within this emphasis inline container: + [Test] + public void ExtensionsInlineCustomContainer_Example008() + { + // Example 8 + // Section: Extensions / Inline Custom Container + // + // The following Markdown: + // This is a text ::with special *emphasis*:: + // + // Should be rendered as: + //

This is a text with special emphasis

+ + Console.WriteLine("Example 8\nSection Extensions / Inline Custom Container \n"); + TestParser.TestSpec("This is a text ::with special *emphasis*::", "

This is a text with special emphasis

", "customcontainers+attributes|advanced"); + } + + // Attributes can be attached to a inline custom container: + [Test] + public void ExtensionsInlineCustomContainer_Example009() + { + // Example 9 + // Section: Extensions / Inline Custom Container + // + // The following Markdown: + // This is a text ::with special emphasis::{#myId .myemphasis} + // + // Should be rendered as: + //

This is a text with special emphasis

+ + Console.WriteLine("Example 9\nSection Extensions / Inline Custom Container \n"); + TestParser.TestSpec("This is a text ::with special emphasis::{#myId .myemphasis}", "

This is a text with special emphasis

", "customcontainers+attributes|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/DefinitionListSpecs.cs b/src/Markdig.Tests/Specs/DefinitionListSpecs.cs new file mode 100644 index 00000000..812c46c2 --- /dev/null +++ b/src/Markdig.Tests/Specs/DefinitionListSpecs.cs @@ -0,0 +1,202 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Definition Lists +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.DefinitionLists +{ + [TestFixture] + public class TestExtensionsDefinitionLists + { + // # Extensions + // + // This section describes the different extensions supported: + // + // ## Definition lists + // + // A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `
...
` it will generate a `
...` block. + [Test] + public void ExtensionsDefinitionLists_Example001() + { + // Example 1 + // Section: Extensions / Definition lists + // + // The following Markdown: + // + // Term 1 + // : This is a definition item + // With a paragraph + // > This is a block quote + // + // - This is a list + // - with an item2 + // + // ```java + // Test + // + // + // ``` + // + // And a last line + // : This ia another definition item + // + // Term2 + // Term3 *with some inline* + // : This is another definition for term2 + // + // Should be rendered as: + //
+ //
Term 1
+ //

This is a definition item + // With a paragraph

+ //
+ //

This is a block quote

+ //
+ //
    + //
  • This is a list
  • + //
  • with an item2
  • + //
+ //
Test
+            //     
+            //     
+            //     
+ //

And a last line

+ //
+ //
This ia another definition item
+ //
Term2
+ //
Term3 with some inline
+ //
This is another definition for term2
+ //
+ + Console.WriteLine("Example 1\nSection Extensions / Definition lists\n"); + TestParser.TestSpec("\nTerm 1\n: This is a definition item\n With a paragraph\n > This is a block quote\n\n - This is a list\n - with an item2\n\n ```java\n Test\n\n\n ```\n\n And a last line\n: This ia another definition item\n\nTerm2\nTerm3 *with some inline*\n: This is another definition for term2", "
\n
Term 1
\n

This is a definition item\nWith a paragraph

\n
\n

This is a block quote

\n
\n
    \n
  • This is a list
  • \n
  • with an item2
  • \n
\n
Test\n\n\n
\n

And a last line

\n
\n
This ia another definition item
\n
Term2
\n
Term3 with some inline
\n
This is another definition for term2
\n
", "definitionlists+attributes|advanced"); + } + + // A definition term can be followed at most by one blank line. Lazy continuations are supported for definitions: + [Test] + public void ExtensionsDefinitionLists_Example002() + { + // Example 2 + // Section: Extensions / Definition lists + // + // The following Markdown: + // Term 1 + // + // : Definition + // with lazy continuation. + // + // Second paragraph of the definition. + // + // Should be rendered as: + //
+ //
Term 1
+ //

Definition + // with lazy continuation.

+ //

Second paragraph of the definition.

+ //
+ //
+ + Console.WriteLine("Example 2\nSection Extensions / Definition lists\n"); + TestParser.TestSpec("Term 1\n\n: Definition\nwith lazy continuation.\n\n Second paragraph of the definition.", "
\n
Term 1
\n

Definition\nwith lazy continuation.

\n

Second paragraph of the definition.

\n
\n
", "definitionlists+attributes|advanced"); + } + + // The definition must be indented to 4 characters including the `:`. + [Test] + public void ExtensionsDefinitionLists_Example003() + { + // Example 3 + // Section: Extensions / Definition lists + // + // The following Markdown: + // Term 1 + // : Invalid with less than 3 characters + // + // Should be rendered as: + //

Term 1 + // : Invalid with less than 3 characters

+ + Console.WriteLine("Example 3\nSection Extensions / Definition lists\n"); + TestParser.TestSpec("Term 1\n: Invalid with less than 3 characters", "

Term 1\n: Invalid with less than 3 characters

", "definitionlists+attributes|advanced"); + } + + // The `:` can be indented up to 3 spaces: + [Test] + public void ExtensionsDefinitionLists_Example004() + { + // Example 4 + // Section: Extensions / Definition lists + // + // The following Markdown: + // Term 1 + // : Valid even if `:` starts at most 3 spaces + // + // Should be rendered as: + //
+ //
Term 1
+ //
Valid even if : starts at most 3 spaces
+ //
+ + Console.WriteLine("Example 4\nSection Extensions / Definition lists\n"); + TestParser.TestSpec("Term 1\n : Valid even if `:` starts at most 3 spaces", "
\n
Term 1
\n
Valid even if : starts at most 3 spaces
\n
", "definitionlists+attributes|advanced"); + } + + // But more than 3 spaces before `:` will trigger an indented code block: + [Test] + public void ExtensionsDefinitionLists_Example005() + { + // Example 5 + // Section: Extensions / Definition lists + // + // The following Markdown: + // Term 1 + // + // : Not valid + // + // Should be rendered as: + //

Term 1

+ //
: Not valid
+            //     
+ + Console.WriteLine("Example 5\nSection Extensions / Definition lists\n"); + TestParser.TestSpec("Term 1\n\n : Not valid", "

Term 1

\n
: Not valid\n
", "definitionlists+attributes|advanced"); + } + + // Definition lists can be nested inside list items + [Test] + public void ExtensionsDefinitionLists_Example006() + { + // Example 6 + // Section: Extensions / Definition lists + // + // The following Markdown: + // 1. First + // + // 2. Second + // + // Term 1 + // : Definition + // + // Term 2 + // : Second Definition + // + // Should be rendered as: + //
    + //
  1. First

  2. + //
  3. Second

    + //
    + //
    Term 1
    + //
    Definition
    + //
    Term 2
    + //
    Second Definition
    + //
  4. + //
+ + Console.WriteLine("Example 6\nSection Extensions / Definition lists\n"); + TestParser.TestSpec("1. First\n \n2. Second\n \n Term 1\n : Definition\n \n Term 2\n : Second Definition", "
    \n
  1. First

  2. \n
  3. Second

    \n
    \n
    Term 1
    \n
    Definition
    \n
    Term 2
    \n
    Second Definition
    \n
  4. \n
", "definitionlists+attributes|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/DiagramsSpecs.cs b/src/Markdig.Tests/Specs/DiagramsSpecs.cs new file mode 100644 index 00000000..4f19b5c1 --- /dev/null +++ b/src/Markdig.Tests/Specs/DiagramsSpecs.cs @@ -0,0 +1,94 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Diagrams +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.Diagrams +{ + [TestFixture] + public class TestExtensionsMermaidDiagrams + { + // # Extensions + // + // Adds support for diagrams extension: + // + // ## Mermaid diagrams + // + // Using a fenced code block with the `mermaid` language info will output a `
` instead of a `pre/code` block: + [Test] + public void ExtensionsMermaidDiagrams_Example001() + { + // Example 1 + // Section: Extensions / Mermaid diagrams + // + // The following Markdown: + // ```mermaid + // graph TD; + // A-->B; + // A-->C; + // B-->D; + // C-->D; + // ``` + // + // Should be rendered as: + //
graph TD; + // A-->B; + // A-->C; + // B-->D; + // C-->D; + //
+ + Console.WriteLine("Example 1\nSection Extensions / Mermaid diagrams\n"); + TestParser.TestSpec("```mermaid\ngraph TD;\n A-->B;\n A-->C;\n B-->D;\n C-->D;\n```", "
graph TD;\n A-->B;\n A-->C;\n B-->D;\n C-->D;\n
", "diagrams|advanced"); + } + } + + [TestFixture] + public class TestExtensionsNomnomlDiagrams + { + // ## nomnoml diagrams + // + // Using a fenced code block with the `nomnoml` language info will output a `
` instead of a `pre/code` block: + [Test] + public void ExtensionsNomnomlDiagrams_Example002() + { + // Example 2 + // Section: Extensions / nomnoml diagrams + // + // The following Markdown: + // ```nomnoml + // [example| + // propertyA: Int + // propertyB: string + // | + // methodA() + // methodB() + // | + // [subA]--[subB] + // [subA]-:>[sub C] + // ] + // ``` + // + // Should be rendered as: + //
[example| + // propertyA: Int + // propertyB: string + // | + // methodA() + // methodB() + // | + // [subA]--[subB] + // [subA]-:>[sub C] + // ] + //
+ + Console.WriteLine("Example 2\nSection Extensions / nomnoml diagrams\n"); + TestParser.TestSpec("```nomnoml\n[example|\n propertyA: Int\n propertyB: string\n|\n methodA()\n methodB()\n|\n [subA]--[subB]\n [subA]-:>[sub C]\n]\n```", "
[example|\n propertyA: Int\n propertyB: string\n|\n methodA()\n methodB()\n|\n [subA]--[subB]\n [subA]-:>[sub C]\n]\n
", "diagrams|advanced"); + } + // TODO: Add other text diagram languages + } +} diff --git a/src/Markdig.Tests/Specs/EmojiSpecs.cs b/src/Markdig.Tests/Specs/EmojiSpecs.cs new file mode 100644 index 00000000..48486025 --- /dev/null +++ b/src/Markdig.Tests/Specs/EmojiSpecs.cs @@ -0,0 +1,91 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Emoji +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.Emoji +{ + [TestFixture] + public class TestExtensionsEmoji + { + // # Extensions + // + // This section describes the different extensions supported: + // + // ## Emoji + // + // Emoji and smiley can be converted to their respective unicode characters: + [Test] + public void ExtensionsEmoji_Example001() + { + // Example 1 + // Section: Extensions / Emoji + // + // The following Markdown: + // This is a test with a :) and a :angry: smiley + // + // Should be rendered as: + //

This is a test with a 😃 and a 😠 smiley

+ + Console.WriteLine("Example 1\nSection Extensions / Emoji\n"); + TestParser.TestSpec("This is a test with a :) and a :angry: smiley", "

This is a test with a 😃 and a 😠 smiley

", "emojis|advanced+emojis"); + } + + // An emoji needs to be preceded by a space: + [Test] + public void ExtensionsEmoji_Example002() + { + // Example 2 + // Section: Extensions / Emoji + // + // The following Markdown: + // These are not:) an emoji with a:) x:angry:x + // + // Should be rendered as: + //

These are not:) an emoji with a:) x:angry:x

+ + Console.WriteLine("Example 2\nSection Extensions / Emoji\n"); + TestParser.TestSpec("These are not:) an emoji with a:) x:angry:x", "

These are not:) an emoji with a:) x:angry:x

", "emojis|advanced+emojis"); + } + + // Emoji can be followed by close ponctuation (or any other characters): + [Test] + public void ExtensionsEmoji_Example003() + { + // Example 3 + // Section: Extensions / Emoji + // + // The following Markdown: + // We all need :), it makes us :muscle:. (and :ok_hand:). + // + // Should be rendered as: + //

We all need 😃, it makes us 💪. (and 👌).

+ + Console.WriteLine("Example 3\nSection Extensions / Emoji\n"); + TestParser.TestSpec("We all need :), it makes us :muscle:. (and :ok_hand:).", "

We all need 😃, it makes us 💪. (and 👌).

", "emojis|advanced+emojis"); + } + + // Sentences can end with Emoji: + [Test] + public void ExtensionsEmoji_Example004() + { + // Example 4 + // Section: Extensions / Emoji + // + // The following Markdown: + // This is a sentence :ok_hand: + // and keeps going to the next line :) + // + // Should be rendered as: + //

This is a sentence 👌 + // and keeps going to the next line 😃

+ + Console.WriteLine("Example 4\nSection Extensions / Emoji\n"); + TestParser.TestSpec("This is a sentence :ok_hand:\nand keeps going to the next line :)", "

This is a sentence 👌\nand keeps going to the next line 😃

", "emojis|advanced+emojis"); + } + } +} diff --git a/src/Markdig.Tests/Specs/EmphasisExtraSpecs.cs b/src/Markdig.Tests/Specs/EmphasisExtraSpecs.cs new file mode 100644 index 00000000..36746f26 --- /dev/null +++ b/src/Markdig.Tests/Specs/EmphasisExtraSpecs.cs @@ -0,0 +1,152 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Emphasis Extra +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.EmphasisExtra +{ + [TestFixture] + public class TestExtensionsStrikethrough + { + // # Extensions + // + // The following additional emphasis are supported: + // + // ## Strikethrough + // + // Allows to strikethrough a span of text by surrounding it by `~~`. The semantic used for the generated HTML is the tag ``. + [Test] + public void ExtensionsStrikethrough_Example001() + { + // Example 1 + // Section: Extensions / Strikethrough + // + // The following Markdown: + // The following text ~~is deleted~~ + // + // Should be rendered as: + //

The following text is deleted

+ + Console.WriteLine("Example 1\nSection Extensions / Strikethrough\n"); + TestParser.TestSpec("The following text ~~is deleted~~", "

The following text is deleted

", "emphasisextras|advanced"); + } + } + + [TestFixture] + public class TestExtensionsSuperscriptAndSubscript + { + // ## Superscript and Subscript + // + // Superscripts can be written by surrounding a text by ^ characters; subscripts can be written by surrounding the subscripted text by ~ characters + [Test] + public void ExtensionsSuperscriptAndSubscript_Example002() + { + // Example 2 + // Section: Extensions / Superscript and Subscript + // + // The following Markdown: + // H~2~O is a liquid. 2^10^ is 1024 + // + // Should be rendered as: + //

H2O is a liquid. 210 is 1024

+ + Console.WriteLine("Example 2\nSection Extensions / Superscript and Subscript\n"); + TestParser.TestSpec("H~2~O is a liquid. 2^10^ is 1024", "

H2O is a liquid. 210 is 1024

", "emphasisextras|advanced"); + } + + // Certain punctuation characters are exempted from the rule forbidding them within inline delimiters + [Test] + public void ExtensionsSuperscriptAndSubscript_Example003() + { + // Example 3 + // Section: Extensions / Superscript and Subscript + // + // The following Markdown: + // One quintillionth can be expressed as 10^-18^ + // + // Daggers^†^ and double-daggers^‡^ can be used to denote notes. + // + // Should be rendered as: + //

One quintillionth can be expressed as 10-18

+ //

Daggers and double-daggers can be used to denote notes.

+ + Console.WriteLine("Example 3\nSection Extensions / Superscript and Subscript\n"); + TestParser.TestSpec("One quintillionth can be expressed as 10^-18^\n\nDaggers^†^ and double-daggers^‡^ can be used to denote notes.", "

One quintillionth can be expressed as 10-18

\n

Daggers and double-daggers can be used to denote notes.

", "emphasisextras|advanced"); + } + } + + [TestFixture] + public class TestExtensionsInserted + { + // ## Inserted + // + // Inserted text can be used to specify that a text has been added to a document. The semantic used for the generated HTML is the tag ``. + [Test] + public void ExtensionsInserted_Example004() + { + // Example 4 + // Section: Extensions / Inserted + // + // The following Markdown: + // ++Inserted text++ + // + // Should be rendered as: + //

Inserted text

+ + Console.WriteLine("Example 4\nSection Extensions / Inserted\n"); + TestParser.TestSpec("++Inserted text++", "

Inserted text

", "emphasisextras|advanced"); + } + } + + [TestFixture] + public class TestExtensionsMarked + { + // ## Marked + // + // Marked text can be used to specify that a text has been marked in a document. The semantic used for the generated HTML is the tag ``. + [Test] + public void ExtensionsMarked_Example005() + { + // Example 5 + // Section: Extensions / Marked + // + // The following Markdown: + // ==Marked text== + // + // Should be rendered as: + //

Marked text

+ + Console.WriteLine("Example 5\nSection Extensions / Marked\n"); + TestParser.TestSpec("==Marked text==", "

Marked text

", "emphasisextras|advanced"); + } + } + + [TestFixture] + public class TestExtensionsEmphasisOnHtmlEntities + { + // ## Emphasis on Html Entities + [Test] + public void ExtensionsEmphasisOnHtmlEntities_Example006() + { + // Example 6 + // Section: Extensions / Emphasis on Html Entities + // + // The following Markdown: + // This is text MyBrand ^®^ and MyTrademark ^™^ + // This is text MyBrand^®^ and MyTrademark^™^ + // This is text MyBrand~®~ and MyCopyright^©^ + // + // Should be rendered as: + //

This is text MyBrand ® and MyTrademark TM + // This is text MyBrand® and MyTrademarkTM + // This is text MyBrand® and MyCopyright©

+ + Console.WriteLine("Example 6\nSection Extensions / Emphasis on Html Entities\n"); + TestParser.TestSpec("This is text MyBrand ^®^ and MyTrademark ^™^\nThis is text MyBrand^®^ and MyTrademark^™^\nThis is text MyBrand~®~ and MyCopyright^©^", "

This is text MyBrand ® and MyTrademark TM\nThis is text MyBrand® and MyTrademarkTM\nThis is text MyBrand® and MyCopyright©

", "emphasisextras|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/FigureFooterAndCiteSpecs.cs b/src/Markdig.Tests/Specs/FigureFooterAndCiteSpecs.cs new file mode 100644 index 00000000..ea03e4be --- /dev/null +++ b/src/Markdig.Tests/Specs/FigureFooterAndCiteSpecs.cs @@ -0,0 +1,91 @@ +// Generated: 21. 01. 2019 14:42:25 + +// -------------------------------- +// Figures, Footers and Cites +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.FiguresFootersAndCites +{ + [TestFixture] + public class TestExtensionsFigures + { + // # Extensions + // + // The following the figure extension: + // + // ## Figures + // + // A figure can be defined by using a pattern equivalent to a fenced code block but with the character `^` + [Test] + public void ExtensionsFigures_Example001() + { + // Example 1 + // Section: Extensions / Figures + // + // The following Markdown: + // ^^^ + // This is a figure + // ^^^ This is a *caption* + // + // Should be rendered as: + //
+ //

This is a figure

+ //
This is a caption
+ //
+ + Console.WriteLine("Example 1\nSection Extensions / Figures\n"); + TestParser.TestSpec("^^^\nThis is a figure\n^^^ This is a *caption*", "
\n

This is a figure

\n
This is a caption
\n
", "figures+footers+citations|advanced"); + } + } + + [TestFixture] + public class TestExtensionsFooters + { + // ## Footers + // + // A footer equivalent to a block quote parsing but starts with double character ^^ + [Test] + public void ExtensionsFooters_Example002() + { + // Example 2 + // Section: Extensions / Footers + // + // The following Markdown: + // ^^ This is a footer + // ^^ multi-line + // + // Should be rendered as: + //
This is a footer + // multi-line
+ + Console.WriteLine("Example 2\nSection Extensions / Footers\n"); + TestParser.TestSpec("^^ This is a footer\n^^ multi-line", "
This is a footer\nmulti-line
", "figures+footers+citations|advanced"); + } + } + + [TestFixture] + public class TestExtensionsCite + { + // ## Cite + // + // A cite is working like an emphasis but using the double character "" + [Test] + public void ExtensionsCite_Example003() + { + // Example 3 + // Section: Extensions / Cite + // + // The following Markdown: + // This is a ""citation of someone"" + // + // Should be rendered as: + //

This is a citation of someone

+ + Console.WriteLine("Example 3\nSection Extensions / Cite\n"); + TestParser.TestSpec("This is a \"\"citation of someone\"\"", "

This is a citation of someone

", "figures+footers+citations|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/FootnotesSpecs.cs b/src/Markdig.Tests/Specs/FootnotesSpecs.cs new file mode 100644 index 00000000..6d7dbe75 --- /dev/null +++ b/src/Markdig.Tests/Specs/FootnotesSpecs.cs @@ -0,0 +1,193 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Footnotes +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.Footnotes +{ + [TestFixture] + public class TestExtensionsFootnotes + { + // # Extensions + // + // This section describes the different extensions supported: + // + // ## Footnotes + // + // Allows footnotes using the following syntax (taken from pandoc example): + [Test] + public void ExtensionsFootnotes_Example001() + { + // Example 1 + // Section: Extensions / Footnotes + // + // The following Markdown: + // Here is a footnote reference,[^1] and another.[^longnote] + // + // This is another reference to [^1] + // + // [^1]: Here is the footnote. + // + // And another reference to [^longnote] + // + // [^longnote]: Here's one with multiple blocks. + // + // Subsequent paragraphs are indented to show that they + // belong to the previous footnote. + // + // > This is a block quote + // > Inside a footnote + // + // { some.code } + // + // The whole paragraph can be indented, or just the first + // line. In this way, multi-paragraph footnotes work like + // multi-paragraph list items. + // + // This paragraph won't be part of the note, because it + // isn't indented. + // + // Should be rendered as: + //

Here is a footnote reference,1 and another.2

+ //

This is another reference to 1

+ //

And another reference to 2

+ //

This paragraph won't be part of the note, because it + // isn't indented.

+ //
+ //
+ //
    + //
  1. + //

    Here is the footnote.

    + //
  2. + //
  3. + //

    Here's one with multiple blocks.

    + //

    Subsequent paragraphs are indented to show that they + // belong to the previous footnote.

    + //
    + //

    This is a block quote + // Inside a footnote

    + //
    + //
    { some.code }
    +            //     
    + //

    The whole paragraph can be indented, or just the first + // line. In this way, multi-paragraph footnotes work like + // multi-paragraph list items.

    + //
  4. + //
+ //
+ + Console.WriteLine("Example 1\nSection Extensions / Footnotes\n"); + TestParser.TestSpec("Here is a footnote reference,[^1] and another.[^longnote]\n\nThis is another reference to [^1]\n\n[^1]: Here is the footnote.\n\nAnd another reference to [^longnote]\n\n[^longnote]: Here's one with multiple blocks.\n\n Subsequent paragraphs are indented to show that they\nbelong to the previous footnote.\n\n > This is a block quote\n > Inside a footnote\n\n { some.code }\n\n The whole paragraph can be indented, or just the first\n line. In this way, multi-paragraph footnotes work like\n multi-paragraph list items.\n\nThis paragraph won't be part of the note, because it\nisn't indented.", "

Here is a footnote reference,1 and another.2

\n

This is another reference to 1

\n

And another reference to 2

\n

This paragraph won't be part of the note, because it\nisn't indented.

\n
\n
\n
    \n
  1. \n

    Here is the footnote.

    \n
  2. \n
  3. \n

    Here's one with multiple blocks.

    \n

    Subsequent paragraphs are indented to show that they\nbelong to the previous footnote.

    \n
    \n

    This is a block quote\nInside a footnote

    \n
    \n
    { some.code }\n
    \n

    The whole paragraph can be indented, or just the first\nline. In this way, multi-paragraph footnotes work like\nmulti-paragraph list items.

    \n
  4. \n
\n
", "footnotes|advanced"); + } + + // Check with mulitple consecutive footnotes: + [Test] + public void ExtensionsFootnotes_Example002() + { + // Example 2 + // Section: Extensions / Footnotes + // + // The following Markdown: + // Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4]. + // + // [^1]: Footnote 1 text + // + // [^2]: Footnote 2 text + // + // a + // + // [^3]: Footnote 3 text + // + // [^4]: Footnote 4 text + // + // Should be rendered as: + //

Here is a footnote1. And another one2. And a third one3. And a fourth4.

+ //

a

+ //
+ //
+ //
    + //
  1. + //

    Footnote 1 text

  2. + //
  3. + //

    Footnote 2 text

  4. + //
  5. + //

    Footnote 3 text

  6. + //
  7. + //

    Footnote 4 text

  8. + //
+ //
+ + Console.WriteLine("Example 2\nSection Extensions / Footnotes\n"); + TestParser.TestSpec("Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4].\n\n[^1]: Footnote 1 text\n\n[^2]: Footnote 2 text\n\na\n\n[^3]: Footnote 3 text\n\n[^4]: Footnote 4 text", "

Here is a footnote1. And another one2. And a third one3. And a fourth4.

\n

a

\n
\n
\n
    \n
  1. \n

    Footnote 1 text

  2. \n
  3. \n

    Footnote 2 text

  4. \n
  5. \n

    Footnote 3 text

  6. \n
  7. \n

    Footnote 4 text

  8. \n
\n
", "footnotes|advanced"); + } + + // Another test with consecutive footnotes without a blank line separator: + [Test] + public void ExtensionsFootnotes_Example003() + { + // Example 3 + // Section: Extensions / Footnotes + // + // The following Markdown: + // Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4]. + // + // [^1]: Footnote 1 text + // [^2]: Footnote 2 text + // [^3]: Footnote 3 text + // [^4]: Footnote 4 text + // + // Should be rendered as: + //

Here is a footnote1. And another one2. And a third one3. And a fourth4.

+ //
+ //
+ //
    + //
  1. + //

    Footnote 1 text

  2. + //
  3. + //

    Footnote 2 text

  4. + //
  5. + //

    Footnote 3 text

  6. + //
  7. + //

    Footnote 4 text

  8. + //
+ //
+ + Console.WriteLine("Example 3\nSection Extensions / Footnotes\n"); + TestParser.TestSpec("Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4].\n\n[^1]: Footnote 1 text\n[^2]: Footnote 2 text\n[^3]: Footnote 3 text\n[^4]: Footnote 4 text", "

Here is a footnote1. And another one2. And a third one3. And a fourth4.

\n
\n
\n
    \n
  1. \n

    Footnote 1 text

  2. \n
  3. \n

    Footnote 2 text

  4. \n
  5. \n

    Footnote 3 text

  6. \n
  7. \n

    Footnote 4 text

  8. \n
\n
", "footnotes|advanced"); + } + + // A footnote link inside a list should work as well: + [Test] + public void ExtensionsFootnotes_Example004() + { + // Example 4 + // Section: Extensions / Footnotes + // + // The following Markdown: + // - abc + // - def[^1] + // + // [^1]: Here is the footnote. + // + // Should be rendered as: + //
    + //
  • abc
  • + //
  • def1
  • + //
+ //
+ //
+ //
    + //
  1. + //

    Here is the footnote.

  2. + //
+ //
+ + Console.WriteLine("Example 4\nSection Extensions / Footnotes\n"); + TestParser.TestSpec("- abc\n- def[^1]\n\n[^1]: Here is the footnote.", "
    \n
  • abc
  • \n
  • def1
  • \n
\n
\n
\n
    \n
  1. \n

    Here is the footnote.

  2. \n
\n
", "footnotes|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/GenericAttributesSpecs.cs b/src/Markdig.Tests/Specs/GenericAttributesSpecs.cs new file mode 100644 index 00000000..ac0e785b --- /dev/null +++ b/src/Markdig.Tests/Specs/GenericAttributesSpecs.cs @@ -0,0 +1,83 @@ +// Generated: 21. 01. 2019 15:02:43 + +// -------------------------------- +// Generic Attributes +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.GenericAttributes +{ + [TestFixture] + public class TestExtensionsGenericAttributes + { + // # Extensions + // + // This section describes the different extensions supported: + // + // ## Generic Attributes + // + // Attributes can be attached to: + // - The previous inline element if the previous element is not a literal + // - The next block if the current block is a paragraph and the attributes is the only inline present in the paragraph + // - Or the current block + // + // Attributes can be of 3 kinds: + // + // - An id element, starting by `#` that will be used to set the `id` property of the HTML element + // - A class element, starting by `.` that will be appended to the CSS class property of the HTML element + // - a `name=value` or `name="value"` that will be appended as an attribute of the HTML element + // + // The following shows that attributes is attached to the current block or the previous inline: + [Test] + public void ExtensionsGenericAttributes_Example001() + { + // Example 1 + // Section: Extensions / Generic Attributes + // + // The following Markdown: + // # This is a heading with an an attribute{#heading-link} + // + // # This is a heading # {#heading-link2} + // + // [This is a link](http://google.com){#a-link .myclass data-lang=fr data-value="This is a value"} + // + // This is a heading{#heading-link2} + // ----------------- + // + // This is a paragraph with an attached attributes {#myparagraph attached-bool-property attached-bool-property2} + // + // Should be rendered as: + //

This is a heading with an an attribute

+ //

This is a heading

+ //

This is a link

+ //

This is a heading

+ //

This is a paragraph with an attached attributes

+ + Console.WriteLine("Example 1\nSection Extensions / Generic Attributes\n"); + TestParser.TestSpec("# This is a heading with an an attribute{#heading-link}\n\n# This is a heading # {#heading-link2}\n\n[This is a link](http://google.com){#a-link .myclass data-lang=fr data-value=\"This is a value\"}\n\nThis is a heading{#heading-link2}\n-----------------\n\nThis is a paragraph with an attached attributes {#myparagraph attached-bool-property attached-bool-property2}", "

This is a heading with an an attribute

\n

This is a heading

\n

This is a link

\n

This is a heading

\n

This is a paragraph with an attached attributes

", "attributes|advanced"); + } + + // The following shows that attributes can be attached to the next block if they are used inside a single line just preceding the block (and preceded by a blank line or beginning of a block container): + [Test] + public void ExtensionsGenericAttributes_Example002() + { + // Example 2 + // Section: Extensions / Generic Attributes + // + // The following Markdown: + // {#fenced-id .fenced-class} + // ~~~ + // This is a fenced with attached attributes + // ~~~ + // + // Should be rendered as: + //
This is a fenced with attached attributes
+            //     
+ + Console.WriteLine("Example 2\nSection Extensions / Generic Attributes\n"); + TestParser.TestSpec("{#fenced-id .fenced-class}\n~~~\nThis is a fenced with attached attributes\n~~~ ", "
This is a fenced with attached attributes\n
", "attributes|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/GenericAttributesSpecs.md b/src/Markdig.Tests/Specs/GenericAttributesSpecs.md index defd2ee2..1cb7bd00 100644 --- a/src/Markdig.Tests/Specs/GenericAttributesSpecs.md +++ b/src/Markdig.Tests/Specs/GenericAttributesSpecs.md @@ -33,7 +33,7 @@ This is a paragraph with an attached attributes {#myparagraph attached-bool-prop

This is a heading

This is a link

This is a heading

-

This is a paragraph with an attached attributes

+

This is a paragraph with an attached attributes

```````````````````````````````` The following shows that attributes can be attached to the next block if they are used inside a single line just preceding the block (and preceded by a blank line or beginning of a block container): diff --git a/src/Markdig.Tests/Specs/GlobalizationSpecs.cs b/src/Markdig.Tests/Specs/GlobalizationSpecs.cs new file mode 100644 index 00000000..60325f21 --- /dev/null +++ b/src/Markdig.Tests/Specs/GlobalizationSpecs.cs @@ -0,0 +1,234 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Globalization +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.Globalization +{ + [TestFixture] + public class TestExtensionsGlobalization + { + // # Extensions + // + // This section describes the different extensions supported: + // + // ## Globalization + // Adds support for RTL content by adding `dir="rtl"` and `align="right` attributes to the appropriate html elements. Left to right text is not affected by this extension. + // + // Whether a markdown block is marked as RTL or not is determined by the [first strong character](https://en.wikipedia.org/wiki/Bi-directional_text#Strong_characters) of the block. + // + // **Note**: You might need to add `` to the head of the html file to be able to see the result correctly. + // + // Headings and block quotes: + [Test] + public void ExtensionsGlobalization_Example001() + { + // Example 1 + // Section: Extensions / Globalization + // + // The following Markdown: + // # Fruits + // In botany, a [fruit](https://en.wikipedia.org/wiki/Fruit) is the seed-bearing structure in flowering plants (also known as angiosperms) formed from the ovary after flowering. + // + // > Fruits are good for health + // -- Anonymous + // + // # میوە + // [میوە](https://ckb.wikipedia.org/wiki/%D9%85%DB%8C%D9%88%DB%95) یان مێوە بەروبوومی ڕوەکیە کە ڕوەکەکان ھەڵیان ئەگرن وەک بەرگێک بۆ تۆوەکانیان، بە زۆری جیادەکرێتەوە بە شیرینی یان ترشی لە تامدا و بە بوونی بڕێکی زۆر ئاو + // + // > میوە بۆ تەندروستی باشە + // -- نەزانراو + // + // Should be rendered as: + //

Fruits

+ //

In botany, a fruit is the seed-bearing structure in flowering plants (also known as angiosperms) formed from the ovary after flowering.

+ //
+ //

Fruits are good for health + // -- Anonymous

+ //
+ //

میوە

+ //

میوە یان مێوە بەروبوومی ڕوەکیە کە ڕوەکەکان ھەڵیان ئەگرن وەک بەرگێک بۆ تۆوەکانیان، بە زۆری جیادەکرێتەوە بە شیرینی یان ترشی لە تامدا و بە بوونی بڕێکی زۆر ئاو

+ //
+ //

میوە بۆ تەندروستی باشە + // -- نەزانراو

+ //
+ + Console.WriteLine("Example 1\nSection Extensions / Globalization\n"); + TestParser.TestSpec("# Fruits\nIn botany, a [fruit](https://en.wikipedia.org/wiki/Fruit) is the seed-bearing structure in flowering plants (also known as angiosperms) formed from the ovary after flowering.\n\n> Fruits are good for health\n-- Anonymous\n\n# میوە\n[میوە](https://ckb.wikipedia.org/wiki/%D9%85%DB%8C%D9%88%DB%95) یان مێوە بەروبوومی ڕوەکیە کە ڕوەکەکان ھەڵیان ئەگرن وەک بەرگێک بۆ تۆوەکانیان، بە زۆری جیادەکرێتەوە بە شیرینی یان ترشی لە تامدا و بە بوونی بڕێکی زۆر ئاو\n\n> میوە بۆ تەندروستی باشە\n-- نەزانراو", "

Fruits

\n

In botany, a fruit is the seed-bearing structure in flowering plants (also known as angiosperms) formed from the ovary after flowering.

\n
\n

Fruits are good for health\n-- Anonymous

\n
\n

میوە

\n

میوە یان مێوە بەروبوومی ڕوەکیە کە ڕوەکەکان ھەڵیان ئەگرن وەک بەرگێک بۆ تۆوەکانیان، بە زۆری جیادەکرێتەوە بە شیرینی یان ترشی لە تامدا و بە بوونی بڕێکی زۆر ئاو

\n
\n

میوە بۆ تەندروستی باشە\n-- نەزانراو

\n
", "globalization+advanced+emojis"); + } + + // Lists: + [Test] + public void ExtensionsGlobalization_Example002() + { + // Example 2 + // Section: Extensions / Globalization + // + // The following Markdown: + // ## Types of fruits + // - Berries + // - Strawberry + // - kiwifruit + // - Citrus + // - Orange + // - Lemon + // + // ## Examples of fruits :yum: + // 1. Apple + // 2. Banana + // 3. Orange + // + // ## Grocery List + // - [X] 􏿽 Watermelon + // - [X] Apricot + // - [ ] Fig + // + // ## نموونەی میوە :yum: + // 1. ? سێو + // 2. 5 مۆز + // 3. 􏿽 پرتەقاڵ + // + // ## جۆرەکانی میوە + // - توو + // - فڕاولە + // - کیوی + // - مزرەمەنی + // - پڕتەقاڵ + // - لیمۆ + // + // ## لیستی کڕین + // - [X] شووتی + // - [X] قەیسی + // - [ ] هەنجیر + // + // Should be rendered as: + //

Types of fruits

+ //
    + //
  • Berries + //
      + //
    • Strawberry
    • + //
    • kiwifruit
    • + //
    + //
  • + //
  • Citrus + //
      + //
    • Orange
    • + //
    • Lemon
    • + //
    + //
  • + //
+ //

Examples of fruits 😋

+ //
    + //
  1. Apple
  2. + //
  3. Banana
  4. + //
  5. Orange
  6. + //
+ //

Grocery List

+ //
    + //
  • 􏿽 Watermelon
  • + //
  • Apricot
  • + //
  • Fig
  • + //
+ //

نموونەی میوە 😋

+ //
    + //
  1. ? سێو
  2. + //
  3. 5 مۆز
  4. + //
  5. 􏿽 پرتەقاڵ
  6. + //
+ //

جۆرەکانی میوە

+ //
    + //
  • توو + //
      + //
    • فڕاولە
    • + //
    • کیوی
    • + //
    + //
  • + //
  • مزرەمەنی + //
      + //
    • پڕتەقاڵ
    • + //
    • لیمۆ
    • + //
    + //
  • + //
+ //

لیستی کڕین

+ //
    + //
  • شووتی
  • + //
  • قەیسی
  • + //
  • هەنجیر
  • + //
+ + Console.WriteLine("Example 2\nSection Extensions / Globalization\n"); + TestParser.TestSpec("## Types of fruits\n- Berries\n - Strawberry\n - kiwifruit\n- Citrus\n - Orange\n - Lemon\n\n## Examples of fruits :yum:\n1. Apple\n2. Banana\n3. Orange\n\n## Grocery List\n- [X] 􏿽 Watermelon\n- [X] Apricot\n- [ ] Fig \n\n## نموونەی میوە :yum:\n1. ? سێو\n2. 5 مۆز \n3. 􏿽 پرتەقاڵ\n\n## جۆرەکانی میوە\n- توو\n - فڕاولە\n - کیوی\n- مزرەمەنی\n - پڕتەقاڵ\n - لیمۆ\n\n## لیستی کڕین\n- [X] شووتی\n- [X] قەیسی\n- [ ] هەنجیر", "

Types of fruits

\n
    \n
  • Berries\n
      \n
    • Strawberry
    • \n
    • kiwifruit
    • \n
    \n
  • \n
  • Citrus\n
      \n
    • Orange
    • \n
    • Lemon
    • \n
    \n
  • \n
\n

Examples of fruits 😋

\n
    \n
  1. Apple
  2. \n
  3. Banana
  4. \n
  5. Orange
  6. \n
\n

Grocery List

\n
    \n
  • 􏿽 Watermelon
  • \n
  • Apricot
  • \n
  • Fig
  • \n
\n

نموونەی میوە 😋

\n
    \n
  1. ? سێو
  2. \n
  3. 5 مۆز
  4. \n
  5. 􏿽 پرتەقاڵ
  6. \n
\n

جۆرەکانی میوە

\n
    \n
  • توو\n
      \n
    • فڕاولە
    • \n
    • کیوی
    • \n
    \n
  • \n
  • مزرەمەنی\n
      \n
    • پڕتەقاڵ
    • \n
    • لیمۆ
    • \n
    \n
  • \n
\n

لیستی کڕین

\n
    \n
  • شووتی
  • \n
  • قەیسی
  • \n
  • هەنجیر
  • \n
", "globalization+advanced+emojis"); + } + + // Tables: + [Test] + public void ExtensionsGlobalization_Example003() + { + // Example 3 + // Section: Extensions / Globalization + // + // The following Markdown: + // Nuitrion |Apple | Oranges + // --|-- | -- + // Calories|52|47 + // Sugar|10g|9g + // + // پێکهاتە |سێو | پڕتەقاڵ + // --|-- | -- + // کالۆری|٥٢|٤٧ + // شەکر| ١٠گ|٩گ + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
NuitrionAppleOranges
Calories5247
Sugar10g9g
+ // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
پێکهاتەسێوپڕتەقاڵ
کالۆری٥٢٤٧
شەکر١٠گ٩گ
+ + Console.WriteLine("Example 3\nSection Extensions / Globalization\n"); + TestParser.TestSpec("Nuitrion |Apple | Oranges\n--|-- | --\nCalories|52|47\nSugar|10g|9g\n\n پێکهاتە |سێو | پڕتەقاڵ\n--|-- | --\nکالۆری|٥٢|٤٧\nشەکر| ١٠گ|٩گ", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
NuitrionAppleOranges
Calories5247
Sugar10g9g
\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
پێکهاتەسێوپڕتەقاڵ
کالۆری٥٢٤٧
شەکر١٠گ٩گ
", "globalization+advanced+emojis"); + } + } +} diff --git a/src/Markdig.Tests/Specs/GridTableSpecs.cs b/src/Markdig.Tests/Specs/GridTableSpecs.cs new file mode 100644 index 00000000..d1aab5a4 --- /dev/null +++ b/src/Markdig.Tests/Specs/GridTableSpecs.cs @@ -0,0 +1,399 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Grid Tables +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.GridTables +{ + [TestFixture] + public class TestExtensionsGridTable + { + // # Extensions + // + // This section describes the different extensions supported: + // + // ## Grid Table + // + // A grid table allows to have multiple lines per cells and allows to span cells over multiple columns. The following shows a simple grid table + // + // ``` + // +---------+---------+ + // | Header | Header | + // | Column1 | Column2 | + // +=========+=========+ + // | 1. ab | > This is a quote + // | 2. cde | > For the second column + // | 3. f | + // +---------+---------+ + // | Second row spanning + // | on two columns + // +---------+---------+ + // | Back | | + // | to | | + // | one | | + // | column | | + // ``` + // + // **Rule #1** + // The first line of a grid table must a **row separator**. It must start with the column separator character `+` used to separate columns in a row separator. Each column separator is: + // - starting by optional spaces + // - followed by an optional `:` to specify left align, followed by optional spaces + // - followed by a sequence of at least one `-` character, followed by optional spaces + // - followed by an optional `:` to specify right align (or center align if left align is also defined) + // - ending by optional spaces + // + // The first row separator must be followed by a *regular row*. A regular row must start with the character `|` that is starting at the same position than the column separator `+` of the first row separator. + // + // + // The following is a valid row separator + [Test] + public void ExtensionsGridTable_Example001() + { + // Example 1 + // Section: Extensions / Grid Table + // + // The following Markdown: + // +---------+---------+ + // | This is | a table | + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + //
This isa table
+ + Console.WriteLine("Example 1\nSection Extensions / Grid Table\n"); + TestParser.TestSpec("+---------+---------+\n| This is | a table |", "\n\n\n\n\n\n\n\n\n
This isa table
", "gridtables|advanced"); + } + + // The following is not a valid row separator + [Test] + public void ExtensionsGridTable_Example002() + { + // Example 2 + // Section: Extensions / Grid Table + // + // The following Markdown: + // |-----xxx----+---------+ + // | This is | not a table + // + // Should be rendered as: + //

|-----xxx----+---------+ + // | This is | not a table

+ + Console.WriteLine("Example 2\nSection Extensions / Grid Table\n"); + TestParser.TestSpec("|-----xxx----+---------+\n| This is | not a table", "

|-----xxx----+---------+\n| This is | not a table

", "gridtables|advanced"); + } + + // **Rule #2** + // A regular row can continue a previous regular row when column separator `|` are positioned at the same position than the previous line. If they are positioned at the same location, the column may span over multiple columns: + [Test] + public void ExtensionsGridTable_Example003() + { + // Example 3 + // Section: Extensions / Grid Table + // + // The following Markdown: + // +---------+---------+---------+ + // | Col1 | Col2 | Col3 | + // | Col1a | Col2a | Col3a | + // | Col1b | Col3b | + // | Col1c | + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
Col1 + // Col1aCol2 + // Col2aCol3 + // Col3a
Col1bCol3b
Col1c
+ + Console.WriteLine("Example 3\nSection Extensions / Grid Table\n"); + TestParser.TestSpec("+---------+---------+---------+\n| Col1 | Col2 | Col3 |\n| Col1a | Col2a | Col3a |\n| Col1b | Col3b |\n| Col1c |", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
Col1\nCol1aCol2\nCol2aCol3\nCol3a
Col1bCol3b
Col1c
", "gridtables|advanced"); + } + + // A row header is separated using `+========+` instead of `+---------+`: + [Test] + public void ExtensionsGridTable_Example004() + { + // Example 4 + // Section: Extensions / Grid Table + // + // The following Markdown: + // +---------+---------+ + // | This is | a table | + // +=========+=========+ + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + //
This isa table
+ + Console.WriteLine("Example 4\nSection Extensions / Grid Table\n"); + TestParser.TestSpec("+---------+---------+\n| This is | a table |\n+=========+=========+", "\n\n\n\n\n\n\n\n\n
This isa table
", "gridtables|advanced"); + } + + // The last column separator `|` may be omitted: + [Test] + public void ExtensionsGridTable_Example005() + { + // Example 5 + // Section: Extensions / Grid Table + // + // The following Markdown: + // +---------+---------+ + // | This is | a table with a longer text in the second column + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + //
This isa table with a longer text in the second column
+ + Console.WriteLine("Example 5\nSection Extensions / Grid Table\n"); + TestParser.TestSpec("+---------+---------+\n| This is | a table with a longer text in the second column", "\n\n\n\n\n\n\n\n\n
This isa table with a longer text in the second column
", "gridtables|advanced"); + } + + // The respective width of the columns are calculated from the ratio between the total size of the first table row without counting the `+`: `+----+--------+----+` would be divided between: + // + // Total size is : 16 + // + // - `----` -> 4 + // - `--------` -> 8 + // - `----` -> 4 + // + // So the width would be 4/16 = 25%, 8/16 = 50%, 4/16 = 25% + [Test] + public void ExtensionsGridTable_Example006() + { + // Example 6 + // Section: Extensions / Grid Table + // + // The following Markdown: + // +----+--------+----+ + // | A | B C D | E | + // +----+--------+----+ + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + //
AB C DE
+ + Console.WriteLine("Example 6\nSection Extensions / Grid Table\n"); + TestParser.TestSpec("+----+--------+----+\n| A | B C D | E |\n+----+--------+----+", "\n\n\n\n\n\n\n\n\n\n\n
AB C DE
", "gridtables|advanced"); + } + + // Alignment might be specified on the first row using the character `:`: + [Test] + public void ExtensionsGridTable_Example007() + { + // Example 7 + // Section: Extensions / Grid Table + // + // The following Markdown: + // +-----+:---:+-----+ + // | A | B | C | + // +-----+-----+-----+ + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + //
ABC
+ + Console.WriteLine("Example 7\nSection Extensions / Grid Table\n"); + TestParser.TestSpec("+-----+:---:+-----+\n| A | B | C |\n+-----+-----+-----+", "\n\n\n\n\n\n\n\n\n\n\n
ABC
", "gridtables|advanced"); + } + + // A grid table may have cells spanning both columns and rows: + [Test] + public void ExtensionsGridTable_Example008() + { + // Example 8 + // Section: Extensions / Grid Table + // + // The following Markdown: + // +---+---+---+ + // | AAAAA | B | + // +---+---+ B + + // | D | E | B | + // + D +---+---+ + // | D | CCCCC | + // +---+---+---+ + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
AAAAAB + // B + // B
D + // D + // DE
CCCCC
+ + Console.WriteLine("Example 8\nSection Extensions / Grid Table\n"); + TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+---+---+ B +\n| D | E | B |\n+ D +---+---+\n| D | CCCCC |\n+---+---+---+", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
AAAAAB\nB\nB
D\nD\nDE
CCCCC
", "gridtables|advanced"); + } + + // A grid table may have cells with both colspan and rowspan: + [Test] + public void ExtensionsGridTable_Example009() + { + // Example 9 + // Section: Extensions / Grid Table + // + // The following Markdown: + // +---+---+---+ + // | AAAAA | B | + // + AAAAA +---+ + // | AAAAA | C | + // +---+---+---+ + // | D | E | F | + // +---+---+---+ + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
AAAAA + // AAAAA + // AAAAAB
C
DEF
+ + Console.WriteLine("Example 9\nSection Extensions / Grid Table\n"); + TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+ AAAAA +---+\n| AAAAA | C |\n+---+---+---+\n| D | E | F |\n+---+---+---+", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
AAAAA\nAAAAA\nAAAAAB
C
DEF
", "gridtables|advanced"); + } + + // A grid table may not have irregularly shaped cells: + [Test] + public void ExtensionsGridTable_Example010() + { + // Example 10 + // Section: Extensions / Grid Table + // + // The following Markdown: + // +---+---+---+ + // | AAAAA | B | + // + A +---+ B + + // | A | C | B | + // +---+---+---+ + // | DDDDD | E | + // +---+---+---+ + // + // Should be rendered as: + //

+---+---+---+ + // | AAAAA | B | + // + A +---+ B + + // | A | C | B | + // +---+---+---+ + // | DDDDD | E | + // +---+---+---+

+ + Console.WriteLine("Example 10\nSection Extensions / Grid Table\n"); + TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+ A +---+ B +\n| A | C | B |\n+---+---+---+\n| DDDDD | E |\n+---+---+---+", "

+---+---+---+\n| AAAAA | B |\n+ A +---+ B +\n| A | C | B |\n+---+---+---+\n| DDDDD | E |\n+---+---+---+

", "gridtables|advanced"); + } + + // An empty `+` on a line should result in a simple empty list output: + [Test] + public void ExtensionsGridTable_Example011() + { + // Example 11 + // Section: Extensions / Grid Table + // + // The following Markdown: + // + + // + // Should be rendered as: + //
    + //
  • + //
+ + Console.WriteLine("Example 11\nSection Extensions / Grid Table\n"); + TestParser.TestSpec("+", "
    \n
  • \n
", "gridtables|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/HardlineBreakSpecs.cs b/src/Markdig.Tests/Specs/HardlineBreakSpecs.cs new file mode 100644 index 00000000..b008336d --- /dev/null +++ b/src/Markdig.Tests/Specs/HardlineBreakSpecs.cs @@ -0,0 +1,40 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Hardline Breaks +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.HardlineBreaks +{ + [TestFixture] + public class TestExtensionsHardlineBreak + { + // # Extensions + // + // This section describes the different extensions supported: + // + // ## Hardline break + // + // When this extension is used, a new line in a paragraph block will result in a hardline break `
`: + [Test] + public void ExtensionsHardlineBreak_Example001() + { + // Example 1 + // Section: Extensions / Hardline break + // + // The following Markdown: + // This is a paragraph + // with a break inside + // + // Should be rendered as: + //

This is a paragraph
+ // with a break inside

+ + Console.WriteLine("Example 1\nSection Extensions / Hardline break\n"); + TestParser.TestSpec("This is a paragraph\nwith a break inside", "

This is a paragraph
\nwith a break inside

", "hardlinebreak|advanced+hardlinebreak"); + } + } +} diff --git a/src/Markdig.Tests/Specs/JiraLinks.cs b/src/Markdig.Tests/Specs/JiraLinks.cs new file mode 100644 index 00000000..8de4c9b5 --- /dev/null +++ b/src/Markdig.Tests/Specs/JiraLinks.cs @@ -0,0 +1,180 @@ +// Generated: 21. 01. 2019 14:22:45 + +// -------------------------------- +// Jira Links +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.JiraLinks +{ + [TestFixture] + public class TestJiraLinks + { + // ## Jira Links + // + // The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g. + // + // ``` + // var pipeline = new MarkdownPipelineBuilder() + // .UseJiraLinks(new JiraLinkOptions("http://your.company.abc")) + // .Build(); + // ``` + // + // The rules for detecting a link are: + // + // - The project key must be composed of onre or more capitalised ASCII letter `[A-Z]+` + // - A single hypen `-` must separate the project key and issue number. + // - The issue number is composed of 1 or more digits `[0, 9]+` + // - The reference must be preceeded by either `(` or whitespace or EOF. + // - The reference must be followed by either `)` or whitespace or EOF. + // + // The following are valid examples: + [Test] + public void JiraLinks_Example001() + { + // Example 1 + // Section: Jira Links + // + // The following Markdown: + // This is a ABCD-123 issue + // + // Should be rendered as: + //

This is a ABCD-123 issue

+ + Console.WriteLine("Example 1\nSection Jira Links\n"); + TestParser.TestSpec("This is a ABCD-123 issue", "

This is a ABCD-123 issue

", "jiralinks"); + } + + [Test] + public void JiraLinks_Example002() + { + // Example 2 + // Section: Jira Links + // + // The following Markdown: + // This is a KIRA-1 issue + // + // Should be rendered as: + //

This is a KIRA-1 issue

+ + Console.WriteLine("Example 2\nSection Jira Links\n"); + TestParser.TestSpec("This is a KIRA-1 issue", "

This is a KIRA-1 issue

", "jiralinks"); + } + + [Test] + public void JiraLinks_Example003() + { + // Example 3 + // Section: Jira Links + // + // The following Markdown: + // This is a Z-1 issue + // + // Should be rendered as: + //

This is a Z-1 issue

+ + Console.WriteLine("Example 3\nSection Jira Links\n"); + TestParser.TestSpec("This is a Z-1 issue", "

This is a Z-1 issue

", "jiralinks"); + } + + // These are also valid links with `(` and `)`: + [Test] + public void JiraLinks_Example004() + { + // Example 4 + // Section: Jira Links + // + // The following Markdown: + // This is a (ABCD-123) issue + // + // Should be rendered as: + //

This is a (ABCD-123) issue

+ + Console.WriteLine("Example 4\nSection Jira Links\n"); + TestParser.TestSpec("This is a (ABCD-123) issue", "

This is a (ABCD-123) issue

", "jiralinks"); + } + + [Test] + public void JiraLinks_Example005() + { + // Example 5 + // Section: Jira Links + // + // The following Markdown: + // This is a (KIRA-1) issue + // + // Should be rendered as: + //

This is a (KIRA-1) issue

+ + Console.WriteLine("Example 5\nSection Jira Links\n"); + TestParser.TestSpec("This is a (KIRA-1) issue", "

This is a (KIRA-1) issue

", "jiralinks"); + } + + [Test] + public void JiraLinks_Example006() + { + // Example 6 + // Section: Jira Links + // + // The following Markdown: + // This is a (Z-1) issue + // + // Should be rendered as: + //

This is a (Z-1) issue

+ + Console.WriteLine("Example 6\nSection Jira Links\n"); + TestParser.TestSpec("This is a (Z-1) issue", "

This is a (Z-1) issue

", "jiralinks"); + } + + // These are not valid links: + [Test] + public void JiraLinks_Example007() + { + // Example 7 + // Section: Jira Links + // + // The following Markdown: + // This is not aJIRA-123 issue + // + // Should be rendered as: + //

This is not aJIRA-123 issue

+ + Console.WriteLine("Example 7\nSection Jira Links\n"); + TestParser.TestSpec("This is not aJIRA-123 issue", "

This is not aJIRA-123 issue

", "jiralinks"); + } + + [Test] + public void JiraLinks_Example008() + { + // Example 8 + // Section: Jira Links + // + // The following Markdown: + // This is not JIRA-123a issue + // + // Should be rendered as: + //

This is not JIRA-123a issue

+ + Console.WriteLine("Example 8\nSection Jira Links\n"); + TestParser.TestSpec("This is not JIRA-123a issue", "

This is not JIRA-123a issue

", "jiralinks"); + } + + [Test] + public void JiraLinks_Example009() + { + // Example 9 + // Section: Jira Links + // + // The following Markdown: + // This is not JIRA- issue + // + // Should be rendered as: + //

This is not JIRA- issue

+ + Console.WriteLine("Example 9\nSection Jira Links\n"); + TestParser.TestSpec("This is not JIRA- issue", "

This is not JIRA- issue

", "jiralinks"); + } + } +} diff --git a/src/Markdig.Tests/Specs/ListExtraSpecs.cs b/src/Markdig.Tests/Specs/ListExtraSpecs.cs new file mode 100644 index 00000000..33c6e15a --- /dev/null +++ b/src/Markdig.Tests/Specs/ListExtraSpecs.cs @@ -0,0 +1,217 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// List Extras +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.ListExtras +{ + [TestFixture] + public class TestExtensionsOrderedListWithAlphaLetter + { + // # Extensions + // + // The following additional list items are supported: + // + // ## Ordered list with alpha letter + // + // Allows to use a list using an alpha letter instead of a number + [Test] + public void ExtensionsOrderedListWithAlphaLetter_Example001() + { + // Example 1 + // Section: Extensions / Ordered list with alpha letter + // + // The following Markdown: + // a. First item + // b. Second item + // c. Last item + // + // Should be rendered as: + //
    + //
  1. First item
  2. + //
  3. Second item
  4. + //
  5. Last item
  6. + //
+ + Console.WriteLine("Example 1\nSection Extensions / Ordered list with alpha letter\n"); + TestParser.TestSpec("a. First item\nb. Second item\nc. Last item", "
    \n
  1. First item
  2. \n
  3. Second item
  4. \n
  5. Last item
  6. \n
", "listextras|advanced"); + } + + // It works also for uppercase alpha: + [Test] + public void ExtensionsOrderedListWithAlphaLetter_Example002() + { + // Example 2 + // Section: Extensions / Ordered list with alpha letter + // + // The following Markdown: + // A. First item + // B. Second item + // C. Last item + // + // Should be rendered as: + //
    + //
  1. First item
  2. + //
  3. Second item
  4. + //
  5. Last item
  6. + //
+ + Console.WriteLine("Example 2\nSection Extensions / Ordered list with alpha letter\n"); + TestParser.TestSpec("A. First item\nB. Second item\nC. Last item", "
    \n
  1. First item
  2. \n
  3. Second item
  4. \n
  5. Last item
  6. \n
", "listextras|advanced"); + } + + // Like for numbered list, a list can start with a different letter + [Test] + public void ExtensionsOrderedListWithAlphaLetter_Example003() + { + // Example 3 + // Section: Extensions / Ordered list with alpha letter + // + // The following Markdown: + // b. First item + // c. Second item + // + // Should be rendered as: + //
    + //
  1. First item
  2. + //
  3. Second item
  4. + //
+ + Console.WriteLine("Example 3\nSection Extensions / Ordered list with alpha letter\n"); + TestParser.TestSpec("b. First item\nc. Second item", "
    \n
  1. First item
  2. \n
  3. Second item
  4. \n
", "listextras|advanced"); + } + + // A different type of list will break the existing list: + [Test] + public void ExtensionsOrderedListWithAlphaLetter_Example004() + { + // Example 4 + // Section: Extensions / Ordered list with alpha letter + // + // The following Markdown: + // a. First item1 + // b. Second item + // A. First item2 + // + // Should be rendered as: + //
    + //
  1. First item1
  2. + //
  3. Second item
  4. + //
+ //
    + //
  1. First item2
  2. + //
+ + Console.WriteLine("Example 4\nSection Extensions / Ordered list with alpha letter\n"); + TestParser.TestSpec("a. First item1\nb. Second item\nA. First item2", "
    \n
  1. First item1
  2. \n
  3. Second item
  4. \n
\n
    \n
  1. First item2
  2. \n
", "listextras|advanced"); + } + } + + [TestFixture] + public class TestExtensionsOrderedListWithRomanLetter + { + // ## Ordered list with roman letter + // + // Allows to use a list using a roman number instead of a number. + [Test] + public void ExtensionsOrderedListWithRomanLetter_Example005() + { + // Example 5 + // Section: Extensions / Ordered list with roman letter + // + // The following Markdown: + // i. First item + // ii. Second item + // iii. Third item + // iv. Last item + // + // Should be rendered as: + //
    + //
  1. First item
  2. + //
  3. Second item
  4. + //
  5. Third item
  6. + //
  7. Last item
  8. + //
+ + Console.WriteLine("Example 5\nSection Extensions / Ordered list with roman letter\n"); + TestParser.TestSpec("i. First item\nii. Second item\niii. Third item\niv. Last item", "
    \n
  1. First item
  2. \n
  3. Second item
  4. \n
  5. Third item
  6. \n
  7. Last item
  8. \n
", "listextras|advanced"); + } + + // It works also for uppercase alpha: + [Test] + public void ExtensionsOrderedListWithRomanLetter_Example006() + { + // Example 6 + // Section: Extensions / Ordered list with roman letter + // + // The following Markdown: + // I. First item + // II. Second item + // III. Third item + // IV. Last item + // + // Should be rendered as: + //
    + //
  1. First item
  2. + //
  3. Second item
  4. + //
  5. Third item
  6. + //
  7. Last item
  8. + //
+ + Console.WriteLine("Example 6\nSection Extensions / Ordered list with roman letter\n"); + TestParser.TestSpec("I. First item\nII. Second item\nIII. Third item\nIV. Last item", "
    \n
  1. First item
  2. \n
  3. Second item
  4. \n
  5. Third item
  6. \n
  7. Last item
  8. \n
", "listextras|advanced"); + } + + // Like for numbered list, a list can start with a different letter + [Test] + public void ExtensionsOrderedListWithRomanLetter_Example007() + { + // Example 7 + // Section: Extensions / Ordered list with roman letter + // + // The following Markdown: + // ii. First item + // iii. Second item + // + // Should be rendered as: + //
    + //
  1. First item
  2. + //
  3. Second item
  4. + //
+ + Console.WriteLine("Example 7\nSection Extensions / Ordered list with roman letter\n"); + TestParser.TestSpec("ii. First item\niii. Second item", "
    \n
  1. First item
  2. \n
  3. Second item
  4. \n
", "listextras|advanced"); + } + + // Lists can be restarted, specifying the start point. + [Test] + public void ExtensionsOrderedListWithRomanLetter_Example008() + { + // Example 8 + // Section: Extensions / Ordered list with roman letter + // + // The following Markdown: + // 1. First item + // + // Some text + // + // 2. Second item + // + // Should be rendered as: + //
    + //
  1. First item
  2. + //
+ //

Some text

+ //
    + //
  1. Second item
  2. + //
+ + Console.WriteLine("Example 8\nSection Extensions / Ordered list with roman letter\n"); + TestParser.TestSpec("1. First item\n\nSome text\n\n2. Second item", "
    \n
  1. First item
  2. \n
\n

Some text

\n
    \n
  1. Second item
  2. \n
", "listextras|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/MathSpecs.cs b/src/Markdig.Tests/Specs/MathSpecs.cs new file mode 100644 index 00000000..383e350c --- /dev/null +++ b/src/Markdig.Tests/Specs/MathSpecs.cs @@ -0,0 +1,326 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Math +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.Math +{ + [TestFixture] + public class TestExtensionsMathInline + { + // # Extensions + // + // Adds support for mathematics spans: + // + // ## Math Inline + // + // Allows to define a mathematic block embraced by `$...$` + [Test] + public void ExtensionsMathInline_Example001() + { + // Example 1 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is a $math block$ + // + // Should be rendered as: + //

This is a math block

+ + Console.WriteLine("Example 1\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is a $math block$", "

This is a math block

", "mathematics|advanced"); + } + + // Or by `$$...$$` embracing it by: + [Test] + public void ExtensionsMathInline_Example002() + { + // Example 2 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is a $$math block$$ + // + // Should be rendered as: + //

This is a math block

+ + Console.WriteLine("Example 2\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is a $$math block$$", "

This is a math block

", "mathematics|advanced"); + } + + // Newlines inside an inline math are not allowed: + [Test] + public void ExtensionsMathInline_Example003() + { + // Example 3 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is not a $$math + // block$$ and? this is a $$math block$$ + // + // Should be rendered as: + //

This is not a $$math + // block$$ and? this is a math block

+ + Console.WriteLine("Example 3\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is not a $$math \nblock$$ and? this is a $$math block$$", "

This is not a $$math\nblock$$ and? this is a math block

", "mathematics|advanced"); + } + + [Test] + public void ExtensionsMathInline_Example004() + { + // Example 4 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is not a $math + // block$ and? this is a $math block$ + // + // Should be rendered as: + //

This is not a $math + // block$ and? this is a math block

+ + Console.WriteLine("Example 4\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is not a $math \nblock$ and? this is a $math block$", "

This is not a $math\nblock$ and? this is a math block

", "mathematics|advanced"); + } + + // An opening `$` can be followed by a space if the closing is also preceded by a space `$`: + [Test] + public void ExtensionsMathInline_Example005() + { + // Example 5 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is a $ math block $ + // + // Should be rendered as: + //

This is a math block

+ + Console.WriteLine("Example 5\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is a $ math block $", "

This is a math block

", "mathematics|advanced"); + } + + [Test] + public void ExtensionsMathInline_Example006() + { + // Example 6 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is a $ math block $ after + // + // Should be rendered as: + //

This is a math block after

+ + Console.WriteLine("Example 6\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is a $ math block $ after", "

This is a math block after

", "mathematics|advanced"); + } + + [Test] + public void ExtensionsMathInline_Example007() + { + // Example 7 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is a $$ math block $$ after + // + // Should be rendered as: + //

This is a math block after

+ + Console.WriteLine("Example 7\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is a $$ math block $$ after", "

This is a math block after

", "mathematics|advanced"); + } + + [Test] + public void ExtensionsMathInline_Example008() + { + // Example 8 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is a not $ math block$ because there is not a whitespace before the closing + // + // Should be rendered as: + //

This is a not $ math block$ because there is not a whitespace before the closing

+ + Console.WriteLine("Example 8\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is a not $ math block$ because there is not a whitespace before the closing", "

This is a not $ math block$ because there is not a whitespace before the closing

", "mathematics|advanced"); + } + + // For the opening `$` it requires a space or a punctuation before (but cannot be used within a word): + [Test] + public void ExtensionsMathInline_Example009() + { + // Example 9 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is not a m$ath block$ + // + // Should be rendered as: + //

This is not a m$ath block$

+ + Console.WriteLine("Example 9\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is not a m$ath block$", "

This is not a m$ath block$

", "mathematics|advanced"); + } + + // For the closing `$` it requires a space after or a punctuation (but cannot be preceded by a space and cannot be used within a word): + [Test] + public void ExtensionsMathInline_Example010() + { + // Example 10 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is not a $math bloc$k + // + // Should be rendered as: + //

This is not a $math bloc$k

+ + Console.WriteLine("Example 10\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is not a $math bloc$k", "

This is not a $math bloc$k

", "mathematics|advanced"); + } + + // For the closing `$` it requires a space after or a punctuation (but cannot be preceded by a space and cannot be used within a word): + [Test] + public void ExtensionsMathInline_Example011() + { + // Example 11 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is should not match a 16$ or a $15 + // + // Should be rendered as: + //

This is should not match a 16$ or a $15

+ + Console.WriteLine("Example 11\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is should not match a 16$ or a $15", "

This is should not match a 16$ or a $15

", "mathematics|advanced"); + } + + // A `$` can be escaped between a math inline block by using the escape `\\` + [Test] + public void ExtensionsMathInline_Example012() + { + // Example 12 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is a $math \$ block$ + // + // Should be rendered as: + //

This is a math \$ block

+ + Console.WriteLine("Example 12\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is a $math \\$ block$", "

This is a math \\$ block

", "mathematics|advanced"); + } + + // At most, two `$` will be matched for the opening and closing: + [Test] + public void ExtensionsMathInline_Example013() + { + // Example 13 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is a $$$math block$$$ + // + // Should be rendered as: + //

This is a $math block$

+ + Console.WriteLine("Example 13\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is a $$$math block$$$", "

This is a $math block$

", "mathematics|advanced"); + } + + // Regular text can come both before and after the math inline + [Test] + public void ExtensionsMathInline_Example014() + { + // Example 14 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is a $math block$ with text on both sides. + // + // Should be rendered as: + //

This is a math block with text on both sides.

+ + Console.WriteLine("Example 14\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is a $math block$ with text on both sides.", "

This is a math block with text on both sides.

", "mathematics|advanced"); + } + + // A mathematic block takes precedence over standard emphasis `*` `_`: + [Test] + public void ExtensionsMathInline_Example015() + { + // Example 15 + // Section: Extensions / Math Inline + // + // The following Markdown: + // This is *a $math* block$ + // + // Should be rendered as: + //

This is *a math* block

+ + Console.WriteLine("Example 15\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("This is *a $math* block$", "

This is *a math* block

", "mathematics|advanced"); + } + + // An opening $$ at the beginning of a line should not be interpreted as a Math block: + [Test] + public void ExtensionsMathInline_Example016() + { + // Example 16 + // Section: Extensions / Math Inline + // + // The following Markdown: + // $$ math $$ starting at a line + // + // Should be rendered as: + //

math starting at a line

+ + Console.WriteLine("Example 16\nSection Extensions / Math Inline\n"); + TestParser.TestSpec("$$ math $$ starting at a line", "

math starting at a line

", "mathematics|advanced"); + } + } + + [TestFixture] + public class TestExtensionsMathBlock + { + // ## Math Block + // + // The match block can spawn on multiple lines by having a $$ starting on a line. + // It is working as a fenced code block. + [Test] + public void ExtensionsMathBlock_Example017() + { + // Example 17 + // Section: Extensions / Math Block + // + // The following Markdown: + // $$ + // \begin{equation} + // \int_0^\infty \frac{x^3}{e^x-1}\,dx = \frac{\pi^4}{15} + // \label{eq:sample} + // \end{equation} + // $$ + // + // Should be rendered as: + //
\begin{equation} + // \int_0^\infty \frac{x^3}{e^x-1}\,dx = \frac{\pi^4}{15} + // \label{eq:sample} + // \end{equation} + //
+ + Console.WriteLine("Example 17\nSection Extensions / Math Block\n"); + TestParser.TestSpec("$$\n\\begin{equation}\n \\int_0^\\infty \\frac{x^3}{e^x-1}\\,dx = \\frac{\\pi^4}{15}\n \\label{eq:sample}\n\\end{equation}\n$$", "
\\begin{equation}\n \\int_0^\\infty \\frac{x^3}{e^x-1}\\,dx = \\frac{\\pi^4}{15}\n \\label{eq:sample}\n\\end{equation}\n
", "mathematics|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/MediaSpecs.cs b/src/Markdig.Tests/Specs/MediaSpecs.cs new file mode 100644 index 00000000..b9ae891a --- /dev/null +++ b/src/Markdig.Tests/Specs/MediaSpecs.cs @@ -0,0 +1,50 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Media +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.Media +{ + [TestFixture] + public class TestExtensionsMediaLinks + { + // # Extensions + // + // Adds support for media links: + // + // ## Media links + // + // Allows to embed audio/video links to popular website: + [Test] + public void ExtensionsMediaLinks_Example001() + { + // Example 1 + // Section: Extensions / Media links + // + // The following Markdown: + // ![Video1](https://www.youtube.com/watch?v=mswPy5bt3TQ) + // + // ![Video2](https://vimeo.com/8607834) + // + // ![Video3](https://sample.com/video.mp4) + // + // ![Audio4](https://music.yandex.ru/album/411845/track/4402274) + // + // ![Video5](https://ok.ru/video/26870090463) + // + // Should be rendered as: + //

+ //

+ //

+ //

+ //

+ + Console.WriteLine("Example 1\nSection Extensions / Media links\n"); + TestParser.TestSpec("![Video1](https://www.youtube.com/watch?v=mswPy5bt3TQ)\n\n![Video2](https://vimeo.com/8607834)\n\n![Video3](https://sample.com/video.mp4)\n\n![Audio4](https://music.yandex.ru/album/411845/track/4402274)\n\n![Video5](https://ok.ru/video/26870090463)", "

\n

\n

\n

\n

", "medialinks|advanced+medialinks"); + } + } +} diff --git a/src/Markdig.Tests/Specs/NoHtmlSpecs.cs b/src/Markdig.Tests/Specs/NoHtmlSpecs.cs new file mode 100644 index 00000000..114f5357 --- /dev/null +++ b/src/Markdig.Tests/Specs/NoHtmlSpecs.cs @@ -0,0 +1,59 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// No Html +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.NoHtml +{ + [TestFixture] + public class TestExtensionsNoHTML + { + // # Extensions + // + // ## NoHTML + // + // The extension DisableHtml allows to disable the parsing of HTML: + // + // For inline HTML: + [Test] + public void ExtensionsNoHTML_Example001() + { + // Example 1 + // Section: Extensions / NoHTML + // + // The following Markdown: + // this is some text + // + // Should be rendered as: + //

this is some text</td></tr>

+ + Console.WriteLine("Example 1\nSection Extensions / NoHTML\n"); + TestParser.TestSpec("this is some text", "

this is some text</td></tr>

", "nohtml"); + } + + // For Block HTML: + [Test] + public void ExtensionsNoHTML_Example002() + { + // Example 2 + // Section: Extensions / NoHTML + // + // The following Markdown: + //
+ // this is some text + //
+ // + // Should be rendered as: + //

<div> + // this is some text + // </div>

+ + Console.WriteLine("Example 2\nSection Extensions / NoHTML\n"); + TestParser.TestSpec("
\nthis is some text\n
", "

<div>\nthis is some text\n</div>

", "nohtml"); + } + } +} diff --git a/src/Markdig.Tests/Specs/PipeTableSpecs.cs b/src/Markdig.Tests/Specs/PipeTableSpecs.cs new file mode 100644 index 00000000..2a3994b7 --- /dev/null +++ b/src/Markdig.Tests/Specs/PipeTableSpecs.cs @@ -0,0 +1,855 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Pipe Tables +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.PipeTables +{ + [TestFixture] + public class TestExtensionsPipeTable + { + // # Extensions + // + // This section describes the different extensions supported: + // + // ## Pipe Table + // + // A pipe table is detected when: + // + // **Rule #1** + // - Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backstick \`) or a HTML inline. + // - The second row must separate the first header row from sub-sequent rows by containing a **header column separator** for each column separated by a column delimiter. A header column separator is: + // - starting by optional spaces + // - followed by an optional `:` to specify left align + // - followed by a sequence of at least one `-` character + // - followed by an optional `:` to specify right align (or center align if left align is also defined) + // - ending by optional spaces + // + // Because a list has a higher precedence than a pipe table, a table header row separator requires at least 2 dashes `--` to start a header row: + [Test] + public void ExtensionsPipeTable_Example001() + { + // Example 1 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b + // -- | - + // 0 | 1 + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
01
+ + Console.WriteLine("Example 1\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a | b\n-- | -\n0 | 1", "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
01
", "pipetables|advanced"); + } + + // The following is also considered as a table, even if the second line starts like a list: + [Test] + public void ExtensionsPipeTable_Example002() + { + // Example 2 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b + // - | - + // 0 | 1 + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
01
+ + Console.WriteLine("Example 2\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a | b\n- | -\n0 | 1", "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
01
", "pipetables|advanced"); + } + + // A pipe table with only one header row is allowed: + [Test] + public void ExtensionsPipeTable_Example003() + { + // Example 3 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b + // -- | -- + // + // Should be rendered as: + // + // + // + // + // + // + // + //
ab
+ + Console.WriteLine("Example 3\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a | b\n-- | --", "\n\n\n\n\n\n\n
ab
", "pipetables|advanced"); + } + + // After a row separator header, they will be interpreted as plain column: + [Test] + public void ExtensionsPipeTable_Example004() + { + // Example 4 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b + // -- | -- + // -- | -- + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
----
+ + Console.WriteLine("Example 4\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a | b\n-- | --\n-- | --", "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
----
", "pipetables|advanced"); + } + + // But if a table doesn't start with a column delimiter, it is not interpreted as a table, even if following lines have a column delimiter + [Test] + public void ExtensionsPipeTable_Example005() + { + // Example 5 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a b + // c | d + // e | f + // + // Should be rendered as: + //

a b + // c | d + // e | f

+ + Console.WriteLine("Example 5\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a b\nc | d\ne | f", "

a b\nc | d\ne | f

", "pipetables|advanced"); + } + + // If a line doesn't have a column delimiter `|` the table is not detected + [Test] + public void ExtensionsPipeTable_Example006() + { + // Example 6 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b + // c no d + // + // Should be rendered as: + //

a | b + // c no d

+ + Console.WriteLine("Example 6\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a | b\nc no d", "

a | b\nc no d

", "pipetables|advanced"); + } + + // If a row contains more column than the header row, it will still be added as a column: + [Test] + public void ExtensionsPipeTable_Example007() + { + // Example 7 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b + // -- | -- + // 0 | 1 | 2 + // 3 | 4 + // 5 | + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
012
34
5
+ + Console.WriteLine("Example 7\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a | b \n-- | --\n0 | 1 | 2\n3 | 4\n5 |", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
012
34
5
", "pipetables|advanced"); + } + + // **Rule #2** + // A pipe table ends after a blank line or the end of the file. + // + // **Rule #3** + // A cell content is trimmed (start and end) from white-spaces. + [Test] + public void ExtensionsPipeTable_Example008() + { + // Example 8 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b | + // -- | -- + // 0 | 1 | + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
01
+ + Console.WriteLine("Example 8\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a | b |\n-- | --\n0 | 1 |", "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
01
", "pipetables|advanced"); + } + + // **Rule #4** + // Column delimiters `|` at the very beginning of a line or just before a line ending with only spaces and/or terminated by a newline can be omitted + [Test] + public void ExtensionsPipeTable_Example009() + { + // Example 9 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b | + // -- | -- + // | 0 | 1 + // | 2 | 3 | + // 4 | 5 + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
01
23
45
+ + Console.WriteLine("Example 9\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec(" a | b |\n-- | --\n| 0 | 1\n| 2 | 3 |\n 4 | 5 ", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
01
23
45
", "pipetables|advanced"); + } + + // A pipe may be present at both the beginning/ending of each line: + [Test] + public void ExtensionsPipeTable_Example010() + { + // Example 10 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // |a|b| + // |-|-| + // |0|1| + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
01
+ + Console.WriteLine("Example 10\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("|a|b|\n|-|-|\n|0|1|", "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
01
", "pipetables|advanced"); + } + + // Or may be ommitted on one side: + [Test] + public void ExtensionsPipeTable_Example011() + { + // Example 11 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a|b| + // -|-| + // 0|1| + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
01
+ + Console.WriteLine("Example 11\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a|b|\n-|-|\n0|1|", "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
01
", "pipetables|advanced"); + } + + [Test] + public void ExtensionsPipeTable_Example012() + { + // Example 12 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // |a|b + // |-|- + // |0|1 + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
01
+ + Console.WriteLine("Example 12\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("|a|b\n|-|-\n|0|1", "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
01
", "pipetables|advanced"); + } + + // Single column table can be declared with lines starting only by a column delimiter: + [Test] + public void ExtensionsPipeTable_Example013() + { + // Example 13 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // | a + // | -- + // | b + // | c + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
a
b
c
+ + Console.WriteLine("Example 13\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("| a\n| --\n| b\n| c ", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n
a
b
c
", "pipetables|advanced"); + } + + // **Rule #5** + // + // The first row is considered as a **header row** if it is separated from the regular rows by a row containing a **header column separator** for each column. A header column separator is: + // + // - starting by optional spaces + // - followed by an optional `:` to specify left align + // - followed by a sequence of at least one `-` character + // - followed by an optional `:` to specify right align (or center align if left align is also defined) + // - ending by optional spaces + [Test] + public void ExtensionsPipeTable_Example014() + { + // Example 14 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b + // -------|------- + // 0 | 1 + // 2 | 3 + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
01
23
+ + Console.WriteLine("Example 14\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec(" a | b \n-------|-------\n 0 | 1 \n 2 | 3 ", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
01
23
", "pipetables|advanced"); + } + + // The text alignment is defined by default to be center for header and left for cells. If the left alignment is applied, it will force the column heading to be left aligned. + // There is no way to define a different alignment for heading and cells (apart from the default). + // The text alignment can be changed by using the character `:` with the header column separator: + [Test] + public void ExtensionsPipeTable_Example015() + { + // Example 15 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b | c + // :------|:-------:| ----: + // 0 | 1 | 2 + // 3 | 4 | 5 + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
abc
012
345
+ + Console.WriteLine("Example 15\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec(" a | b | c \n:------|:-------:| ----:\n 0 | 1 | 2 \n 3 | 4 | 5 ", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
abc
012
345
", "pipetables|advanced"); + } + + // Test alignment with starting and ending pipes: + [Test] + public void ExtensionsPipeTable_Example016() + { + // Example 16 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // | abc | def | ghi | + // |:---:|-----|----:| + // | 1 | 2 | 3 | + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
abcdefghi
123
+ + Console.WriteLine("Example 16\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("| abc | def | ghi |\n|:---:|-----|----:|\n| 1 | 2 | 3 |", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
abcdefghi
123
", "pipetables|advanced"); + } + + // The following example shows a non matching header column separator: + [Test] + public void ExtensionsPipeTable_Example017() + { + // Example 17 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b + // -------|---x--- + // 0 | 1 + // 2 | 3 + // + // Should be rendered as: + //

a | b + // -------|---x--- + // 0 | 1 + // 2 | 3

+ + Console.WriteLine("Example 17\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec(" a | b\n-------|---x---\n 0 | 1\n 2 | 3 ", "

a | b\n-------|---x---\n0 | 1\n2 | 3

", "pipetables|advanced"); + } + + // **Rule #6** + // + // A column delimiter has a higher priority than emphasis delimiter + [Test] + public void ExtensionsPipeTable_Example018() + { + // Example 18 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // *a* | b + // ----- |----- + // 0 | _1_ + // _2 | 3* + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
01
_23*
+ + Console.WriteLine("Example 18\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec(" *a* | b\n----- |-----\n 0 | _1_\n _2 | 3* ", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
01
_23*
", "pipetables|advanced"); + } + + // **Rule #7** + // + // A backstick/code delimiter has a higher precedence than a column delimiter `|`: + [Test] + public void ExtensionsPipeTable_Example019() + { + // Example 19 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b ` + // 0 | ` + // + // Should be rendered as: + //

a | b 0 |

+ + Console.WriteLine("Example 19\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a | b `\n0 | ` ", "

a | b 0 |

", "pipetables|advanced"); + } + + // **Rule #7** + // + // A HTML inline has a higher precedence than a column delimiter `|`: + [Test] + public void ExtensionsPipeTable_Example020() + { + // Example 20 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b + // -- | -- + // 0 | 1 + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + //
a b
01
+ + Console.WriteLine("Example 20\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a | b\n-- | --\n0 | 1", "\n\n\n\n\n\n\n\n\n\n\n\n\n
a b
01
", "pipetables|advanced"); + } + + // **Rule #8** + // + // Links have a higher precedence than the column delimiter character `|`: + [Test] + public void ExtensionsPipeTable_Example021() + { + // Example 21 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b + // -- | -- + // [This is a link with a | inside the label](http://google.com) | 1 + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
This is a link with a | inside the label1
+ + Console.WriteLine("Example 21\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a | b\n-- | --\n[This is a link with a | inside the label](http://google.com) | 1", "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
This is a link with a | inside the label1
", "pipetables|advanced"); + } + + // ** Rule #9** + // + // It is possible to have a single row header only: + [Test] + public void ExtensionsPipeTable_Example022() + { + // Example 22 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b + // -- | -- + // + // Should be rendered as: + // + // + // + // + // + // + // + //
ab
+ + Console.WriteLine("Example 22\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a | b\n-- | --", "\n\n\n\n\n\n\n
ab
", "pipetables|advanced"); + } + + [Test] + public void ExtensionsPipeTable_Example023() + { + // Example 23 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // |a|b|c + // |---|---|---| + // + // Should be rendered as: + // + // + // + // + // + // + // + // + //
abc
+ + Console.WriteLine("Example 23\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("|a|b|c\n|---|---|---|", "\n\n\n\n\n\n\n\n
abc
", "pipetables|advanced"); + } + + // ** Tests ** + // + // Tests trailing spaces after pipes + [Test] + public void ExtensionsPipeTable_Example024() + { + // Example 24 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // | abc | def | + // |---|---| + // | cde| ddd| + // | eee| fff| + // | fff | fffff | + // |gggg | ffff | + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
abcdef
cdeddd
eeefff
ffffffff
ggggffff
+ + Console.WriteLine("Example 24\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("| abc | def | \n|---|---|\n| cde| ddd| \n| eee| fff|\n| fff | fffff | \n|gggg | ffff | ", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
abcdef
cdeddd
eeefff
ffffffff
ggggffff
", "pipetables|advanced"); + } + + // ** Normalized columns count ** + // + // The tables are normalized to the maximum number of columns found in a table + [Test] + public void ExtensionsPipeTable_Example025() + { + // Example 25 + // Section: Extensions / Pipe Table + // + // The following Markdown: + // a | b + // -- | - + // 0 | 1 | 2 + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
012
+ + Console.WriteLine("Example 25\nSection Extensions / Pipe Table\n"); + TestParser.TestSpec("a | b\n-- | - \n0 | 1 | 2", "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
012
", "pipetables|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/SmartyPantsSpecs.cs b/src/Markdig.Tests/Specs/SmartyPantsSpecs.cs new file mode 100644 index 00000000..242bfc7f --- /dev/null +++ b/src/Markdig.Tests/Specs/SmartyPantsSpecs.cs @@ -0,0 +1,336 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Smarty Pants +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.SmartyPants +{ + [TestFixture] + public class TestExtensionsSmartyPantsQuotes + { + // # Extensions + // + // Adds support for smarty pants: + // + // ## SmartyPants Quotes + // + // Converts the following character to smarty pants: + [Test] + public void ExtensionsSmartyPantsQuotes_Example001() + { + // Example 1 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // This is a "text" + // + // Should be rendered as: + //

This is a “text”

+ + Console.WriteLine("Example 1\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("This is a \"text\"", "

This is a “text”

", "pipetables+smartypants|advanced+smartypants"); + } + + [Test] + public void ExtensionsSmartyPantsQuotes_Example002() + { + // Example 2 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // This is a 'text' + // + // Should be rendered as: + //

This is a ‘text’

+ + Console.WriteLine("Example 2\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("This is a 'text'", "

This is a ‘text’

", "pipetables+smartypants|advanced+smartypants"); + } + + [Test] + public void ExtensionsSmartyPantsQuotes_Example003() + { + // Example 3 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // This is a <> + // + // Should be rendered as: + //

This is a «text»

+ + Console.WriteLine("Example 3\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("This is a <>", "

This is a «text»

", "pipetables+smartypants|advanced+smartypants"); + } + + // Unbalanced quotes are not changed: + [Test] + public void ExtensionsSmartyPantsQuotes_Example004() + { + // Example 4 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // This is a "text + // + // Should be rendered as: + //

This is a "text

+ + Console.WriteLine("Example 4\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("This is a \"text", "

This is a "text

", "pipetables+smartypants|advanced+smartypants"); + } + + [Test] + public void ExtensionsSmartyPantsQuotes_Example005() + { + // Example 5 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // This is a 'text + // + // Should be rendered as: + //

This is a 'text

+ + Console.WriteLine("Example 5\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("This is a 'text", "

This is a 'text

", "pipetables+smartypants|advanced+smartypants"); + } + + [Test] + public void ExtensionsSmartyPantsQuotes_Example006() + { + // Example 6 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // This is a <This is a <<text

+ + Console.WriteLine("Example 6\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("This is a <This is a <<text

", "pipetables+smartypants|advanced+smartypants"); + } + + // Unbalanced quotes inside other quotes are not changed: + [Test] + public void ExtensionsSmartyPantsQuotes_Example007() + { + // Example 7 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // This is a "text 'with" a another text' + // + // Should be rendered as: + //

This is a “text 'with” a another text'

+ + Console.WriteLine("Example 7\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("This is a \"text 'with\" a another text'", "

This is a “text 'with” a another text'

", "pipetables+smartypants|advanced+smartypants"); + } + + [Test] + public void ExtensionsSmartyPantsQuotes_Example008() + { + // Example 8 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // This is a 'text <> + // + // Should be rendered as: + //

This is a ‘text <<with’ a another text>>

+ + Console.WriteLine("Example 8\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("This is a 'text <>", "

This is a ‘text <<with’ a another text>>

", "pipetables+smartypants|advanced+smartypants"); + } + + [Test] + public void ExtensionsSmartyPantsQuotes_Example009() + { + // Example 9 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // This is a <> a another text' + // + // Should be rendered as: + //

This is a «text 'with» a another text'

+ + Console.WriteLine("Example 9\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("This is a <> a another text'", "

This is a «text 'with» a another text'

", "pipetables+smartypants|advanced+smartypants"); + } + + // Quotes requires to have the same rules than emphasis `_` regarding left/right frankling rules: + [Test] + public void ExtensionsSmartyPantsQuotes_Example010() + { + // Example 10 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // It's not quotes' + // + // Should be rendered as: + //

It's not quotes'

+ + Console.WriteLine("Example 10\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("It's not quotes'", "

It's not quotes'

", "pipetables+smartypants|advanced+smartypants"); + } + + [Test] + public void ExtensionsSmartyPantsQuotes_Example011() + { + // Example 11 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // They are ' not matching quotes ' + // + // Should be rendered as: + //

They are ' not matching quotes '

+ + Console.WriteLine("Example 11\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("They are ' not matching quotes '", "

They are ' not matching quotes '

", "pipetables+smartypants|advanced+smartypants"); + } + + [Test] + public void ExtensionsSmartyPantsQuotes_Example012() + { + // Example 12 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // They are' not matching 'quotes + // + // Should be rendered as: + //

They are' not matching 'quotes

+ + Console.WriteLine("Example 12\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("They are' not matching 'quotes", "

They are' not matching 'quotes

", "pipetables+smartypants|advanced+smartypants"); + } + + // An emphasis starting inside left/right quotes will span over the right quote: + [Test] + public void ExtensionsSmartyPantsQuotes_Example013() + { + // Example 13 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // This is "a *text" with an emphasis* + // + // Should be rendered as: + //

This is “a text” with an emphasis

+ + Console.WriteLine("Example 13\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("This is \"a *text\" with an emphasis*", "

This is “a text” with an emphasis

", "pipetables+smartypants|advanced+smartypants"); + } + } + + [TestFixture] + public class TestExtensionsSmartyPantsSeparators + { + // ## SmartyPants Separators + [Test] + public void ExtensionsSmartyPantsSeparators_Example014() + { + // Example 14 + // Section: Extensions / SmartyPants Separators + // + // The following Markdown: + // This is a -- text + // + // Should be rendered as: + //

This is a – text

+ + Console.WriteLine("Example 14\nSection Extensions / SmartyPants Separators\n"); + TestParser.TestSpec("This is a -- text", "

This is a – text

", "pipetables+smartypants|advanced+smartypants"); + } + + [Test] + public void ExtensionsSmartyPantsSeparators_Example015() + { + // Example 15 + // Section: Extensions / SmartyPants Separators + // + // The following Markdown: + // This is a --- text + // + // Should be rendered as: + //

This is a — text

+ + Console.WriteLine("Example 15\nSection Extensions / SmartyPants Separators\n"); + TestParser.TestSpec("This is a --- text", "

This is a — text

", "pipetables+smartypants|advanced+smartypants"); + } + + [Test] + public void ExtensionsSmartyPantsSeparators_Example016() + { + // Example 16 + // Section: Extensions / SmartyPants Separators + // + // The following Markdown: + // This is a en ellipsis... + // + // Should be rendered as: + //

This is a en ellipsis…

+ + Console.WriteLine("Example 16\nSection Extensions / SmartyPants Separators\n"); + TestParser.TestSpec("This is a en ellipsis...", "

This is a en ellipsis…

", "pipetables+smartypants|advanced+smartypants"); + } + + // Check that a smartypants are not breaking pipetable parsing: + [Test] + public void ExtensionsSmartyPantsSeparators_Example017() + { + // Example 17 + // Section: Extensions / SmartyPants Separators + // + // The following Markdown: + // a | b + // -- | -- + // 0 | 1 + // + // Should be rendered as: + // + // + // + // + // + // + // + // + // + // + // + // + // + //
ab
01
+ + Console.WriteLine("Example 17\nSection Extensions / SmartyPants Separators\n"); + TestParser.TestSpec("a | b\n-- | --\n0 | 1", "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
01
", "pipetables+smartypants|advanced+smartypants"); + } + + // Check quotes and dash: + [Test] + public void ExtensionsSmartyPantsSeparators_Example018() + { + // Example 18 + // Section: Extensions / SmartyPants Separators + // + // The following Markdown: + // A "quote" with a --- + // + // Should be rendered as: + //

A “quote” with a —

+ + Console.WriteLine("Example 18\nSection Extensions / SmartyPants Separators\n"); + TestParser.TestSpec("A \"quote\" with a ---", "

A “quote” with a —

", "pipetables+smartypants|advanced+smartypants"); + } + } +} diff --git a/src/Markdig.Tests/Specs/TaskListSpecs.cs b/src/Markdig.Tests/Specs/TaskListSpecs.cs new file mode 100644 index 00000000..de8aa585 --- /dev/null +++ b/src/Markdig.Tests/Specs/TaskListSpecs.cs @@ -0,0 +1,63 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Task Lists +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.TaskLists +{ + [TestFixture] + public class TestExtensionsTaskLists + { + // # Extensions + // + // Adds support for task lists: + // + // ## TaskLists + // + // A task list item consist of `[ ]` or `[x]` or `[X]` inside a list item (ordered or unordered) + [Test] + public void ExtensionsTaskLists_Example001() + { + // Example 1 + // Section: Extensions / TaskLists + // + // The following Markdown: + // - [ ] Item1 + // - [x] Item2 + // - [ ] Item3 + // - Item4 + // + // Should be rendered as: + //
    + //
  • Item1
  • + //
  • Item2
  • + //
  • Item3
  • + //
  • Item4
  • + //
+ + Console.WriteLine("Example 1\nSection Extensions / TaskLists\n"); + TestParser.TestSpec("- [ ] Item1\n- [x] Item2\n- [ ] Item3\n- Item4", "
    \n
  • Item1
  • \n
  • Item2
  • \n
  • Item3
  • \n
  • Item4
  • \n
", "tasklists|advanced"); + } + + // A task is not recognized outside a list item: + [Test] + public void ExtensionsTaskLists_Example002() + { + // Example 2 + // Section: Extensions / TaskLists + // + // The following Markdown: + // [ ] This is not a task list + // + // Should be rendered as: + //

[ ] This is not a task list

+ + Console.WriteLine("Example 2\nSection Extensions / TaskLists\n"); + TestParser.TestSpec("[ ] This is not a task list", "

[ ] This is not a task list

", "tasklists|advanced"); + } + } +} diff --git a/src/Markdig.Tests/Specs/YamlSpecs.cs b/src/Markdig.Tests/Specs/YamlSpecs.cs new file mode 100644 index 00000000..0f0b072d --- /dev/null +++ b/src/Markdig.Tests/Specs/YamlSpecs.cs @@ -0,0 +1,214 @@ +// Generated: 21. 01. 2019 14:26:34 + +// -------------------------------- +// Yaml +// -------------------------------- + +using System; +using NUnit.Framework; + +namespace Markdig.Tests.Specs.Yaml +{ + [TestFixture] + public class TestExtensionsYAMLFrontmatterDiscard + { + // # Extensions + // + // Adds support for YAML frontmatter parsing: + // + // ## YAML frontmatter discard + // + // If a frontmatter is present, it will not be rendered: + [Test] + public void ExtensionsYAMLFrontmatterDiscard_Example001() + { + // Example 1 + // Section: Extensions / YAML frontmatter discard + // + // The following Markdown: + // --- + // this: is a frontmatter + // --- + // This is a text + // + // Should be rendered as: + //

This is a text

+ + Console.WriteLine("Example 1\nSection Extensions / YAML frontmatter discard\n"); + TestParser.TestSpec("---\nthis: is a frontmatter\n---\nThis is a text", "

This is a text

", "yaml"); + } + + // But if a frontmatter doesn't happen on the first line, it will be parse as regular Markdown content + [Test] + public void ExtensionsYAMLFrontmatterDiscard_Example002() + { + // Example 2 + // Section: Extensions / YAML frontmatter discard + // + // The following Markdown: + // This is a text1 + // --- + // this: is a frontmatter + // --- + // This is a text2 + // + // Should be rendered as: + //

This is a text1

+ //

this: is a frontmatter

+ //

This is a text2

+ + Console.WriteLine("Example 2\nSection Extensions / YAML frontmatter discard\n"); + TestParser.TestSpec("This is a text1\n---\nthis: is a frontmatter\n---\nThis is a text2", "

This is a text1

\n

this: is a frontmatter

\n

This is a text2

", "yaml"); + } + + // It expects an exact 3 dashes `---`: + [Test] + public void ExtensionsYAMLFrontmatterDiscard_Example003() + { + // Example 3 + // Section: Extensions / YAML frontmatter discard + // + // The following Markdown: + // ---- + // this: is a frontmatter + // ---- + // This is a text + // + // Should be rendered as: + //
+ //

this: is a frontmatter

+ //

This is a text

+ + Console.WriteLine("Example 3\nSection Extensions / YAML frontmatter discard\n"); + TestParser.TestSpec("----\nthis: is a frontmatter\n----\nThis is a text", "
\n

this: is a frontmatter

\n

This is a text

", "yaml"); + } + + // It can end with three dots `...`: + [Test] + public void ExtensionsYAMLFrontmatterDiscard_Example004() + { + // Example 4 + // Section: Extensions / YAML frontmatter discard + // + // The following Markdown: + // --- + // this: is a frontmatter + // + // ... + // This is a text + // + // Should be rendered as: + //

This is a text

+ + Console.WriteLine("Example 4\nSection Extensions / YAML frontmatter discard\n"); + TestParser.TestSpec("---\nthis: is a frontmatter\n\n...\nThis is a text", "

This is a text

", "yaml"); + } + + // If the end front matter marker (`...` or `---`) is not present, it will render the `---` has a `
`: + [Test] + public void ExtensionsYAMLFrontmatterDiscard_Example005() + { + // Example 5 + // Section: Extensions / YAML frontmatter discard + // + // The following Markdown: + // --- + // this: is a frontmatter + // This is a text + // + // Should be rendered as: + //
+ //

this: is a frontmatter + // This is a text

+ + Console.WriteLine("Example 5\nSection Extensions / YAML frontmatter discard\n"); + TestParser.TestSpec("---\nthis: is a frontmatter\nThis is a text", "
\n

this: is a frontmatter\nThis is a text

", "yaml"); + } + + // It expects exactly three dots `...`: + [Test] + public void ExtensionsYAMLFrontmatterDiscard_Example006() + { + // Example 6 + // Section: Extensions / YAML frontmatter discard + // + // The following Markdown: + // --- + // this: is a frontmatter + // .... + // This is a text + // + // Should be rendered as: + //
+ //

this: is a frontmatter + // .... + // This is a text

+ + Console.WriteLine("Example 6\nSection Extensions / YAML frontmatter discard\n"); + TestParser.TestSpec("---\nthis: is a frontmatter\n....\nThis is a text", "
\n

this: is a frontmatter\n....\nThis is a text

", "yaml"); + } + + // Front matter ends with the first line containing three dots `...` or three dashes `---`: + [Test] + public void ExtensionsYAMLFrontmatterDiscard_Example007() + { + // Example 7 + // Section: Extensions / YAML frontmatter discard + // + // The following Markdown: + // --- + // this: is a frontmatter + // .... + // + // Hello + // --- + // This is a text + // + // Should be rendered as: + //

This is a text

+ + Console.WriteLine("Example 7\nSection Extensions / YAML frontmatter discard\n"); + TestParser.TestSpec("---\nthis: is a frontmatter\n....\n\nHello\n---\nThis is a text", "

This is a text

", "yaml"); + } + + // It expects whitespace can exist after the leading characters + [Test] + public void ExtensionsYAMLFrontmatterDiscard_Example008() + { + // Example 8 + // Section: Extensions / YAML frontmatter discard + // + // The following Markdown: + // --- + // this: is a frontmatter + // ... + // This is a text + // + // Should be rendered as: + //

This is a text

+ + Console.WriteLine("Example 8\nSection Extensions / YAML frontmatter discard\n"); + TestParser.TestSpec("--- \nthis: is a frontmatter\n...\nThis is a text", "

This is a text

", "yaml"); + } + + // It expects whitespace can exist after the trailing characters + [Test] + public void ExtensionsYAMLFrontmatterDiscard_Example009() + { + // Example 9 + // Section: Extensions / YAML frontmatter discard + // + // The following Markdown: + // --- + // this: is a frontmatter + // ... + // This is a text + // + // Should be rendered as: + //

This is a text

+ + Console.WriteLine("Example 9\nSection Extensions / YAML frontmatter discard\n"); + TestParser.TestSpec("---\nthis: is a frontmatter\n... \nThis is a text", "

This is a text

", "yaml"); + } + } +} diff --git a/src/Markdig.Tests/Specs/TestEmphasisPlus.cs b/src/Markdig.Tests/TestEmphasisPlus.cs similarity index 100% rename from src/Markdig.Tests/Specs/TestEmphasisPlus.cs rename to src/Markdig.Tests/TestEmphasisPlus.cs