Compare commits

...

77 Commits

Author SHA1 Message Date
Alexandre Mutel
ccf455d316 Fix AssemblyVersion with MinVer (#612) 2022-03-27 10:15:16 +02:00
Alexandre Mutel
8beb096814 Fix emphasis parsing with table delimiters (#614) 2022-03-27 10:04:14 +02:00
Alexandre Mutel
6a35ec45b9 Merge pull request #611 from MihaZupan/renderer-perf
Improve rendering performance
2022-03-27 09:45:19 +02:00
Miha Zupan
ed83943ba5 Use custom StringWriter for rendering internally 2022-03-20 13:49:38 +01:00
Miha Zupan
9adf60116b More WriteRaw 2022-03-20 11:24:05 +01:00
Miha Zupan
31904f6c53 Avoid allocating WriteEscapeIndexOfAnyChars
Roslyn doesn't support static char arrays yet
2022-03-20 10:54:09 +01:00
Miha Zupan
3f3b3c46b6 Optimize renderers 2022-03-20 10:21:36 +01:00
Miha Zupan
f3d6c2775b Add Unsafe.As polyfill for NETSTANDARD 2.1 2022-03-20 04:02:16 +01:00
Miha Zupan
bb6ace15b7 Optimize RendererBase.Write 2022-03-20 03:39:47 +01:00
Miha Zupan
202ac1e4f9 Simplify RendererBase ctor 2022-03-20 02:36:02 +01:00
Miha Zupan
2604239764 Move TryGetRenderer to cold path 2022-03-20 02:12:35 +01:00
Miha Zupan
cc04208b95 Change IMarkdownObjectRenderer.Accept to take a Type instead of instance 2022-03-20 02:06:08 +01:00
Miha Zupan
14ab45cf8f Move TryWriters to cold path 2022-03-20 01:56:48 +01:00
Miha Zupan
e36d4564f1 Remove NormalizeAutoLinkRenderer 2022-03-20 01:53:20 +01:00
Alexandre Mutel
358a5f09ef Merge pull request #608 from MihaZupan/perf-march-2022-2
Some CPU improvements
2022-03-19 14:24:43 +01:00
Miha Zupan
315ffd42ab Move InternalsVisibleTo from targets to non-signed csproj 2022-03-14 11:33:04 +01:00
Miha Zupan
2675b4dd1e Fixup FencedBlockParserBase nullability 2022-03-14 11:31:42 +01:00
Miha Zupan
58d7fae12d Cleanup exit condition in Unescape 2022-03-14 11:11:35 +01:00
Miha Zupan
e16ed79dcd Optimize StringLineGroup iteration 2022-03-14 10:58:21 +01:00
Miha Zupan
9ef5171369 Reduce type check and casting overhead 2022-03-14 10:56:59 +01:00
Alexandre Mutel
0cfe6d7da4 Merge pull request #606 from MihaZupan/perf-march-2022
Improvements when TrackTrivia is disabled
2022-03-14 09:46:26 +01:00
Miha Zupan
fe65c1b187 Add & use ValueStringBuilder 2022-03-14 07:36:10 +01:00
Miha Zupan
92385ee19a Set SkipLocalsInit for Markdig 2022-03-14 05:05:35 +01:00
Miha Zupan
9f651feac0 Properly trim & cache FencedCodeBlock Info strings 2022-03-14 04:23:44 +01:00
Miha Zupan
b7d02cadbb Fix TrackTrivia /// comments 2022-03-13 01:54:44 +01:00
Miha Zupan
6f75b5156c Aggressively avoid TrackTrivia work and allocations when not requested for Inlines 2022-03-13 01:34:47 +01:00
Miha Zupan
61452c91e9 Aggressively avoid TrackTrivia work and allocations when not requested 2022-03-13 01:21:33 +01:00
Miha Zupan
b697a03c2b Lazily allocate Trivia properties on LinkReferenceDefinition 2022-03-12 23:34:30 +01:00
Miha Zupan
9f734ba3c9 Lazily allocate Trivia properties on LinkInline 2022-03-12 23:28:16 +01:00
Miha Zupan
88cdbf3a17 Lazily allocate CodeBlock.CodeBlockLines 2022-03-12 22:42:15 +01:00
Miha Zupan
fb9561cf89 Fix roughLineCountEstimate calculation (min/max order) 2022-03-12 22:26:41 +01:00
Miha Zupan
9145f47f89 Move TryParseInlineLinkTrivia to cold path 2022-03-12 22:25:52 +01:00
Miha Zupan
1862b37bbd Optimize LineReader.ReadLine 2022-03-12 02:18:50 +01:00
Alexandre Mutel
983187eace Fix emphasis when EnableTrackTrivia() is used (#561) 2022-03-11 08:16:42 +01:00
Alexandre Mutel
94581d9655 Try to workaround track trivia not generating valid HTML (#561) 2022-03-10 09:36:24 +01:00
Alexandre Mutel
6aebd68413 Fix specfilegen 2022-03-10 09:35:08 +01:00
Alexandre Mutel
a3f21b7639 Merge pull request #600 from gauss-lvs/master
Version "Unknown" if AssemblyFileVersionAttribute is missing
2022-03-03 18:43:54 +01:00
Patrick
653c9d7f16 Version returns "Unknown" if the AssemblyFileVersionAttribute is not found. 2022-03-02 09:09:59 +01:00
Alexandre Mutel
9bbf6855e1 Use bash with dotnet-releaser in GitHub Action 2022-03-01 08:27:16 +01:00
Alexandre Mutel
28f5503cfe Fix ci with dotnet-releaser when secrets are not available (bis) 2022-02-28 22:17:49 +01:00
Alexandre Mutel
ba990c739e Fix ci with dotnet-releaser when secrets are not available 2022-02-28 21:43:54 +01:00
Alexandre Mutel
0c45e19723 Remove logs from tests if no errors 2022-02-28 09:47:11 +01:00
Alexandre Mutel
73b8bbe1c7 Update ci to use dotnet-releaser 2022-02-28 09:18:40 +01:00
Alexandre Mutel
996b04cadb Merge pull request #593 from tibel/define-NETCORE-removed
remove NETCORE constant
2022-02-05 14:38:17 +01:00
Thomas Ibel
e7d7cbe010 remove NETCORE constant
and replace by NETSTANDARD2_1_OR_GREATER and NETCOREAPP3_1_OR_GREATER
2022-02-05 07:19:49 +01:00
Alexandre Mutel
ff89b48c33 Merge pull request #591 from carbon/net60
Drop .netcoreapp2.1 target and cross target .net6.0
2022-01-30 18:36:39 +01:00
Jason Nelson
58de5dbcea Update build note 2022-01-28 11:53:06 -08:00
Jason Nelson
fbd7d83cda Future proof NETCORE pragmas 2022-01-28 11:50:34 -08:00
Jason Nelson
13a9c066f7 Use built-in MemberNotNullAttribute on NET5.0+ 2022-01-28 11:47:05 -08:00
Jason Nelson
b7be61a914 Remove NETCOREAPP2_1 conditions 2022-01-27 19:56:53 -08:00
Jason Nelson
c212f9efa8 Use C# 10 2022-01-27 19:56:19 -08:00
Jason Nelson
e0961d7e86 Run benchmarks against net6.0 2022-01-27 19:53:54 -08:00
Jason Nelson
c67a802e69 Drop netcoreapp2.1 target and cross-target net6.0 2022-01-27 19:52:41 -08:00
Alexandre Mutel
5e3527b7d2 Bump to 0.27.0 2022-01-23 16:10:37 +01:00
Alexandre Mutel
d56e080fd7 Merge pull request #590 from yufeih/bug-crlf-link
Fix link reference definition parse bug with title and CRLF
2022-01-23 16:05:02 +01:00
Yufei Huang
d807255e13 Fix link reference definition parse bug with title and CRLF 2022-01-21 23:37:27 +08:00
Alexandre Mutel
029da6c99b Merge pull request #587 from wbaldoumas/add_markdown_colorcode
Add Markdown.ColorCode to README
2022-01-20 13:29:33 +01:00
Alexandre Mutel
b59c9e8925 Merge pull request #586 from tibel/feature/net6.0
.NET 6.0
2022-01-20 13:29:18 +01:00
Alexandre Mutel
22662b248d Update src/global.json 2022-01-20 12:50:58 +01:00
William Baldoumas
9d51ab176c Add Markdown.ColorCode 2022-01-19 21:37:52 -05:00
Thomas Ibel
584378967d fix build warnings 2022-01-19 20:12:41 +01:00
Thomas Ibel
f553bdd4c7 use await for http client 2022-01-19 19:18:46 +01:00
Thomas Ibel
16d77b7bb8 fix github action version 2022-01-19 18:46:54 +01:00
Thomas Ibel
d267cbe173 update github actions 2022-01-19 18:40:19 +01:00
Thomas Ibel
f54944962f update test and benchmark dependencies 2022-01-19 18:32:17 +01:00
Thomas Ibel
5a54af1235 fix warnings 2022-01-19 18:05:28 +01:00
Thomas Ibel
4567d86c15 use .NET 6.0 SDK 2022-01-19 18:01:30 +01:00
Alexandre Mutel
2b6dde9415 Merge pull request #576 from SimonCropp/patch-1
Strike.V8 is deprecated
2021-11-26 08:11:18 +01:00
Simon Cropp
ea8d9b608a Strike.V8 is deprecated 2021-11-15 13:53:50 +11:00
Alexandre Mutel
1469cc8fdb Merge pull request #575 from boxofyellow/master
Fix typo in EmphasisExtraOptions descriptions
2021-10-31 09:14:13 +01:00
Alexandre Mutel
daf2171366 Update src/Markdig/Extensions/EmphasisExtras/EmphasisExtraOptions.cs
Co-authored-by: Miha Zupan <mihazupan.zupan1@gmail.com>
2021-10-31 08:54:20 +01:00
Alexandre Mutel
63a9f2406b Update src/Markdig/Extensions/EmphasisExtras/EmphasisExtraOptions.cs
Co-authored-by: Miha Zupan <mihazupan.zupan1@gmail.com>
2021-10-31 08:54:12 +01:00
boxofyellow
fd100d1796 Fix typos in EmphasisExtraOptions descriptions 2021-10-30 14:55:59 -04:00
Alexandre Mutel
2c5a51d89b Merge pull request #572 from flcdrg/patch-1
Fix named parameter syntax
2021-09-16 06:21:45 +02:00
Alexandre Mutel
28db7fbd6b Merge pull request #573 from lajjne/target-blank
Fixes #571
2021-09-16 06:21:14 +02:00
Linus Birgerstam
56470a72a8 Fixes #571 2021-09-15 20:08:17 +02:00
David Gardiner
6b163a50c3 Fix named parameter syntax 2021-09-14 18:40:25 +09:30
135 changed files with 3960 additions and 4101 deletions

View File

@@ -1,8 +1,5 @@
name: ci
env:
PROJECT_NAME: Markdig
on:
push:
paths-ignore:
@@ -18,47 +15,18 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v2
with:
submodules: true
fetch-depth: 0
- name: Install .NET 5.0
- name: Install .NET 6.0
uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.x'
dotnet-version: '6.0.x'
- name: Build (Release)
run: dotnet build src -c Release
- name: SpecFileGen
run: dotnet src/SpecFileGen/bin/Release/net5.0/SpecFileGen.dll
- name: Test (Release)
run: dotnet test src -c Release
- name: Build & Test (Debug)
run: dotnet test src -c Debug
- name: Coverlet
run: dotnet test src -c Release -f net5.0 /p:Include=\"[${{env.PROJECT_NAME}}]*\" /p:CollectCoverage=true /p:CoverletOutputFormat=lcov
- name: Coveralls Upload
uses: coverallsapp/github-action@v1.0.1
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: src/${{env.PROJECT_NAME}}.Tests/coverage.info
- name: Pack
run: dotnet pack src -c Release
- name: Pack Signed
run: dotnet pack -c Release src/${{env.PROJECT_NAME}}.Signed/${{env.PROJECT_NAME}}.Signed.csproj
- name: Publish
if: github.event_name == 'push'
run: |
if ( "${{github.ref}}" -match "^refs/tags/[0-9]+\.[0-9]+\.[0-9]+$" ) {
dotnet nuget push src\${{env.PROJECT_NAME}}\bin\Release\*.nupkg -s nuget.org -k ${{secrets.NUGET_TOKEN}}
dotnet nuget push src\${{env.PROJECT_NAME}}.Signed\bin\Release\*.nupkg -s nuget.org -k ${{secrets.NUGET_TOKEN}}
} else {
echo "publish is only enabled by tagging with a release tag"
}
- name: Build, Test, Pack, Publish
shell: bash
run: |
dotnet tool install -g dotnet-releaser
dotnet-releaser run --nuget-token "${{secrets.NUGET_TOKEN}}" --github-token "${{secrets.GITHUB_TOKEN}}" src/dotnet-releaser.toml

3
.gitignore vendored
View File

@@ -239,3 +239,6 @@ _Pvt_Extensions
**/.idea/**/*.iml
**/.idea/**/contentModel.xml
**/.idea/**/modules.xml
# Remove artifacts produced by dotnet-releaser
artifacts-dotnet-releaser/

View File

@@ -1,5 +1,9 @@
# Changelog
## 0.27.0 (23 Jan 2022)
- Fix link reference definition parse bug with title and CRLF ([PR #590](https://github.com/lunet-io/markdig/pull/590))
- Move tests to net6.0 ([PR #560](https://github.com/lunet-io/markdig/pull/560))
## 0.26.0 (27 Aug 2021)
- Fix rendering diff between line endings ([PR #560](https://github.com/lunet-io/markdig/pull/560))
- Make Mathematics extension respect EnableHtml* options ([PR #570](https://github.com/lunet-io/markdig/pull/570))

View File

@@ -60,6 +60,7 @@ If you are looking for support for an old .NET Framework 3.5 or 4.0, you can dow
- [**WPF/XAML Markdown Renderer**: `markdig.wpf`](https://github.com/Kryptos-FR/markdig.wpf)
- [**WPF/XAML Markdown Renderer**: `Neo.Markdig.Xaml`](https://github.com/neolithos/NeoMarkdigXaml)
- [**Syntax highlighting**: `Markdig.SyntaxHighlighting`](https://github.com/RichardSlater/Markdig.SyntaxHighlighting)
- [**Syntax highlighting using ColorCode-Universal**: `Markdown.ColorCode`](https://github.com/wbaldoumas/markdown-colorcode)
- [**Syntax highlighting using Prism.js**: `WebStoating.Markdig.Prism`](https://github.com/ilich/Markdig.Prism)
- [**Embedded C# scripting**: `Markdig.Extensions.ScriptCs`](https://github.com/macaba/Markdig.Extensions.ScriptCs)
@@ -102,7 +103,7 @@ You can have a look at the [MarkdownExtensions](https://github.com/lunet-io/mark
## Build
In order to build Markdig, you need to install [.NET Core RTM](https://www.microsoft.com/net/core)
In order to build Markdig, you need to install [.NET 6.0](https://dotnet.microsoft.com/en-us/download)
## License
@@ -128,10 +129,6 @@ This is an early preview of the benchmarking against various implementations:
- [Marked.NET](https://github.com/T-Alex/MarkedNet) (version: 1.0.5) port of original [marked.js](https://github.com/chjj/marked) project
- [Microsoft.DocAsCode.MarkdownLite](https://github.com/dotnet/docfx/tree/dev/src/Microsoft.DocAsCode.MarkdownLite) (version: 2.0.1) used by the [docfx](https://github.com/dotnet/docfx) project
**JavaScript/V8 implementations**:
- [Strike.V8](https://github.com/SimonCropp/Strike) (version: 1.5.0) [marked.js](https://github.com/chjj/marked) running in Google V8 (not .NET based)
### Analysis of the results:
- Markdig is roughly **x100 times faster than MarkdownSharp**, **30x times faster than docfx**
@@ -166,7 +163,6 @@ CommonMark.NET(pipe_tables) | 5.6164 ms | 0.0298 ms | 0.72 | 111.00| 56.00|
MarkdownDeep | 7.8193 ms | 0.0334 ms | 1.00 | 120.00| 56.00| 49.00| 1,884,854.85 |
cmark | 4.2698 ms | 0.1526 ms | 0.55 | -| -| -| NA |
Moonshine | 6.0929 ms | 0.1053 ms | 1.28 | -| -| -| NA |
Strike.V8 | 10.5895 ms | 0.0492 ms | 1.35 | -| -| -| NA |
Marked.NET | 207.3169 ms | 5.2628 ms | 26.51 | 0.00| 0.00| 0.00| 303,125,228.65 |
MarkdownSharp | 675.0185 ms | 2.8447 ms | 86.32 | 40.00| 27.00| 41.00| 2,413,394.17 |
Microsoft DocfxMarkdownLite | 166.3357 ms | 0.4529 ms | 21.27 |4,452.00|948.00|11,167.00| 180,218,359.60 |

View File

@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net471</TargetFrameworks>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPackable>false</IsPackable>
@@ -36,12 +36,12 @@
</Content>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.12.1" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.12.1" />
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.13.1" />
<PackageReference Include="CommonMark.NET" Version="0.15.1" />
<PackageReference Include="MarkdownSharp" Version="2.0.5" />
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.0.161401" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.62" />
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.0.226801" />
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.74" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Markdig\Markdig.csproj" />

View File

@@ -1,24 +1,53 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Exe</OutputType>
<IsPackable>false</IsPackable>
<StartupObject>Markdig.Tests.Program</StartupObject>
<SpecExecutable>$(MSBuildProjectDirectory)\..\SpecFileGen\bin\$(Configuration)\net6.0\SpecFileGen.dll</SpecExecutable>
<SpecTimestamp>$(MSBuildProjectDirectory)\..\SpecFileGen\bin\$(Configuration)\net6.0\SpecFileGen.timestamp</SpecTimestamp>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="coverlet.msbuild" Version="2.9.0">
<PackageReference Include="coverlet.msbuild" Version="3.1.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
<PackageReference Include="NUnit" Version="3.13.2" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Markdig\Markdig.csproj" />
<ProjectReference Include="..\SpecFileGen\SpecFileGen.csproj" />
</ItemGroup>
<ItemGroup>
<ItemSpecExecutable Include="$(SpecExecutable)" />
<InputSpecFiles Include="Specs\*.md" />
<InputSpecFiles Include="NormalizeSpecs\*.md" />
<InputSpecFiles Include="PlainTextSpecs\*.md" />
<InputSpecFiles Include="RoundtripSpecs\*.md" />
<InputSpecFiles Remove="Specs\readme.md" />
<!-- Allow Visual Studio up-to-date check to verify that nothing has changed - https://github.com/dotnet/project-system/blob/main/docs/up-to-date-check.md -->
<UpToDateCheckInput Include="@(InputSpecFiles)"/>
<OutputSpecFiles Include="@(InputSpecFiles->'%(RelativeDir)%(Filename).generated.cs')" />
</ItemGroup>
<Target Name="GeneratedSpecsFile" BeforeTargets="BeforeCompile;CoreCompile" Inputs="@(ItemSpecExecutable);@(InputSpecFiles)" Outputs="@(ItemSpecExecutable->'%(RelativeDir)%(Filename).timestamp');@(InputSpecFiles->'%(RelativeDir)%(Filename).generated.cs')">
<Message Importance="high" Text="Regenerating Specs Files" />
<Exec Command="dotnet $(SpecExecutable)" />
<WriteLinesToFile File="$(SpecTimestamp)" Lines="$([System.DateTime]::Now)" />
<ItemGroup>
<FileWrites Include="$(SpecTimestamp)" />
<_GeneratedSpecsFile Include="Specs\*.generated.cs" />
<_GeneratedSpecsFile Include="NormalizeSpecs\*.generated.cs" />
<_GeneratedSpecsFile Include="PlainTextSpecs\*.generated.cs" />
<_GeneratedSpecsFile Include="RoundtripSpecs\*.generated.cs" />
<_GeneratedSpecsFile Remove="@(Compile)" />
<Compile Include="@(_GeneratedSpecsFile)" />
</ItemGroup>
</Target>
</Project>

View File

@@ -206,13 +206,10 @@ $$
\end{align}
</div>
";
Console.WriteLine("Math Expressions:\n");
//Console.WriteLine("Math Expressions:\n");
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
var html = Markdown.ToHtml(math, pl);
Console.WriteLine(html);
//Console.WriteLine(html);
}
[Test]
@@ -225,10 +222,16 @@ $\frac{n!}{k!(n-k)!} = \binom{n}{k}$
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
var html = Markdown.ToHtml(math, pl);
Console.WriteLine(html);
Assert.IsTrue(html.Contains("<p><span class=\"math\">\\("), "Leading bracket missing");
Assert.IsTrue(html.Contains("\\)</span></p>"), "Trailing bracket missing");
var test1 = html.Contains("<p><span class=\"math\">\\(");
var test2 = html.Contains("\\)</span></p>");
if (!test1 || !test2)
{
Console.WriteLine(html);
}
Assert.IsTrue(test1, "Leading bracket missing");
Assert.IsTrue(test2, "Trailing bracket missing");
}
[Test]
@@ -243,10 +246,15 @@ $$
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
var html = Markdown.ToHtml(math, pl);
Console.WriteLine(html);
var test1 = html.Contains("<div class=\"math\">\n\\[");
var test2 = html.Contains("\\]</div>");
if (!test1 || !test2)
{
Console.WriteLine(html);
}
Assert.IsTrue(html.Contains("<div class=\"math\">\n\\["), "Leading bracket missing");
Assert.IsTrue(html.Contains("\\]</div>"), "Trailing bracket missing");
Assert.IsTrue(test1, "Leading bracket missing");
Assert.IsTrue(test2, "Trailing bracket missing");
}
[Test]
@@ -272,7 +280,7 @@ $$
var newWindowPipeline = new MarkdownPipelineBuilder().UseAutoLinks(new AutoLinkOptions() { OpenInNewWindow = true }).Build();
TestParser.TestSpec("www.foo.bar", "<p><a href=\"http://www.foo.bar\">www.foo.bar</a></p>", pipeline);
TestParser.TestSpec("www.foo.bar", "<p><a href=\"http://www.foo.bar\" target=\"blank\">www.foo.bar</a></p>", newWindowPipeline);
TestParser.TestSpec("www.foo.bar", "<p><a href=\"http://www.foo.bar\" target=\"_blank\">www.foo.bar</a></p>", newWindowPipeline);
}
[Test]

View File

@@ -44,8 +44,7 @@ namespace Markdig.Tests.Specs.Normalize.Headings
//
// ###### Heading 6
Console.WriteLine("Example 1\nSection Headings\n");
TestNormalize.TestSpec("# Heading 1\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6", "# Heading 1\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6", "");
TestNormalize.TestSpec("# Heading 1\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6", "# Heading 1\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6", "", context: "Example 1\nSection Headings\n");
}
[Test]
@@ -64,8 +63,7 @@ namespace Markdig.Tests.Specs.Normalize.Headings
//
// Text after two newlines
Console.WriteLine("Example 2\nSection Headings\n");
TestNormalize.TestSpec("###### Heading\n\nText after two newlines", "###### Heading\n\nText after two newlines", "");
TestNormalize.TestSpec("###### Heading\n\nText after two newlines", "###### Heading\n\nText after two newlines", "", context: "Example 2\nSection Headings\n");
}
[Test]
@@ -85,8 +83,7 @@ namespace Markdig.Tests.Specs.Normalize.Headings
//
// Text after two newlines 1
Console.WriteLine("Example 3\nSection Headings\n");
TestNormalize.TestSpec("Heading\n=======\n\nText after two newlines 1", "# Heading\n\nText after two newlines 1", "");
TestNormalize.TestSpec("Heading\n=======\n\nText after two newlines 1", "# Heading\n\nText after two newlines 1", "", context: "Example 3\nSection Headings\n");
}
}
}

View File

@@ -27,8 +27,7 @@ namespace Markdig.Tests.Specs.PlainText.Sample
// Hello, world!
//
Console.WriteLine("Example 1\nSection Sample plain text spec\n");
TestPlainText.TestSpec("*Hello*, [world](http://example.com)!", "Hello, world!\n", "");
TestPlainText.TestSpec("*Hello*, [world](http://example.com)!", "Hello, world!\n", "", context: "Example 1\nSection Sample plain text spec\n");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -34,8 +34,7 @@ namespace Markdig.Tests.Specs.Abbreviations
// Should be rendered as:
// <p>Later in a text we are using <abbr title="Hypertext Markup Language">HTML</abbr> and it becomes an abbr tag <abbr title="Hypertext Markup Language">HTML</abbr></p>
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", "<p>Later in a text we are using <abbr title=\"Hypertext Markup Language\">HTML</abbr> and it becomes an abbr tag <abbr title=\"Hypertext Markup Language\">HTML</abbr></p>", "abbreviations|advanced");
TestParser.TestSpec("*[HTML]: Hypertext Markup Language\n\nLater in a text we are using HTML and it becomes an abbr tag HTML", "<p>Later in a text we are using <abbr title=\"Hypertext Markup Language\">HTML</abbr> and it becomes an abbr tag <abbr title=\"Hypertext Markup Language\">HTML</abbr></p>", "abbreviations|advanced", context: "Example 1\nSection Extensions / Abbreviation\n");
}
// An abbreviation definition can be indented at most 3 spaces
@@ -53,8 +52,7 @@ namespace Markdig.Tests.Specs.Abbreviations
// <pre><code>*[This]: is not an abbreviation
// </code></pre>
Console.WriteLine("Example 2\nSection Extensions / Abbreviation\n");
TestParser.TestSpec("*[HTML]: Hypertext Markup Language\n *[This]: is not an abbreviation", "<pre><code>*[This]: is not an abbreviation\n</code></pre>", "abbreviations|advanced");
TestParser.TestSpec("*[HTML]: Hypertext Markup Language\n *[This]: is not an abbreviation", "<pre><code>*[This]: is not an abbreviation\n</code></pre>", "abbreviations|advanced", context: "Example 2\nSection Extensions / Abbreviation\n");
}
// An abbreviation may contain spaces:
@@ -72,8 +70,7 @@ namespace Markdig.Tests.Specs.Abbreviations
// Should be rendered as:
// <p>This is a <abbr title="Super Hypertext Markup Language">SUPER HTML</abbr> document</p>
Console.WriteLine("Example 3\nSection Extensions / Abbreviation\n");
TestParser.TestSpec("*[SUPER HTML]: Super Hypertext Markup Language\n\nThis is a SUPER HTML document ", "<p>This is a <abbr title=\"Super Hypertext Markup Language\">SUPER HTML</abbr> document</p>", "abbreviations|advanced");
TestParser.TestSpec("*[SUPER HTML]: Super Hypertext Markup Language\n\nThis is a SUPER HTML document ", "<p>This is a <abbr title=\"Super Hypertext Markup Language\">SUPER HTML</abbr> document</p>", "abbreviations|advanced", context: "Example 3\nSection Extensions / Abbreviation\n");
}
// Abbreviation may contain any unicode characters:
@@ -91,8 +88,7 @@ namespace Markdig.Tests.Specs.Abbreviations
// Should be rendered as:
// <p>This is a <abbr title="Hypertext Markup Language">😃 HTML</abbr> document</p>
Console.WriteLine("Example 4\nSection Extensions / Abbreviation\n");
TestParser.TestSpec("*[😃 HTML]: Hypertext Markup Language\n\nThis is a 😃 HTML document ", "<p>This is a <abbr title=\"Hypertext Markup Language\">😃 HTML</abbr> document</p>", "abbreviations|advanced");
TestParser.TestSpec("*[😃 HTML]: Hypertext Markup Language\n\nThis is a 😃 HTML document ", "<p>This is a <abbr title=\"Hypertext Markup Language\">😃 HTML</abbr> document</p>", "abbreviations|advanced", context: "Example 4\nSection Extensions / Abbreviation\n");
}
// Abbreviations may be similar:
@@ -112,8 +108,7 @@ namespace Markdig.Tests.Specs.Abbreviations
// Should be rendered as:
// <p>We can abbreviate <abbr title="First">1A</abbr>, <abbr title="Second">1A1</abbr> and <abbr title="Third">1A2</abbr>!</p>
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!", "<p>We can abbreviate <abbr title=\"First\">1A</abbr>, <abbr title=\"Second\">1A1</abbr> and <abbr title=\"Third\">1A2</abbr>!</p>", "abbreviations|advanced");
TestParser.TestSpec("*[1A]: First\n*[1A1]: Second\n*[1A2]: Third\n\nWe can abbreviate 1A, 1A1 and 1A2!", "<p>We can abbreviate <abbr title=\"First\">1A</abbr>, <abbr title=\"Second\">1A1</abbr> and <abbr title=\"Third\">1A2</abbr>!</p>", "abbreviations|advanced", context: "Example 5\nSection Extensions / Abbreviation\n");
}
// Abbreviations should match whole word only:
@@ -131,8 +126,7 @@ namespace Markdig.Tests.Specs.Abbreviations
// Should be rendered as:
// <p>We should not abbreviate 1.1A or 11A!</p>
Console.WriteLine("Example 6\nSection Extensions / Abbreviation\n");
TestParser.TestSpec("*[1A]: First\n\nWe should not abbreviate 1.1A or 11A!", "<p>We should not abbreviate 1.1A or 11A!</p>", "abbreviations|advanced");
TestParser.TestSpec("*[1A]: First\n\nWe should not abbreviate 1.1A or 11A!", "<p>We should not abbreviate 1.1A or 11A!</p>", "abbreviations|advanced", context: "Example 6\nSection Extensions / Abbreviation\n");
}
// Abbreviations should match whole word only, even if the word is the entire content:
@@ -150,8 +144,7 @@ namespace Markdig.Tests.Specs.Abbreviations
// Should be rendered as:
// <p>1.1A</p>
Console.WriteLine("Example 7\nSection Extensions / Abbreviation\n");
TestParser.TestSpec("*[1A]: First\n\n1.1A", "<p>1.1A</p>", "abbreviations|advanced");
TestParser.TestSpec("*[1A]: First\n\n1.1A", "<p>1.1A</p>", "abbreviations|advanced", context: "Example 7\nSection Extensions / Abbreviation\n");
}
// Abbreviations should match whole word only, even if there is another glossary term:
@@ -170,8 +163,7 @@ namespace Markdig.Tests.Specs.Abbreviations
// Should be rendered as:
// <p><abbr title="Second">SCOM</abbr></p>
Console.WriteLine("Example 8\nSection Extensions / Abbreviation\n");
TestParser.TestSpec("*[SCO]: First\n*[SCOM]: Second\n\nSCOM", "<p><abbr title=\"Second\">SCOM</abbr></p>", "abbreviations|advanced");
TestParser.TestSpec("*[SCO]: First\n*[SCOM]: Second\n\nSCOM", "<p><abbr title=\"Second\">SCOM</abbr></p>", "abbreviations|advanced", context: "Example 8\nSection Extensions / Abbreviation\n");
}
// Abbreviations should only match when surrounded by whitespace:
@@ -189,8 +181,7 @@ namespace Markdig.Tests.Specs.Abbreviations
// Should be rendered as:
// <p>PRAA</p>
Console.WriteLine("Example 9\nSection Extensions / Abbreviation\n");
TestParser.TestSpec("*[PR]: Pull Request\n\nPRAA", "<p>PRAA</p>", "abbreviations|advanced");
TestParser.TestSpec("*[PR]: Pull Request\n\nPRAA", "<p>PRAA</p>", "abbreviations|advanced", context: "Example 9\nSection Extensions / Abbreviation\n");
}
// Single character abbreviations should be matched
@@ -208,8 +199,7 @@ namespace Markdig.Tests.Specs.Abbreviations
// Should be rendered as:
// <p><abbr title="Foo">A</abbr></p>
Console.WriteLine("Example 10\nSection Extensions / Abbreviation\n");
TestParser.TestSpec("*[A]: Foo\n\nA", "<p><abbr title=\"Foo\">A</abbr></p>", "abbreviations|advanced");
TestParser.TestSpec("*[A]: Foo\n\nA", "<p><abbr title=\"Foo\">A</abbr></p>", "abbreviations|advanced", context: "Example 10\nSection Extensions / Abbreviation\n");
}
// The longest matching abbreviation should be used
@@ -228,8 +218,7 @@ namespace Markdig.Tests.Specs.Abbreviations
// Should be rendered as:
// <p><abbr title="foo">Foo</abbr> B</p>
Console.WriteLine("Example 11\nSection Extensions / Abbreviation\n");
TestParser.TestSpec("*[Foo]: foo\n*[Foo Bar]: foobar\n\nFoo B", "<p><abbr title=\"foo\">Foo</abbr> B</p>", "abbreviations|advanced");
TestParser.TestSpec("*[Foo]: foo\n*[Foo Bar]: foobar\n\nFoo B", "<p><abbr title=\"foo\">Foo</abbr> B</p>", "abbreviations|advanced", context: "Example 11\nSection Extensions / Abbreviation\n");
}
}
}

View File

@@ -30,8 +30,7 @@ namespace Markdig.Tests.Specs.AutoIdentifiers
// Should be rendered as:
// <h1 id="this-is-a-heading">This is a heading</h1>
Console.WriteLine("Example 1\nSection Extensions / Heading Auto Identifiers\n");
TestParser.TestSpec("# This is a heading", "<h1 id=\"this-is-a-heading\">This is a heading</h1>", "autoidentifiers|advanced");
TestParser.TestSpec("# This is a heading", "<h1 id=\"this-is-a-heading\">This is a heading</h1>", "autoidentifiers|advanced", context: "Example 1\nSection Extensions / Heading Auto Identifiers\n");
}
// Only punctuation `-`, `_` and `.` is kept, all other non letter characters are discarded.
@@ -49,8 +48,7 @@ namespace Markdig.Tests.Specs.AutoIdentifiers
// Should be rendered as:
// <h1 id="this-is-a-heading_with.and">This - is a &amp;@! heading _ with . and ! -</h1>
Console.WriteLine("Example 2\nSection Extensions / Heading Auto Identifiers\n");
TestParser.TestSpec("# This - is a &@! heading _ with . and ! -", "<h1 id=\"this-is-a-heading_with.and\">This - is a &amp;@! heading _ with . and ! -</h1>", "autoidentifiers|advanced");
TestParser.TestSpec("# This - is a &@! heading _ with . and ! -", "<h1 id=\"this-is-a-heading_with.and\">This - is a &amp;@! heading _ with . and ! -</h1>", "autoidentifiers|advanced", context: "Example 2\nSection Extensions / Heading Auto Identifiers\n");
}
// Formatting (emphasis) are also discarded:
@@ -66,8 +64,7 @@ namespace Markdig.Tests.Specs.AutoIdentifiers
// Should be rendered as:
// <h1 id="this-is-a-heading">This is a <em>heading</em></h1>
Console.WriteLine("Example 3\nSection Extensions / Heading Auto Identifiers\n");
TestParser.TestSpec("# This is a *heading*", "<h1 id=\"this-is-a-heading\">This is a <em>heading</em></h1>", "autoidentifiers|advanced");
TestParser.TestSpec("# This is a *heading*", "<h1 id=\"this-is-a-heading\">This is a <em>heading</em></h1>", "autoidentifiers|advanced", context: "Example 3\nSection Extensions / Heading Auto Identifiers\n");
}
// Links are also removed:
@@ -83,8 +80,7 @@ namespace Markdig.Tests.Specs.AutoIdentifiers
// Should be rendered as:
// <h1 id="this-is-a-heading">This is a <a href="/url">heading</a></h1>
Console.WriteLine("Example 4\nSection Extensions / Heading Auto Identifiers\n");
TestParser.TestSpec("# This is a [heading](/url)", "<h1 id=\"this-is-a-heading\">This is a <a href=\"/url\">heading</a></h1>", "autoidentifiers|advanced");
TestParser.TestSpec("# This is a [heading](/url)", "<h1 id=\"this-is-a-heading\">This is a <a href=\"/url\">heading</a></h1>", "autoidentifiers|advanced", context: "Example 4\nSection Extensions / Heading Auto Identifiers\n");
}
// If multiple heading have the same text, -1, -2...-n will be postfix to the header id.
@@ -102,8 +98,7 @@ namespace Markdig.Tests.Specs.AutoIdentifiers
// <h1 id="this-is-a-heading">This is a heading</h1>
// <h1 id="this-is-a-heading-1">This is a heading</h1>
Console.WriteLine("Example 5\nSection Extensions / Heading Auto Identifiers\n");
TestParser.TestSpec("# This is a heading\n# This is a heading", "<h1 id=\"this-is-a-heading\">This is a heading</h1>\n<h1 id=\"this-is-a-heading-1\">This is a heading</h1>", "autoidentifiers|advanced");
TestParser.TestSpec("# This is a heading\n# This is a heading", "<h1 id=\"this-is-a-heading\">This is a heading</h1>\n<h1 id=\"this-is-a-heading-1\">This is a heading</h1>", "autoidentifiers|advanced", context: "Example 5\nSection Extensions / Heading Auto Identifiers\n");
}
// The heading Id will start on the first letter character of the heading, all previous characters will be discarded:
@@ -119,8 +114,7 @@ namespace Markdig.Tests.Specs.AutoIdentifiers
// Should be rendered as:
// <h1 id="this-is-a-heading">1.0 This is a heading</h1>
Console.WriteLine("Example 6\nSection Extensions / Heading Auto Identifiers\n");
TestParser.TestSpec("# 1.0 This is a heading", "<h1 id=\"this-is-a-heading\">1.0 This is a heading</h1>", "autoidentifiers|advanced");
TestParser.TestSpec("# 1.0 This is a heading", "<h1 id=\"this-is-a-heading\">1.0 This is a heading</h1>", "autoidentifiers|advanced", context: "Example 6\nSection Extensions / Heading Auto Identifiers\n");
}
// If the heading is all stripped by the previous rules, the id `section` will be used instead:
@@ -138,8 +132,7 @@ namespace Markdig.Tests.Specs.AutoIdentifiers
// <h1 id="section">1.0 &amp; ^ % *</h1>
// <h1 id="section-1">1.0 &amp; ^ % *</h1>
Console.WriteLine("Example 7\nSection Extensions / Heading Auto Identifiers\n");
TestParser.TestSpec("# 1.0 & ^ % *\n# 1.0 & ^ % *", "<h1 id=\"section\">1.0 &amp; ^ % *</h1>\n<h1 id=\"section-1\">1.0 &amp; ^ % *</h1>", "autoidentifiers|advanced");
TestParser.TestSpec("# 1.0 & ^ % *\n# 1.0 & ^ % *", "<h1 id=\"section\">1.0 &amp; ^ % *</h1>\n<h1 id=\"section-1\">1.0 &amp; ^ % *</h1>", "autoidentifiers|advanced", context: "Example 7\nSection Extensions / Heading Auto Identifiers\n");
}
// When the options "AutoLink" is setup, it is possible to link to an existing heading by using the
@@ -158,8 +151,7 @@ namespace Markdig.Tests.Specs.AutoIdentifiers
// <h1 id="this-is-a-heading">This is a heading</h1>
// <p><a href="#this-is-a-heading">This is a heading</a></p>
Console.WriteLine("Example 8\nSection Extensions / Heading Auto Identifiers\n");
TestParser.TestSpec("# This is a heading\n[This is a heading]", "<h1 id=\"this-is-a-heading\">This is a heading</h1>\n<p><a href=\"#this-is-a-heading\">This is a heading</a></p>", "autoidentifiers|advanced");
TestParser.TestSpec("# This is a heading\n[This is a heading]", "<h1 id=\"this-is-a-heading\">This is a heading</h1>\n<p><a href=\"#this-is-a-heading\">This is a heading</a></p>", "autoidentifiers|advanced", context: "Example 8\nSection Extensions / Heading Auto Identifiers\n");
}
// Links before the heading are also working:
@@ -177,8 +169,7 @@ namespace Markdig.Tests.Specs.AutoIdentifiers
// <p><a href="#this-is-a-heading">This is a heading</a></p>
// <h1 id="this-is-a-heading">This is a heading</h1>
Console.WriteLine("Example 9\nSection Extensions / Heading Auto Identifiers\n");
TestParser.TestSpec("[This is a heading]\n# This is a heading", "<p><a href=\"#this-is-a-heading\">This is a heading</a></p>\n<h1 id=\"this-is-a-heading\">This is a heading</h1>", "autoidentifiers|advanced");
TestParser.TestSpec("[This is a heading]\n# This is a heading", "<p><a href=\"#this-is-a-heading\">This is a heading</a></p>\n<h1 id=\"this-is-a-heading\">This is a heading</h1>", "autoidentifiers|advanced", context: "Example 9\nSection Extensions / Heading Auto Identifiers\n");
}
// The text of the link can be changed:
@@ -196,8 +187,7 @@ namespace Markdig.Tests.Specs.AutoIdentifiers
// <p><a href="#this-is-a-heading">With a new text</a></p>
// <h1 id="this-is-a-heading">This is a heading</h1>
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", "<p><a href=\"#this-is-a-heading\">With a new text</a></p>\n<h1 id=\"this-is-a-heading\">This is a heading</h1>", "autoidentifiers|advanced");
TestParser.TestSpec("[With a new text][This is a heading]\n# This is a heading", "<p><a href=\"#this-is-a-heading\">With a new text</a></p>\n<h1 id=\"this-is-a-heading\">This is a heading</h1>", "autoidentifiers|advanced", context: "Example 10\nSection Extensions / Heading Auto Identifiers\n");
}
// An autoidentifier should not conflict with an existing link:
@@ -216,8 +206,7 @@ namespace Markdig.Tests.Specs.AutoIdentifiers
// <p><img src="./scenario.png" alt="scenario image" /></p>
// <h2 id="scenario">Scenario</h2>
Console.WriteLine("Example 11\nSection Extensions / Heading Auto Identifiers\n");
TestParser.TestSpec("![scenario image][scenario]\n## Scenario\n[scenario]: ./scenario.png", "<p><img src=\"./scenario.png\" alt=\"scenario image\" /></p>\n<h2 id=\"scenario\">Scenario</h2>", "autoidentifiers|advanced");
TestParser.TestSpec("![scenario image][scenario]\n## Scenario\n[scenario]: ./scenario.png", "<p><img src=\"./scenario.png\" alt=\"scenario image\" /></p>\n<h2 id=\"scenario\">Scenario</h2>", "autoidentifiers|advanced", context: "Example 11\nSection Extensions / Heading Auto Identifiers\n");
}
}
}

View File

@@ -44,8 +44,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// And a <a href="tel:+1555123456">+1555123456</a>
// And a plain <a href="http://www.google.com">www.google.com</a></p>
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 tel:+1555123456\nAnd a plain www.google.com", "<p>This is a <a href=\"http://www.google.com\">http://www.google.com</a> URL and <a href=\"https://www.google.com\">https://www.google.com</a>\nThis is a <a href=\"ftp://test.com\">ftp://test.com</a>\nAnd a <a href=\"mailto:email@toto.com\">email@toto.com</a>\nAnd a <a href=\"tel:+1555123456\">+1555123456</a>\nAnd a plain <a href=\"http://www.google.com\">www.google.com</a></p>", "autolinks|advanced");
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 tel:+1555123456\nAnd a plain www.google.com", "<p>This is a <a href=\"http://www.google.com\">http://www.google.com</a> URL and <a href=\"https://www.google.com\">https://www.google.com</a>\nThis is a <a href=\"ftp://test.com\">ftp://test.com</a>\nAnd a <a href=\"mailto:email@toto.com\">email@toto.com</a>\nAnd a <a href=\"tel:+1555123456\">+1555123456</a>\nAnd a plain <a href=\"http://www.google.com\">www.google.com</a></p>", "autolinks|advanced", context: "Example 1\nSection Extensions / AutoLinks\n");
}
// But incomplete links will not be matched:
@@ -69,8 +68,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// And not a plain www. or a www.x
// And not a tel:</p>
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 \nAnd not a tel:", "<p>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\nAnd not a tel:</p>", "autolinks|advanced");
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 \nAnd not a tel:", "<p>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\nAnd not a tel:</p>", "autolinks|advanced", context: "Example 2\nSection Extensions / AutoLinks\n");
}
// Previous character must be a punctuation or a valid space (tab, space, new line):
@@ -86,8 +84,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p>This is not a nhttp://www.google.com URL but this is (<a href="https://www.google.com">https://www.google.com</a>)</p>
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)", "<p>This is not a nhttp://www.google.com URL but this is (<a href=\"https://www.google.com\">https://www.google.com</a>)</p>", "autolinks|advanced");
TestParser.TestSpec("This is not a nhttp://www.google.com URL but this is (https://www.google.com)", "<p>This is not a nhttp://www.google.com URL but this is (<a href=\"https://www.google.com\">https://www.google.com</a>)</p>", "autolinks|advanced", context: "Example 3\nSection Extensions / AutoLinks\n");
}
// An autolink should not interfere with an `<a>` HTML inline:
@@ -103,8 +100,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p>This is an HTML <a href="http://www.google.com">http://www.google.com</a> link</p>
Console.WriteLine("Example 4\nSection Extensions / AutoLinks\n");
TestParser.TestSpec("This is an HTML <a href=\"http://www.google.com\">http://www.google.com</a> link", "<p>This is an HTML <a href=\"http://www.google.com\">http://www.google.com</a> link</p>", "autolinks|advanced");
TestParser.TestSpec("This is an HTML <a href=\"http://www.google.com\">http://www.google.com</a> link", "<p>This is an HTML <a href=\"http://www.google.com\">http://www.google.com</a> link</p>", "autolinks|advanced", context: "Example 4\nSection Extensions / AutoLinks\n");
}
// or even within emphasis:
@@ -120,8 +116,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p>This is an HTML <a href="http://www.google.com"> <strong>http://www.google.com</strong> </a> link</p>
Console.WriteLine("Example 5\nSection Extensions / AutoLinks\n");
TestParser.TestSpec("This is an HTML <a href=\"http://www.google.com\"> **http://www.google.com** </a> link", "<p>This is an HTML <a href=\"http://www.google.com\"> <strong>http://www.google.com</strong> </a> link</p>", "autolinks|advanced");
TestParser.TestSpec("This is an HTML <a href=\"http://www.google.com\"> **http://www.google.com** </a> link", "<p>This is an HTML <a href=\"http://www.google.com\"> <strong>http://www.google.com</strong> </a> link</p>", "autolinks|advanced", context: "Example 5\nSection Extensions / AutoLinks\n");
}
// An autolink should not interfere with a markdown link:
@@ -137,8 +132,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p>This is an HTML <a href="http://www.google.com">http://www.google.com</a> link</p>
Console.WriteLine("Example 6\nSection Extensions / AutoLinks\n");
TestParser.TestSpec("This is an HTML [http://www.google.com](http://www.google.com) link", "<p>This is an HTML <a href=\"http://www.google.com\">http://www.google.com</a> link</p>", "autolinks|advanced");
TestParser.TestSpec("This is an HTML [http://www.google.com](http://www.google.com) link", "<p>This is an HTML <a href=\"http://www.google.com\">http://www.google.com</a> link</p>", "autolinks|advanced", context: "Example 6\nSection Extensions / AutoLinks\n");
}
// A link embraced by pending emphasis should let the emphasis takes precedence if characters are placed at the end of the matched link:
@@ -154,8 +148,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p>Check <strong><a href="http://www.a.com">http://www.a.com</a></strong> or <strong><a href="http://www.b.com">http://www.b.com</a></strong></p>
Console.WriteLine("Example 7\nSection Extensions / AutoLinks\n");
TestParser.TestSpec("Check **http://www.a.com** or __http://www.b.com__", "<p>Check <strong><a href=\"http://www.a.com\">http://www.a.com</a></strong> or <strong><a href=\"http://www.b.com\">http://www.b.com</a></strong></p>", "autolinks|advanced");
TestParser.TestSpec("Check **http://www.a.com** or __http://www.b.com__", "<p>Check <strong><a href=\"http://www.a.com\">http://www.a.com</a></strong> or <strong><a href=\"http://www.b.com\">http://www.b.com</a></strong></p>", "autolinks|advanced", context: "Example 7\nSection Extensions / AutoLinks\n");
}
// 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):
@@ -171,8 +164,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p><a href="mailto:email@test.com">email@test.com</a> is okay, but mailto:@test.com is not</p>
Console.WriteLine("Example 8\nSection Extensions / AutoLinks\n");
TestParser.TestSpec("mailto:email@test.com is okay, but mailto:@test.com is not", "<p><a href=\"mailto:email@test.com\">email@test.com</a> is okay, but mailto:@test.com is not</p>", "autolinks|advanced");
TestParser.TestSpec("mailto:email@test.com is okay, but mailto:@test.com is not", "<p><a href=\"mailto:email@test.com\">email@test.com</a> is okay, but mailto:@test.com is not</p>", "autolinks|advanced", context: "Example 8\nSection Extensions / AutoLinks\n");
}
}
@@ -194,8 +186,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p><a href="http://www.commonmark.org">www.commonmark.org</a></p>
Console.WriteLine("Example 9\nSection Extensions / AutoLinks / GFM Support\n");
TestParser.TestSpec("www.commonmark.org", "<p><a href=\"http://www.commonmark.org\">www.commonmark.org</a></p>", "autolinks|advanced");
TestParser.TestSpec("www.commonmark.org", "<p><a href=\"http://www.commonmark.org\">www.commonmark.org</a></p>", "autolinks|advanced", context: "Example 9\nSection Extensions / AutoLinks / GFM Support\n");
}
[Test]
@@ -210,8 +201,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p>Visit <a href="http://www.commonmark.org/help">www.commonmark.org/help</a> for more information.</p>
Console.WriteLine("Example 10\nSection Extensions / AutoLinks / GFM Support\n");
TestParser.TestSpec("Visit www.commonmark.org/help for more information.", "<p>Visit <a href=\"http://www.commonmark.org/help\">www.commonmark.org/help</a> for more information.</p>", "autolinks|advanced");
TestParser.TestSpec("Visit www.commonmark.org/help for more information.", "<p>Visit <a href=\"http://www.commonmark.org/help\">www.commonmark.org/help</a> for more information.</p>", "autolinks|advanced", context: "Example 10\nSection Extensions / AutoLinks / GFM Support\n");
}
[Test]
@@ -229,8 +219,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// <p>Visit <a href="http://www.commonmark.org">www.commonmark.org</a>.</p>
// <p>Visit <a href="http://www.commonmark.org/a.b">www.commonmark.org/a.b</a>.</p>
Console.WriteLine("Example 11\nSection Extensions / AutoLinks / GFM Support\n");
TestParser.TestSpec("Visit www.commonmark.org.\n\nVisit www.commonmark.org/a.b.", "<p>Visit <a href=\"http://www.commonmark.org\">www.commonmark.org</a>.</p>\n<p>Visit <a href=\"http://www.commonmark.org/a.b\">www.commonmark.org/a.b</a>.</p>", "autolinks|advanced");
TestParser.TestSpec("Visit www.commonmark.org.\n\nVisit www.commonmark.org/a.b.", "<p>Visit <a href=\"http://www.commonmark.org\">www.commonmark.org</a>.</p>\n<p>Visit <a href=\"http://www.commonmark.org/a.b\">www.commonmark.org/a.b</a>.</p>", "autolinks|advanced", context: "Example 11\nSection Extensions / AutoLinks / GFM Support\n");
}
[Test]
@@ -248,8 +237,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// <p><a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a></p>
// <p>(<a href="http://www.google.com/search?q=Markup+(business)">www.google.com/search?q=Markup+(business)</a>)</p>
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))", "<p><a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a></p>\n<p>(<a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a>)</p>", "autolinks|advanced");
TestParser.TestSpec("www.google.com/search?q=Markup+(business)\n\n(www.google.com/search?q=Markup+(business))", "<p><a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a></p>\n<p>(<a href=\"http://www.google.com/search?q=Markup+(business)\">www.google.com/search?q=Markup+(business)</a>)</p>", "autolinks|advanced", context: "Example 12\nSection Extensions / AutoLinks / GFM Support\n");
}
[Test]
@@ -267,8 +255,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// <p><a href="http://www.google.com/search?q=commonmark&amp;hl=en">www.google.com/search?q=commonmark&amp;hl=en</a></p>
// <p><a href="http://www.google.com/search?q=commonmark">www.google.com/search?q=commonmark</a>&amp;hl;</p>
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;", "<p><a href=\"http://www.google.com/search?q=commonmark&amp;hl=en\">www.google.com/search?q=commonmark&amp;hl=en</a></p>\n<p><a href=\"http://www.google.com/search?q=commonmark\">www.google.com/search?q=commonmark</a>&amp;hl;</p>", "autolinks|advanced");
TestParser.TestSpec("www.google.com/search?q=commonmark&hl=en\n\nwww.google.com/search?q=commonmark&hl;", "<p><a href=\"http://www.google.com/search?q=commonmark&amp;hl=en\">www.google.com/search?q=commonmark&amp;hl=en</a></p>\n<p><a href=\"http://www.google.com/search?q=commonmark\">www.google.com/search?q=commonmark</a>&amp;hl;</p>", "autolinks|advanced", context: "Example 13\nSection Extensions / AutoLinks / GFM Support\n");
}
[Test]
@@ -283,8 +270,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p><a href="http://www.commonmark.org/he">www.commonmark.org/he</a>&lt;lp</p>
Console.WriteLine("Example 14\nSection Extensions / AutoLinks / GFM Support\n");
TestParser.TestSpec("www.commonmark.org/he<lp", "<p><a href=\"http://www.commonmark.org/he\">www.commonmark.org/he</a>&lt;lp</p>", "autolinks|advanced");
TestParser.TestSpec("www.commonmark.org/he<lp", "<p><a href=\"http://www.commonmark.org/he\">www.commonmark.org/he</a>&lt;lp</p>", "autolinks|advanced", context: "Example 14\nSection Extensions / AutoLinks / GFM Support\n");
}
[Test]
@@ -305,8 +291,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// <p>(Visit <a href="https://encrypted.google.com/search?q=Markup+(business)">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>
// <p>Anonymous FTP is available at <a href="ftp://foo.bar.baz">ftp://foo.bar.baz</a>.</p>
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.", "<p><a href=\"http://commonmark.org\">http://commonmark.org</a></p>\n<p>(Visit <a href=\"https://encrypted.google.com/search?q=Markup+(business)\">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>\n<p>Anonymous FTP is available at <a href=\"ftp://foo.bar.baz\">ftp://foo.bar.baz</a>.</p>", "autolinks|advanced");
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.", "<p><a href=\"http://commonmark.org\">http://commonmark.org</a></p>\n<p>(Visit <a href=\"https://encrypted.google.com/search?q=Markup+(business)\">https://encrypted.google.com/search?q=Markup+(business)</a>)</p>\n<p>Anonymous FTP is available at <a href=\"ftp://foo.bar.baz\">ftp://foo.bar.baz</a>.</p>", "autolinks|advanced", context: "Example 15\nSection Extensions / AutoLinks / GFM Support\n");
}
}
@@ -346,8 +331,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// mailto:email@test.
// mailto:email@.test</p>
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", "<p>www..\nwww..com\nhttp://test.\nhttp://.test\nhttp://.\nhttp://..\nftp://test.\nftp://.test\nmailto:email@test.\nmailto:email@.test</p>", "autolinks|advanced");
TestParser.TestSpec("www..\nwww..com\nhttp://test.\nhttp://.test\nhttp://.\nhttp://..\nftp://test.\nftp://.test\nmailto:email@test.\nmailto:email@.test", "<p>www..\nwww..com\nhttp://test.\nhttp://.test\nhttp://.\nhttp://..\nftp://test.\nftp://.test\nmailto:email@test.\nmailto:email@.test</p>", "autolinks|advanced", context: "Example 16\nSection Extensions / AutoLinks / Valid Domain Tests\n");
}
// Domain names with too few segments won't be matched
@@ -371,8 +355,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// ftp://test
// mailto:email@test</p>
Console.WriteLine("Example 17\nSection Extensions / AutoLinks / Valid Domain Tests\n");
TestParser.TestSpec("www\nwww.com\nhttp://test\nftp://test\nmailto:email@test", "<p>www\nwww.com\nhttp://test\nftp://test\nmailto:email@test</p>", "autolinks|advanced");
TestParser.TestSpec("www\nwww.com\nhttp://test\nftp://test\nmailto:email@test", "<p>www\nwww.com\nhttp://test\nftp://test\nmailto:email@test</p>", "autolinks|advanced", context: "Example 17\nSection Extensions / AutoLinks / Valid Domain Tests\n");
}
// Domain names that contain an underscores in the last two segments won't be matched
@@ -400,8 +383,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// <p><a href="ftp://test_.foo.bar">ftp://test_.foo.bar</a> is okay, but ftp://test.fo_o is not</p>
// <p><a href="mailto:email@_test.foo.bar">email@_test.foo.bar</a> is okay, but mailto:email@_test.foo is not</p>
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", "<p><a href=\"http://www._test.foo.bar\">www._test.foo.bar</a> is okay, but www._test.foo is not</p>\n<p><a href=\"http://te_st.foo.bar\">http://te_st.foo.bar</a> is okay, as is <a href=\"http://test.foo_.bar.foo\">http://test.foo_.bar.foo</a></p>\n<p>But http://te_st.foo, http://test.foo_.bar and http://test._foo are not</p>\n<p><a href=\"ftp://test_.foo.bar\">ftp://test_.foo.bar</a> is okay, but ftp://test.fo_o is not</p>\n<p><a href=\"mailto:email@_test.foo.bar\">email@_test.foo.bar</a> is okay, but mailto:email@_test.foo is not</p>", "autolinks|advanced");
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", "<p><a href=\"http://www._test.foo.bar\">www._test.foo.bar</a> is okay, but www._test.foo is not</p>\n<p><a href=\"http://te_st.foo.bar\">http://te_st.foo.bar</a> is okay, as is <a href=\"http://test.foo_.bar.foo\">http://test.foo_.bar.foo</a></p>\n<p>But http://te_st.foo, http://test.foo_.bar and http://test._foo are not</p>\n<p><a href=\"ftp://test_.foo.bar\">ftp://test_.foo.bar</a> is okay, but ftp://test.fo_o is not</p>\n<p><a href=\"mailto:email@_test.foo.bar\">email@_test.foo.bar</a> is okay, but mailto:email@_test.foo is not</p>", "autolinks|advanced", context: "Example 18\nSection Extensions / AutoLinks / Valid Domain Tests\n");
}
// Domain names that contain invalid characters (not AlphaNumberic, -, _ or .) won't be matched
@@ -417,8 +399,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p>https://[your-domain]/api</p>
Console.WriteLine("Example 19\nSection Extensions / AutoLinks / Valid Domain Tests\n");
TestParser.TestSpec("https://[your-domain]/api", "<p>https://[your-domain]/api</p>", "autolinks|advanced");
TestParser.TestSpec("https://[your-domain]/api", "<p>https://[your-domain]/api</p>", "autolinks|advanced", context: "Example 19\nSection Extensions / AutoLinks / Valid Domain Tests\n");
}
// Domain names followed by ?, : or # instead of / are matched
@@ -446,8 +427,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// <p><a href="https://github.com">https://github.com</a>:</p>
// <p><a href="https://github.com:443">https://github.com:443</a></p>
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", "<p><a href=\"https://github.com\">https://github.com</a>?</p>\n<p><a href=\"https://github.com?a\">https://github.com?a</a></p>\n<p><a href=\"https://github.com#a\">https://github.com#a</a></p>\n<p><a href=\"https://github.com\">https://github.com</a>:</p>\n<p><a href=\"https://github.com:443\">https://github.com:443</a></p>", "autolinks|advanced");
TestParser.TestSpec("https://github.com?\n\nhttps://github.com?a\n\nhttps://github.com#a\n\nhttps://github.com:\n\nhttps://github.com:443", "<p><a href=\"https://github.com\">https://github.com</a>?</p>\n<p><a href=\"https://github.com?a\">https://github.com?a</a></p>\n<p><a href=\"https://github.com#a\">https://github.com#a</a></p>\n<p><a href=\"https://github.com\">https://github.com</a>:</p>\n<p><a href=\"https://github.com:443\">https://github.com:443</a></p>", "autolinks|advanced", context: "Example 20\nSection Extensions / AutoLinks / Valid Domain Tests\n");
}
}
@@ -478,8 +458,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// <p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
// <p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
Console.WriteLine("Example 21\nSection Extensions / AutoLinks / Unicode support\n");
TestParser.TestSpec("http://abc.net/☃\n\nhttp://abc.net?☃\n\nhttp://abc.net#☃\n\nhttp://abc.net/foo#☃", "<p><a href=\"http://abc.net/%E2%98%83\">http://abc.net/☃</a></p>\n<p><a href=\"http://abc.net?%E2%98%83\">http://abc.net?☃</a></p>\n<p><a href=\"http://abc.net#%E2%98%83\">http://abc.net#☃</a></p>\n<p><a href=\"http://abc.net/foo#%E2%98%83\">http://abc.net/foo#☃</a></p>", "autolinks|advanced");
TestParser.TestSpec("http://abc.net/☃\n\nhttp://abc.net?☃\n\nhttp://abc.net#☃\n\nhttp://abc.net/foo#☃", "<p><a href=\"http://abc.net/%E2%98%83\">http://abc.net/☃</a></p>\n<p><a href=\"http://abc.net?%E2%98%83\">http://abc.net?☃</a></p>\n<p><a href=\"http://abc.net#%E2%98%83\">http://abc.net#☃</a></p>\n<p><a href=\"http://abc.net/foo#%E2%98%83\">http://abc.net/foo#☃</a></p>", "autolinks|advanced", context: "Example 21\nSection Extensions / AutoLinks / Unicode support\n");
}
// Unicode characters in the FQDN are matched and IDNA encoded
@@ -495,8 +474,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
Console.WriteLine("Example 22\nSection Extensions / AutoLinks / Unicode support\n");
TestParser.TestSpec("http://☃.net?☃", "<p><a href=\"http://xn--n3h.net?%E2%98%83\">http://☃.net?☃</a></p>", "autolinks|advanced");
TestParser.TestSpec("http://☃.net?☃", "<p><a href=\"http://xn--n3h.net?%E2%98%83\">http://☃.net?☃</a></p>", "autolinks|advanced", context: "Example 22\nSection Extensions / AutoLinks / Unicode support\n");
}
// Same goes for regular autolinks
@@ -521,8 +499,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// <p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
// <p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
Console.WriteLine("Example 23\nSection Extensions / AutoLinks / Unicode support\n");
TestParser.TestSpec("<http://abc.net/☃>\n\n<http://abc.net?☃>\n\n<http://abc.net#☃>\n\n<http://abc.net/foo#☃>", "<p><a href=\"http://abc.net/%E2%98%83\">http://abc.net/☃</a></p>\n<p><a href=\"http://abc.net?%E2%98%83\">http://abc.net?☃</a></p>\n<p><a href=\"http://abc.net#%E2%98%83\">http://abc.net#☃</a></p>\n<p><a href=\"http://abc.net/foo#%E2%98%83\">http://abc.net/foo#☃</a></p>", "autolinks|advanced");
TestParser.TestSpec("<http://abc.net/☃>\n\n<http://abc.net?☃>\n\n<http://abc.net#☃>\n\n<http://abc.net/foo#☃>", "<p><a href=\"http://abc.net/%E2%98%83\">http://abc.net/☃</a></p>\n<p><a href=\"http://abc.net?%E2%98%83\">http://abc.net?☃</a></p>\n<p><a href=\"http://abc.net#%E2%98%83\">http://abc.net#☃</a></p>\n<p><a href=\"http://abc.net/foo#%E2%98%83\">http://abc.net/foo#☃</a></p>", "autolinks|advanced", context: "Example 23\nSection Extensions / AutoLinks / Unicode support\n");
}
[Test]
@@ -537,8 +514,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
Console.WriteLine("Example 24\nSection Extensions / AutoLinks / Unicode support\n");
TestParser.TestSpec("<http://☃.net?☃>", "<p><a href=\"http://xn--n3h.net?%E2%98%83\">http://☃.net?☃</a></p>", "autolinks|advanced");
TestParser.TestSpec("<http://☃.net?☃>", "<p><a href=\"http://xn--n3h.net?%E2%98%83\">http://☃.net?☃</a></p>", "autolinks|advanced", context: "Example 24\nSection Extensions / AutoLinks / Unicode support\n");
}
// It also complies with CommonMark's vision of priority.
@@ -555,8 +531,7 @@ namespace Markdig.Tests.Specs.AutoLinks
// Should be rendered as:
// <p><a href="http://xn--fo-gka.bar.%60baz">http://foö.bar.`baz</a>`</p>
Console.WriteLine("Example 25\nSection Extensions / AutoLinks / Unicode support\n");
TestParser.TestSpec("<http://foö.bar.`baz>`", "<p><a href=\"http://xn--fo-gka.bar.%60baz\">http://foö.bar.`baz</a>`</p>", "autolinks|advanced");
TestParser.TestSpec("<http://foö.bar.`baz>`", "<p><a href=\"http://xn--fo-gka.bar.%60baz\">http://foö.bar.`baz</a>`</p>", "autolinks|advanced", context: "Example 25\nSection Extensions / AutoLinks / Unicode support\n");
}
}
}

View File

@@ -45,8 +45,7 @@ namespace Markdig.Tests.Specs.Bootstrap
// </tbody>
// </table>
Console.WriteLine("Example 1\nSection Extensions / Bootstrap\n");
TestParser.TestSpec("Name | Value\n-----| -----\nAbc | 16", "<table class=\"table\">\n<thead>\n<tr>\n<th>Name</th>\n<th>Value</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Abc</td>\n<td>16</td>\n</tr>\n</tbody>\n</table>", "bootstrap+pipetables+figures+attributes");
TestParser.TestSpec("Name | Value\n-----| -----\nAbc | 16", "<table class=\"table\">\n<thead>\n<tr>\n<th>Name</th>\n<th>Value</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Abc</td>\n<td>16</td>\n</tr>\n</tbody>\n</table>", "bootstrap+pipetables+figures+attributes", context: "Example 1\nSection Extensions / Bootstrap\n");
}
// Adds bootstrap `.blockquote` class to `<blockquote>`:
@@ -64,8 +63,7 @@ namespace Markdig.Tests.Specs.Bootstrap
// <p>This is a blockquote</p>
// </blockquote>
Console.WriteLine("Example 2\nSection Extensions / Bootstrap\n");
TestParser.TestSpec("> This is a blockquote", "<blockquote class=\"blockquote\">\n<p>This is a blockquote</p>\n</blockquote>", "bootstrap+pipetables+figures+attributes");
TestParser.TestSpec("> This is a blockquote", "<blockquote class=\"blockquote\">\n<p>This is a blockquote</p>\n</blockquote>", "bootstrap+pipetables+figures+attributes", context: "Example 2\nSection Extensions / Bootstrap\n");
}
// Adds bootstrap `.figure` class to `<figure>` and `.figure-caption` to `<figcaption>`
@@ -86,8 +84,7 @@ namespace Markdig.Tests.Specs.Bootstrap
// <figcaption class="figure-caption">This is the caption</figcaption>
// </figure>
Console.WriteLine("Example 3\nSection Extensions / Bootstrap\n");
TestParser.TestSpec("^^^\nThis is a text in a caption\n^^^ This is the caption", "<figure class=\"figure\">\n<p>This is a text in a caption</p>\n<figcaption class=\"figure-caption\">This is the caption</figcaption>\n</figure>", "bootstrap+pipetables+figures+attributes");
TestParser.TestSpec("^^^\nThis is a text in a caption\n^^^ This is the caption", "<figure class=\"figure\">\n<p>This is a text in a caption</p>\n<figcaption class=\"figure-caption\">This is the caption</figcaption>\n</figure>", "bootstrap+pipetables+figures+attributes", context: "Example 3\nSection Extensions / Bootstrap\n");
}
// Adds the `.img-fluid` class to all image links `<img>`
@@ -103,8 +100,7 @@ namespace Markdig.Tests.Specs.Bootstrap
// Should be rendered as:
// <p><img src="/url" class="img-fluid" alt="Image Link" /></p>
Console.WriteLine("Example 4\nSection Extensions / Bootstrap\n");
TestParser.TestSpec("![Image Link](/url)", "<p><img src=\"/url\" class=\"img-fluid\" alt=\"Image Link\" /></p>", "bootstrap+pipetables+figures+attributes");
TestParser.TestSpec("![Image Link](/url)", "<p><img src=\"/url\" class=\"img-fluid\" alt=\"Image Link\" /></p>", "bootstrap+pipetables+figures+attributes", context: "Example 4\nSection Extensions / Bootstrap\n");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -33,8 +33,7 @@ namespace Markdig.Tests.Specs.CustomContainers
// <div class="spoiler"><p>This is a <em>spoiler</em></p>
// </div>
Console.WriteLine("Example 1\nSection Extensions / Custom Container\n");
TestParser.TestSpec(":::spoiler\nThis is a *spoiler*\n:::", "<div class=\"spoiler\"><p>This is a <em>spoiler</em></p>\n</div>", "customcontainers+attributes|advanced");
TestParser.TestSpec(":::spoiler\nThis is a *spoiler*\n:::", "<div class=\"spoiler\"><p>This is a <em>spoiler</em></p>\n</div>", "customcontainers+attributes|advanced", context: "Example 1\nSection Extensions / Custom Container\n");
}
// The text following the opened custom container is optional:
@@ -53,8 +52,7 @@ namespace Markdig.Tests.Specs.CustomContainers
// <div><p>This is a regular div</p>
// </div>
Console.WriteLine("Example 2\nSection Extensions / Custom Container\n");
TestParser.TestSpec(":::\nThis is a regular div\n:::", "<div><p>This is a regular div</p>\n</div>", "customcontainers+attributes|advanced");
TestParser.TestSpec(":::\nThis is a regular div\n:::", "<div><p>This is a regular div</p>\n</div>", "customcontainers+attributes|advanced", context: "Example 2\nSection Extensions / Custom Container\n");
}
// Like for fenced code block, you can use more than 3 `:` characters as long as the closing has the same number of characters:
@@ -73,8 +71,7 @@ namespace Markdig.Tests.Specs.CustomContainers
// <div class="spoiler"><p>This is a spoiler</p>
// </div>
Console.WriteLine("Example 3\nSection Extensions / Custom Container\n");
TestParser.TestSpec("::::::::::::spoiler\nThis is a spoiler\n::::::::::::", "<div class=\"spoiler\"><p>This is a spoiler</p>\n</div>", "customcontainers+attributes|advanced");
TestParser.TestSpec("::::::::::::spoiler\nThis is a spoiler\n::::::::::::", "<div class=\"spoiler\"><p>This is a spoiler</p>\n</div>", "customcontainers+attributes|advanced", context: "Example 3\nSection Extensions / Custom Container\n");
}
// Like for fenced code block, a custom container can span over multiple empty lines in a list block:
@@ -106,8 +103,7 @@ namespace Markdig.Tests.Specs.CustomContainers
// <li>A second item in the list</li>
// </ul>
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", "<ul>\n<li>This is a list\n<div class=\"spoiler\">This is a spoiler\n<ul>\n<li>item1</li>\n<li>item2</li>\n</ul>\n</div>\n</li>\n<li>A second item in the list</li>\n</ul>", "customcontainers+attributes|advanced");
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", "<ul>\n<li>This is a list\n<div class=\"spoiler\">This is a spoiler\n<ul>\n<li>item1</li>\n<li>item2</li>\n</ul>\n</div>\n</li>\n<li>A second item in the list</li>\n</ul>", "customcontainers+attributes|advanced", context: "Example 4\nSection Extensions / Custom Container\n");
}
// Attributes extension is also supported for Custom Container, as long as the Attributes extension is activated after the CustomContainer extension (`.UseCustomContainer().UseAttributes()`)
@@ -126,8 +122,7 @@ namespace Markdig.Tests.Specs.CustomContainers
// <div id="myspoiler" class="spoiler" myprop="yes"><p>This is a spoiler</p>
// </div>
Console.WriteLine("Example 5\nSection Extensions / Custom Container\n");
TestParser.TestSpec(":::spoiler {#myspoiler myprop=yes}\nThis is a spoiler\n:::", "<div id=\"myspoiler\" class=\"spoiler\" myprop=\"yes\"><p>This is a spoiler</p>\n</div>", "customcontainers+attributes|advanced");
TestParser.TestSpec(":::spoiler {#myspoiler myprop=yes}\nThis is a spoiler\n:::", "<div id=\"myspoiler\" class=\"spoiler\" myprop=\"yes\"><p>This is a spoiler</p>\n</div>", "customcontainers+attributes|advanced", context: "Example 5\nSection Extensions / Custom Container\n");
}
// The content of a custom container can contain any blocks:
@@ -146,8 +141,7 @@ namespace Markdig.Tests.Specs.CustomContainers
// <div class="mycontainer"><p>This is a raw spoiler</p>
// </div>
Console.WriteLine("Example 6\nSection Extensions / Custom Container\n");
TestParser.TestSpec(":::mycontainer\n<p>This is a raw spoiler</p>\n:::", "<div class=\"mycontainer\"><p>This is a raw spoiler</p>\n</div>", "customcontainers+attributes|advanced");
TestParser.TestSpec(":::mycontainer\n<p>This is a raw spoiler</p>\n:::", "<div class=\"mycontainer\"><p>This is a raw spoiler</p>\n</div>", "customcontainers+attributes|advanced", context: "Example 6\nSection Extensions / Custom Container\n");
}
}
@@ -169,8 +163,7 @@ namespace Markdig.Tests.Specs.CustomContainers
// Should be rendered as:
// <p>This is a text <span>with special emphasis</span></p>
Console.WriteLine("Example 7\nSection Extensions / Inline Custom Container \n");
TestParser.TestSpec("This is a text ::with special emphasis::", "<p>This is a text <span>with special emphasis</span></p>", "customcontainers+attributes|advanced");
TestParser.TestSpec("This is a text ::with special emphasis::", "<p>This is a text <span>with special emphasis</span></p>", "customcontainers+attributes|advanced", context: "Example 7\nSection Extensions / Inline Custom Container \n");
}
// Any other emphasis inline can be used within this emphasis inline container:
@@ -186,8 +179,7 @@ namespace Markdig.Tests.Specs.CustomContainers
// Should be rendered as:
// <p>This is a text <span>with special <em>emphasis</em></span></p>
Console.WriteLine("Example 8\nSection Extensions / Inline Custom Container \n");
TestParser.TestSpec("This is a text ::with special *emphasis*::", "<p>This is a text <span>with special <em>emphasis</em></span></p>", "customcontainers+attributes|advanced");
TestParser.TestSpec("This is a text ::with special *emphasis*::", "<p>This is a text <span>with special <em>emphasis</em></span></p>", "customcontainers+attributes|advanced", context: "Example 8\nSection Extensions / Inline Custom Container \n");
}
// Attributes can be attached to a inline custom container:
@@ -203,8 +195,7 @@ namespace Markdig.Tests.Specs.CustomContainers
// Should be rendered as:
// <p>This is a text <span id="myId" class="myemphasis">with special emphasis</span></p>
Console.WriteLine("Example 9\nSection Extensions / Inline Custom Container \n");
TestParser.TestSpec("This is a text ::with special emphasis::{#myId .myemphasis}", "<p>This is a text <span id=\"myId\" class=\"myemphasis\">with special emphasis</span></p>", "customcontainers+attributes|advanced");
TestParser.TestSpec("This is a text ::with special emphasis::{#myId .myemphasis}", "<p>This is a text <span id=\"myId\" class=\"myemphasis\">with special emphasis</span></p>", "customcontainers+attributes|advanced", context: "Example 9\nSection Extensions / Inline Custom Container \n");
}
}
}

View File

@@ -71,8 +71,7 @@ namespace Markdig.Tests.Specs.DefinitionLists
// <dd>This is another definition for term2</dd>
// </dl>
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", "<dl>\n<dt>Term 1</dt>\n<dd><p>This is a definition item\nWith a paragraph</p>\n<blockquote>\n<p>This is a block quote</p>\n</blockquote>\n<ul>\n<li>This is a list</li>\n<li>with an item2</li>\n</ul>\n<pre><code class=\"language-java\">Test\n\n\n</code></pre>\n<p>And a last line</p>\n</dd>\n<dd>This ia another definition item</dd>\n<dt>Term2</dt>\n<dt>Term3 <em>with some inline</em></dt>\n<dd>This is another definition for term2</dd>\n</dl>", "definitionlists+attributes|advanced");
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", "<dl>\n<dt>Term 1</dt>\n<dd><p>This is a definition item\nWith a paragraph</p>\n<blockquote>\n<p>This is a block quote</p>\n</blockquote>\n<ul>\n<li>This is a list</li>\n<li>with an item2</li>\n</ul>\n<pre><code class=\"language-java\">Test\n\n\n</code></pre>\n<p>And a last line</p>\n</dd>\n<dd>This ia another definition item</dd>\n<dt>Term2</dt>\n<dt>Term3 <em>with some inline</em></dt>\n<dd>This is another definition for term2</dd>\n</dl>", "definitionlists+attributes|advanced", context: "Example 1\nSection Extensions / Definition lists\n");
}
// A definition term can be followed at most by one blank line. Lazy continuations are supported for definitions:
@@ -99,8 +98,7 @@ namespace Markdig.Tests.Specs.DefinitionLists
// </dd>
// </dl>
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.", "<dl>\n<dt>Term 1</dt>\n<dd><p>Definition\nwith lazy continuation.</p>\n<p>Second paragraph of the definition.</p>\n</dd>\n</dl>", "definitionlists+attributes|advanced");
TestParser.TestSpec("Term 1\n\n: Definition\nwith lazy continuation.\n\n Second paragraph of the definition.", "<dl>\n<dt>Term 1</dt>\n<dd><p>Definition\nwith lazy continuation.</p>\n<p>Second paragraph of the definition.</p>\n</dd>\n</dl>", "definitionlists+attributes|advanced", context: "Example 2\nSection Extensions / Definition lists\n");
}
// The definition must be indented to 4 characters including the `:`.
@@ -118,8 +116,7 @@ namespace Markdig.Tests.Specs.DefinitionLists
// <p>Term 1
// : Invalid with less than 3 characters</p>
Console.WriteLine("Example 3\nSection Extensions / Definition lists\n");
TestParser.TestSpec("Term 1\n: Invalid with less than 3 characters", "<p>Term 1\n: Invalid with less than 3 characters</p>", "definitionlists+attributes|advanced");
TestParser.TestSpec("Term 1\n: Invalid with less than 3 characters", "<p>Term 1\n: Invalid with less than 3 characters</p>", "definitionlists+attributes|advanced", context: "Example 3\nSection Extensions / Definition lists\n");
}
// The `:` can be indented up to 3 spaces:
@@ -139,8 +136,7 @@ namespace Markdig.Tests.Specs.DefinitionLists
// <dd>Valid even if <code>:</code> starts at most 3 spaces</dd>
// </dl>
Console.WriteLine("Example 4\nSection Extensions / Definition lists\n");
TestParser.TestSpec("Term 1\n : Valid even if `:` starts at most 3 spaces", "<dl>\n<dt>Term 1</dt>\n<dd>Valid even if <code>:</code> starts at most 3 spaces</dd>\n</dl>", "definitionlists+attributes|advanced");
TestParser.TestSpec("Term 1\n : Valid even if `:` starts at most 3 spaces", "<dl>\n<dt>Term 1</dt>\n<dd>Valid even if <code>:</code> starts at most 3 spaces</dd>\n</dl>", "definitionlists+attributes|advanced", context: "Example 4\nSection Extensions / Definition lists\n");
}
// But more than 3 spaces before `:` will trigger an indented code block:
@@ -160,8 +156,7 @@ namespace Markdig.Tests.Specs.DefinitionLists
// <pre><code>: Not valid
// </code></pre>
Console.WriteLine("Example 5\nSection Extensions / Definition lists\n");
TestParser.TestSpec("Term 1\n\n : Not valid", "<p>Term 1</p>\n<pre><code>: Not valid\n</code></pre>", "definitionlists+attributes|advanced");
TestParser.TestSpec("Term 1\n\n : Not valid", "<p>Term 1</p>\n<pre><code>: Not valid\n</code></pre>", "definitionlists+attributes|advanced", context: "Example 5\nSection Extensions / Definition lists\n");
}
// Definition lists can be nested inside list items
@@ -194,8 +189,7 @@ namespace Markdig.Tests.Specs.DefinitionLists
// </dl></li>
// </ol>
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", "<ol>\n<li><p>First</p></li>\n<li><p>Second</p>\n<dl>\n<dt>Term 1</dt>\n<dd>Definition</dd>\n<dt>Term 2</dt>\n<dd>Second Definition</dd>\n</dl></li>\n</ol>", "definitionlists+attributes|advanced");
TestParser.TestSpec("1. First\n \n2. Second\n \n Term 1\n : Definition\n \n Term 2\n : Second Definition", "<ol>\n<li><p>First</p></li>\n<li><p>Second</p>\n<dl>\n<dt>Term 1</dt>\n<dd>Definition</dd>\n<dt>Term 2</dt>\n<dd>Second Definition</dd>\n</dl></li>\n</ol>", "definitionlists+attributes|advanced", context: "Example 6\nSection Extensions / Definition lists\n");
}
}
}

View File

@@ -41,8 +41,7 @@ namespace Markdig.Tests.Specs.Diagrams
// C-->D;
// </div>
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```", "<div class=\"mermaid\">graph TD;\n A-->B;\n A-->C;\n B-->D;\n C-->D;\n</div>", "diagrams|advanced");
TestParser.TestSpec("```mermaid\ngraph TD;\n A-->B;\n A-->C;\n B-->D;\n C-->D;\n```", "<div class=\"mermaid\">graph TD;\n A-->B;\n A-->C;\n B-->D;\n C-->D;\n</div>", "diagrams|advanced", context: "Example 1\nSection Extensions / Mermaid diagrams\n");
}
}
@@ -85,8 +84,7 @@ namespace Markdig.Tests.Specs.Diagrams
// ]
// </div>
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```", "<div class=\"nomnoml\">[example|\n propertyA: Int\n propertyB: string\n|\n methodA()\n methodB()\n|\n [subA]--[subB]\n [subA]-:>[sub C]\n]\n</div>", "diagrams|advanced");
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```", "<div class=\"nomnoml\">[example|\n propertyA: Int\n propertyB: string\n|\n methodA()\n methodB()\n|\n [subA]--[subB]\n [subA]-:>[sub C]\n]\n</div>", "diagrams|advanced", context: "Example 2\nSection Extensions / nomnoml diagrams\n");
}
// TODO: Add other text diagram languages
}

View File

@@ -30,8 +30,7 @@ namespace Markdig.Tests.Specs.Emoji
// Should be rendered as:
// <p>This is a test with a 😃 and a 😠 smiley</p>
Console.WriteLine("Example 1\nSection Extensions / Emoji\n");
TestParser.TestSpec("This is a test with a :) and a :angry: smiley", "<p>This is a test with a 😃 and a 😠 smiley</p>", "emojis|advanced+emojis");
TestParser.TestSpec("This is a test with a :) and a :angry: smiley", "<p>This is a test with a 😃 and a 😠 smiley</p>", "emojis|advanced+emojis", context: "Example 1\nSection Extensions / Emoji\n");
}
// An emoji needs to be preceded by a space:
@@ -47,8 +46,7 @@ namespace Markdig.Tests.Specs.Emoji
// Should be rendered as:
// <p>These are not:) an emoji with a:) x:angry:x</p>
Console.WriteLine("Example 2\nSection Extensions / Emoji\n");
TestParser.TestSpec("These are not:) an emoji with a:) x:angry:x", "<p>These are not:) an emoji with a:) x:angry:x</p>", "emojis|advanced+emojis");
TestParser.TestSpec("These are not:) an emoji with a:) x:angry:x", "<p>These are not:) an emoji with a:) x:angry:x</p>", "emojis|advanced+emojis", context: "Example 2\nSection Extensions / Emoji\n");
}
// Emojis can be followed by close punctuation (or any other characters):
@@ -64,8 +62,7 @@ namespace Markdig.Tests.Specs.Emoji
// Should be rendered as:
// <p>We all need 😃, it makes us 💪. (and 👌).</p>
Console.WriteLine("Example 3\nSection Extensions / Emoji\n");
TestParser.TestSpec("We all need :), it makes us :muscle:. (and :ok_hand:).", "<p>We all need 😃, it makes us 💪. (and 👌).</p>", "emojis|advanced+emojis");
TestParser.TestSpec("We all need :), it makes us :muscle:. (and :ok_hand:).", "<p>We all need 😃, it makes us 💪. (and 👌).</p>", "emojis|advanced+emojis", context: "Example 3\nSection Extensions / Emoji\n");
}
// Sentences can end with emojis:
@@ -83,8 +80,7 @@ namespace Markdig.Tests.Specs.Emoji
// <p>This is a sentence 👌
// and keeps going to the next line 😃</p>
Console.WriteLine("Example 4\nSection Extensions / Emoji\n");
TestParser.TestSpec("This is a sentence :ok_hand:\nand keeps going to the next line :)", "<p>This is a sentence 👌\nand keeps going to the next line 😃</p>", "emojis|advanced+emojis");
TestParser.TestSpec("This is a sentence :ok_hand:\nand keeps going to the next line :)", "<p>This is a sentence 👌\nand keeps going to the next line 😃</p>", "emojis|advanced+emojis", context: "Example 4\nSection Extensions / Emoji\n");
}
}
}

View File

@@ -30,8 +30,7 @@ namespace Markdig.Tests.Specs.EmphasisExtra
// Should be rendered as:
// <p>The following text <del>is deleted</del></p>
Console.WriteLine("Example 1\nSection Extensions / Strikethrough\n");
TestParser.TestSpec("The following text ~~is deleted~~", "<p>The following text <del>is deleted</del></p>", "emphasisextras|advanced");
TestParser.TestSpec("The following text ~~is deleted~~", "<p>The following text <del>is deleted</del></p>", "emphasisextras|advanced", context: "Example 1\nSection Extensions / Strikethrough\n");
}
}
@@ -53,8 +52,7 @@ namespace Markdig.Tests.Specs.EmphasisExtra
// Should be rendered as:
// <p>H<sub>2</sub>O is a liquid. 2<sup>10</sup> is 1024</p>
Console.WriteLine("Example 2\nSection Extensions / Superscript and Subscript\n");
TestParser.TestSpec("H~2~O is a liquid. 2^10^ is 1024", "<p>H<sub>2</sub>O is a liquid. 2<sup>10</sup> is 1024</p>", "emphasisextras|advanced");
TestParser.TestSpec("H~2~O is a liquid. 2^10^ is 1024", "<p>H<sub>2</sub>O is a liquid. 2<sup>10</sup> is 1024</p>", "emphasisextras|advanced", context: "Example 2\nSection Extensions / Superscript and Subscript\n");
}
// Certain punctuation characters are exempted from the rule forbidding them within inline delimiters
@@ -73,8 +71,7 @@ namespace Markdig.Tests.Specs.EmphasisExtra
// <p>One quintillionth can be expressed as 10<sup>-18</sup></p>
// <p>Daggers<sup>†</sup> and double-daggers<sup>‡</sup> can be used to denote notes.</p>
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.", "<p>One quintillionth can be expressed as 10<sup>-18</sup></p>\n<p>Daggers<sup>†</sup> and double-daggers<sup>‡</sup> can be used to denote notes.</p>", "emphasisextras|advanced");
TestParser.TestSpec("One quintillionth can be expressed as 10^-18^\n\nDaggers^†^ and double-daggers^‡^ can be used to denote notes.", "<p>One quintillionth can be expressed as 10<sup>-18</sup></p>\n<p>Daggers<sup>†</sup> and double-daggers<sup>‡</sup> can be used to denote notes.</p>", "emphasisextras|advanced", context: "Example 3\nSection Extensions / Superscript and Subscript\n");
}
}
@@ -96,8 +93,7 @@ namespace Markdig.Tests.Specs.EmphasisExtra
// Should be rendered as:
// <p><ins>Inserted text</ins></p>
Console.WriteLine("Example 4\nSection Extensions / Inserted\n");
TestParser.TestSpec("++Inserted text++", "<p><ins>Inserted text</ins></p>", "emphasisextras|advanced");
TestParser.TestSpec("++Inserted text++", "<p><ins>Inserted text</ins></p>", "emphasisextras|advanced", context: "Example 4\nSection Extensions / Inserted\n");
}
}
@@ -119,8 +115,7 @@ namespace Markdig.Tests.Specs.EmphasisExtra
// Should be rendered as:
// <p><mark>Marked text</mark></p>
Console.WriteLine("Example 5\nSection Extensions / Marked\n");
TestParser.TestSpec("==Marked text==", "<p><mark>Marked text</mark></p>", "emphasisextras|advanced");
TestParser.TestSpec("==Marked text==", "<p><mark>Marked text</mark></p>", "emphasisextras|advanced", context: "Example 5\nSection Extensions / Marked\n");
}
}
@@ -144,8 +139,7 @@ namespace Markdig.Tests.Specs.EmphasisExtra
// This is text MyBrand<sup>®</sup> and MyTrademark<sup>TM</sup>
// This is text MyBrand<sub>®</sub> and MyCopyright<sup>©</sup></p>
Console.WriteLine("Example 6\nSection Extensions / Emphasis on Html Entities\n");
TestParser.TestSpec("This is text MyBrand ^&reg;^ and MyTrademark ^&trade;^\nThis is text MyBrand^&reg;^ and MyTrademark^&trade;^\nThis is text MyBrand~&reg;~ and MyCopyright^&copy;^", "<p>This is text MyBrand <sup>®</sup> and MyTrademark <sup>TM</sup>\nThis is text MyBrand<sup>®</sup> and MyTrademark<sup>TM</sup>\nThis is text MyBrand<sub>®</sub> and MyCopyright<sup>©</sup></p>", "emphasisextras|advanced");
TestParser.TestSpec("This is text MyBrand ^&reg;^ and MyTrademark ^&trade;^\nThis is text MyBrand^&reg;^ and MyTrademark^&trade;^\nThis is text MyBrand~&reg;~ and MyCopyright^&copy;^", "<p>This is text MyBrand <sup>®</sup> and MyTrademark <sup>TM</sup>\nThis is text MyBrand<sup>®</sup> and MyTrademark<sup>TM</sup>\nThis is text MyBrand<sub>®</sub> and MyCopyright<sup>©</sup></p>", "emphasisextras|advanced", context: "Example 6\nSection Extensions / Emphasis on Html Entities\n");
}
}
}

View File

@@ -35,8 +35,7 @@ namespace Markdig.Tests.Specs.FiguresFootersAndCites
// <figcaption>This is a <em>caption</em></figcaption>
// </figure>
Console.WriteLine("Example 1\nSection Extensions / Figures\n");
TestParser.TestSpec("^^^\nThis is a figure\n^^^ This is a *caption*", "<figure>\n<p>This is a figure</p>\n<figcaption>This is a <em>caption</em></figcaption>\n</figure>", "figures+footers+citations|advanced");
TestParser.TestSpec("^^^\nThis is a figure\n^^^ This is a *caption*", "<figure>\n<p>This is a figure</p>\n<figcaption>This is a <em>caption</em></figcaption>\n</figure>", "figures+footers+citations|advanced", context: "Example 1\nSection Extensions / Figures\n");
}
}
@@ -60,8 +59,7 @@ namespace Markdig.Tests.Specs.FiguresFootersAndCites
// <footer>This is a footer
// multi-line</footer>
Console.WriteLine("Example 2\nSection Extensions / Footers\n");
TestParser.TestSpec("^^ This is a footer\n^^ multi-line", "<footer>This is a footer\nmulti-line</footer>", "figures+footers+citations|advanced");
TestParser.TestSpec("^^ This is a footer\n^^ multi-line", "<footer>This is a footer\nmulti-line</footer>", "figures+footers+citations|advanced", context: "Example 2\nSection Extensions / Footers\n");
}
}
@@ -83,8 +81,7 @@ namespace Markdig.Tests.Specs.FiguresFootersAndCites
// Should be rendered as:
// <p>This is a <cite>citation of someone</cite></p>
Console.WriteLine("Example 3\nSection Extensions / Cite\n");
TestParser.TestSpec("This is a \"\"citation of someone\"\"", "<p>This is a <cite>citation of someone</cite></p>", "figures+footers+citations|advanced");
TestParser.TestSpec("This is a \"\"citation of someone\"\"", "<p>This is a <cite>citation of someone</cite></p>", "figures+footers+citations|advanced", context: "Example 3\nSection Extensions / Cite\n");
}
}
}

View File

@@ -79,8 +79,7 @@ namespace Markdig.Tests.Specs.Footnotes
// </ol>
// </div>
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.", "<p>Here is a footnote reference,<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a> and another.<a id=\"fnref:3\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a></p>\n<p>This is another reference to <a id=\"fnref:2\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a></p>\n<p>And another reference to <a id=\"fnref:4\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a></p>\n<p>This paragraph won't be part of the note, because it\nisn't indented.</p>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Here is the footnote.<a href=\"#fnref:1\" class=\"footnote-back-ref\">&#8617;</a><a href=\"#fnref:2\" class=\"footnote-back-ref\">&#8617;</a></p>\n</li>\n<li id=\"fn:2\">\n<p>Here's one with multiple blocks.</p>\n<p>Subsequent paragraphs are indented to show that they\nbelong to the previous footnote.</p>\n<blockquote>\n<p>This is a block quote\nInside a footnote</p>\n</blockquote>\n<pre><code>{ some.code }\n</code></pre>\n<p>The whole paragraph can be indented, or just the first\nline. In this way, multi-paragraph footnotes work like\nmulti-paragraph list items.<a href=\"#fnref:3\" class=\"footnote-back-ref\">&#8617;</a><a href=\"#fnref:4\" class=\"footnote-back-ref\">&#8617;</a></p>\n</li>\n</ol>\n</div>", "footnotes|advanced");
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.", "<p>Here is a footnote reference,<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a> and another.<a id=\"fnref:3\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a></p>\n<p>This is another reference to <a id=\"fnref:2\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a></p>\n<p>And another reference to <a id=\"fnref:4\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a></p>\n<p>This paragraph won't be part of the note, because it\nisn't indented.</p>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Here is the footnote.<a href=\"#fnref:1\" class=\"footnote-back-ref\">&#8617;</a><a href=\"#fnref:2\" class=\"footnote-back-ref\">&#8617;</a></p>\n</li>\n<li id=\"fn:2\">\n<p>Here's one with multiple blocks.</p>\n<p>Subsequent paragraphs are indented to show that they\nbelong to the previous footnote.</p>\n<blockquote>\n<p>This is a block quote\nInside a footnote</p>\n</blockquote>\n<pre><code>{ some.code }\n</code></pre>\n<p>The whole paragraph can be indented, or just the first\nline. In this way, multi-paragraph footnotes work like\nmulti-paragraph list items.<a href=\"#fnref:3\" class=\"footnote-back-ref\">&#8617;</a><a href=\"#fnref:4\" class=\"footnote-back-ref\">&#8617;</a></p>\n</li>\n</ol>\n</div>", "footnotes|advanced", context: "Example 1\nSection Extensions / Footnotes\n");
}
// Check with multiple consecutive footnotes:
@@ -120,8 +119,7 @@ namespace Markdig.Tests.Specs.Footnotes
// </ol>
// </div>
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", "<p>Here is a footnote<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a>. And another one<a id=\"fnref:2\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a>. And a third one<a id=\"fnref:3\" href=\"#fn:3\" class=\"footnote-ref\"><sup>3</sup></a>. And a fourth<a id=\"fnref:4\" href=\"#fn:4\" class=\"footnote-ref\"><sup>4</sup></a>.</p>\n<p>a</p>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Footnote 1 text<a href=\"#fnref:1\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:2\">\n<p>Footnote 2 text<a href=\"#fnref:2\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:3\">\n<p>Footnote 3 text<a href=\"#fnref:3\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:4\">\n<p>Footnote 4 text<a href=\"#fnref:4\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n</ol>\n</div>", "footnotes|advanced");
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", "<p>Here is a footnote<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a>. And another one<a id=\"fnref:2\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a>. And a third one<a id=\"fnref:3\" href=\"#fn:3\" class=\"footnote-ref\"><sup>3</sup></a>. And a fourth<a id=\"fnref:4\" href=\"#fn:4\" class=\"footnote-ref\"><sup>4</sup></a>.</p>\n<p>a</p>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Footnote 1 text<a href=\"#fnref:1\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:2\">\n<p>Footnote 2 text<a href=\"#fnref:2\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:3\">\n<p>Footnote 3 text<a href=\"#fnref:3\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:4\">\n<p>Footnote 4 text<a href=\"#fnref:4\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n</ol>\n</div>", "footnotes|advanced", context: "Example 2\nSection Extensions / Footnotes\n");
}
// Another test with consecutive footnotes without a blank line separator:
@@ -155,8 +153,7 @@ namespace Markdig.Tests.Specs.Footnotes
// </ol>
// </div>
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", "<p>Here is a footnote<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a>. And another one<a id=\"fnref:2\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a>. And a third one<a id=\"fnref:3\" href=\"#fn:3\" class=\"footnote-ref\"><sup>3</sup></a>. And a fourth<a id=\"fnref:4\" href=\"#fn:4\" class=\"footnote-ref\"><sup>4</sup></a>.</p>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Footnote 1 text<a href=\"#fnref:1\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:2\">\n<p>Footnote 2 text<a href=\"#fnref:2\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:3\">\n<p>Footnote 3 text<a href=\"#fnref:3\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:4\">\n<p>Footnote 4 text<a href=\"#fnref:4\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n</ol>\n</div>", "footnotes|advanced");
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", "<p>Here is a footnote<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a>. And another one<a id=\"fnref:2\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a>. And a third one<a id=\"fnref:3\" href=\"#fn:3\" class=\"footnote-ref\"><sup>3</sup></a>. And a fourth<a id=\"fnref:4\" href=\"#fn:4\" class=\"footnote-ref\"><sup>4</sup></a>.</p>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Footnote 1 text<a href=\"#fnref:1\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:2\">\n<p>Footnote 2 text<a href=\"#fnref:2\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:3\">\n<p>Footnote 3 text<a href=\"#fnref:3\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n<li id=\"fn:4\">\n<p>Footnote 4 text<a href=\"#fnref:4\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n</ol>\n</div>", "footnotes|advanced", context: "Example 3\nSection Extensions / Footnotes\n");
}
// A footnote link inside a list should work as well:
@@ -185,8 +182,7 @@ namespace Markdig.Tests.Specs.Footnotes
// </ol>
// </div>
Console.WriteLine("Example 4\nSection Extensions / Footnotes\n");
TestParser.TestSpec("- abc\n- def[^1]\n\n[^1]: Here is the footnote.", "<ul>\n<li>abc</li>\n<li>def<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a></li>\n</ul>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Here is the footnote.<a href=\"#fnref:1\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n</ol>\n</div>", "footnotes|advanced");
TestParser.TestSpec("- abc\n- def[^1]\n\n[^1]: Here is the footnote.", "<ul>\n<li>abc</li>\n<li>def<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a></li>\n</ul>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Here is the footnote.<a href=\"#fnref:1\" class=\"footnote-back-ref\">&#8617;</a></p></li>\n</ol>\n</div>", "footnotes|advanced", context: "Example 4\nSection Extensions / Footnotes\n");
}
}
}

View File

@@ -54,8 +54,7 @@ namespace Markdig.Tests.Specs.GenericAttributes
// <h2 id="heading-link2">This is a heading</h2>
// <p id="myparagraph" attached-bool-property="" attached-bool-property2="">This is a paragraph with an attached attributes </p>
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}", "<h1 id=\"heading-link\">This is a heading with an an attribute</h1>\n<h1 id=\"heading-link2\">This is a heading</h1>\n<p><a href=\"http://google.com\" id=\"a-link\" class=\"myclass\" data-lang=\"fr\" data-value=\"This is a value\">This is a link</a></p>\n<h2 id=\"heading-link2\">This is a heading</h2>\n<p id=\"myparagraph\" attached-bool-property=\"\" attached-bool-property2=\"\">This is a paragraph with an attached attributes </p>", "attributes|advanced");
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}", "<h1 id=\"heading-link\">This is a heading with an an attribute</h1>\n<h1 id=\"heading-link2\">This is a heading</h1>\n<p><a href=\"http://google.com\" id=\"a-link\" class=\"myclass\" data-lang=\"fr\" data-value=\"This is a value\">This is a link</a></p>\n<h2 id=\"heading-link2\">This is a heading</h2>\n<p id=\"myparagraph\" attached-bool-property=\"\" attached-bool-property2=\"\">This is a paragraph with an attached attributes </p>", "attributes|advanced", context: "Example 1\nSection Extensions / Generic Attributes\n");
}
// 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):
@@ -75,8 +74,7 @@ namespace Markdig.Tests.Specs.GenericAttributes
// <pre><code id="fenced-id" class="fenced-class">This is a fenced with attached attributes
// </code></pre>
Console.WriteLine("Example 2\nSection Extensions / Generic Attributes\n");
TestParser.TestSpec("{#fenced-id .fenced-class}\n~~~\nThis is a fenced with attached attributes\n~~~ ", "<pre><code id=\"fenced-id\" class=\"fenced-class\">This is a fenced with attached attributes\n</code></pre>", "attributes|advanced");
TestParser.TestSpec("{#fenced-id .fenced-class}\n~~~\nThis is a fenced with attached attributes\n~~~ ", "<pre><code id=\"fenced-id\" class=\"fenced-class\">This is a fenced with attached attributes\n</code></pre>", "attributes|advanced", context: "Example 2\nSection Extensions / Generic Attributes\n");
}
// Attribute values can be one character long
@@ -98,8 +96,7 @@ namespace Markdig.Tests.Specs.GenericAttributes
// <p><a href="url" data-x="1">Foo</a></p>
// <p><a href="url" data-x="11">Foo</a></p>
Console.WriteLine("Example 3\nSection Extensions / Generic Attributes\n");
TestParser.TestSpec("[Foo](url){data-x=1}\n\n[Foo](url){data-x='1'}\n\n[Foo](url){data-x=11}", "<p><a href=\"url\" data-x=\"1\">Foo</a></p>\n<p><a href=\"url\" data-x=\"1\">Foo</a></p>\n<p><a href=\"url\" data-x=\"11\">Foo</a></p>", "attributes|advanced");
TestParser.TestSpec("[Foo](url){data-x=1}\n\n[Foo](url){data-x='1'}\n\n[Foo](url){data-x=11}", "<p><a href=\"url\" data-x=\"1\">Foo</a></p>\n<p><a href=\"url\" data-x=\"1\">Foo</a></p>\n<p><a href=\"url\" data-x=\"11\">Foo</a></p>", "attributes|advanced", context: "Example 3\nSection Extensions / Generic Attributes\n");
}
}
}

View File

@@ -56,8 +56,7 @@ namespace Markdig.Tests.Specs.Globalization
// -- نەزانراو</p>
// </blockquote>
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-- نەزانراو", "<h1 id=\"fruits\">Fruits</h1>\n<p>In botany, a <a href=\"https://en.wikipedia.org/wiki/Fruit\">fruit</a> is the seed-bearing structure in flowering plants (also known as angiosperms) formed from the ovary after flowering.</p>\n<blockquote>\n<p>Fruits are good for health\n-- Anonymous</p>\n</blockquote>\n<h1 id=\"section\" dir=\"rtl\">میوە</h1>\n<p dir=\"rtl\"><a href=\"https://ckb.wikipedia.org/wiki/%D9%85%DB%8C%D9%88%DB%95\" dir=\"rtl\">میوە</a> یان مێوە بەروبوومی ڕوەکیە کە ڕوەکەکان ھەڵیان ئەگرن وەک بەرگێک بۆ تۆوەکانیان، بە زۆری جیادەکرێتەوە بە شیرینی یان ترشی لە تامدا و بە بوونی بڕێکی زۆر ئاو</p>\n<blockquote dir=\"rtl\">\n<p dir=\"rtl\">میوە بۆ تەندروستی باشە\n-- نەزانراو</p>\n</blockquote>", "globalization+advanced+emojis");
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-- نەزانراو", "<h1 id=\"fruits\">Fruits</h1>\n<p>In botany, a <a href=\"https://en.wikipedia.org/wiki/Fruit\">fruit</a> is the seed-bearing structure in flowering plants (also known as angiosperms) formed from the ovary after flowering.</p>\n<blockquote>\n<p>Fruits are good for health\n-- Anonymous</p>\n</blockquote>\n<h1 id=\"section\" dir=\"rtl\">میوە</h1>\n<p dir=\"rtl\"><a href=\"https://ckb.wikipedia.org/wiki/%D9%85%DB%8C%D9%88%DB%95\" dir=\"rtl\">میوە</a> یان مێوە بەروبوومی ڕوەکیە کە ڕوەکەکان ھەڵیان ئەگرن وەک بەرگێک بۆ تۆوەکانیان، بە زۆری جیادەکرێتەوە بە شیرینی یان ترشی لە تامدا و بە بوونی بڕێکی زۆر ئاو</p>\n<blockquote dir=\"rtl\">\n<p dir=\"rtl\">میوە بۆ تەندروستی باشە\n-- نەزانراو</p>\n</blockquote>", "globalization+advanced+emojis", context: "Example 1\nSection Extensions / Globalization\n");
}
// Lists:
@@ -160,8 +159,7 @@ namespace Markdig.Tests.Specs.Globalization
// <li class="task-list-item"><input disabled="disabled" type="checkbox" /> هەنجیر</li>
// </ul>
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- [ ] هەنجیر", "<h2 id=\"types-of-fruits\">Types of fruits</h2>\n<ul>\n<li>Berries\n<ul>\n<li>Strawberry</li>\n<li>kiwifruit</li>\n</ul>\n</li>\n<li>Citrus\n<ul>\n<li>Orange</li>\n<li>Lemon</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"examples-of-fruits\">Examples of fruits 😋</h2>\n<ol>\n<li>Apple</li>\n<li>Banana</li>\n<li>Orange</li>\n</ol>\n<h2 id=\"grocery-list\">Grocery List</h2>\n<ul class=\"contains-task-list\">\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> 􏿽 Watermelon</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> Apricot</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" /> Fig</li>\n</ul>\n<h2 id=\"section\" dir=\"rtl\">نموونەی میوە 😋</h2>\n<ol dir=\"rtl\">\n<li>? سێو</li>\n<li>5 مۆز</li>\n<li>􏿽 پرتەقاڵ</li>\n</ol>\n<h2 id=\"section-1\" dir=\"rtl\">جۆرەکانی میوە</h2>\n<ul dir=\"rtl\">\n<li>توو\n<ul dir=\"rtl\">\n<li>فڕاولە</li>\n<li>کیوی</li>\n</ul>\n</li>\n<li>مزرەمەنی\n<ul dir=\"rtl\">\n<li>پڕتەقاڵ</li>\n<li>لیمۆ</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"section-2\" dir=\"rtl\">لیستی کڕین</h2>\n<ul class=\"contains-task-list\" dir=\"rtl\">\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> شووتی</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> قەیسی</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" /> هەنجیر</li>\n</ul>", "globalization+advanced+emojis");
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- [ ] هەنجیر", "<h2 id=\"types-of-fruits\">Types of fruits</h2>\n<ul>\n<li>Berries\n<ul>\n<li>Strawberry</li>\n<li>kiwifruit</li>\n</ul>\n</li>\n<li>Citrus\n<ul>\n<li>Orange</li>\n<li>Lemon</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"examples-of-fruits\">Examples of fruits 😋</h2>\n<ol>\n<li>Apple</li>\n<li>Banana</li>\n<li>Orange</li>\n</ol>\n<h2 id=\"grocery-list\">Grocery List</h2>\n<ul class=\"contains-task-list\">\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> 􏿽 Watermelon</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> Apricot</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" /> Fig</li>\n</ul>\n<h2 id=\"section\" dir=\"rtl\">نموونەی میوە 😋</h2>\n<ol dir=\"rtl\">\n<li>? سێو</li>\n<li>5 مۆز</li>\n<li>􏿽 پرتەقاڵ</li>\n</ol>\n<h2 id=\"section-1\" dir=\"rtl\">جۆرەکانی میوە</h2>\n<ul dir=\"rtl\">\n<li>توو\n<ul dir=\"rtl\">\n<li>فڕاولە</li>\n<li>کیوی</li>\n</ul>\n</li>\n<li>مزرەمەنی\n<ul dir=\"rtl\">\n<li>پڕتەقاڵ</li>\n<li>لیمۆ</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"section-2\" dir=\"rtl\">لیستی کڕین</h2>\n<ul class=\"contains-task-list\" dir=\"rtl\">\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> شووتی</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> قەیسی</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" /> هەنجیر</li>\n</ul>", "globalization+advanced+emojis", context: "Example 2\nSection Extensions / Globalization\n");
}
// Tables:
@@ -226,8 +224,7 @@ namespace Markdig.Tests.Specs.Globalization
// </tbody>
// </table>
Console.WriteLine("Example 3\nSection Extensions / Globalization\n");
TestParser.TestSpec("Nutrition |Apple | Oranges\n--|-- | --\nCalories|52|47\nSugar|10g|9g\n\n پێکهاتە |سێو | پڕتەقاڵ\n--|-- | --\nکالۆری|٥٢|٤٧\nشەکر| ١٠گ|٩گ", "<table>\n<thead>\n<tr>\n<th>Nutrition</th>\n<th>Apple</th>\n<th>Oranges</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Calories</td>\n<td>52</td>\n<td>47</td>\n</tr>\n<tr>\n<td>Sugar</td>\n<td>10g</td>\n<td>9g</td>\n</tr>\n</tbody>\n</table>\n<table dir=\"rtl\" align=\"right\">\n<thead>\n<tr>\n<th>پێکهاتە</th>\n<th>سێو</th>\n<th>پڕتەقاڵ</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>کالۆری</td>\n<td>٥٢</td>\n<td>٤٧</td>\n</tr>\n<tr>\n<td>شەکر</td>\n<td>١٠گ</td>\n<td>٩گ</td>\n</tr>\n</tbody>\n</table>", "globalization+advanced+emojis");
TestParser.TestSpec("Nutrition |Apple | Oranges\n--|-- | --\nCalories|52|47\nSugar|10g|9g\n\n پێکهاتە |سێو | پڕتەقاڵ\n--|-- | --\nکالۆری|٥٢|٤٧\nشەکر| ١٠گ|٩گ", "<table>\n<thead>\n<tr>\n<th>Nutrition</th>\n<th>Apple</th>\n<th>Oranges</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Calories</td>\n<td>52</td>\n<td>47</td>\n</tr>\n<tr>\n<td>Sugar</td>\n<td>10g</td>\n<td>9g</td>\n</tr>\n</tbody>\n</table>\n<table dir=\"rtl\" align=\"right\">\n<thead>\n<tr>\n<th>پێکهاتە</th>\n<th>سێو</th>\n<th>پڕتەقاڵ</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>کالۆری</td>\n<td>٥٢</td>\n<td>٤٧</td>\n</tr>\n<tr>\n<td>شەکر</td>\n<td>١٠گ</td>\n<td>٩گ</td>\n</tr>\n</tbody>\n</table>", "globalization+advanced+emojis", context: "Example 3\nSection Extensions / Globalization\n");
}
}
}

View File

@@ -71,8 +71,7 @@ namespace Markdig.Tests.Specs.GridTables
// </tbody>
// </table>
Console.WriteLine("Example 1\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+---------+---------+\n| This is | a table |", "<table>\n<col style=\"width:50%\" />\n<col style=\"width:50%\" />\n<tbody>\n<tr>\n<td>This is</td>\n<td>a table</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+---------+---------+\n| This is | a table |", "<table>\n<col style=\"width:50%\" />\n<col style=\"width:50%\" />\n<tbody>\n<tr>\n<td>This is</td>\n<td>a table</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced", context: "Example 1\nSection Extensions / Grid Table\n");
}
// The following is not a valid row separator
@@ -90,8 +89,7 @@ namespace Markdig.Tests.Specs.GridTables
// <p>|-----xxx----+---------+
// | This is | not a table</p>
Console.WriteLine("Example 2\nSection Extensions / Grid Table\n");
TestParser.TestSpec("|-----xxx----+---------+\n| This is | not a table", "<p>|-----xxx----+---------+\n| This is | not a table</p>", "gridtables|advanced");
TestParser.TestSpec("|-----xxx----+---------+\n| This is | not a table", "<p>|-----xxx----+---------+\n| This is | not a table</p>", "gridtables|advanced", context: "Example 2\nSection Extensions / Grid Table\n");
}
// **Rule #2**
@@ -133,8 +131,7 @@ namespace Markdig.Tests.Specs.GridTables
// </tbody>
// </table>
Console.WriteLine("Example 3\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+---------+---------+---------+\n| Col1 | Col2 | Col3 |\n| Col1a | Col2a | Col3a |\n| Col1b | Col3b |\n| Col1c |", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td>Col1\nCol1a</td>\n<td>Col2\nCol2a</td>\n<td>Col3\nCol3a</td>\n</tr>\n<tr>\n<td colspan=\"2\">Col1b</td>\n<td>Col3b</td>\n</tr>\n<tr>\n<td colspan=\"3\">Col1c</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+---------+---------+---------+\n| Col1 | Col2 | Col3 |\n| Col1a | Col2a | Col3a |\n| Col1b | Col3b |\n| Col1c |", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td>Col1\nCol1a</td>\n<td>Col2\nCol2a</td>\n<td>Col3\nCol3a</td>\n</tr>\n<tr>\n<td colspan=\"2\">Col1b</td>\n<td>Col3b</td>\n</tr>\n<tr>\n<td colspan=\"3\">Col1c</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced", context: "Example 3\nSection Extensions / Grid Table\n");
}
// A row header is separated using `+========+` instead of `+---------+`:
@@ -161,8 +158,7 @@ namespace Markdig.Tests.Specs.GridTables
// </thead>
// </table>
Console.WriteLine("Example 4\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+---------+---------+\n| This is | a table |\n+=========+=========+", "<table>\n<col style=\"width:50%\" />\n<col style=\"width:50%\" />\n<thead>\n<tr>\n<th>This is</th>\n<th>a table</th>\n</tr>\n</thead>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+---------+---------+\n| This is | a table |\n+=========+=========+", "<table>\n<col style=\"width:50%\" />\n<col style=\"width:50%\" />\n<thead>\n<tr>\n<th>This is</th>\n<th>a table</th>\n</tr>\n</thead>\n</table>", "gridtables|advanced", context: "Example 4\nSection Extensions / Grid Table\n");
}
// The last column separator `|` may be omitted:
@@ -188,8 +184,7 @@ namespace Markdig.Tests.Specs.GridTables
// </tbody>
// </table>
Console.WriteLine("Example 5\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+---------+---------+\n| This is | a table with a longer text in the second column", "<table>\n<col style=\"width:50%\" />\n<col style=\"width:50%\" />\n<tbody>\n<tr>\n<td>This is</td>\n<td>a table with a longer text in the second column</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+---------+---------+\n| This is | a table with a longer text in the second column", "<table>\n<col style=\"width:50%\" />\n<col style=\"width:50%\" />\n<tbody>\n<tr>\n<td>This is</td>\n<td>a table with a longer text in the second column</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced", context: "Example 5\nSection Extensions / Grid Table\n");
}
// 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:
@@ -226,8 +221,7 @@ namespace Markdig.Tests.Specs.GridTables
// </tbody>
// </table>
Console.WriteLine("Example 6\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+----+--------+----+\n| A | B C D | E |\n+----+--------+----+", "<table>\n<col style=\"width:25%\" />\n<col style=\"width:50%\" />\n<col style=\"width:25%\" />\n<tbody>\n<tr>\n<td>A</td>\n<td>B C D</td>\n<td>E</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+----+--------+----+\n| A | B C D | E |\n+----+--------+----+", "<table>\n<col style=\"width:25%\" />\n<col style=\"width:50%\" />\n<col style=\"width:25%\" />\n<tbody>\n<tr>\n<td>A</td>\n<td>B C D</td>\n<td>E</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced", context: "Example 6\nSection Extensions / Grid Table\n");
}
// Alignment might be specified on the first row using the character `:`:
@@ -256,8 +250,7 @@ namespace Markdig.Tests.Specs.GridTables
// </tbody>
// </table>
Console.WriteLine("Example 7\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+-----+:---:+-----+\n| A | B | C |\n+-----+-----+-----+", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td>A</td>\n<td style=\"text-align: center;\">B</td>\n<td>C</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+-----+:---:+-----+\n| A | B | C |\n+-----+-----+-----+", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td>A</td>\n<td style=\"text-align: center;\">B</td>\n<td>C</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced", context: "Example 7\nSection Extensions / Grid Table\n");
}
// A grid table may have cells spanning both columns and rows:
@@ -300,8 +293,7 @@ namespace Markdig.Tests.Specs.GridTables
// </tbody>
// </table>
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+---+---+---+", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td colspan=\"2\">AAAAA</td>\n<td rowspan=\"2\">B\nB\nB</td>\n</tr>\n<tr>\n<td rowspan=\"2\">D\nD\nD</td>\n<td>E</td>\n</tr>\n<tr>\n<td colspan=\"2\">CCCCC</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+---+---+ B +\n| D | E | B |\n+ D +---+---+\n| D | CCCCC |\n+---+---+---+", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td colspan=\"2\">AAAAA</td>\n<td rowspan=\"2\">B\nB\nB</td>\n</tr>\n<tr>\n<td rowspan=\"2\">D\nD\nD</td>\n<td>E</td>\n</tr>\n<tr>\n<td colspan=\"2\">CCCCC</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced", context: "Example 8\nSection Extensions / Grid Table\n");
}
// A grid table may have cells with both colspan and rowspan:
@@ -343,8 +335,7 @@ namespace Markdig.Tests.Specs.GridTables
// </tbody>
// </table>
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+---+---+---+", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td colspan=\"2\" rowspan=\"2\">AAAAA\nAAAAA\nAAAAA</td>\n<td>B</td>\n</tr>\n<tr>\n<td>C</td>\n</tr>\n<tr>\n<td>D</td>\n<td>E</td>\n<td>F</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced");
TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+ AAAAA +---+\n| AAAAA | C |\n+---+---+---+\n| D | E | F |\n+---+---+---+", "<table>\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<col style=\"width:33.33%\" />\n<tbody>\n<tr>\n<td colspan=\"2\" rowspan=\"2\">AAAAA\nAAAAA\nAAAAA</td>\n<td>B</td>\n</tr>\n<tr>\n<td>C</td>\n</tr>\n<tr>\n<td>D</td>\n<td>E</td>\n<td>F</td>\n</tr>\n</tbody>\n</table>", "gridtables|advanced", context: "Example 9\nSection Extensions / Grid Table\n");
}
// A grid table may not have irregularly shaped cells:
@@ -372,8 +363,7 @@ namespace Markdig.Tests.Specs.GridTables
// | DDDDD | E |
// +---+---+---+</p>
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+---+---+---+", "<p>+---+---+---+\n| AAAAA | B |\n+ A +---+ B +\n| A | C | B |\n+---+---+---+\n| DDDDD | E |\n+---+---+---+</p>", "gridtables|advanced");
TestParser.TestSpec("+---+---+---+\n| AAAAA | B |\n+ A +---+ B +\n| A | C | B |\n+---+---+---+\n| DDDDD | E |\n+---+---+---+", "<p>+---+---+---+\n| AAAAA | B |\n+ A +---+ B +\n| A | C | B |\n+---+---+---+\n| DDDDD | E |\n+---+---+---+</p>", "gridtables|advanced", context: "Example 10\nSection Extensions / Grid Table\n");
}
// An empty `+` on a line should result in a simple empty list output:
@@ -391,8 +381,7 @@ namespace Markdig.Tests.Specs.GridTables
// <li></li>
// </ul>
Console.WriteLine("Example 11\nSection Extensions / Grid Table\n");
TestParser.TestSpec("+", "<ul>\n<li></li>\n</ul>", "gridtables|advanced");
TestParser.TestSpec("+", "<ul>\n<li></li>\n</ul>", "gridtables|advanced", context: "Example 11\nSection Extensions / Grid Table\n");
}
}
}

View File

@@ -32,8 +32,7 @@ namespace Markdig.Tests.Specs.HardlineBreaks
// <p>This is a paragraph<br />
// with a break inside</p>
Console.WriteLine("Example 1\nSection Extensions / Hardline break\n");
TestParser.TestSpec("This is a paragraph\nwith a break inside", "<p>This is a paragraph<br />\nwith a break inside</p>", "hardlinebreak|advanced+hardlinebreak");
TestParser.TestSpec("This is a paragraph\nwith a break inside", "<p>This is a paragraph<br />\nwith a break inside</p>", "hardlinebreak|advanced+hardlinebreak", context: "Example 1\nSection Extensions / Hardline break\n");
}
}
}

View File

@@ -40,10 +40,9 @@ namespace Markdig.Tests.Specs.JiraLinks
// This is a ABCD-123 issue
//
// Should be rendered as:
// <p>This is a <a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</a> issue</p>
// <p>This is a <a href="http://your.company.abc/browse/ABCD-123" target="_blank">ABCD-123</a> issue</p>
Console.WriteLine("Example 1\nSection Jira Links\n");
TestParser.TestSpec("This is a ABCD-123 issue", "<p>This is a <a href=\"http://your.company.abc/browse/ABCD-123\" target=\"blank\">ABCD-123</a> issue</p>", "jiralinks");
TestParser.TestSpec("This is a ABCD-123 issue", "<p>This is a <a href=\"http://your.company.abc/browse/ABCD-123\" target=\"_blank\">ABCD-123</a> issue</p>", "jiralinks", context: "Example 1\nSection Jira Links\n");
}
[Test]
@@ -56,10 +55,9 @@ namespace Markdig.Tests.Specs.JiraLinks
// This is a ABC4-123 issue
//
// Should be rendered as:
// <p>This is a <a href="http://your.company.abc/browse/ABC4-123" target="blank">ABC4-123</a> issue</p>
// <p>This is a <a href="http://your.company.abc/browse/ABC4-123" target="_blank">ABC4-123</a> issue</p>
Console.WriteLine("Example 2\nSection Jira Links\n");
TestParser.TestSpec("This is a ABC4-123 issue", "<p>This is a <a href=\"http://your.company.abc/browse/ABC4-123\" target=\"blank\">ABC4-123</a> issue</p>", "jiralinks");
TestParser.TestSpec("This is a ABC4-123 issue", "<p>This is a <a href=\"http://your.company.abc/browse/ABC4-123\" target=\"_blank\">ABC4-123</a> issue</p>", "jiralinks", context: "Example 2\nSection Jira Links\n");
}
[Test]
@@ -72,10 +70,9 @@ namespace Markdig.Tests.Specs.JiraLinks
// This is a ABC45-123 issue
//
// Should be rendered as:
// <p>This is a <a href="http://your.company.abc/browse/ABC45-123" target="blank">ABC45-123</a> issue</p>
// <p>This is a <a href="http://your.company.abc/browse/ABC45-123" target="_blank">ABC45-123</a> issue</p>
Console.WriteLine("Example 3\nSection Jira Links\n");
TestParser.TestSpec("This is a ABC45-123 issue", "<p>This is a <a href=\"http://your.company.abc/browse/ABC45-123\" target=\"blank\">ABC45-123</a> issue</p>", "jiralinks");
TestParser.TestSpec("This is a ABC45-123 issue", "<p>This is a <a href=\"http://your.company.abc/browse/ABC45-123\" target=\"_blank\">ABC45-123</a> issue</p>", "jiralinks", context: "Example 3\nSection Jira Links\n");
}
[Test]
@@ -88,10 +85,9 @@ namespace Markdig.Tests.Specs.JiraLinks
// This is a KIRA-1 issue
//
// Should be rendered as:
// <p>This is a <a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a> issue</p>
// <p>This is a <a href="http://your.company.abc/browse/KIRA-1" target="_blank">KIRA-1</a> issue</p>
Console.WriteLine("Example 4\nSection Jira Links\n");
TestParser.TestSpec("This is a KIRA-1 issue", "<p>This is a <a href=\"http://your.company.abc/browse/KIRA-1\" target=\"blank\">KIRA-1</a> issue</p>", "jiralinks");
TestParser.TestSpec("This is a KIRA-1 issue", "<p>This is a <a href=\"http://your.company.abc/browse/KIRA-1\" target=\"_blank\">KIRA-1</a> issue</p>", "jiralinks", context: "Example 4\nSection Jira Links\n");
}
[Test]
@@ -104,10 +100,9 @@ namespace Markdig.Tests.Specs.JiraLinks
// This is a Z-1 issue
//
// Should be rendered as:
// <p>This is a <a href="http://your.company.abc/browse/Z-1" target="blank">Z-1</a> issue</p>
// <p>This is a <a href="http://your.company.abc/browse/Z-1" target="_blank">Z-1</a> issue</p>
Console.WriteLine("Example 5\nSection Jira Links\n");
TestParser.TestSpec("This is a Z-1 issue", "<p>This is a <a href=\"http://your.company.abc/browse/Z-1\" target=\"blank\">Z-1</a> issue</p>", "jiralinks");
TestParser.TestSpec("This is a Z-1 issue", "<p>This is a <a href=\"http://your.company.abc/browse/Z-1\" target=\"_blank\">Z-1</a> issue</p>", "jiralinks", context: "Example 5\nSection Jira Links\n");
}
// These are also valid links with `(` and `)`:
@@ -121,10 +116,9 @@ namespace Markdig.Tests.Specs.JiraLinks
// This is a (ABCD-123) issue
//
// Should be rendered as:
// <p>This is a (<a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</a>) issue</p>
// <p>This is a (<a href="http://your.company.abc/browse/ABCD-123" target="_blank">ABCD-123</a>) issue</p>
Console.WriteLine("Example 6\nSection Jira Links\n");
TestParser.TestSpec("This is a (ABCD-123) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/ABCD-123\" target=\"blank\">ABCD-123</a>) issue</p>", "jiralinks");
TestParser.TestSpec("This is a (ABCD-123) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/ABCD-123\" target=\"_blank\">ABCD-123</a>) issue</p>", "jiralinks", context: "Example 6\nSection Jira Links\n");
}
[Test]
@@ -137,10 +131,9 @@ namespace Markdig.Tests.Specs.JiraLinks
// This is a (ABC4-123) issue
//
// Should be rendered as:
// <p>This is a (<a href="http://your.company.abc/browse/ABC4-123" target="blank">ABC4-123</a>) issue</p>
// <p>This is a (<a href="http://your.company.abc/browse/ABC4-123" target="_blank">ABC4-123</a>) issue</p>
Console.WriteLine("Example 7\nSection Jira Links\n");
TestParser.TestSpec("This is a (ABC4-123) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/ABC4-123\" target=\"blank\">ABC4-123</a>) issue</p>", "jiralinks");
TestParser.TestSpec("This is a (ABC4-123) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/ABC4-123\" target=\"_blank\">ABC4-123</a>) issue</p>", "jiralinks", context: "Example 7\nSection Jira Links\n");
}
[Test]
@@ -153,10 +146,9 @@ namespace Markdig.Tests.Specs.JiraLinks
// This is a (KIRA-1) issue
//
// Should be rendered as:
// <p>This is a (<a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a>) issue</p>
// <p>This is a (<a href="http://your.company.abc/browse/KIRA-1" target="_blank">KIRA-1</a>) issue</p>
Console.WriteLine("Example 8\nSection Jira Links\n");
TestParser.TestSpec("This is a (KIRA-1) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/KIRA-1\" target=\"blank\">KIRA-1</a>) issue</p>", "jiralinks");
TestParser.TestSpec("This is a (KIRA-1) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/KIRA-1\" target=\"_blank\">KIRA-1</a>) issue</p>", "jiralinks", context: "Example 8\nSection Jira Links\n");
}
[Test]
@@ -169,10 +161,9 @@ namespace Markdig.Tests.Specs.JiraLinks
// This is a (Z-1) issue
//
// Should be rendered as:
// <p>This is a (<a href="http://your.company.abc/browse/Z-1" target="blank">Z-1</a>) issue</p>
// <p>This is a (<a href="http://your.company.abc/browse/Z-1" target="_blank">Z-1</a>) issue</p>
Console.WriteLine("Example 9\nSection Jira Links\n");
TestParser.TestSpec("This is a (Z-1) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/Z-1\" target=\"blank\">Z-1</a>) issue</p>", "jiralinks");
TestParser.TestSpec("This is a (Z-1) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/Z-1\" target=\"_blank\">Z-1</a>) issue</p>", "jiralinks", context: "Example 9\nSection Jira Links\n");
}
// These are not valid links:
@@ -188,8 +179,7 @@ namespace Markdig.Tests.Specs.JiraLinks
// Should be rendered as:
// <p>This is not aJIRA-123 issue</p>
Console.WriteLine("Example 10\nSection Jira Links\n");
TestParser.TestSpec("This is not aJIRA-123 issue", "<p>This is not aJIRA-123 issue</p>", "jiralinks");
TestParser.TestSpec("This is not aJIRA-123 issue", "<p>This is not aJIRA-123 issue</p>", "jiralinks", context: "Example 10\nSection Jira Links\n");
}
[Test]
@@ -204,8 +194,7 @@ namespace Markdig.Tests.Specs.JiraLinks
// Should be rendered as:
// <p>This is not 4JIRA-123 issue</p>
Console.WriteLine("Example 11\nSection Jira Links\n");
TestParser.TestSpec("This is not 4JIRA-123 issue", "<p>This is not 4JIRA-123 issue</p>", "jiralinks");
TestParser.TestSpec("This is not 4JIRA-123 issue", "<p>This is not 4JIRA-123 issue</p>", "jiralinks", context: "Example 11\nSection Jira Links\n");
}
[Test]
@@ -220,8 +209,7 @@ namespace Markdig.Tests.Specs.JiraLinks
// Should be rendered as:
// <p>This is not JIRA-123a issue</p>
Console.WriteLine("Example 12\nSection Jira Links\n");
TestParser.TestSpec("This is not JIRA-123a issue", "<p>This is not JIRA-123a issue</p>", "jiralinks");
TestParser.TestSpec("This is not JIRA-123a issue", "<p>This is not JIRA-123a issue</p>", "jiralinks", context: "Example 12\nSection Jira Links\n");
}
[Test]
@@ -236,8 +224,7 @@ namespace Markdig.Tests.Specs.JiraLinks
// Should be rendered as:
// <p>This is not JIRA- issue</p>
Console.WriteLine("Example 13\nSection Jira Links\n");
TestParser.TestSpec("This is not JIRA- issue", "<p>This is not JIRA- issue</p>", "jiralinks");
TestParser.TestSpec("This is not JIRA- issue", "<p>This is not JIRA- issue</p>", "jiralinks", context: "Example 13\nSection Jira Links\n");
}
[Test]
@@ -252,8 +239,7 @@ namespace Markdig.Tests.Specs.JiraLinks
// Should be rendered as:
// <p>This is not JIR4- issue</p>
Console.WriteLine("Example 14\nSection Jira Links\n");
TestParser.TestSpec("This is not JIR4- issue", "<p>This is not JIR4- issue</p>", "jiralinks");
TestParser.TestSpec("This is not JIR4- issue", "<p>This is not JIR4- issue</p>", "jiralinks", context: "Example 14\nSection Jira Links\n");
}
}
}

View File

@@ -21,31 +21,31 @@ The following are valid examples:
```````````````````````````````` example
This is a ABCD-123 issue
.
<p>This is a <a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</a> issue</p>
<p>This is a <a href="http://your.company.abc/browse/ABCD-123" target="_blank">ABCD-123</a> issue</p>
````````````````````````````````
```````````````````````````````` example
This is a ABC4-123 issue
.
<p>This is a <a href="http://your.company.abc/browse/ABC4-123" target="blank">ABC4-123</a> issue</p>
<p>This is a <a href="http://your.company.abc/browse/ABC4-123" target="_blank">ABC4-123</a> issue</p>
````````````````````````````````
```````````````````````````````` example
This is a ABC45-123 issue
.
<p>This is a <a href="http://your.company.abc/browse/ABC45-123" target="blank">ABC45-123</a> issue</p>
<p>This is a <a href="http://your.company.abc/browse/ABC45-123" target="_blank">ABC45-123</a> issue</p>
````````````````````````````````
```````````````````````````````` example
This is a KIRA-1 issue
.
<p>This is a <a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a> issue</p>
<p>This is a <a href="http://your.company.abc/browse/KIRA-1" target="_blank">KIRA-1</a> issue</p>
````````````````````````````````
```````````````````````````````` example
This is a Z-1 issue
.
<p>This is a <a href="http://your.company.abc/browse/Z-1" target="blank">Z-1</a> issue</p>
<p>This is a <a href="http://your.company.abc/browse/Z-1" target="_blank">Z-1</a> issue</p>
````````````````````````````````
These are also valid links with `(` and `)`:
@@ -53,25 +53,25 @@ These are also valid links with `(` and `)`:
```````````````````````````````` example
This is a (ABCD-123) issue
.
<p>This is a (<a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</a>) issue</p>
<p>This is a (<a href="http://your.company.abc/browse/ABCD-123" target="_blank">ABCD-123</a>) issue</p>
````````````````````````````````
```````````````````````````````` example
This is a (ABC4-123) issue
.
<p>This is a (<a href="http://your.company.abc/browse/ABC4-123" target="blank">ABC4-123</a>) issue</p>
<p>This is a (<a href="http://your.company.abc/browse/ABC4-123" target="_blank">ABC4-123</a>) issue</p>
````````````````````````````````
```````````````````````````````` example
This is a (KIRA-1) issue
.
<p>This is a (<a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a>) issue</p>
<p>This is a (<a href="http://your.company.abc/browse/KIRA-1" target="_blank">KIRA-1</a>) issue</p>
````````````````````````````````
```````````````````````````````` example
This is a (Z-1) issue
.
<p>This is a (<a href="http://your.company.abc/browse/Z-1" target="blank">Z-1</a>) issue</p>
<p>This is a (<a href="http://your.company.abc/browse/Z-1" target="_blank">Z-1</a>) issue</p>
````````````````````````````````
These are not valid links:

View File

@@ -36,8 +36,7 @@ namespace Markdig.Tests.Specs.ListExtras
// <li>Last item</li>
// </ol>
Console.WriteLine("Example 1\nSection Extensions / Ordered list with alpha letter\n");
TestParser.TestSpec("a. First item\nb. Second item\nc. Last item", "<ol type=\"a\">\n<li>First item</li>\n<li>Second item</li>\n<li>Last item</li>\n</ol>", "listextras|advanced");
TestParser.TestSpec("a. First item\nb. Second item\nc. Last item", "<ol type=\"a\">\n<li>First item</li>\n<li>Second item</li>\n<li>Last item</li>\n</ol>", "listextras|advanced", context: "Example 1\nSection Extensions / Ordered list with alpha letter\n");
}
// It works also for uppercase alpha:
@@ -59,8 +58,7 @@ namespace Markdig.Tests.Specs.ListExtras
// <li>Last item</li>
// </ol>
Console.WriteLine("Example 2\nSection Extensions / Ordered list with alpha letter\n");
TestParser.TestSpec("A. First item\nB. Second item\nC. Last item", "<ol type=\"A\">\n<li>First item</li>\n<li>Second item</li>\n<li>Last item</li>\n</ol>", "listextras|advanced");
TestParser.TestSpec("A. First item\nB. Second item\nC. Last item", "<ol type=\"A\">\n<li>First item</li>\n<li>Second item</li>\n<li>Last item</li>\n</ol>", "listextras|advanced", context: "Example 2\nSection Extensions / Ordered list with alpha letter\n");
}
// Like for numbered list, a list can start with a different letter
@@ -80,8 +78,7 @@ namespace Markdig.Tests.Specs.ListExtras
// <li>Second item</li>
// </ol>
Console.WriteLine("Example 3\nSection Extensions / Ordered list with alpha letter\n");
TestParser.TestSpec("b. First item\nc. Second item", "<ol type=\"a\" start=\"2\">\n<li>First item</li>\n<li>Second item</li>\n</ol>", "listextras|advanced");
TestParser.TestSpec("b. First item\nc. Second item", "<ol type=\"a\" start=\"2\">\n<li>First item</li>\n<li>Second item</li>\n</ol>", "listextras|advanced", context: "Example 3\nSection Extensions / Ordered list with alpha letter\n");
}
// A different type of list will break the existing list:
@@ -105,8 +102,7 @@ namespace Markdig.Tests.Specs.ListExtras
// <li>First item2</li>
// </ol>
Console.WriteLine("Example 4\nSection Extensions / Ordered list with alpha letter\n");
TestParser.TestSpec("a. First item1\nb. Second item\nA. First item2", "<ol type=\"a\">\n<li>First item1</li>\n<li>Second item</li>\n</ol>\n<ol type=\"A\">\n<li>First item2</li>\n</ol>", "listextras|advanced");
TestParser.TestSpec("a. First item1\nb. Second item\nA. First item2", "<ol type=\"a\">\n<li>First item1</li>\n<li>Second item</li>\n</ol>\n<ol type=\"A\">\n<li>First item2</li>\n</ol>", "listextras|advanced", context: "Example 4\nSection Extensions / Ordered list with alpha letter\n");
}
}
@@ -136,8 +132,7 @@ namespace Markdig.Tests.Specs.ListExtras
// <li>Last item</li>
// </ol>
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", "<ol type=\"i\">\n<li>First item</li>\n<li>Second item</li>\n<li>Third item</li>\n<li>Last item</li>\n</ol>", "listextras|advanced");
TestParser.TestSpec("i. First item\nii. Second item\niii. Third item\niv. Last item", "<ol type=\"i\">\n<li>First item</li>\n<li>Second item</li>\n<li>Third item</li>\n<li>Last item</li>\n</ol>", "listextras|advanced", context: "Example 5\nSection Extensions / Ordered list with roman letter\n");
}
// It works also for uppercase alpha:
@@ -161,8 +156,7 @@ namespace Markdig.Tests.Specs.ListExtras
// <li>Last item</li>
// </ol>
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", "<ol type=\"I\">\n<li>First item</li>\n<li>Second item</li>\n<li>Third item</li>\n<li>Last item</li>\n</ol>", "listextras|advanced");
TestParser.TestSpec("I. First item\nII. Second item\nIII. Third item\nIV. Last item", "<ol type=\"I\">\n<li>First item</li>\n<li>Second item</li>\n<li>Third item</li>\n<li>Last item</li>\n</ol>", "listextras|advanced", context: "Example 6\nSection Extensions / Ordered list with roman letter\n");
}
// Like for numbered list, a list can start with a different letter
@@ -182,8 +176,7 @@ namespace Markdig.Tests.Specs.ListExtras
// <li>Second item</li>
// </ol>
Console.WriteLine("Example 7\nSection Extensions / Ordered list with roman letter\n");
TestParser.TestSpec("ii. First item\niii. Second item", "<ol type=\"i\" start=\"2\">\n<li>First item</li>\n<li>Second item</li>\n</ol>", "listextras|advanced");
TestParser.TestSpec("ii. First item\niii. Second item", "<ol type=\"i\" start=\"2\">\n<li>First item</li>\n<li>Second item</li>\n</ol>", "listextras|advanced", context: "Example 7\nSection Extensions / Ordered list with roman letter\n");
}
// Lists can be restarted, specifying the start point.
@@ -209,8 +202,7 @@ namespace Markdig.Tests.Specs.ListExtras
// <li>Second item</li>
// </ol>
Console.WriteLine("Example 8\nSection Extensions / Ordered list with roman letter\n");
TestParser.TestSpec("1. First item\n\nSome text\n\n2. Second item", "<ol>\n<li>First item</li>\n</ol>\n<p>Some text</p>\n<ol start=\"2\">\n<li>Second item</li>\n</ol>", "listextras|advanced");
TestParser.TestSpec("1. First item\n\nSome text\n\n2. Second item", "<ol>\n<li>First item</li>\n</ol>\n<p>Some text</p>\n<ol start=\"2\">\n<li>Second item</li>\n</ol>", "listextras|advanced", context: "Example 8\nSection Extensions / Ordered list with roman letter\n");
}
}
}

View File

@@ -30,8 +30,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is a <span class="math">\(math block\)</span></p>
Console.WriteLine("Example 1\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is a $math block$", "<p>This is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced");
TestParser.TestSpec("This is a $math block$", "<p>This is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced", context: "Example 1\nSection Extensions / Math Inline\n");
}
// Or by `$$...$$` embracing it by:
@@ -47,8 +46,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is a <span class="math">\(math block\)</span></p>
Console.WriteLine("Example 2\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is a $$math block$$", "<p>This is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced");
TestParser.TestSpec("This is a $$math block$$", "<p>This is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced", context: "Example 2\nSection Extensions / Math Inline\n");
}
// Newlines inside an inline math are not allowed:
@@ -66,8 +64,7 @@ namespace Markdig.Tests.Specs.Math
// <p>This is not a $$math
// block$$ and? this is a <span class="math">\(math block\)</span></p>
Console.WriteLine("Example 3\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is not a $$math \nblock$$ and? this is a $$math block$$", "<p>This is not a $$math\nblock$$ and? this is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced");
TestParser.TestSpec("This is not a $$math \nblock$$ and? this is a $$math block$$", "<p>This is not a $$math\nblock$$ and? this is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced", context: "Example 3\nSection Extensions / Math Inline\n");
}
[Test]
@@ -84,8 +81,7 @@ namespace Markdig.Tests.Specs.Math
// <p>This is not a $math
// block$ and? this is a <span class="math">\(math block\)</span></p>
Console.WriteLine("Example 4\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is not a $math \nblock$ and? this is a $math block$", "<p>This is not a $math\nblock$ and? this is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced");
TestParser.TestSpec("This is not a $math \nblock$ and? this is a $math block$", "<p>This is not a $math\nblock$ and? this is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced", context: "Example 4\nSection Extensions / Math Inline\n");
}
// An opening `$` can be followed by a space if the closing is also preceded by a space `$`:
@@ -101,8 +97,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is a <span class="math">\(math block\)</span></p>
Console.WriteLine("Example 5\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is a $ math block $", "<p>This is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced");
TestParser.TestSpec("This is a $ math block $", "<p>This is a <span class=\"math\">\\(math block\\)</span></p>", "mathematics|advanced", context: "Example 5\nSection Extensions / Math Inline\n");
}
[Test]
@@ -117,8 +112,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is a <span class="math">\(math block\)</span> after</p>
Console.WriteLine("Example 6\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is a $ math block $ after", "<p>This is a <span class=\"math\">\\(math block\\)</span> after</p>", "mathematics|advanced");
TestParser.TestSpec("This is a $ math block $ after", "<p>This is a <span class=\"math\">\\(math block\\)</span> after</p>", "mathematics|advanced", context: "Example 6\nSection Extensions / Math Inline\n");
}
[Test]
@@ -133,8 +127,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is a <span class="math">\(math block\)</span> after</p>
Console.WriteLine("Example 7\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is a $$ math block $$ after", "<p>This is a <span class=\"math\">\\(math block\\)</span> after</p>", "mathematics|advanced");
TestParser.TestSpec("This is a $$ math block $$ after", "<p>This is a <span class=\"math\">\\(math block\\)</span> after</p>", "mathematics|advanced", context: "Example 7\nSection Extensions / Math Inline\n");
}
[Test]
@@ -149,8 +142,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is a not $ math block$ because there is not a whitespace before the closing</p>
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", "<p>This is a not $ math block$ because there is not a whitespace before the closing</p>", "mathematics|advanced");
TestParser.TestSpec("This is a not $ math block$ because there is not a whitespace before the closing", "<p>This is a not $ math block$ because there is not a whitespace before the closing</p>", "mathematics|advanced", context: "Example 8\nSection Extensions / Math Inline\n");
}
// For the opening `$` it requires a space or a punctuation before (but cannot be used within a word):
@@ -166,8 +158,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is not a m$ath block$</p>
Console.WriteLine("Example 9\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is not a m$ath block$", "<p>This is not a m$ath block$</p>", "mathematics|advanced");
TestParser.TestSpec("This is not a m$ath block$", "<p>This is not a m$ath block$</p>", "mathematics|advanced", context: "Example 9\nSection Extensions / Math Inline\n");
}
// 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):
@@ -183,8 +174,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is not a $math bloc$k</p>
Console.WriteLine("Example 10\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is not a $math bloc$k", "<p>This is not a $math bloc$k</p>", "mathematics|advanced");
TestParser.TestSpec("This is not a $math bloc$k", "<p>This is not a $math bloc$k</p>", "mathematics|advanced", context: "Example 10\nSection Extensions / Math Inline\n");
}
// 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):
@@ -200,8 +190,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is should not match a 16$ or a $15</p>
Console.WriteLine("Example 11\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is should not match a 16$ or a $15", "<p>This is should not match a 16$ or a $15</p>", "mathematics|advanced");
TestParser.TestSpec("This is should not match a 16$ or a $15", "<p>This is should not match a 16$ or a $15</p>", "mathematics|advanced", context: "Example 11\nSection Extensions / Math Inline\n");
}
// A `$` can be escaped between a math inline block by using the escape `\\`
@@ -217,8 +206,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is a <span class="math">\(math \$ block\)</span></p>
Console.WriteLine("Example 12\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is a $math \\$ block$", "<p>This is a <span class=\"math\">\\(math \\$ block\\)</span></p>", "mathematics|advanced");
TestParser.TestSpec("This is a $math \\$ block$", "<p>This is a <span class=\"math\">\\(math \\$ block\\)</span></p>", "mathematics|advanced", context: "Example 12\nSection Extensions / Math Inline\n");
}
// At most, two `$` will be matched for the opening and closing:
@@ -234,8 +222,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is a <span class="math">\($math block$\)</span></p>
Console.WriteLine("Example 13\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is a $$$math block$$$", "<p>This is a <span class=\"math\">\\($math block$\\)</span></p>", "mathematics|advanced");
TestParser.TestSpec("This is a $$$math block$$$", "<p>This is a <span class=\"math\">\\($math block$\\)</span></p>", "mathematics|advanced", context: "Example 13\nSection Extensions / Math Inline\n");
}
// Regular text can come both before and after the math inline
@@ -251,8 +238,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is a <span class="math">\(math block\)</span> with text on both sides.</p>
Console.WriteLine("Example 14\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is a $math block$ with text on both sides.", "<p>This is a <span class=\"math\">\\(math block\\)</span> with text on both sides.</p>", "mathematics|advanced");
TestParser.TestSpec("This is a $math block$ with text on both sides.", "<p>This is a <span class=\"math\">\\(math block\\)</span> with text on both sides.</p>", "mathematics|advanced", context: "Example 14\nSection Extensions / Math Inline\n");
}
// A mathematic block takes precedence over standard emphasis `*` `_`:
@@ -268,8 +254,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p>This is *a <span class="math">\(math* block\)</span></p>
Console.WriteLine("Example 15\nSection Extensions / Math Inline\n");
TestParser.TestSpec("This is *a $math* block$", "<p>This is *a <span class=\"math\">\\(math* block\\)</span></p>", "mathematics|advanced");
TestParser.TestSpec("This is *a $math* block$", "<p>This is *a <span class=\"math\">\\(math* block\\)</span></p>", "mathematics|advanced", context: "Example 15\nSection Extensions / Math Inline\n");
}
// An opening $$ at the beginning of a line should not be interpreted as a Math block:
@@ -285,8 +270,7 @@ namespace Markdig.Tests.Specs.Math
// Should be rendered as:
// <p><span class="math">\(math\)</span> starting at a line</p>
Console.WriteLine("Example 16\nSection Extensions / Math Inline\n");
TestParser.TestSpec("$$ math $$ starting at a line", "<p><span class=\"math\">\\(math\\)</span> starting at a line</p>", "mathematics|advanced");
TestParser.TestSpec("$$ math $$ starting at a line", "<p><span class=\"math\">\\(math\\)</span> starting at a line</p>", "mathematics|advanced", context: "Example 16\nSection Extensions / Math Inline\n");
}
}
@@ -320,8 +304,7 @@ namespace Markdig.Tests.Specs.Math
// \end{equation}
// \]</div>
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$$", "<div class=\"math\">\n\\[\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\\]</div>", "mathematics|advanced");
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$$", "<div class=\"math\">\n\\[\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\\]</div>", "mathematics|advanced", context: "Example 17\nSection Extensions / Math Block\n");
}
}
}

View File

@@ -57,8 +57,7 @@ namespace Markdig.Tests.Specs.Media
// <p><iframe src="https://music.yandex.ru/iframe/#track/4402274/411845/" class="yandex" width="500" height="281" frameborder="0"></iframe></p>
// <p><iframe src="https://ok.ru/videoembed/26870090463" class="odnoklassniki" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
Console.WriteLine("Example 1\nSection Extensions / Media links\n");
TestParser.TestSpec("![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)\n\n![youtube.com with t](https://www.youtube.com/watch?v=mswPy5bt3TQ&t=100)\n\n![youtu.be](https://youtu.be/mswPy5bt3TQ)\n\n![youtu.be with t](https://youtu.be/mswPy5bt3TQ?t=100)\n\n![youtube.com/embed 1](https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0)\n\n![youtube.com/embed 2](https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6)\n\n![vimeo](https://vimeo.com/8607834)\n\n![static mp4](https://sample.com/video.mp4)\n\n![yandex.ru](https://music.yandex.ru/album/411845/track/4402274)\n\n![ok.ru](https://ok.ru/video/26870090463)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100&amp;rel=0\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed?listType=playlist&amp;list=PLC77007E23FF423C6\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://player.vimeo.com/video/8607834\" class=\"vimeo\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"https://sample.com/video.mp4\"></source></video></p>\n<p><iframe src=\"https://music.yandex.ru/iframe/#track/4402274/411845/\" class=\"yandex\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n<p><iframe src=\"https://ok.ru/videoembed/26870090463\" class=\"odnoklassniki\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>", "medialinks|advanced+medialinks");
TestParser.TestSpec("![youtube.com](https://www.youtube.com/watch?v=mswPy5bt3TQ)\n\n![youtube.com with t](https://www.youtube.com/watch?v=mswPy5bt3TQ&t=100)\n\n![youtu.be](https://youtu.be/mswPy5bt3TQ)\n\n![youtu.be with t](https://youtu.be/mswPy5bt3TQ?t=100)\n\n![youtube.com/embed 1](https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0)\n\n![youtube.com/embed 2](https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6)\n\n![vimeo](https://vimeo.com/8607834)\n\n![static mp4](https://sample.com/video.mp4)\n\n![yandex.ru](https://music.yandex.ru/album/411845/track/4402274)\n\n![ok.ru](https://ok.ru/video/26870090463)", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100&amp;rel=0\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed?listType=playlist&amp;list=PLC77007E23FF423C6\" class=\"youtube\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://player.vimeo.com/video/8607834\" class=\"vimeo\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"https://sample.com/video.mp4\"></source></video></p>\n<p><iframe src=\"https://music.yandex.ru/iframe/#track/4402274/411845/\" class=\"yandex\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n<p><iframe src=\"https://ok.ru/videoembed/26870090463\" class=\"odnoklassniki\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>", "medialinks|advanced+medialinks", context: "Example 1\nSection Extensions / Media links\n");
}
}
}

View File

@@ -30,8 +30,7 @@ namespace Markdig.Tests.Specs.NoHtml
// Should be rendered as:
// <p>this is some text&lt;/td&gt;&lt;/tr&gt;</p>
Console.WriteLine("Example 1\nSection Extensions / NoHTML\n");
TestParser.TestSpec("this is some text</td></tr>", "<p>this is some text&lt;/td&gt;&lt;/tr&gt;</p>", "nohtml");
TestParser.TestSpec("this is some text</td></tr>", "<p>this is some text&lt;/td&gt;&lt;/tr&gt;</p>", "nohtml", context: "Example 1\nSection Extensions / NoHTML\n");
}
// For Block HTML:
@@ -51,8 +50,7 @@ namespace Markdig.Tests.Specs.NoHtml
// this is some text
// &lt;/div&gt;</p>
Console.WriteLine("Example 2\nSection Extensions / NoHTML\n");
TestParser.TestSpec("<div>\nthis is some text\n</div>", "<p>&lt;div&gt;\nthis is some text\n&lt;/div&gt;</p>", "nohtml");
TestParser.TestSpec("<div>\nthis is some text\n</div>", "<p>&lt;div&gt;\nthis is some text\n&lt;/div&gt;</p>", "nohtml", context: "Example 2\nSection Extensions / NoHTML\n");
}
}
}

View File

@@ -58,8 +58,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 1\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a | b\n-- | -\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("a | b\n-- | -\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 1\nSection Extensions / Gfm Pipe Table\n");
}
// The following is also considered as a table, even if the second line starts like a list:
@@ -90,8 +89,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 2\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a | b\n- | -\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("a | b\n- | -\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 2\nSection Extensions / Gfm Pipe Table\n");
}
// A pipe table with only one header row is allowed:
@@ -115,8 +113,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </thead>
// </table>
Console.WriteLine("Example 3\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a | b\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>", "gfm-pipetables");
TestParser.TestSpec("a | b\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>", "gfm-pipetables", context: "Example 3\nSection Extensions / Gfm Pipe Table\n");
}
// After a row separator header, they will be interpreted as plain column:
@@ -147,8 +144,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 4\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a | b\n-- | --\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>--</td>\n<td>--</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("a | b\n-- | --\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>--</td>\n<td>--</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 4\nSection Extensions / Gfm Pipe Table\n");
}
// 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
@@ -168,8 +164,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// c | d
// e | f</p>
Console.WriteLine("Example 5\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a b\nc | d\ne | f", "<p>a b\nc | d\ne | f</p>", "gfm-pipetables");
TestParser.TestSpec("a b\nc | d\ne | f", "<p>a b\nc | d\ne | f</p>", "gfm-pipetables", context: "Example 5\nSection Extensions / Gfm Pipe Table\n");
}
// If a line doesn't have a column delimiter `|` the table is not detected
@@ -187,8 +182,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// <p>a | b
// c no d</p>
Console.WriteLine("Example 6\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a | b\nc no d", "<p>a | b\nc no d</p>", "gfm-pipetables");
TestParser.TestSpec("a | b\nc no d", "<p>a | b\nc no d</p>", "gfm-pipetables", context: "Example 6\nSection Extensions / Gfm Pipe Table\n");
}
// If a row contains more columns than the header row, the extra columns will be ignored:
@@ -229,8 +223,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 7\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a | b \n-- | --\n0 | 1 | 2\n3 | 4\n5 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>3</td>\n<td>4</td>\n</tr>\n<tr>\n<td>5</td>\n<td></td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("a | b \n-- | --\n0 | 1 | 2\n3 | 4\n5 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>3</td>\n<td>4</td>\n</tr>\n<tr>\n<td>5</td>\n<td></td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 7\nSection Extensions / Gfm Pipe Table\n");
}
// **Rule #2**
@@ -265,8 +258,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 8\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a | b |\n-- | --\n0 | 1 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("a | b |\n-- | --\n0 | 1 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 8\nSection Extensions / Gfm Pipe Table\n");
}
// **Rule #4**
@@ -308,8 +300,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 9\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec(" a | b |\n-- | --\n| 0 | 1\n| 2 | 3 |\n 4 | 5 ", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>2</td>\n<td>3</td>\n</tr>\n<tr>\n<td>4</td>\n<td>5</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec(" a | b |\n-- | --\n| 0 | 1\n| 2 | 3 |\n 4 | 5 ", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>2</td>\n<td>3</td>\n</tr>\n<tr>\n<td>4</td>\n<td>5</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 9\nSection Extensions / Gfm Pipe Table\n");
}
// A pipe may be present at both the beginning/ending of each line:
@@ -340,8 +331,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 10\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("|a|b|\n|-|-|\n|0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("|a|b|\n|-|-|\n|0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 10\nSection Extensions / Gfm Pipe Table\n");
}
// Or may be omitted on one side:
@@ -372,8 +362,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 11\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a|b|\n-|-|\n0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("a|b|\n-|-|\n0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 11\nSection Extensions / Gfm Pipe Table\n");
}
[Test]
@@ -403,8 +392,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 12\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("|a|b\n|-|-\n|0|1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("|a|b\n|-|-\n|0|1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 12\nSection Extensions / Gfm Pipe Table\n");
}
// Single column table can be declared with lines starting only by a column delimiter:
@@ -437,8 +425,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 13\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("| a\n| --\n| b\n| c ", "<table>\n<thead>\n<tr>\n<th>a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b</td>\n</tr>\n<tr>\n<td>c</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("| a\n| --\n| b\n| c ", "<table>\n<thead>\n<tr>\n<th>a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b</td>\n</tr>\n<tr>\n<td>c</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 13\nSection Extensions / Gfm Pipe Table\n");
}
// **Rule #5**
@@ -482,8 +469,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 14\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec(" a | b \n-------|-------\n 0 | 1 \n 2 | 3 ", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>2</td>\n<td>3</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec(" a | b \n-------|-------\n 0 | 1 \n 2 | 3 ", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>2</td>\n<td>3</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 14\nSection Extensions / Gfm Pipe Table\n");
}
// 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.
@@ -524,8 +510,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 15\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec(" a | b | c \n:------|:-------:| ----:\n 0 | 1 | 2 \n 3 | 4 | 5 ", "<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">a</th>\n<th style=\"text-align: center;\">b</th>\n<th style=\"text-align: right;\">c</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\">0</td>\n<td style=\"text-align: center;\">1</td>\n<td style=\"text-align: right;\">2</td>\n</tr>\n<tr>\n<td style=\"text-align: left;\">3</td>\n<td style=\"text-align: center;\">4</td>\n<td style=\"text-align: right;\">5</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec(" a | b | c \n:------|:-------:| ----:\n 0 | 1 | 2 \n 3 | 4 | 5 ", "<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">a</th>\n<th style=\"text-align: center;\">b</th>\n<th style=\"text-align: right;\">c</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\">0</td>\n<td style=\"text-align: center;\">1</td>\n<td style=\"text-align: right;\">2</td>\n</tr>\n<tr>\n<td style=\"text-align: left;\">3</td>\n<td style=\"text-align: center;\">4</td>\n<td style=\"text-align: right;\">5</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 15\nSection Extensions / Gfm Pipe Table\n");
}
// Test alignment with starting and ending pipes:
@@ -558,8 +543,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 16\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("| abc | def | ghi |\n|:---:|-----|----:|\n| 1 | 2 | 3 |", "<table>\n<thead>\n<tr>\n<th style=\"text-align: center;\">abc</th>\n<th>def</th>\n<th style=\"text-align: right;\">ghi</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: center;\">1</td>\n<td>2</td>\n<td style=\"text-align: right;\">3</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("| abc | def | ghi |\n|:---:|-----|----:|\n| 1 | 2 | 3 |", "<table>\n<thead>\n<tr>\n<th style=\"text-align: center;\">abc</th>\n<th>def</th>\n<th style=\"text-align: right;\">ghi</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: center;\">1</td>\n<td>2</td>\n<td style=\"text-align: right;\">3</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 16\nSection Extensions / Gfm Pipe Table\n");
}
// The following example shows a non matching header column separator:
@@ -581,8 +565,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// 0 | 1
// 2 | 3</p>
Console.WriteLine("Example 17\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec(" a | b\n-------|---x---\n 0 | 1\n 2 | 3 ", "<p>a | b\n-------|---x---\n0 | 1\n2 | 3</p> ", "gfm-pipetables");
TestParser.TestSpec(" a | b\n-------|---x---\n 0 | 1\n 2 | 3 ", "<p>a | b\n-------|---x---\n0 | 1\n2 | 3</p> ", "gfm-pipetables", context: "Example 17\nSection Extensions / Gfm Pipe Table\n");
}
// **Rule #6**
@@ -620,8 +603,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 18\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec(" *a* | b\n----- |-----\n 0 | _1_\n _2 | 3* ", "<table>\n<thead>\n<tr>\n<th><em>a</em></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td><em>1</em></td>\n</tr>\n<tr>\n<td>_2</td>\n<td>3*</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec(" *a* | b\n----- |-----\n 0 | _1_\n _2 | 3* ", "<table>\n<thead>\n<tr>\n<th><em>a</em></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td><em>1</em></td>\n</tr>\n<tr>\n<td>_2</td>\n<td>3*</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 18\nSection Extensions / Gfm Pipe Table\n");
}
// **Rule #7**
@@ -640,8 +622,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// Should be rendered as:
// <p>a | b <code>0 |</code></p>
Console.WriteLine("Example 19\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a | b `\n0 | ` ", "<p>a | b <code>0 |</code></p> ", "gfm-pipetables");
TestParser.TestSpec("a | b `\n0 | ` ", "<p>a | b <code>0 |</code></p> ", "gfm-pipetables", context: "Example 19\nSection Extensions / Gfm Pipe Table\n");
}
// **Rule #8**
@@ -674,8 +655,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 20\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a <a href=\"\" title=\"|\"></a> | b\n-- | --\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a <a href=\"\" title=\"|\"></a></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("a <a href=\"\" title=\"|\"></a> | b\n-- | --\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a <a href=\"\" title=\"|\"></a></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 20\nSection Extensions / Gfm Pipe Table\n");
}
// **Rule #9**
@@ -708,8 +688,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 21\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a | b\n-- | --\n[This is a link with a | inside the label](http://google.com) | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><a href=\"http://google.com\">This is a link with a | inside the label</a></td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("a | b\n-- | --\n[This is a link with a | inside the label](http://google.com) | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><a href=\"http://google.com\">This is a link with a | inside the label</a></td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 21\nSection Extensions / Gfm Pipe Table\n");
}
// **Rule #10**
@@ -735,8 +714,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </thead>
// </table>
Console.WriteLine("Example 22\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a | b\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>", "gfm-pipetables");
TestParser.TestSpec("a | b\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>", "gfm-pipetables", context: "Example 22\nSection Extensions / Gfm Pipe Table\n");
}
[Test]
@@ -760,8 +738,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </thead>
// </table>
Console.WriteLine("Example 23\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("|a|b|c\n|---|---|---|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n</tr>\n</thead>\n</table>", "gfm-pipetables");
TestParser.TestSpec("|a|b|c\n|---|---|---|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n</tr>\n</thead>\n</table>", "gfm-pipetables", context: "Example 23\nSection Extensions / Gfm Pipe Table\n");
}
// **Tests**
@@ -809,8 +786,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 24\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("| abc | def | \n|---|---|\n| cde| ddd| \n| eee| fff|\n| fff | fffff | \n|gggg | ffff | ", "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>cde</td>\n<td>ddd</td>\n</tr>\n<tr>\n<td>eee</td>\n<td>fff</td>\n</tr>\n<tr>\n<td>fff</td>\n<td>fffff</td>\n</tr>\n<tr>\n<td>gggg</td>\n<td>ffff</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("| abc | def | \n|---|---|\n| cde| ddd| \n| eee| fff|\n| fff | fffff | \n|gggg | ffff | ", "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>cde</td>\n<td>ddd</td>\n</tr>\n<tr>\n<td>eee</td>\n<td>fff</td>\n</tr>\n<tr>\n<td>fff</td>\n<td>fffff</td>\n</tr>\n<tr>\n<td>gggg</td>\n<td>ffff</td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 24\nSection Extensions / Gfm Pipe Table\n");
}
// **Normalized columns count**
@@ -849,8 +825,7 @@ namespace Markdig.Tests.Specs.GFMPipeTables
// </tbody>
// </table>
Console.WriteLine("Example 25\nSection Extensions / Gfm Pipe Table\n");
TestParser.TestSpec("a | b\n-- | - \n0 | 1 | 2\n3 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>3</td>\n<td></td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables");
TestParser.TestSpec("a | b\n-- | - \n0 | 1 | 2\n3 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>3</td>\n<td></td>\n</tr>\n</tbody>\n</table>", "gfm-pipetables", context: "Example 25\nSection Extensions / Gfm Pipe Table\n");
}
}
}

View File

@@ -56,8 +56,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 1\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a | b\n-- | -\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("a | b\n-- | -\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 1\nSection Extensions / Pipe Table\n");
}
// The following is also considered as a table, even if the second line starts like a list:
@@ -88,8 +87,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 2\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a | b\n- | -\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("a | b\n- | -\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 2\nSection Extensions / Pipe Table\n");
}
// A pipe table with only one header row is allowed:
@@ -113,8 +111,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </thead>
// </table>
Console.WriteLine("Example 3\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a | b\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>", "pipetables|advanced");
TestParser.TestSpec("a | b\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>", "pipetables|advanced", context: "Example 3\nSection Extensions / Pipe Table\n");
}
// After a row separator header, they will be interpreted as plain column:
@@ -145,8 +142,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 4\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a | b\n-- | --\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>--</td>\n<td>--</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("a | b\n-- | --\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>--</td>\n<td>--</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 4\nSection Extensions / Pipe Table\n");
}
// 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
@@ -166,8 +162,7 @@ namespace Markdig.Tests.Specs.PipeTables
// c | d
// e | f</p>
Console.WriteLine("Example 5\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a b\nc | d\ne | f", "<p>a b\nc | d\ne | f</p>", "pipetables|advanced");
TestParser.TestSpec("a b\nc | d\ne | f", "<p>a b\nc | d\ne | f</p>", "pipetables|advanced", context: "Example 5\nSection Extensions / Pipe Table\n");
}
// If a line doesn't have a column delimiter `|` the table is not detected
@@ -185,8 +180,7 @@ namespace Markdig.Tests.Specs.PipeTables
// <p>a | b
// c no d</p>
Console.WriteLine("Example 6\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a | b\nc no d", "<p>a | b\nc no d</p>", "pipetables|advanced");
TestParser.TestSpec("a | b\nc no d", "<p>a | b\nc no d</p>", "pipetables|advanced", context: "Example 6\nSection Extensions / Pipe Table\n");
}
// If a row contains more column than the header row, it will still be added as a column:
@@ -231,8 +225,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 7\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a | b \n-- | --\n0 | 1 | 2\n3 | 4\n5 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n<td>2</td>\n</tr>\n<tr>\n<td>3</td>\n<td>4</td>\n<td></td>\n</tr>\n<tr>\n<td>5</td>\n<td></td>\n<td></td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("a | b \n-- | --\n0 | 1 | 2\n3 | 4\n5 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n<td>2</td>\n</tr>\n<tr>\n<td>3</td>\n<td>4</td>\n<td></td>\n</tr>\n<tr>\n<td>5</td>\n<td></td>\n<td></td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 7\nSection Extensions / Pipe Table\n");
}
// **Rule #2**
@@ -267,8 +260,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 8\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a | b |\n-- | --\n0 | 1 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("a | b |\n-- | --\n0 | 1 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 8\nSection Extensions / Pipe Table\n");
}
// **Rule #4**
@@ -310,8 +302,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 9\nSection Extensions / Pipe Table\n");
TestParser.TestSpec(" a | b |\n-- | --\n| 0 | 1\n| 2 | 3 |\n 4 | 5 ", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>2</td>\n<td>3</td>\n</tr>\n<tr>\n<td>4</td>\n<td>5</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec(" a | b |\n-- | --\n| 0 | 1\n| 2 | 3 |\n 4 | 5 ", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>2</td>\n<td>3</td>\n</tr>\n<tr>\n<td>4</td>\n<td>5</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 9\nSection Extensions / Pipe Table\n");
}
// A pipe may be present at both the beginning/ending of each line:
@@ -342,8 +333,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 10\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("|a|b|\n|-|-|\n|0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("|a|b|\n|-|-|\n|0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 10\nSection Extensions / Pipe Table\n");
}
// Or may be omitted on one side:
@@ -374,8 +364,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 11\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a|b|\n-|-|\n0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("a|b|\n-|-|\n0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 11\nSection Extensions / Pipe Table\n");
}
[Test]
@@ -405,8 +394,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 12\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("|a|b\n|-|-\n|0|1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("|a|b\n|-|-\n|0|1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 12\nSection Extensions / Pipe Table\n");
}
// Single column table can be declared with lines starting only by a column delimiter:
@@ -439,8 +427,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 13\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("| a\n| --\n| b\n| c ", "<table>\n<thead>\n<tr>\n<th>a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b</td>\n</tr>\n<tr>\n<td>c</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("| a\n| --\n| b\n| c ", "<table>\n<thead>\n<tr>\n<th>a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b</td>\n</tr>\n<tr>\n<td>c</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 13\nSection Extensions / Pipe Table\n");
}
// **Rule #5**
@@ -484,8 +471,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 14\nSection Extensions / Pipe Table\n");
TestParser.TestSpec(" a | b \n-------|-------\n 0 | 1 \n 2 | 3 ", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>2</td>\n<td>3</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec(" a | b \n-------|-------\n 0 | 1 \n 2 | 3 ", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n<tr>\n<td>2</td>\n<td>3</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 14\nSection Extensions / Pipe Table\n");
}
// 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.
@@ -526,8 +512,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 15\nSection Extensions / Pipe Table\n");
TestParser.TestSpec(" a | b | c \n:------|:-------:| ----:\n 0 | 1 | 2 \n 3 | 4 | 5 ", "<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">a</th>\n<th style=\"text-align: center;\">b</th>\n<th style=\"text-align: right;\">c</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\">0</td>\n<td style=\"text-align: center;\">1</td>\n<td style=\"text-align: right;\">2</td>\n</tr>\n<tr>\n<td style=\"text-align: left;\">3</td>\n<td style=\"text-align: center;\">4</td>\n<td style=\"text-align: right;\">5</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec(" a | b | c \n:------|:-------:| ----:\n 0 | 1 | 2 \n 3 | 4 | 5 ", "<table>\n<thead>\n<tr>\n<th style=\"text-align: left;\">a</th>\n<th style=\"text-align: center;\">b</th>\n<th style=\"text-align: right;\">c</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: left;\">0</td>\n<td style=\"text-align: center;\">1</td>\n<td style=\"text-align: right;\">2</td>\n</tr>\n<tr>\n<td style=\"text-align: left;\">3</td>\n<td style=\"text-align: center;\">4</td>\n<td style=\"text-align: right;\">5</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 15\nSection Extensions / Pipe Table\n");
}
// Test alignment with starting and ending pipes:
@@ -560,8 +545,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 16\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("| abc | def | ghi |\n|:---:|-----|----:|\n| 1 | 2 | 3 |", "<table>\n<thead>\n<tr>\n<th style=\"text-align: center;\">abc</th>\n<th>def</th>\n<th style=\"text-align: right;\">ghi</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: center;\">1</td>\n<td>2</td>\n<td style=\"text-align: right;\">3</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("| abc | def | ghi |\n|:---:|-----|----:|\n| 1 | 2 | 3 |", "<table>\n<thead>\n<tr>\n<th style=\"text-align: center;\">abc</th>\n<th>def</th>\n<th style=\"text-align: right;\">ghi</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align: center;\">1</td>\n<td>2</td>\n<td style=\"text-align: right;\">3</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 16\nSection Extensions / Pipe Table\n");
}
// The following example shows a non matching header column separator:
@@ -583,8 +567,7 @@ namespace Markdig.Tests.Specs.PipeTables
// 0 | 1
// 2 | 3</p>
Console.WriteLine("Example 17\nSection Extensions / Pipe Table\n");
TestParser.TestSpec(" a | b\n-------|---x---\n 0 | 1\n 2 | 3 ", "<p>a | b\n-------|---x---\n0 | 1\n2 | 3</p> ", "pipetables|advanced");
TestParser.TestSpec(" a | b\n-------|---x---\n 0 | 1\n 2 | 3 ", "<p>a | b\n-------|---x---\n0 | 1\n2 | 3</p> ", "pipetables|advanced", context: "Example 17\nSection Extensions / Pipe Table\n");
}
// **Rule #6**
@@ -622,8 +605,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 18\nSection Extensions / Pipe Table\n");
TestParser.TestSpec(" *a* | b\n----- |-----\n 0 | _1_\n _2 | 3* ", "<table>\n<thead>\n<tr>\n<th><em>a</em></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td><em>1</em></td>\n</tr>\n<tr>\n<td>_2</td>\n<td>3*</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec(" *a* | b\n----- |-----\n 0 | _1_\n _2 | 3* ", "<table>\n<thead>\n<tr>\n<th><em>a</em></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td><em>1</em></td>\n</tr>\n<tr>\n<td>_2</td>\n<td>3*</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 18\nSection Extensions / Pipe Table\n");
}
// **Rule #7**
@@ -642,8 +624,7 @@ namespace Markdig.Tests.Specs.PipeTables
// Should be rendered as:
// <p>a | b <code>0 |</code></p>
Console.WriteLine("Example 19\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a | b `\n0 | ` ", "<p>a | b <code>0 |</code></p> ", "pipetables|advanced");
TestParser.TestSpec("a | b `\n0 | ` ", "<p>a | b <code>0 |</code></p> ", "pipetables|advanced", context: "Example 19\nSection Extensions / Pipe Table\n");
}
// **Rule #8**
@@ -676,8 +657,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 20\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a <a href=\"\" title=\"|\"></a> | b\n-- | --\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a <a href=\"\" title=\"|\"></a></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("a <a href=\"\" title=\"|\"></a> | b\n-- | --\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a <a href=\"\" title=\"|\"></a></th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 20\nSection Extensions / Pipe Table\n");
}
// **Rule #9**
@@ -710,8 +690,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
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", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><a href=\"http://google.com\">This is a link with a | inside the label</a></td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("a | b\n-- | --\n[This is a link with a | inside the label](http://google.com) | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><a href=\"http://google.com\">This is a link with a | inside the label</a></td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 21\nSection Extensions / Pipe Table\n");
}
// **Rule #10**
@@ -737,8 +716,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </thead>
// </table>
Console.WriteLine("Example 22\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a | b\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>", "pipetables|advanced");
TestParser.TestSpec("a | b\n-- | --", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>", "pipetables|advanced", context: "Example 22\nSection Extensions / Pipe Table\n");
}
[Test]
@@ -762,8 +740,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </thead>
// </table>
Console.WriteLine("Example 23\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("|a|b|c\n|---|---|---|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n</tr>\n</thead>\n</table>", "pipetables|advanced");
TestParser.TestSpec("|a|b|c\n|---|---|---|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th>c</th>\n</tr>\n</thead>\n</table>", "pipetables|advanced", context: "Example 23\nSection Extensions / Pipe Table\n");
}
// **Tests**
@@ -811,8 +788,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
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 | ", "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>cde</td>\n<td>ddd</td>\n</tr>\n<tr>\n<td>eee</td>\n<td>fff</td>\n</tr>\n<tr>\n<td>fff</td>\n<td>fffff</td>\n</tr>\n<tr>\n<td>gggg</td>\n<td>ffff</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("| abc | def | \n|---|---|\n| cde| ddd| \n| eee| fff|\n| fff | fffff | \n|gggg | ffff | ", "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>cde</td>\n<td>ddd</td>\n</tr>\n<tr>\n<td>eee</td>\n<td>fff</td>\n</tr>\n<tr>\n<td>fff</td>\n<td>fffff</td>\n</tr>\n<tr>\n<td>gggg</td>\n<td>ffff</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 24\nSection Extensions / Pipe Table\n");
}
// **Normalized columns count**
@@ -847,8 +823,7 @@ namespace Markdig.Tests.Specs.PipeTables
// </tbody>
// </table>
Console.WriteLine("Example 25\nSection Extensions / Pipe Table\n");
TestParser.TestSpec("a | b\n-- | - \n0 | 1 | 2", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n<td>2</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("a | b\n-- | - \n0 | 1 | 2", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n<td>2</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced", context: "Example 25\nSection Extensions / Pipe Table\n");
}
}
}

View File

@@ -30,8 +30,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a &ldquo;text&rdquo;</p>
Console.WriteLine("Example 1\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a \"text\"", "<p>This is a &ldquo;text&rdquo;</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is a \"text\"", "<p>This is a &ldquo;text&rdquo;</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 1\nSection Extensions / SmartyPants Quotes\n");
}
[Test]
@@ -46,8 +45,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a &lsquo;text&rsquo;</p>
Console.WriteLine("Example 2\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a 'text'", "<p>This is a &lsquo;text&rsquo;</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is a 'text'", "<p>This is a &lsquo;text&rsquo;</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 2\nSection Extensions / SmartyPants Quotes\n");
}
[Test]
@@ -62,8 +60,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a &laquo;text&raquo;</p>
Console.WriteLine("Example 3\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a <<text>>", "<p>This is a &laquo;text&raquo;</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is a <<text>>", "<p>This is a &laquo;text&raquo;</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 3\nSection Extensions / SmartyPants Quotes\n");
}
// Unbalanced quotes are not changed:
@@ -79,8 +76,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a &quot;text</p>
Console.WriteLine("Example 4\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a \"text", "<p>This is a &quot;text</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is a \"text", "<p>This is a &quot;text</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 4\nSection Extensions / SmartyPants Quotes\n");
}
[Test]
@@ -95,8 +91,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a 'text</p>
Console.WriteLine("Example 5\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a 'text", "<p>This is a 'text</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is a 'text", "<p>This is a 'text</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 5\nSection Extensions / SmartyPants Quotes\n");
}
[Test]
@@ -111,8 +106,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a &lt;&lt;text</p>
Console.WriteLine("Example 6\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a <<text", "<p>This is a &lt;&lt;text</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is a <<text", "<p>This is a &lt;&lt;text</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 6\nSection Extensions / SmartyPants Quotes\n");
}
// Unbalanced quotes inside other quotes are not changed:
@@ -128,8 +122,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a &ldquo;text 'with&rdquo; a another text'</p>
Console.WriteLine("Example 7\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a \"text 'with\" a another text'", "<p>This is a &ldquo;text 'with&rdquo; a another text'</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is a \"text 'with\" a another text'", "<p>This is a &ldquo;text 'with&rdquo; a another text'</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 7\nSection Extensions / SmartyPants Quotes\n");
}
[Test]
@@ -144,8 +137,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is &lsquo;a &ldquo;text 'with&rdquo; a another text&rsquo;</p>
Console.WriteLine("Example 8\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is 'a \"text 'with\" a another text'", "<p>This is &lsquo;a &ldquo;text 'with&rdquo; a another text&rsquo;</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is 'a \"text 'with\" a another text'", "<p>This is &lsquo;a &ldquo;text 'with&rdquo; a another text&rsquo;</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 8\nSection Extensions / SmartyPants Quotes\n");
}
[Test]
@@ -160,8 +152,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a &lsquo;text &lt;&lt;with&rsquo; a another text&gt;&gt;</p>
Console.WriteLine("Example 9\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a 'text <<with' a another text>>", "<p>This is a &lsquo;text &lt;&lt;with&rsquo; a another text&gt;&gt;</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is a 'text <<with' a another text>>", "<p>This is a &lsquo;text &lt;&lt;with&rsquo; a another text&gt;&gt;</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 9\nSection Extensions / SmartyPants Quotes\n");
}
[Test]
@@ -176,8 +167,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a &laquo;text 'with&raquo; a another text'</p>
Console.WriteLine("Example 10\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is a <<text 'with>> a another text'", "<p>This is a &laquo;text 'with&raquo; a another text'</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is a <<text 'with>> a another text'", "<p>This is a &laquo;text 'with&raquo; a another text'</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 10\nSection Extensions / SmartyPants Quotes\n");
}
// Quotes requires to have the same rules than emphasis `_` regarding left/right frankling rules:
@@ -193,8 +183,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>It's not quotes'</p>
Console.WriteLine("Example 11\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("It's not quotes'", "<p>It's not quotes'</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("It's not quotes'", "<p>It's not quotes'</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 11\nSection Extensions / SmartyPants Quotes\n");
}
[Test]
@@ -209,8 +198,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>They are ' not matching quotes '</p>
Console.WriteLine("Example 12\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("They are ' not matching quotes '", "<p>They are ' not matching quotes '</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("They are ' not matching quotes '", "<p>They are ' not matching quotes '</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 12\nSection Extensions / SmartyPants Quotes\n");
}
[Test]
@@ -225,8 +213,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>They are' not matching 'quotes</p>
Console.WriteLine("Example 13\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("They are' not matching 'quotes", "<p>They are' not matching 'quotes</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("They are' not matching 'quotes", "<p>They are' not matching 'quotes</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 13\nSection Extensions / SmartyPants Quotes\n");
}
// An emphasis starting inside left/right quotes will span over the right quote:
@@ -242,8 +229,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is &ldquo;a <em>text&rdquo; with an emphasis</em></p>
Console.WriteLine("Example 14\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("This is \"a *text\" with an emphasis*", "<p>This is &ldquo;a <em>text&rdquo; with an emphasis</em></p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is \"a *text\" with an emphasis*", "<p>This is &ldquo;a <em>text&rdquo; with an emphasis</em></p>", "pipetables+smartypants|advanced+smartypants", context: "Example 14\nSection Extensions / SmartyPants Quotes\n");
}
// Multiple sets of quotes can be used
@@ -259,8 +245,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>&ldquo;aaa&rdquo; &ldquo;bbb&rdquo; &ldquo;ccc&rdquo; &ldquo;ddd&rdquo;</p>
Console.WriteLine("Example 15\nSection Extensions / SmartyPants Quotes\n");
TestParser.TestSpec("\"aaa\" \"bbb\" \"ccc\" \"ddd\"", "<p>&ldquo;aaa&rdquo; &ldquo;bbb&rdquo; &ldquo;ccc&rdquo; &ldquo;ddd&rdquo;</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("\"aaa\" \"bbb\" \"ccc\" \"ddd\"", "<p>&ldquo;aaa&rdquo; &ldquo;bbb&rdquo; &ldquo;ccc&rdquo; &ldquo;ddd&rdquo;</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 15\nSection Extensions / SmartyPants Quotes\n");
}
}
@@ -280,8 +265,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a &ndash; text</p>
Console.WriteLine("Example 16\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("This is a -- text", "<p>This is a &ndash; text</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is a -- text", "<p>This is a &ndash; text</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 16\nSection Extensions / SmartyPants Separators\n");
}
[Test]
@@ -296,8 +280,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a &mdash; text</p>
Console.WriteLine("Example 17\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("This is a --- text", "<p>This is a &mdash; text</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is a --- text", "<p>This is a &mdash; text</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 17\nSection Extensions / SmartyPants Separators\n");
}
[Test]
@@ -312,8 +295,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>This is a en ellipsis&hellip;</p>
Console.WriteLine("Example 18\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("This is a en ellipsis...", "<p>This is a en ellipsis&hellip;</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("This is a en ellipsis...", "<p>This is a en ellipsis&hellip;</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 18\nSection Extensions / SmartyPants Separators\n");
}
// Check that a smartypants are not breaking pipetable parsing:
@@ -344,8 +326,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// </tbody>
// </table>
Console.WriteLine("Example 19\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("a | b\n-- | --\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("a | b\n-- | --\n0 | 1", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables+smartypants|advanced+smartypants", context: "Example 19\nSection Extensions / SmartyPants Separators\n");
}
// Check quotes and dash:
@@ -361,8 +342,7 @@ namespace Markdig.Tests.Specs.SmartyPants
// Should be rendered as:
// <p>A &ldquo;quote&rdquo; with a &mdash;</p>
Console.WriteLine("Example 20\nSection Extensions / SmartyPants Separators\n");
TestParser.TestSpec("A \"quote\" with a ---", "<p>A &ldquo;quote&rdquo; with a &mdash;</p>", "pipetables+smartypants|advanced+smartypants");
TestParser.TestSpec("A \"quote\" with a ---", "<p>A &ldquo;quote&rdquo; with a &mdash;</p>", "pipetables+smartypants|advanced+smartypants", context: "Example 20\nSection Extensions / SmartyPants Separators\n");
}
}
}

View File

@@ -38,8 +38,7 @@ namespace Markdig.Tests.Specs.TaskLists
// <li>Item4</li>
// </ul>
Console.WriteLine("Example 1\nSection Extensions / TaskLists\n");
TestParser.TestSpec("- [ ] Item1\n- [x] Item2\n- [ ] Item3\n- Item4", "<ul class=\"contains-task-list\">\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" /> Item1</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> Item2</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" /> Item3</li>\n<li>Item4</li>\n</ul>", "tasklists|advanced");
TestParser.TestSpec("- [ ] Item1\n- [x] Item2\n- [ ] Item3\n- Item4", "<ul class=\"contains-task-list\">\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" /> Item1</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" checked=\"checked\" /> Item2</li>\n<li class=\"task-list-item\"><input disabled=\"disabled\" type=\"checkbox\" /> Item3</li>\n<li>Item4</li>\n</ul>", "tasklists|advanced", context: "Example 1\nSection Extensions / TaskLists\n");
}
// A task is not recognized outside a list item:
@@ -55,8 +54,7 @@ namespace Markdig.Tests.Specs.TaskLists
// Should be rendered as:
// <p>[ ] This is not a task list</p>
Console.WriteLine("Example 2\nSection Extensions / TaskLists\n");
TestParser.TestSpec("[ ] This is not a task list", "<p>[ ] This is not a task list</p>", "tasklists|advanced");
TestParser.TestSpec("[ ] This is not a task list", "<p>[ ] This is not a task list</p>", "tasklists|advanced", context: "Example 2\nSection Extensions / TaskLists\n");
}
}
}

View File

@@ -33,8 +33,7 @@ namespace Markdig.Tests.Specs.Yaml
// Should be rendered as:
// <p>This is a text</p>
Console.WriteLine("Example 1\nSection Extensions / YAML frontmatter discard\n");
TestParser.TestSpec("---\nthis: is a frontmatter\n---\nThis is a text", "<p>This is a text</p>", "yaml");
TestParser.TestSpec("---\nthis: is a frontmatter\n---\nThis is a text", "<p>This is a text</p>", "yaml", context: "Example 1\nSection Extensions / YAML frontmatter discard\n");
}
// But if a frontmatter doesn't happen on the first line, it will be parse as regular Markdown content
@@ -56,8 +55,7 @@ namespace Markdig.Tests.Specs.Yaml
// <h2>this: is a frontmatter</h2>
// <p>This is a text2</p>
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", "<h2>This is a text1</h2>\n<h2>this: is a frontmatter</h2>\n<p>This is a text2</p>", "yaml");
TestParser.TestSpec("This is a text1\n---\nthis: is a frontmatter\n---\nThis is a text2", "<h2>This is a text1</h2>\n<h2>this: is a frontmatter</h2>\n<p>This is a text2</p>", "yaml", context: "Example 2\nSection Extensions / YAML frontmatter discard\n");
}
// It expects an exact 3 dashes `---`:
@@ -78,8 +76,7 @@ namespace Markdig.Tests.Specs.Yaml
// <h2>this: is a frontmatter</h2>
// <p>This is a text</p>
Console.WriteLine("Example 3\nSection Extensions / YAML frontmatter discard\n");
TestParser.TestSpec("----\nthis: is a frontmatter\n----\nThis is a text", "<hr />\n<h2>this: is a frontmatter</h2>\n<p>This is a text</p>", "yaml");
TestParser.TestSpec("----\nthis: is a frontmatter\n----\nThis is a text", "<hr />\n<h2>this: is a frontmatter</h2>\n<p>This is a text</p>", "yaml", context: "Example 3\nSection Extensions / YAML frontmatter discard\n");
}
// It can end with three dots `...`:
@@ -99,8 +96,7 @@ namespace Markdig.Tests.Specs.Yaml
// Should be rendered as:
// <p>This is a text</p>
Console.WriteLine("Example 4\nSection Extensions / YAML frontmatter discard\n");
TestParser.TestSpec("---\nthis: is a frontmatter\n\n...\nThis is a text", "<p>This is a text</p>", "yaml");
TestParser.TestSpec("---\nthis: is a frontmatter\n\n...\nThis is a text", "<p>This is a text</p>", "yaml", context: "Example 4\nSection Extensions / YAML frontmatter discard\n");
}
// If the end front matter marker (`...` or `---`) is not present, it will render the `---` has a `<hr>`:
@@ -120,8 +116,7 @@ namespace Markdig.Tests.Specs.Yaml
// <p>this: is a frontmatter
// This is a text</p>
Console.WriteLine("Example 5\nSection Extensions / YAML frontmatter discard\n");
TestParser.TestSpec("---\nthis: is a frontmatter\nThis is a text", "<hr />\n<p>this: is a frontmatter\nThis is a text</p>", "yaml");
TestParser.TestSpec("---\nthis: is a frontmatter\nThis is a text", "<hr />\n<p>this: is a frontmatter\nThis is a text</p>", "yaml", context: "Example 5\nSection Extensions / YAML frontmatter discard\n");
}
// It expects exactly three dots `...`:
@@ -143,8 +138,7 @@ namespace Markdig.Tests.Specs.Yaml
// ....
// This is a text</p>
Console.WriteLine("Example 6\nSection Extensions / YAML frontmatter discard\n");
TestParser.TestSpec("---\nthis: is a frontmatter\n....\nThis is a text", "<hr />\n<p>this: is a frontmatter\n....\nThis is a text</p>", "yaml");
TestParser.TestSpec("---\nthis: is a frontmatter\n....\nThis is a text", "<hr />\n<p>this: is a frontmatter\n....\nThis is a text</p>", "yaml", context: "Example 6\nSection Extensions / YAML frontmatter discard\n");
}
// Front matter ends with the first line containing three dots `...` or three dashes `---`:
@@ -166,8 +160,7 @@ namespace Markdig.Tests.Specs.Yaml
// Should be rendered as:
// <p>This is a text</p>
Console.WriteLine("Example 7\nSection Extensions / YAML frontmatter discard\n");
TestParser.TestSpec("---\nthis: is a frontmatter\n....\n\nHello\n---\nThis is a text", "<p>This is a text</p>", "yaml");
TestParser.TestSpec("---\nthis: is a frontmatter\n....\n\nHello\n---\nThis is a text", "<p>This is a text</p>", "yaml", context: "Example 7\nSection Extensions / YAML frontmatter discard\n");
}
// It expects whitespace can exist after the leading characters
@@ -186,8 +179,7 @@ namespace Markdig.Tests.Specs.Yaml
// Should be rendered as:
// <p>This is a text</p>
Console.WriteLine("Example 8\nSection Extensions / YAML frontmatter discard\n");
TestParser.TestSpec("--- \nthis: is a frontmatter\n...\nThis is a text", "<p>This is a text</p>", "yaml");
TestParser.TestSpec("--- \nthis: is a frontmatter\n...\nThis is a text", "<p>This is a text</p>", "yaml", context: "Example 8\nSection Extensions / YAML frontmatter discard\n");
}
// It expects whitespace can exist after the trailing characters
@@ -206,8 +198,7 @@ namespace Markdig.Tests.Specs.Yaml
// Should be rendered as:
// <p>This is a text</p>
Console.WriteLine("Example 9\nSection Extensions / YAML frontmatter discard\n");
TestParser.TestSpec("---\nthis: is a frontmatter\n... \nThis is a text", "<p>This is a text</p>", "yaml");
TestParser.TestSpec("---\nthis: is a frontmatter\n... \nThis is a text", "<p>This is a text</p>", "yaml", context: "Example 9\nSection Extensions / YAML frontmatter discard\n");
}
}
}

View File

@@ -0,0 +1,189 @@
using Markdig.Helpers;
using NUnit.Framework;
using System;
using System.Text;
using System.Threading.Tasks;
namespace Markdig.Tests
{
[TestFixture]
public class TestFastStringWriter
{
private const string NewLineReplacement = "~~NEW_LINE~~";
private FastStringWriter _writer = new();
[SetUp]
public void Setup()
{
_writer = new FastStringWriter
{
NewLine = NewLineReplacement
};
}
public void AssertToString(string value)
{
value = value.Replace("\n", NewLineReplacement);
Assert.AreEqual(value, _writer.ToString());
Assert.AreEqual(value, _writer.ToString());
}
[Test]
public async Task NewLine()
{
Assert.AreEqual("\n", new FastStringWriter().NewLine);
_writer.NewLine = "\r";
Assert.AreEqual("\r", _writer.NewLine);
_writer.NewLine = "foo";
Assert.AreEqual("foo", _writer.NewLine);
_writer.WriteLine();
await _writer.WriteLineAsync();
_writer.WriteLine("bar");
Assert.AreEqual("foofoobarfoo", _writer.ToString());
}
[Test]
public async Task FlushCloseDispose()
{
_writer.Write('a');
// Nops
_writer.Close();
_writer.Dispose();
await _writer.DisposeAsync();
_writer.Flush();
await _writer.FlushAsync();
_writer.Write('b');
AssertToString("ab");
}
[Test]
public async Task Write_Char()
{
_writer.Write('a');
AssertToString("a");
_writer.Write('b');
AssertToString("ab");
_writer.Write('\0');
_writer.Write('\r');
_writer.Write('\u1234');
AssertToString("ab\0\r\u1234");
_writer.Reset();
AssertToString("");
_writer.Write('a');
_writer.WriteLine('b');
_writer.Write('c');
_writer.Write('d');
_writer.WriteLine('e');
AssertToString("ab\ncde\n");
await _writer.WriteAsync('f');
await _writer.WriteLineAsync('g');
AssertToString("ab\ncde\nfg\n");
_writer.Reset();
for (int i = 0; i < 2050; i++)
{
_writer.Write('a');
AssertToString(new string('a', i + 1));
}
}
[Test]
public async Task Write_String()
{
_writer.Write("foo");
AssertToString("foo");
_writer.WriteLine("bar");
AssertToString("foobar\n");
await _writer.WriteAsync("baz");
await _writer.WriteLineAsync("foo");
AssertToString("foobar\nbazfoo\n");
_writer.Write(new string('a', 1050));
AssertToString("foobar\nbazfoo\n" + new string('a', 1050));
}
[Test]
public async Task Write_Span()
{
_writer.Write("foo".AsSpan());
AssertToString("foo");
_writer.WriteLine("bar".AsSpan());
AssertToString("foobar\n");
await _writer.WriteAsync("baz".AsMemory());
await _writer.WriteLineAsync("foo".AsMemory());
AssertToString("foobar\nbazfoo\n");
_writer.Write(new string('a', 1050).AsSpan());
AssertToString("foobar\nbazfoo\n" + new string('a', 1050));
}
[Test]
public async Task Write_CharArray()
{
_writer.Write("foo".ToCharArray());
AssertToString("foo");
_writer.WriteLine("bar".ToCharArray());
AssertToString("foobar\n");
await _writer.WriteAsync("baz".ToCharArray());
await _writer.WriteLineAsync("foo".ToCharArray());
AssertToString("foobar\nbazfoo\n");
_writer.Write(new string('a', 1050).ToCharArray());
AssertToString("foobar\nbazfoo\n" + new string('a', 1050));
}
[Test]
public async Task Write_CharArrayWithIndexes()
{
_writer.Write("foo".ToCharArray(), 1, 1);
AssertToString("o");
_writer.WriteLine("bar".ToCharArray(), 0, 2);
AssertToString("oba\n");
await _writer.WriteAsync("baz".ToCharArray(), 0, 1);
await _writer.WriteLineAsync("foo".ToCharArray(), 0, 3);
AssertToString("oba\nbfoo\n");
_writer.Write(new string('a', 1050).ToCharArray(), 10, 1035);
AssertToString("oba\nbfoo\n" + new string('a', 1035));
}
[Test]
public async Task Write_StringBuilder()
{
_writer.Write(new StringBuilder("foo"));
AssertToString("foo");
_writer.WriteLine(new StringBuilder("bar"));
AssertToString("foobar\n");
await _writer.WriteAsync(new StringBuilder("baz"));
await _writer.WriteLineAsync(new StringBuilder("foo"));
AssertToString("foobar\nbazfoo\n");
var sb = new StringBuilder("foo");
sb.Append('a', 1050);
_writer.Write(sb);
AssertToString("foobar\nbazfoo\nfoo" + new string('a', 1050));
}
}
}

View File

@@ -0,0 +1,46 @@
using System.Linq;
using Markdig.Syntax;
using NUnit.Framework;
namespace Markdig.Tests
{
public class TestFencedCodeBlocks
{
[Test]
[TestCase("c#", "c#", "")]
[TestCase("C#", "C#", "")]
[TestCase(" c#", "c#", "")]
[TestCase(" c# ", "c#", "")]
[TestCase(" \tc# ", "c#", "")]
[TestCase("\t c# \t", "c#", "")]
[TestCase(" c# ", "c#", "")]
[TestCase(" c# foo", "c#", "foo")]
[TestCase(" c# \t fOo \t", "c#", "fOo")]
[TestCase("in\\%fo arg\\%ument", "in%fo", "arg%ument")]
[TestCase("info&#9; arg&acute;ument", "info\t", "arg\u00B4ument")]
public void TestInfoAndArguments(string infoString, string expectedInfo, string expectedArguments)
{
Test('`');
Test('~');
void Test(char fencedChar)
{
const string Contents = "Foo\nBar\n";
string fence = new string(fencedChar, 3);
string markdownText = $"{fence}{infoString}\n{Contents}\n{fence}\n";
MarkdownDocument document = Markdown.Parse(markdownText);
FencedCodeBlock codeBlock = document.Descendants<FencedCodeBlock>().Single();
Assert.AreEqual(fencedChar, codeBlock.FencedChar);
Assert.AreEqual(3, codeBlock.OpeningFencedCharCount);
Assert.AreEqual(3, codeBlock.ClosingFencedCharCount);
Assert.AreEqual(expectedInfo, codeBlock.Info);
Assert.AreEqual(expectedArguments, codeBlock.Arguments);
Assert.AreEqual(Contents, codeBlock.Lines.ToString());
}
}
}
}

View File

@@ -458,18 +458,18 @@ This is a last line";
Assert.AreEqual(expected, actual);
}
public static void TestSpec(string inputText, string expectedOutputText, string extensions = null)
public static void TestSpec(string inputText, string expectedOutputText, string extensions = null, string context = null)
{
foreach (var pipeline in TestParser.GetPipeline(extensions))
{
AssertNormalize(inputText, expectedOutputText, trim: false, pipeline: pipeline.Value);
AssertNormalize(inputText, expectedOutputText, trim: false, pipeline: pipeline.Value, context: context);
}
}
public static void AssertNormalizeNoTrim(string input, string expected = null, NormalizeOptions options = null)
=> AssertNormalize(input, expected, false, options);
public static void AssertNormalize(string input, string expected = null, bool trim = true, NormalizeOptions options = null, MarkdownPipeline pipeline = null)
public static void AssertNormalize(string input, string expected = null, bool trim = true, NormalizeOptions options = null, MarkdownPipeline pipeline = null, string context = null)
{
expected = expected ?? input;
input = NormText(input, trim);
@@ -484,7 +484,7 @@ This is a last line";
var result = Markdown.Normalize(input, options, pipeline: pipeline);
result = NormText(result, trim);
TestParser.PrintAssertExpected(input, result, expected);
TestParser.PrintAssertExpected(input, result, expected, context);
}
private static string NormText(string text, bool trim)

View File

@@ -67,16 +67,20 @@ namespace Markdig.Tests
TestDescendantsOrder.TestSchemas(specsSyntaxTrees);
}
public static void TestSpec(string inputText, string expectedOutputText, string extensions = null, bool plainText = false)
public static void TestSpec(string inputText, string expectedOutputText, string extensions = null, bool plainText = false, string context = null)
{
context ??= string.Empty;
if (!string.IsNullOrEmpty(context))
{
context += "\n";
}
foreach (var pipeline in GetPipeline(extensions))
{
Console.WriteLine($"Pipeline configured with extensions: {pipeline.Key}");
TestSpec(inputText, expectedOutputText, pipeline.Value, plainText);
TestSpec(inputText, expectedOutputText, pipeline.Value, plainText, context: context + $"Pipeline configured with extensions: {pipeline.Key}");
}
}
public static void TestSpec(string inputText, string expectedOutputText, MarkdownPipeline pipeline, bool plainText = false)
public static void TestSpec(string inputText, string expectedOutputText, MarkdownPipeline pipeline, bool plainText = false, string context = null)
{
// Uncomment this line to get more debug information for process inlines.
//pipeline.DebugLog = Console.Out;
@@ -85,20 +89,27 @@ namespace Markdig.Tests
result = Compact(result);
expectedOutputText = Compact(expectedOutputText);
PrintAssertExpected(inputText, result, expectedOutputText);
PrintAssertExpected(inputText, result, expectedOutputText, context);
}
public static void PrintAssertExpected(string source, string result, string expected)
public static void PrintAssertExpected(string source, string result, string expected, string context = null)
{
Console.WriteLine("```````````````````Source");
Console.WriteLine(DisplaySpaceAndTabs(source));
Console.WriteLine("```````````````````Result");
Console.WriteLine(DisplaySpaceAndTabs(result));
Console.WriteLine("```````````````````Expected");
Console.WriteLine(DisplaySpaceAndTabs(expected));
Console.WriteLine("```````````````````");
Console.WriteLine();
TextAssert.AreEqual(expected, result);
if (expected != result)
{
if (context != null)
{
Console.WriteLine(context);
}
Console.WriteLine("```````````````````Source");
Console.WriteLine(DisplaySpaceAndTabs(source));
Console.WriteLine("```````````````````Result");
Console.WriteLine(DisplaySpaceAndTabs(result));
Console.WriteLine("```````````````````Expected");
Console.WriteLine(DisplaySpaceAndTabs(expected));
Console.WriteLine("```````````````````");
Console.WriteLine();
TextAssert.AreEqual(expected, result);
}
}
public static IEnumerable<KeyValuePair<string, MarkdownPipeline>> GetPipeline(string extensionsGroupText)
@@ -108,6 +119,8 @@ namespace Markdig.Tests
{
yield return new KeyValuePair<string, MarkdownPipeline>("default", new MarkdownPipelineBuilder().Build());
//yield return new KeyValuePair<string, MarkdownPipeline>("default-trivia", new MarkdownPipelineBuilder().EnableTrackTrivia().Build());
yield return new KeyValuePair<string, MarkdownPipeline>("advanced", new MarkdownPipelineBuilder() // Use similar to advanced extension without auto-identifier
.UseAbbreviations()
//.UseAutoIdentifiers()

View File

@@ -36,9 +36,9 @@ namespace Markdig.Tests
TestParser.TestSpec(markdownText, expected, extensions, plainText: true);
}
public static void TestSpec(string markdownText, string expected, string extensions)
public static void TestSpec(string markdownText, string expected, string extensions, string context = null)
{
TestParser.TestSpec(markdownText, expected, extensions, plainText: true);
TestParser.TestSpec(markdownText, expected, extensions, plainText: true, context: context);
}
}
}

View File

@@ -12,14 +12,26 @@ namespace Markdig.Tests
[TestFixture]
public class TestPlayParser
{
[Test]
public void TestBugWithEmphasisAndTable()
{
TestParser.TestSpec("**basics | 8:00**", "<p><strong>basics | 8:00</strong></p>", "advanced");
}
[Test]
public void TestLinksWithCarriageReturn()
{
{
var text = "[Link 1][link-1], [link 2][link-2].\r\n\r\n[link-1]: https://example.com\r\n[link-2]: https://example.com";
var result = Markdown.ToHtml(text).TrimEnd();
Assert.AreEqual("<p><a href=\"https://example.com\">Link 1</a>, <a href=\"https://example.com\">link 2</a>.</p>", result);
}
var text = "[Link 1][link-1], [link 2][link-2].\r\n\r\n[link-1]: https://example.com\r\n[link-2]: https://example.com";
var result = Markdown.ToHtml(text).TrimEnd();
Assert.AreEqual("<p><a href=\"https://example.com\">Link 1</a>, <a href=\"https://example.com\">link 2</a>.</p>", result);
}
[Test]
public void TestLinksWithTitleAndCarriageReturn()
{
var text = "[Link 1][link-1], [link 2][link-2].\r\n\r\n[link-1]: https://example.com \"title 1\" \r\n[link-2]: https://example.com \"title 2\"";
var result = Markdown.ToHtml(text).TrimEnd();
Assert.AreEqual("<p><a href=\"https://example.com\" title=\"title 1\">Link 1</a>, <a href=\"https://example.com\" title=\"title 2\">link 2</a>.</p>", result);
}
[Test]
@@ -49,7 +61,6 @@ namespace Markdig.Tests
Later in a text we are using HTML and it becomes an abbr tag HTML
";
// var reader = new StringReader(@"> > toto tata
//> titi toto
//");
@@ -57,7 +68,7 @@ Later in a text we are using HTML and it becomes an abbr tag HTML
//var result = Markdown.ToHtml(text, new MarkdownPipeline().UseFootnotes().UseEmphasisExtras());
var result = Markdown.ToHtml(text, new MarkdownPipelineBuilder().UseAbbreviations().Build());
//File.WriteAllText("test.html", result, Encoding.UTF8);
Console.WriteLine(result);
//Console.WriteLine(result);
}
[Test]

View File

@@ -7,12 +7,12 @@ namespace Markdig.Tests
{
internal static class TestRoundtrip
{
internal static void TestSpec(string markdownText, string expected, string extensions)
internal static void TestSpec(string markdownText, string expected, string extensions, string context = null)
{
RoundTrip(markdownText);
RoundTrip(markdownText, context);
}
internal static void RoundTrip(string markdown)
internal static void RoundTrip(string markdown, string context = null)
{
var pipelineBuilder = new MarkdownPipelineBuilder();
pipelineBuilder.EnableTrackTrivia();
@@ -24,7 +24,7 @@ namespace Markdig.Tests
nr.Write(markdownDocument);
var result = sw.ToString();
Assert.AreEqual(markdown, result);
TestParser.PrintAssertExpected("", result, markdown, context);
}
}
}

View File

@@ -0,0 +1,102 @@
using System;
using System.Linq;
using Markdig.Helpers;
using NUnit.Framework;
namespace Markdig.Tests
{
public class TestTransformedStringCache
{
[Test]
public void GetRunsTransformationCallback()
{
var cache = new TransformedStringCache(static s => "callback-" + s);
Assert.AreEqual("callback-foo", cache.Get("foo"));
Assert.AreEqual("callback-bar", cache.Get("bar"));
Assert.AreEqual("callback-baz", cache.Get("baz"));
}
[Test]
public void CachesTransformedInstance()
{
var cache = new TransformedStringCache(static s => "callback-" + s);
string transformedBar = cache.Get("bar");
Assert.AreSame(transformedBar, cache.Get("bar"));
string transformedFoo = cache.Get("foo".AsSpan());
Assert.AreSame(transformedFoo, cache.Get("foo"));
Assert.AreSame(cache.Get("baz"), cache.Get("baz".AsSpan()));
Assert.AreSame(transformedBar, cache.Get("bar"));
Assert.AreSame(transformedFoo, cache.Get("foo"));
Assert.AreSame(transformedBar, cache.Get("bar".AsSpan()));
Assert.AreSame(transformedFoo, cache.Get("foo".AsSpan()));
}
[Test]
public void DoesNotCacheEmptyInputs()
{
var cache = new TransformedStringCache(static s => new string('a', 4));
string cached = cache.Get("");
string cached2 = cache.Get("");
string cached3 = cache.Get(ReadOnlySpan<char>.Empty);
Assert.AreEqual("aaaa", cached);
Assert.AreEqual(cached, cached2);
Assert.AreEqual(cached, cached3);
Assert.AreNotSame(cached, cached2);
Assert.AreNotSame(cached, cached3);
Assert.AreNotSame(cached2, cached3);
}
[Test]
[TestCase(TransformedStringCache.InputLengthLimit, true)]
[TestCase(TransformedStringCache.InputLengthLimit + 1, false)]
public void DoesNotCacheLongInputs(int length, bool shouldBeCached)
{
var cache = new TransformedStringCache(static s => "callback-" + s);
string input = new string('a', length);
string cached = cache.Get(input);
string cached2 = cache.Get(input);
Assert.AreEqual("callback-" + input, cached);
Assert.AreEqual(cached, cached2);
if (shouldBeCached)
{
Assert.AreSame(cached, cached2);
}
else
{
Assert.AreNotSame(cached, cached2);
}
}
[Test]
public void CachesAtMostNEntriesPerCharacter()
{
var cache = new TransformedStringCache(static s => "callback-" + s);
int limit = TransformedStringCache.MaxEntriesPerCharacter;
string[] a = Enumerable.Range(1, limit + 1).Select(i => $"a{i}").ToArray();
string[] cachedAs = a.Select(a => cache.Get(a)).ToArray();
for (int i = 0; i < limit; i++)
{
Assert.AreSame(cachedAs[i], cache.Get(a[i]));
}
Assert.AreNotSame(cachedAs[limit], cache.Get(a[limit]));
Assert.AreSame(cache.Get("b1"), cache.Get("b1"));
}
}
}

View File

@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<PreserveCompilationContext>true</PreserveCompilationContext>
<AssemblyName>Markdig.WebApp</AssemblyName>
<OutputType>Exe</OutputType>
@@ -13,7 +13,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.16.0" />
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.20.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -2,13 +2,14 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Markdig.WebApp
{
public class Startup
{
public Startup(IHostingEnvironment env)
public Startup(IWebHostEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
@@ -37,7 +38,7 @@ namespace Markdig.WebApp
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{

View File

@@ -172,17 +172,22 @@ namespace Markdig.Extensions.AutoIdentifiers
var baseHeadingId = string.IsNullOrEmpty(headingText) ? "section" : headingText;
// Add a trailing -1, -2, -3...etc. in case of collision
int index = 0;
var headingId = baseHeadingId;
var headingBuffer = StringBuilderCache.Local();
while (!identifiers.Add(headingId))
if (!identifiers.Add(headingId))
{
index++;
var headingBuffer = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
headingBuffer.Append(baseHeadingId);
headingBuffer.Append('-');
headingBuffer.Append(index);
headingId = headingBuffer.ToString();
headingBuffer.Length = 0;
uint index = 0;
do
{
index++;
headingBuffer.Append(index);
headingId = headingBuffer.AsSpan().ToString();
headingBuffer.Length = baseHeadingId.Length + 1;
}
while (!identifiers.Add(headingId));
headingBuffer.Dispose();
}
attributes.Id = headingId;

View File

@@ -3,8 +3,6 @@
// See the license.txt file in the project root for more information.
using Markdig.Renderers;
using Markdig.Renderers.Normalize;
using Markdig.Renderers.Normalize.Inlines;
using Markdig.Syntax.Inlines;
namespace Markdig.Extensions.AutoLinks
@@ -33,10 +31,6 @@ namespace Markdig.Extensions.AutoLinks
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
{
if (renderer is NormalizeRenderer normalizeRenderer && !normalizeRenderer.ObjectRenderers.Contains<NormalizeAutoLinkRenderer>())
{
normalizeRenderer.ObjectRenderers.InsertBefore<LinkInlineRenderer>(new NormalizeAutoLinkRenderer());
}
}
}
}

View File

@@ -201,7 +201,7 @@ namespace Markdig.Extensions.AutoLinks
if (Options.OpenInNewWindow)
{
inline.GetAttributes().AddPropertyIfNotExist("target", "blank");
inline.GetAttributes().AddPropertyIfNotExist("target", "_blank");
}
return true;

View File

@@ -1,33 +0,0 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using Markdig.Renderers;
using Markdig.Renderers.Normalize;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
namespace Markdig.Extensions.AutoLinks
{
public class NormalizeAutoLinkRenderer : NormalizeObjectRenderer<LinkInline>
{
public override bool Accept(RendererBase renderer, MarkdownObject obj)
{
if (base.Accept(renderer, obj))
{
return renderer is NormalizeRenderer normalizeRenderer
&& obj is LinkInline link
&& !normalizeRenderer.Options.ExpandAutoLinks
&& link.IsAutoLink;
}
else
{
return false;
}
}
protected override void Write(NormalizeRenderer renderer, LinkInline obj)
{
renderer.Write(obj.Url);
}
}
}

View File

@@ -33,12 +33,12 @@ namespace Markdig.Extensions.EmphasisExtras
Superscript = 4,
/// <summary>
/// A text that can be rendered as a inserted using the character ++
/// A text that can be rendered as inserted using the double character ++
/// </summary>
Inserted = 8,
/// <summary>
/// A text that can be rendered as a inserted using the character ==
/// A text that can be rendered as marked using the double character ==
/// </summary>
Marked = 16,
}

View File

@@ -95,18 +95,24 @@ namespace Markdig.Extensions.JiraLinks
jiraLink.Span.End = jiraLink.Span.Start + (endIssue - startKey);
// Builds the Url
var builder = StringBuilderCache.Local();
builder.Append(_baseUrl).Append('/').Append(jiraLink.ProjectKey).Append('-').Append(jiraLink.Issue);
jiraLink.Url = builder.ToString();
var builder = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
builder.Append(_baseUrl);
builder.Append('/');
builder.Append(jiraLink.ProjectKey.AsSpan());
builder.Append('-');
builder.Append(jiraLink.Issue.AsSpan());
jiraLink.Url = builder.AsSpan().ToString();
// Builds the Label
builder.Length = 0;
builder.Append(jiraLink.ProjectKey).Append('-').Append(jiraLink.Issue);
builder.Append(jiraLink.ProjectKey.AsSpan());
builder.Append('-');
builder.Append(jiraLink.Issue.AsSpan());
jiraLink.AppendChild(new LiteralInline(builder.ToString()));
if (_options.OpenInNewWindow)
{
jiraLink.GetAttributes().AddProperty("target", "blank");
jiraLink.GetAttributes().AddProperty("target", "_blank");
}
processor.Inline = jiraLink;

View File

@@ -2,7 +2,8 @@
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System.Text;
using Markdig.Helpers;
using System;
namespace Markdig.Extensions.JiraLinks
{
@@ -38,20 +39,10 @@ namespace Markdig.Extensions.JiraLinks
/// </summary>
public virtual string GetUrl()
{
var url = new StringBuilder();
var baseUrl = BaseUrl;
if (baseUrl != null)
{
url.Append(baseUrl.TrimEnd('/'));
}
url.Append("/");
if (BasePath != null)
{
url.Append(BasePath.Trim('/'));
}
var url = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
url.Append(BaseUrl.AsSpan().TrimEnd('/'));
url.Append('/');
url.Append(BasePath.AsSpan().Trim('/'));
return url.ToString();
}
}

View File

@@ -43,7 +43,7 @@ namespace Markdig.Extensions.Tables
public override bool Match(InlineProcessor processor, ref StringSlice slice)
{
// Only working on Paragraph block
if (!(processor.Block is ParagraphBlock))
if (!processor.Block!.IsParagraphBlock)
{
return false;
}

View File

@@ -107,7 +107,7 @@ namespace Markdig.Helpers
{
if (nonAsciiMap is null)
{
#if NETCOREAPP3_1
#if NETCOREAPP3_1_OR_GREATER
ref char textRef = ref Unsafe.AsRef(in text.GetPinnableReference());
for (; start <= end; start++)
{
@@ -154,12 +154,12 @@ namespace Markdig.Helpers
private int IndexOfOpeningCharacterNonAscii(string text, int start, int end)
{
#if NETCOREAPP3_1
#if NETCOREAPP3_1_OR_GREATER
ref char textRef = ref Unsafe.AsRef(in text.GetPinnableReference());
for (int i = start; i <= end; i++)
{
char c = Unsafe.Add(ref textRef, i);
if (c < 128 ? isOpeningCharacter[c] : nonAsciiMap.ContainsKey(c))
if (c < 128 ? isOpeningCharacter[c] : nonAsciiMap!.ContainsKey(c))
{
return i;
}

View File

@@ -19,8 +19,6 @@ using System.Runtime.CompilerServices;
* Please note the lack of a Remove method on this data structure
*/
// Relies on NETCORE being set for selective use of Spans
//namespace SharpCollections.Generic
namespace Markdig.Helpers
{

View File

@@ -33,7 +33,6 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Markdig.Helpers
{
@@ -69,7 +68,7 @@ namespace Markdig.Helpers
utf32 -= 65536;
return new string(
#if NETCORE
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP3_1_OR_GREATER
stackalloc
#else
new
@@ -81,7 +80,7 @@ namespace Markdig.Helpers
});
}
public static void DecodeEntity(int utf32, StringBuilder sb)
internal static void DecodeEntity(int utf32, ref ValueStringBuilder sb)
{
if (!CharHelper.IsInInclusiveRange(utf32, 1, 1114111) || CharHelper.IsInInclusiveRange(utf32, 55296, 57343))
{
@@ -99,7 +98,7 @@ namespace Markdig.Helpers
}
}
#region [ EntityMap ]
#region [ EntityMap ]
/// <summary>
/// Source: http://www.w3.org/html/wg/drafts/html/master/syntax.html#named-character-references
/// </summary>

View File

@@ -0,0 +1,293 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Markdig.Helpers
{
internal sealed class FastStringWriter : TextWriter
{
#if NET452
private static Task CompletedTask => Task.FromResult(0);
#else
private static Task CompletedTask => Task.CompletedTask;
#endif
public override Encoding Encoding => Encoding.Unicode;
private char[] _chars;
private int _pos;
private string _newLine;
public FastStringWriter()
{
_chars = new char[1024];
_newLine = "\n";
}
[AllowNull]
public override string NewLine
{
get => _newLine;
set => _newLine = value ?? Environment.NewLine;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Write(char value)
{
char[] chars = _chars;
int pos = _pos;
if ((uint)pos < (uint)chars.Length)
{
chars[pos] = value;
_pos = pos + 1;
}
else
{
GrowAndAppend(value);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void WriteLine(char value)
{
Write(value);
WriteLine();
}
public override Task WriteAsync(char value)
{
Write(value);
return CompletedTask;
}
public override Task WriteLineAsync(char value)
{
WriteLine(value);
return CompletedTask;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Write(string? value)
{
if (value is not null)
{
if (_pos > _chars.Length - value.Length)
{
Grow(value.Length);
}
value.AsSpan().CopyTo(_chars.AsSpan(_pos));
_pos += value.Length;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void WriteLine(string? value)
{
Write(value);
WriteLine();
}
public override Task WriteAsync(string? value)
{
Write(value);
return CompletedTask;
}
public override Task WriteLineAsync(string? value)
{
WriteLine(value);
return CompletedTask;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Write(char[]? buffer)
{
if (buffer is not null)
{
if (_pos > _chars.Length - buffer.Length)
{
Grow(buffer.Length);
}
buffer.CopyTo(_chars.AsSpan(_pos));
_pos += buffer.Length;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void WriteLine(char[]? buffer)
{
Write(buffer);
WriteLine();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Write(char[] buffer, int index, int count)
{
if (buffer is not null)
{
if (_pos > _chars.Length - count)
{
Grow(buffer.Length);
}
buffer.AsSpan(index, count).CopyTo(_chars.AsSpan(_pos));
_pos += count;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void WriteLine(char[] buffer, int index, int count)
{
Write(buffer, index, count);
WriteLine();
}
public override Task WriteAsync(char[] buffer, int index, int count)
{
Write(buffer, index, count);
return CompletedTask;
}
public override Task WriteLineAsync(char[] buffer, int index, int count)
{
WriteLine(buffer, index, count);
return CompletedTask;
}
#if !(NET452 || NETSTANDARD2_0)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Write(ReadOnlySpan<char> value)
{
if (_pos > _chars.Length - value.Length)
{
Grow(value.Length);
}
value.CopyTo(_chars.AsSpan(_pos));
_pos += value.Length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void WriteLine(ReadOnlySpan<char> buffer)
{
Write(buffer);
WriteLine();
}
public override Task WriteAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken = default)
{
Write(buffer.Span);
return CompletedTask;
}
public override Task WriteLineAsync(ReadOnlyMemory<char> buffer, CancellationToken cancellationToken = default)
{
WriteLine(buffer.Span);
return CompletedTask;
}
#endif
#if !(NET452 || NETSTANDARD2_0 || NETSTANDARD2_1)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Write(StringBuilder? value)
{
if (value is not null)
{
int length = value.Length;
if (_pos > _chars.Length - length)
{
Grow(length);
}
value.CopyTo(0, _chars.AsSpan(_pos), length);
_pos += length;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void WriteLine(StringBuilder? value)
{
Write(value);
WriteLine();
}
public override Task WriteAsync(StringBuilder? value, CancellationToken cancellationToken = default)
{
Write(value);
return CompletedTask;
}
public override Task WriteLineAsync(StringBuilder? value, CancellationToken cancellationToken = default)
{
WriteLine(value);
return CompletedTask;
}
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void WriteLine()
{
foreach (char c in _newLine)
{
Write(c);
}
}
public override Task WriteLineAsync()
{
WriteLine();
return CompletedTask;
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void GrowAndAppend(char value)
{
Grow(1);
Write(value);
}
private void Grow(int additionalCapacityBeyondPos)
{
Debug.Assert(additionalCapacityBeyondPos > 0);
Debug.Assert(_pos > _chars.Length - additionalCapacityBeyondPos, "No resize is needed.");
char[] newArray = new char[(int)Math.Max((uint)(_pos + additionalCapacityBeyondPos), (uint)_chars.Length * 2)];
_chars.AsSpan(0, _pos).CopyTo(newArray);
_chars = newArray;
}
public override void Flush() { }
public override void Close() { }
public override Task FlushAsync() => CompletedTask;
#if !(NET452 || NETSTANDARD2_0)
public override ValueTask DisposeAsync() => default;
#endif
public void Reset()
{
_pos = 0;
}
public override string ToString()
{
return _chars.AsSpan(0, _pos).ToString();
}
}
}

View File

@@ -4,7 +4,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Text;
namespace Markdig.Helpers
{
@@ -39,22 +38,22 @@ namespace Markdig.Helpers
public static bool TryParseHtmlTag(ref StringSlice text, [NotNullWhen(true)] out string? htmlTag)
{
var builder = StringBuilderCache.Local();
if (TryParseHtmlTag(ref text, builder))
var builder = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
if (TryParseHtmlTag(ref text, ref builder))
{
htmlTag = builder.GetStringAndReset();
htmlTag = builder.ToString();
return true;
}
else
{
builder.Dispose();
htmlTag = null;
return false;
}
}
public static bool TryParseHtmlTag(ref StringSlice text, StringBuilder builder)
private static bool TryParseHtmlTag(ref StringSlice text, ref ValueStringBuilder builder)
{
if (builder is null) ThrowHelper.ArgumentNullException(nameof(builder));
var c = text.CurrentChar;
if (c != '<')
{
@@ -67,29 +66,29 @@ namespace Markdig.Helpers
switch (c)
{
case '/':
return TryParseHtmlCloseTag(ref text, builder);
return TryParseHtmlCloseTag(ref text, ref builder);
case '?':
return TryParseHtmlTagProcessingInstruction(ref text, builder);
return TryParseHtmlTagProcessingInstruction(ref text, ref builder);
case '!':
builder.Append(c);
c = text.NextChar();
if (c == '-')
{
return TryParseHtmlTagHtmlComment(ref text, builder);
return TryParseHtmlTagHtmlComment(ref text, ref builder);
}
if (c == '[')
{
return TryParseHtmlTagCData(ref text, builder);
return TryParseHtmlTagCData(ref text, ref builder);
}
return TryParseHtmlTagDeclaration(ref text, builder);
return TryParseHtmlTagDeclaration(ref text, ref builder);
}
return TryParseHtmlTagOpenTag(ref text, builder);
return TryParseHtmlTagOpenTag(ref text, ref builder);
}
internal static bool TryParseHtmlTagOpenTag(ref StringSlice text, StringBuilder builder)
internal static bool TryParseHtmlTagOpenTag(ref StringSlice text, ref ValueStringBuilder builder)
{
var c = text.CurrentChar;
@@ -244,7 +243,7 @@ namespace Markdig.Helpers
}
}
private static bool TryParseHtmlTagDeclaration(ref StringSlice text, StringBuilder builder)
private static bool TryParseHtmlTagDeclaration(ref StringSlice text, ref ValueStringBuilder builder)
{
var c = text.CurrentChar;
bool hasAlpha = false;
@@ -279,7 +278,7 @@ namespace Markdig.Helpers
}
}
private static bool TryParseHtmlTagCData(ref StringSlice text, StringBuilder builder)
private static bool TryParseHtmlTagCData(ref StringSlice text, ref ValueStringBuilder builder)
{
if (text.Match("[CDATA["))
{
@@ -310,7 +309,7 @@ namespace Markdig.Helpers
return false;
}
internal static bool TryParseHtmlCloseTag(ref StringSlice text, StringBuilder builder)
internal static bool TryParseHtmlCloseTag(ref StringSlice text, ref ValueStringBuilder builder)
{
// </[A-Za-z][A-Za-z0-9]+\s*>
builder.Append('/');
@@ -355,7 +354,7 @@ namespace Markdig.Helpers
}
private static bool TryParseHtmlTagHtmlComment(ref StringSlice text, StringBuilder builder)
private static bool TryParseHtmlTagHtmlComment(ref StringSlice text, ref ValueStringBuilder builder)
{
var c = text.NextChar();
if (c != '-')
@@ -393,7 +392,7 @@ namespace Markdig.Helpers
}
}
private static bool TryParseHtmlTagProcessingInstruction(ref StringSlice text, StringBuilder builder)
private static bool TryParseHtmlTagProcessingInstruction(ref StringSlice text, ref ValueStringBuilder builder)
{
builder.Append('?');
var prevChar = '\0';
@@ -435,13 +434,12 @@ namespace Markdig.Helpers
// remove backslashes before punctuation chars:
int searchPos = 0;
int lastPos = 0;
char c;
char c = '\0';
char[] search = removeBackSlash ? SearchBackAndAmp : SearchAmp;
StringBuilder? sb = null;
var sb = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
while ((searchPos = text!.IndexOfAny(search, searchPos)) != -1)
{
sb ??= StringBuilderCache.Local();
c = text[searchPos];
if (removeBackSlash && c == '\\')
{
@@ -453,7 +451,7 @@ namespace Markdig.Helpers
c = text[searchPos];
if (c.IsEscapableSymbol())
{
sb.Append(text, lastPos, searchPos - lastPos - 1);
sb.Append(text.AsSpan(lastPos, searchPos - lastPos - 1));
lastPos = searchPos;
}
}
@@ -473,26 +471,29 @@ namespace Markdig.Helpers
var decoded = EntityHelper.DecodeEntity(text.AsSpan(entityNameStart, entityNameLength));
if (decoded != null)
{
sb.Append(text, lastPos, searchPos - match - lastPos);
sb.Append(text.AsSpan(lastPos, searchPos - match - lastPos));
sb.Append(decoded);
lastPos = searchPos;
}
}
else if (numericEntity >= 0)
{
sb.Append(text, lastPos, searchPos - match - lastPos);
EntityHelper.DecodeEntity(numericEntity, sb);
sb.Append(text.AsSpan(lastPos, searchPos - match - lastPos));
EntityHelper.DecodeEntity(numericEntity, ref sb);
lastPos = searchPos;
}
}
}
}
if (sb is null || lastPos == 0)
if (c == 0)
{
sb.Dispose();
return text;
}
sb.Append(text, lastPos, text.Length - lastPos);
return sb.GetStringAndReset();
sb.Append(text.AsSpan(lastPos, text.Length - lastPos));
return sb.ToString();
}
/// <summary>

View File

@@ -4,6 +4,8 @@
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Markdig.Helpers
{
@@ -39,41 +41,55 @@ namespace Markdig.Helpers
/// <returns>A new line or null if the end of <see cref="TextReader"/> has been reached</returns>
public StringSlice ReadLine()
{
string text = _text;
string? text = _text;
int end = text.Length;
int sourcePosition = SourcePosition;
int newSourcePosition = int.MaxValue;
NewLine newLine = NewLine.None;
for (int i = sourcePosition; i < text.Length; i++)
if ((uint)sourcePosition >= (uint)end)
{
char c = text[i];
if (c == '\r')
text = null;
}
else
{
#if NETCOREAPP3_1_OR_GREATER
ReadOnlySpan<char> span = MemoryMarshal.CreateReadOnlySpan(ref Unsafe.Add(ref Unsafe.AsRef(text.GetPinnableReference()), sourcePosition), end - sourcePosition);
#else
ReadOnlySpan<char> span = text.AsSpan(sourcePosition);
#endif
int crlf = span.IndexOfAny('\r', '\n');
if (crlf >= 0)
{
int length = 1;
var newLine = NewLine.CarriageReturn;
if (c == '\r' && (uint)(i + 1) < (uint)text.Length && text[i + 1] == '\n')
end = sourcePosition + crlf;
newSourcePosition = end + 1;
#if NETCOREAPP3_1_OR_GREATER
if (Unsafe.Add(ref Unsafe.AsRef(text.GetPinnableReference()), end) == '\r')
#else
if ((uint)end < (uint)text.Length && text[end] == '\r')
#endif
{
i++;
length = 2;
newLine = NewLine.CarriageReturnLineFeed;
if ((uint)(newSourcePosition) < (uint)text.Length && text[newSourcePosition] == '\n')
{
newLine = NewLine.CarriageReturnLineFeed;
newSourcePosition++;
}
else
{
newLine = NewLine.CarriageReturn;
}
}
else
{
newLine = NewLine.LineFeed;
}
var slice = new StringSlice(text, sourcePosition, i - length, newLine);
SourcePosition = i + 1;
return slice;
}
if (c == '\n')
{
var slice = new StringSlice(text, sourcePosition, i - 1, NewLine.LineFeed);
SourcePosition = i + 1;
return slice;
}
}
if (sourcePosition >= text.Length)
return default;
SourcePosition = int.MaxValue;
return new StringSlice(text, sourcePosition, text.Length - 1);
SourcePosition = newSourcePosition;
return new StringSlice(text, sourcePosition, end - 1, newLine, dummy: false);
}
}
}

View File

@@ -4,7 +4,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Text;
using Markdig.Syntax;
namespace Markdig.Helpers
@@ -21,7 +20,7 @@ namespace Markdig.Helpers
public static string Urilize(string headingText, bool allowOnlyAscii, bool keepOpeningDigits = false)
{
var headingBuffer = StringBuilderCache.Local();
var headingBuffer = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
bool hasLetter = keepOpeningDigits && headingText.Length > 0 && char.IsLetterOrDigit(headingText[0]);
bool previousIsSpace = false;
for (int i = 0; i < headingText.Length; i++)
@@ -92,15 +91,13 @@ namespace Markdig.Helpers
}
}
var text = headingBuffer.ToString();
headingBuffer.Length = 0;
return text;
return headingBuffer.ToString();
}
public static string UrilizeAsGfm(string headingText)
{
// Following https://github.com/jch/html-pipeline/blob/master/lib/html/pipeline/toc_filter.rb
var headingBuffer = StringBuilderCache.Local();
var headingBuffer = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
for (int i = 0; i < headingText.Length; i++)
{
var c = headingText[i];
@@ -109,7 +106,7 @@ namespace Markdig.Helpers
headingBuffer.Append(c == ' ' ? '-' : char.ToLowerInvariant(c));
}
}
return headingBuffer.GetStringAndReset();
return headingBuffer.ToString();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -165,7 +162,7 @@ namespace Markdig.Helpers
}
}
var builder = StringBuilderCache.Local();
var builder = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
// ****************************
// 1. Scan scheme or user email
@@ -193,8 +190,7 @@ namespace Markdig.Helpers
// a scheme is any sequence of 232 characters
if (state > 0 && builder.Length >= 32)
{
builder.Length = 0;
return false;
goto ReturnFalse;
}
builder.Append(c);
}
@@ -202,8 +198,7 @@ namespace Markdig.Helpers
{
if (state < 0 || builder.Length <= 2)
{
builder.Length = 0;
return false;
goto ReturnFalse;
}
state = 1;
break;
@@ -211,16 +206,14 @@ namespace Markdig.Helpers
{
if (state > 0)
{
builder.Length = 0;
return false;
goto ReturnFalse;
}
state = -1;
break;
}
else
{
builder.Length = 0;
return false;
goto ReturnFalse;
}
}
@@ -249,7 +242,6 @@ namespace Markdig.Helpers
text.SkipChar();
link = builder.ToString();
builder.Length = 0;
return true;
}
@@ -297,7 +289,6 @@ namespace Markdig.Helpers
{
text.SkipChar();
link = builder.ToString();
builder.Length = 0;
return true;
}
@@ -318,7 +309,8 @@ namespace Markdig.Helpers
}
}
builder.Length = 0;
ReturnFalse:
builder.Dispose();
return false;
}
@@ -528,8 +520,7 @@ namespace Markdig.Helpers
public static bool TryParseTitle<T>(ref T text, out string? title, out char enclosingCharacter) where T : ICharIterator
{
bool isValid = false;
var buffer = StringBuilderCache.Local();
var buffer = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
enclosingCharacter = '\0';
// a sequence of zero or more characters between straight double-quote characters ("), including a " character only if it is backslash-escaped, or
@@ -582,8 +573,7 @@ namespace Markdig.Helpers
// Skip last quote
text.SkipChar();
isValid = true;
break;
goto ReturnValid;
}
if (hasEscape && !c.IsAsciiPunctuation())
@@ -606,7 +596,7 @@ namespace Markdig.Helpers
hasOnlyWhiteSpacesSinceLastLine = 1;
}
}
else if (c != '\n' && c != '\r' && (c != '\r' && text.PeekChar() != '\n'))
else if (c != '\n' && c != '\r' && text.PeekChar() != '\n')
{
hasOnlyWhiteSpacesSinceLastLine = 0;
}
@@ -615,15 +605,18 @@ namespace Markdig.Helpers
}
}
title = isValid ? buffer.ToString() : null;
buffer.Length = 0;
return isValid;
buffer.Dispose();
title = null;
return false;
ReturnValid:
title = buffer.ToString();
return true;
}
public static bool TryParseTitleTrivia<T>(ref T text, out string? title, out char enclosingCharacter) where T : ICharIterator
{
bool isValid = false;
var buffer = StringBuilderCache.Local();
var buffer = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
enclosingCharacter = '\0';
// a sequence of zero or more characters between straight double-quote characters ("), including a " character only if it is backslash-escaped, or
@@ -676,8 +669,7 @@ namespace Markdig.Helpers
// Skip last quote
text.SkipChar();
isValid = true;
break;
goto ReturnValid;
}
if (hasEscape && !c.IsAsciiPunctuation())
@@ -700,7 +692,7 @@ namespace Markdig.Helpers
hasOnlyWhiteSpacesSinceLastLine = 1;
}
}
else if (c != '\n' && c != '\r' && (c != '\r' && text.PeekChar() != '\n'))
else if (c != '\n' && c != '\r' && text.PeekChar() != '\n')
{
hasOnlyWhiteSpacesSinceLastLine = 0;
}
@@ -709,9 +701,13 @@ namespace Markdig.Helpers
}
}
title = isValid ? buffer.ToString() : null;
buffer.Length = 0;
return isValid;
buffer.Dispose();
title = null;
return false;
ReturnValid:
title = buffer.ToString();
return true;
}
public static bool TryParseUrl<T>(T text, [NotNullWhen(true)] out string? link) where T : ICharIterator
@@ -723,7 +719,7 @@ namespace Markdig.Helpers
{
bool isValid = false;
hasPointyBrackets = false;
var buffer = StringBuilderCache.Local();
var buffer = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
var c = text.CurrentChar;
@@ -854,8 +850,15 @@ namespace Markdig.Helpers
}
}
link = isValid ? buffer.ToString() : null;
buffer.Length = 0;
if (isValid)
{
link = buffer.ToString();
}
else
{
buffer.Dispose();
link = null;
}
return isValid;
}
@@ -863,8 +866,7 @@ namespace Markdig.Helpers
{
bool isValid = false;
hasPointyBrackets = false;
var buffer = StringBuilderCache.Local();
var unescaped = new StringBuilder();
var buffer = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
var c = text.CurrentChar;
@@ -892,13 +894,11 @@ namespace Markdig.Helpers
if (hasEscape && !c.IsAsciiPunctuation())
{
buffer.Append('\\');
unescaped.Append('\\');
}
if (c == '\\')
{
hasEscape = true;
unescaped.Append('\\');
continue;
}
@@ -910,7 +910,6 @@ namespace Markdig.Helpers
hasEscape = false;
buffer.Append(c);
unescaped.Append(c);
} while (c != '\0');
}
@@ -958,7 +957,6 @@ namespace Markdig.Helpers
{
hasEscape = true;
c = text.NextChar();
unescaped.Append('\\');
continue;
}
@@ -989,7 +987,6 @@ namespace Markdig.Helpers
}
buffer.Append(c);
unescaped.Append(c);
c = text.NextChar();
}
@@ -1000,8 +997,15 @@ namespace Markdig.Helpers
}
}
link = isValid ? buffer.ToString() : null;
buffer.Length = 0;
if (isValid)
{
link = buffer.ToString();
}
else
{
buffer.Dispose();
link = null;
}
return isValid;
}
@@ -1141,7 +1145,7 @@ namespace Markdig.Helpers
c = text.NextChar();
}
if (c != '\0' && c != '\n')
if (c != '\0' && c != '\n' && c != '\r' && text.PeekChar() != '\n')
{
// If we were able to parse the url but the title doesn't end with space,
// we are still returning a valid definition
@@ -1158,6 +1162,11 @@ namespace Markdig.Helpers
return false;
}
if (c == '\r' && text.PeekChar() == '\n')
{
text.SkipChar();
}
return true;
}
@@ -1276,7 +1285,7 @@ namespace Markdig.Helpers
c = text.NextChar();
}
if (c != '\0' && c != '\n' && c != '\r' && (c != '\r' && text.PeekChar() != '\n'))
if (c != '\0' && c != '\n' && c != '\r' && text.PeekChar() != '\n')
{
// If we were able to parse the url but the title doesn't end with space,
// we are still returning a valid definition
@@ -1307,6 +1316,7 @@ namespace Markdig.Helpers
else if (c == '\r' && text.PeekChar() == '\n')
{
newLine = NewLine.CarriageReturnLineFeed;
text.SkipChar();
}
else if (c == '\r')
{
@@ -1351,7 +1361,7 @@ namespace Markdig.Helpers
{
return false;
}
var buffer = StringBuilderCache.Local();
var buffer = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
var startLabel = -1;
var endLabel = -1;
@@ -1359,7 +1369,6 @@ namespace Markdig.Helpers
bool hasEscape = false;
bool previousWhitespace = true;
bool hasNonWhiteSpace = false;
bool isValid = false;
while (true)
{
c = lines.NextChar();
@@ -1407,9 +1416,7 @@ namespace Markdig.Helpers
{
labelSpan = SourceSpan.Empty;
}
label = buffer.ToString();
isValid = true;
goto ReturnValid;
}
}
break;
@@ -1452,9 +1459,12 @@ namespace Markdig.Helpers
previousWhitespace = isWhitespace;
}
buffer.Length = 0;
buffer.Dispose();
return false;
return isValid;
ReturnValid:
label = buffer.ToString();
return true;
}
public static bool TryParseLabelTrivia<T>(ref T lines, bool allowEmpty, out string? label, out SourceSpan labelSpan) where T : ICharIterator
@@ -1466,7 +1476,7 @@ namespace Markdig.Helpers
{
return false;
}
var buffer = StringBuilderCache.Local();
var buffer = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
var startLabel = -1;
var endLabel = -1;
@@ -1474,7 +1484,6 @@ namespace Markdig.Helpers
bool hasEscape = false;
bool previousWhitespace = true;
bool hasNonWhiteSpace = false;
bool isValid = false;
while (true)
{
c = lines.NextChar();
@@ -1522,9 +1531,7 @@ namespace Markdig.Helpers
{
labelSpan = SourceSpan.Empty;
}
label = buffer.ToString();
isValid = true;
goto ReturnValid;
}
}
break;
@@ -1571,10 +1578,12 @@ namespace Markdig.Helpers
previousWhitespace = isWhitespace;
}
buffer.Length = 0;
buffer.Dispose();
return false;
return isValid;
ReturnValid:
label = buffer.ToString();
return true;
}
}
}

View File

@@ -20,12 +20,5 @@ namespace Markdig.Helpers
{
return builder.Append(slice.Text, slice.Start, slice.Length);
}
internal static string GetStringAndReset(this StringBuilder builder)
{
string text = builder.ToString();
builder.Length = 0;
return text;
}
}
}

View File

@@ -26,6 +26,7 @@ namespace Markdig.Helpers
/// <param name="line">The line.</param>
/// <param name="column">The column.</param>
/// <param name="position">The position.</param>
/// <param name="newLine">The line separation.</param>
public StringLine(StringSlice slice, int line, int column, int position, NewLine newLine)
{
Slice = slice;
@@ -42,6 +43,7 @@ namespace Markdig.Helpers
/// <param name="line">The line.</param>
/// <param name="column">The column.</param>
/// <param name="position">The position.</param>
/// <param name="newLine">The line separation.</param>
public StringLine(ref StringSlice slice, int line, int column, int position, NewLine newLine)
{
Slice = slice;

View File

@@ -85,6 +85,14 @@ namespace Markdig.Helpers
Count--;
}
internal void RemoveStartRange(int toRemove)
{
int remaining = Count - toRemove;
Count = remaining;
Array.Copy(Lines, toRemove, Lines, 0, remaining);
Array.Clear(Lines, remaining, toRemove);
}
/// <summary>
/// Adds the specified line to this instance.
/// </summary>
@@ -139,7 +147,7 @@ namespace Markdig.Helpers
}
// Else use a builder
var builder = StringBuilderCache.Local();
var builder = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
int previousStartOfLine = 0;
var newLine = NewLine.None;
for (int i = 0; i < Count; i++)
@@ -152,13 +160,13 @@ namespace Markdig.Helpers
ref StringLine line = ref Lines[i];
if (!line.Slice.IsEmpty)
{
builder.Append(line.Slice.Text, line.Slice.Start, line.Slice.Length);
builder.Append(line.Slice.AsSpan());
}
newLine = line.NewLine;
lineOffsets?.Add(new LineOffset(line.Position, line.Column, line.Slice.Start - line.Position, previousStartOfLine, builder.Length));
}
return new StringSlice(builder.GetStringAndReset());
return new StringSlice(builder.ToString());
}
/// <summary>
@@ -213,21 +221,24 @@ namespace Markdig.Helpers
public struct Iterator : ICharIterator
{
private readonly StringLineGroup _lines;
private StringSlice _currentSlice;
private int _offset;
public Iterator(StringLineGroup lines)
public Iterator(StringLineGroup stringLineGroup)
{
this._lines = lines;
_lines = stringLineGroup;
Start = -1;
_offset = -1;
SliceIndex = 0;
CurrentChar = '\0';
End = -1;
for (int i = 0; i < lines.Count; i++)
StringLine[] lines = stringLineGroup.Lines;
for (int i = 0; i < stringLineGroup.Count && i < lines.Length; i++)
{
ref StringLine line = ref lines.Lines[i];
End += line.Slice.Length + line.NewLine.Length(); // Add chars
ref StringSlice slice = ref lines[i].Slice;
End += slice.Length + slice.NewLine.Length(); // Add chars
}
_currentSlice = _lines.Lines[0].Slice;
SkipChar();
}
@@ -243,17 +254,14 @@ namespace Markdig.Helpers
public StringLineGroup Remaining()
{
var lines = _lines;
StringLineGroup lines = _lines;
if (IsEmpty)
{
lines.Clear();
}
else
{
for (int i = SliceIndex - 1; i >= 0; i--)
{
lines.RemoveAt(i);
}
lines.RemoveStartRange(SliceIndex);
if (lines.Count > 0 && _offset > 0)
{
@@ -266,59 +274,85 @@ namespace Markdig.Helpers
return lines;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public char NextChar()
{
Start++;
if (Start <= End)
{
var slice = _lines.Lines[SliceIndex].Slice;
ref StringSlice slice = ref _currentSlice;
_offset++;
if (_offset < slice.Length)
int index = slice.Start + _offset;
string text = slice.Text;
if (index <= slice.End && (uint)index < (uint)text.Length)
{
CurrentChar = slice[slice.Start + _offset];
char c = text[index];
CurrentChar = c;
return c;
}
else
{
var newLine = slice.NewLine;
if (_offset == slice.Length)
{
if (newLine == NewLine.LineFeed)
{
CurrentChar = '\n';
SliceIndex++;
_offset = -1;
}
else if (newLine == NewLine.CarriageReturn)
{
CurrentChar = '\r';
SliceIndex++;
_offset = -1;
}
else if (newLine == NewLine.CarriageReturnLineFeed)
{
CurrentChar = '\r';
}
}
else if (_offset - 1 == slice.Length)
{
if (newLine == NewLine.CarriageReturnLineFeed)
{
CurrentChar = '\n';
SliceIndex++;
_offset = -1;
}
}
return NextCharNewLine();
}
}
else
{
CurrentChar = '\0';
Start = End + 1;
SliceIndex = _lines.Count;
return NextCharEndOfEnumerator();
}
}
private char NextCharNewLine()
{
int sliceLength = _currentSlice.Length;
NewLine newLine = _currentSlice.NewLine;
if (_offset == sliceLength)
{
if (newLine == NewLine.LineFeed)
{
CurrentChar = '\n';
goto MoveToNewLine;
}
else if (newLine == NewLine.CarriageReturn)
{
CurrentChar = '\r';
goto MoveToNewLine;
}
else if (newLine == NewLine.CarriageReturnLineFeed)
{
CurrentChar = '\r';
}
}
else if (_offset - 1 == sliceLength)
{
if (newLine == NewLine.CarriageReturnLineFeed)
{
CurrentChar = '\n';
goto MoveToNewLine;
}
}
goto Return;
MoveToNewLine:
SliceIndex++;
_offset = -1;
_currentSlice = _lines.Lines[SliceIndex];
Return:
return CurrentChar;
}
private char NextCharEndOfEnumerator()
{
CurrentChar = '\0';
Start = End + 1;
SliceIndex = _lines.Count;
return '\0';
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SkipChar() => NextChar();
public readonly char PeekChar() => PeekChar(1);
@@ -335,16 +369,17 @@ namespace Markdig.Helpers
offset += _offset;
int sliceIndex = SliceIndex;
ref StringLine line = ref _lines.Lines[sliceIndex];
ref StringSlice slice = ref line.Slice;
if (!(line.NewLine == NewLine.CarriageReturnLineFeed && offset == slice.Length + 1))
ref StringSlice slice = ref _lines.Lines[sliceIndex].Slice;
NewLine newLine = slice.NewLine;
if (!(newLine == NewLine.CarriageReturnLineFeed && offset == slice.Length + 1))
{
while (offset > slice.Length)
{
// We are not peeking at the same line
offset -= slice.Length + 1; // + 1 for new line
Debug.Assert(sliceIndex + 1 < _lines.Lines.Length, "'Start + offset > End' check above should prevent us from indexing out of range");
Debug.Assert(sliceIndex + 1 < _lines.Count, "'Start + offset > End' check above should prevent us from indexing out of range");
slice = ref _lines.Lines[++sliceIndex].Slice;
}
}
@@ -358,15 +393,15 @@ namespace Markdig.Helpers
if (offset == slice.Length)
{
if (line.NewLine == NewLine.LineFeed)
if (newLine == NewLine.LineFeed)
{
return '\n';
}
if (line.NewLine == NewLine.CarriageReturn)
if (newLine == NewLine.CarriageReturn)
{
return '\r';
}
if (line.NewLine == NewLine.CarriageReturnLineFeed)
if (newLine == NewLine.CarriageReturnLineFeed)
{
return '\r'; // /r of /r/n (first character)
}

View File

@@ -6,6 +6,7 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace Markdig.Helpers
{
@@ -36,6 +37,7 @@ namespace Markdig.Helpers
/// Initializes a new instance of the <see cref="StringSlice"/> struct.
/// </summary>
/// <param name="text">The text.</param>
/// <param name="newLine">The line separation.</param>
public StringSlice(string text, NewLine newLine)
{
Text = text;
@@ -68,6 +70,7 @@ namespace Markdig.Helpers
/// <param name="text">The text.</param>
/// <param name="start">The start.</param>
/// <param name="end">The end.</param>
/// <param name="newLine">The line separation.</param>
/// <exception cref="ArgumentNullException"></exception>
public StringSlice(string text, int start, int end, NewLine newLine)
{
@@ -80,6 +83,15 @@ namespace Markdig.Helpers
NewLine = newLine;
}
// Internal ctor to skip the null check
internal StringSlice(string text, int start, int end, NewLine newLine, bool dummy)
{
Text = text;
Start = start;
End = end;
NewLine = newLine;
}
/// <summary>
/// The text of this slice.
/// </summary>
@@ -451,6 +463,25 @@ namespace Markdig.Helpers
return text.Substring(start, length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly ReadOnlySpan<char> AsSpan()
{
string text = Text;
int start = Start;
int length = End - start + 1;
if (text is null || (ulong)(uint)start + (ulong)(uint)length > (ulong)(uint)text.Length)
{
return default;
}
#if NETCOREAPP3_1_OR_GREATER
return MemoryMarshal.CreateReadOnlySpan(ref Unsafe.Add(ref Unsafe.AsRef(text.GetPinnableReference()), start), length);
#else
return text.AsSpan(start, length);
#endif
}
/// <summary>
/// Determines whether this slice is empty or made only of whitespaces.
/// </summary>

View File

@@ -0,0 +1,130 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System;
using System.Linq;
using System.Threading;
namespace Markdig.Helpers
{
internal sealed class TransformedStringCache
{
internal const int InputLengthLimit = 20; // Avoid caching unreasonably long strings
internal const int MaxEntriesPerCharacter = 8; // Avoid growing too much
private readonly EntryGroup[] _groups; // One per ASCII character
private readonly Func<string, string> _transformation;
public TransformedStringCache(Func<string, string> transformation)
{
_transformation = transformation ?? throw new ArgumentNullException(nameof(transformation));
_groups = new EntryGroup[128];
}
public string Get(ReadOnlySpan<char> inputSpan)
{
if ((uint)(inputSpan.Length - 1) < InputLengthLimit) // Length: [1, LengthLimit]
{
int firstCharacter = inputSpan[0];
EntryGroup[] groups = _groups;
if ((uint)firstCharacter < (uint)groups.Length)
{
ref EntryGroup group = ref groups[firstCharacter];
string? transformed = group.TryGet(inputSpan);
if (transformed is null)
{
string input = inputSpan.ToString();
transformed = _transformation(input);
group.TryAdd(input, transformed);
}
return transformed;
}
}
return _transformation(inputSpan.ToString());
}
public string Get(string input)
{
if ((uint)(input.Length - 1) < InputLengthLimit) // Length: [1, LengthLimit]
{
int firstCharacter = input[0];
EntryGroup[] groups = _groups;
if ((uint)firstCharacter < (uint)groups.Length)
{
ref EntryGroup group = ref groups[firstCharacter];
string? transformed = group.TryGet(input.AsSpan());
if (transformed is null)
{
transformed = _transformation(input);
group.TryAdd(input, transformed);
}
return transformed;
}
}
return _transformation(input);
}
private struct EntryGroup
{
private struct Entry
{
public string Input;
public string Transformed;
}
private Entry[]? _entries;
public string? TryGet(ReadOnlySpan<char> inputSpan)
{
Entry[]? entries = _entries;
if (entries is not null)
{
for (int i = 0; i < entries.Length; i++)
{
if (inputSpan.SequenceEqual(entries[i].Input.AsSpan()))
{
return entries[i].Transformed;
}
}
}
return null;
}
public void TryAdd(string input, string transformed)
{
if (_entries is null)
{
Interlocked.CompareExchange(ref _entries, new Entry[MaxEntriesPerCharacter], null);
}
if (_entries[MaxEntriesPerCharacter - 1].Input is null) // There is still space
{
lock (_entries)
{
for (int i = 0; i < _entries.Length; i++)
{
string? existingInput = _entries[i].Input;
if (existingInput is null)
{
ref Entry entry = ref _entries[i];
Volatile.Write(ref entry.Transformed, transformed);
Volatile.Write(ref entry.Input, input);
break;
}
if (input == existingInput)
{
// We lost a race and a different thread already added the same value
break;
}
}
}
}
}
}
}
}

View File

@@ -0,0 +1,197 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
// Inspired by https://github.com/dotnet/runtime/blob/main/src/libraries/Common/src/System/Text/ValueStringBuilder.cs
using System;
using System.Buffers;
using System.Diagnostics;
using System.Runtime.CompilerServices;
namespace Markdig.Helpers
{
internal ref partial struct ValueStringBuilder
{
#if DEBUG
public const int StackallocThreshold = 7;
#else
#if NET5_0_OR_GREATER
// NET5+ has SkipLocalsInit, so allocating more is "free"
public const int StackallocThreshold = 256;
#else
public const int StackallocThreshold = 64;
#endif
#endif
private char[]? _arrayToReturnToPool;
private Span<char> _chars;
private int _pos;
public ValueStringBuilder(Span<char> initialBuffer)
{
_arrayToReturnToPool = null;
_chars = initialBuffer;
_pos = 0;
}
public int Length
{
get => _pos;
set
{
Debug.Assert(value >= 0);
Debug.Assert(value <= _chars.Length);
_pos = value;
}
}
public ref char this[int index]
{
get
{
Debug.Assert(index < _pos);
return ref _chars[index];
}
}
public override string ToString()
{
string s = _chars.Slice(0, _pos).ToString();
Dispose();
return s;
}
public ReadOnlySpan<char> AsSpan() => _chars.Slice(0, _pos);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(char c)
{
int pos = _pos;
Span<char> chars = _chars;
if ((uint)pos < (uint)chars.Length)
{
chars[pos] = c;
_pos = pos + 1;
}
else
{
GrowAndAppend(c);
}
}
public void Append(char c, int count)
{
if (_pos > _chars.Length - count)
{
Grow(count);
}
Span<char> dst = _chars.Slice(_pos, count);
for (int i = 0; i < dst.Length; i++)
{
dst[i] = c;
}
_pos += count;
}
public void Append(uint i)
{
if (i < 10)
{
Append((char)('0' + i));
}
else
{
Append(i.ToString());
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(string s)
{
int pos = _pos;
if (pos > _chars.Length - s.Length)
{
Grow(s.Length);
}
s
#if !NET5_0_OR_GREATER
.AsSpan()
#endif
.CopyTo(_chars.Slice(pos));
_pos += s.Length;
}
public void Append(ReadOnlySpan<char> value)
{
if (_pos > _chars.Length - value.Length)
{
Grow(value.Length);
}
value.CopyTo(_chars.Slice(_pos));
_pos += value.Length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<char> AppendSpan(int length)
{
int origPos = _pos;
if (origPos > _chars.Length - length)
{
Grow(length);
}
_pos = origPos + length;
return _chars.Slice(origPos, length);
}
[MethodImpl(MethodImplOptions.NoInlining)]
private void GrowAndAppend(char c)
{
Grow(1);
Append(c);
}
/// <summary>
/// Resize the internal buffer either by doubling current buffer size or
/// by adding <paramref name="additionalCapacityBeyondPos"/> to
/// <see cref="_pos"/> whichever is greater.
/// </summary>
/// <param name="additionalCapacityBeyondPos">
/// Number of chars requested beyond current position.
/// </param>
[MethodImpl(MethodImplOptions.NoInlining)]
private void Grow(int additionalCapacityBeyondPos)
{
Debug.Assert(additionalCapacityBeyondPos > 0);
Debug.Assert(_pos > _chars.Length - additionalCapacityBeyondPos, "Grow called incorrectly, no resize is needed.");
// Make sure to let Rent throw an exception if the caller has a bug and the desired capacity is negative
char[] poolArray = ArrayPool<char>.Shared.Rent((int)Math.Max((uint)(_pos + additionalCapacityBeyondPos), (uint)_chars.Length * 2));
_chars.Slice(0, _pos).CopyTo(poolArray);
char[]? toReturn = _arrayToReturnToPool;
_chars = _arrayToReturnToPool = poolArray;
if (toReturn != null)
{
ArrayPool<char>.Shared.Return(toReturn);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
char[]? toReturn = _arrayToReturnToPool;
this = default; // for safety, to avoid using pooled array if this instance is erroneously appended to again
if (toReturn != null)
{
ArrayPool<char>.Shared.Return(toReturn);
}
}
}
}

View File

@@ -7,6 +7,11 @@
<None Remove="readme.md" />
</ItemGroup>
<ItemGroup>
<AdditionalFiles Include="readme.md" LunetApiDotNet="true"/>
<AdditionalFiles Include="readme.md" LunetApiDotNet="true" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="Markdig.Tests" />
</ItemGroup>
</Project>

View File

@@ -4,19 +4,22 @@
<Description>A fast, powerful, CommonMark compliant, extensible Markdown processor for .NET with 20+ builtin extensions (pipetables, footnotes, definition lists... etc.)</Description>
<Copyright>Alexandre Mutel</Copyright>
<NeutralLanguage>en-US</NeutralLanguage>
<VersionPrefix>0.26.0</VersionPrefix>
<Authors>Alexandre Mutel</Authors>
<!-- Markdig.Wpf still supports net452, a target still supported by by Microsoft until January 10, 2023 -->
<!-- see: https://github.com/xoofx/markdig/pull/466 -->
<TargetFrameworks>net452;netstandard2.0;netstandard2.1;netcoreapp2.1;netcoreapp3.1</TargetFrameworks>
<TargetFrameworks>net452;netstandard2.0;netstandard2.1;netcoreapp3.1;net6.0</TargetFrameworks>
<CheckEolTargetFramework>false</CheckEolTargetFramework>
<PackageTags>Markdown CommonMark md html md2html</PackageTags>
<PackageReleaseNotes>https://github.com/lunet-io/markdig/blob/master/changelog.md</PackageReleaseNotes>
<PackageLicenseExpression>BSD-2-Clause</PackageLicenseExpression>
<PackageReadmeFile>readme.md</PackageReadmeFile>
<PackageIcon>markdig.png</PackageIcon>
<PackageProjectUrl>https://github.com/lunet-io/markdig</PackageProjectUrl>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>9</LangVersion>
<LangVersion>10</LangVersion>
<Nullable>enable</Nullable>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<!--Add support for sourcelink-->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<IncludeSymbols>true</IncludeSymbols>
@@ -30,27 +33,23 @@
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="System.Memory" Version="4.5.4" />
</ItemGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.1' ">
<DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">
<DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp3.1' ">
<DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<None Include="../../img/markdig.png" Pack="true" PackagePath="" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.*" PrivateAssets="All"/>
<None Include="../../readme.md" Pack="true" PackagePath="/"/>
<PackageReference Include="MinVer" Version="3.1.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.*" PrivateAssets="All"/>
</ItemGroup>
<Target Name="PatchVersion" AfterTargets="MinVer">
<PropertyGroup>
<!--In Markdig, the minor version is like a major version because Major is 0
Need to remove this when Markdig will be >= 1.0-->
<AssemblyVersion>$(MinVerMajor).$(MinVerMinor).0.0</AssemblyVersion>
</PropertyGroup>
</Target>
</Project>

View File

@@ -4,6 +4,7 @@
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using Markdig.Extensions.SelfPipeline;
using Markdig.Helpers;
@@ -19,7 +20,16 @@ namespace Markdig
/// </summary>
public static partial class Markdown
{
public static readonly string Version = ((AssemblyFileVersionAttribute) typeof(Markdown).Assembly.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false)[0]).Version;
public static string Version
{
get
{
if (_Version == null)
_Version = ((AssemblyFileVersionAttribute)typeof(Markdown).Assembly.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false).FirstOrDefault())?.Version ?? "Unknown";
return _Version;
}
}
private static string? _Version;
internal static readonly MarkdownPipeline DefaultPipeline = new MarkdownPipelineBuilder().Build();
private static readonly MarkdownPipeline _defaultTrackTriviaPipeline = new MarkdownPipelineBuilder().EnableTrackTrivia().Build();

View File

@@ -94,9 +94,7 @@ namespace Markdig
internal sealed class HtmlRendererCache : ObjectCache<HtmlRenderer>
{
private const int InitialCapacity = 1024;
private static readonly StringWriter _dummyWriter = new();
private static readonly TextWriter s_dummyWriter = new StringWriter();
private readonly MarkdownPipeline _pipeline;
private readonly bool _customWriter;
@@ -109,7 +107,7 @@ namespace Markdig
protected override HtmlRenderer NewInstance()
{
var writer = _customWriter ? _dummyWriter : new StringWriter(new StringBuilder(InitialCapacity));
TextWriter writer = _customWriter ? s_dummyWriter : new FastStringWriter();
var renderer = new HtmlRenderer(writer);
_pipeline.Setup(renderer);
return renderer;
@@ -121,11 +119,11 @@ namespace Markdig
if (_customWriter)
{
instance.Writer = _dummyWriter;
instance.Writer = s_dummyWriter;
}
else
{
((StringWriter)instance.Writer).GetStringBuilder().Length = 0;
((FastStringWriter)instance.Writer).Reset();
}
}
}

View File

@@ -83,7 +83,7 @@ namespace Markdig
public bool TrackTrivia { get; internal set; }
/// <summary>
/// Occurs when a document has been processed after the <see cref="MarkdownParser.Parse()"/> method.
/// Occurs when a document has been processed after the <see cref="MarkdownParser.Parse"/> method.
/// </summary>
public event ProcessDocumentDelegate? DocumentProcessed;

View File

@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.CompilerServices;
using Markdig.Helpers;
using Markdig.Syntax;
@@ -592,24 +593,27 @@ namespace Markdig.Parsers
/// <param name="stackIndex">Index of a block in a stack considered as the last block to update from.</param>
private void UpdateLastBlockAndContainer(int stackIndex = -1)
{
currentStackIndex = stackIndex < 0 ? OpenedBlocks.Count - 1 : stackIndex;
CurrentBlock = null;
LastBlock = null;
for (int i = OpenedBlocks.Count - 1; i >= 0; i--)
{
var block = OpenedBlocks[i];
if (CurrentBlock is null)
{
CurrentBlock = block;
}
List<Block> openedBlocks = OpenedBlocks;
currentStackIndex = stackIndex < 0 ? openedBlocks.Count - 1 : stackIndex;
if (block is ContainerBlock container)
Block? currentBlock = null;
for (int i = openedBlocks.Count - 1; i >= 0; i--)
{
var block = openedBlocks[i];
currentBlock ??= block;
if (block.IsContainerBlock)
{
CurrentContainer = container;
LastBlock = CurrentContainer.LastChild;
break;
var currentContainer = Unsafe.As<ContainerBlock>(block);
CurrentContainer = currentContainer;
LastBlock = currentContainer.LastChild;
CurrentBlock = currentBlock;
return;
}
}
CurrentBlock = currentBlock;
LastBlock = null;
}
/// <summary>
@@ -639,7 +643,7 @@ namespace Markdig.Parsers
ParseIndent();
// If we have a paragraph block, we want to try to match other blocks before trying the Paragraph
if (block is ParagraphBlock)
if (block.IsParagraphBlock)
{
break;
}
@@ -675,7 +679,7 @@ namespace Markdig.Parsers
}
// If we have a leaf block
if (block is LeafBlock leaf && NewBlocks.Count == 0)
if (block.IsLeafBlock && NewBlocks.Count == 0)
{
ContinueProcessingLine = false;
if (!result.IsDiscard())
@@ -689,7 +693,8 @@ namespace Markdig.Parsers
UnwindAllIndents();
}
}
leaf.AppendLine(ref Line, Column, LineIndex, CurrentLineStartPosition, TrackTrivia);
Unsafe.As<LeafBlock>(block).AppendLine(ref Line, Column, LineIndex, CurrentLineStartPosition, TrackTrivia);
}
}
@@ -804,7 +809,7 @@ namespace Markdig.Parsers
continue;
}
IsLazy = blockParser is ParagraphBlockParser && lastBlock is ParagraphBlock;
IsLazy = lastBlock.IsParagraphBlock && blockParser is ParagraphBlockParser;
var result = IsLazy
? blockParser.TryContinue(this, lastBlock)
@@ -825,7 +830,7 @@ namespace Markdig.Parsers
// Special case for paragraph
UpdateLastBlockAndContainer();
if (IsLazy && CurrentBlock is ParagraphBlock paragraph)
if (IsLazy && CurrentBlock is { } currentBlock && currentBlock.IsParagraphBlock)
{
Debug.Assert(NewBlocks.Count == 0);
@@ -835,12 +840,13 @@ namespace Markdig.Parsers
{
UnwindAllIndents();
}
paragraph.AppendLine(ref Line, Column, LineIndex, CurrentLineStartPosition, TrackTrivia);
Unsafe.As<ParagraphBlock>(currentBlock).AppendLine(ref Line, Column, LineIndex, CurrentLineStartPosition, TrackTrivia);
}
if (TrackTrivia)
{
// special case: take care when refactoring this
if (paragraph.Parent is QuoteBlock qb)
if (currentBlock.Parent is QuoteBlock qb)
{
var triviaAfter = UseTrivia(Start - 1);
qb.QuoteLines.Last().TriviaAfter = triviaAfter;
@@ -893,20 +899,19 @@ namespace Markdig.Parsers
block.Line = LineIndex;
// If we have a leaf block
var leaf = block as LeafBlock;
if (leaf != null)
if (block.IsLeafBlock)
{
if (!result.IsDiscard())
{
if (TrackTrivia)
{
if (block is ParagraphBlock ||
block is HtmlBlock)
if (block.IsParagraphBlock || block is HtmlBlock)
{
UnwindAllIndents();
}
}
leaf.AppendLine(ref Line, Column, LineIndex, CurrentLineStartPosition, TrackTrivia);
Unsafe.As<LeafBlock>(block).AppendLine(ref Line, Column, LineIndex, CurrentLineStartPosition, TrackTrivia);
}
if (newBlocks.Count > 0)
@@ -934,7 +939,7 @@ namespace Markdig.Parsers
// Add a block BlockProcessor to the stack (and leave it opened)
OpenedBlocks.Add(block);
if (leaf != null)
if (block.IsLeafBlock)
{
ContinueProcessingLine = false;
return;

View File

@@ -3,7 +3,7 @@
// See the license.txt file in the project root for more information.
using System;
using System.Diagnostics;
using Markdig.Helpers;
using Markdig.Renderers.Html;
using Markdig.Syntax;
@@ -40,6 +40,9 @@ namespace Markdig.Parsers
/// <seealso cref="BlockParser" />
public abstract class FencedBlockParserBase<T> : FencedBlockParserBase where T : Block, IFencedBlock
{
private static readonly TransformedStringCache _infoStringCache = new(static infoString => HtmlHelper.Unescape(infoString));
private TransformedStringCache? _infoPrefixCache;
/// <summary>
/// Initializes a new instance of the <see cref="FencedBlockParserBase{T}"/> class.
/// </summary>
@@ -50,10 +53,22 @@ namespace Markdig.Parsers
MaximumMatchCount = int.MaxValue;
}
private string? _infoPrefix;
/// <summary>
/// Gets or sets the language prefix (default is "language-")
/// </summary>
public string? InfoPrefix { get; set; }
public string? InfoPrefix
{
get => _infoPrefix;
set
{
if (_infoPrefix != value)
{
_infoPrefixCache = new TransformedStringCache(infoString => value + infoString);
_infoPrefix = value;
}
}
}
public int MinimumMatchCount { get; set; }
@@ -161,7 +176,7 @@ namespace Markdig.Parsers
end:
fenced.TriviaAfterFencedChar = afterFence;
fenced.Info = HtmlHelper.Unescape(info.ToString());
fenced.Info = _infoStringCache.Get(info.AsSpan());
fenced.UnescapedInfo = info;
fenced.TriviaAfterInfo = afterInfo;
fenced.Arguments = HtmlHelper.Unescape(arg.ToString());
@@ -182,9 +197,6 @@ namespace Markdig.Parsers
/// <returns><c>true</c> if parsing of the line is successfull; <c>false</c> otherwise</returns>
public static bool DefaultInfoParser(BlockProcessor state, ref StringSlice line, IFencedBlock fenced, char openingCharacter)
{
string infoString;
string? argString = null;
// An info string cannot contain any backticks (unless it is a tilde block)
int firstSpace = -1;
if (openingCharacter == '`')
@@ -215,9 +227,12 @@ namespace Markdig.Parsers
}
}
StringSlice infoStringSlice;
string? argString = null;
if (firstSpace > 0)
{
infoString = line.Text.AsSpan(line.Start, firstSpace - line.Start).Trim().ToString();
infoStringSlice = new StringSlice(line.Text, line.Start, firstSpace - 1);
// Skip any spaces after info string
firstSpace++;
@@ -234,16 +249,18 @@ namespace Markdig.Parsers
}
}
argString = line.Text.Substring(firstSpace, line.End - firstSpace + 1).Trim();
var argStringSlice = new StringSlice(line.Text, firstSpace, line.End);
argStringSlice.Trim();
argString = argStringSlice.ToString();
}
else
{
var lineCopy = line;
lineCopy.Trim();
infoString = lineCopy.ToString();
infoStringSlice = line;
}
fenced.Info = HtmlHelper.Unescape(infoString);
infoStringSlice.Trim();
fenced.Info = _infoStringCache.Get(infoStringSlice.AsSpan());
fenced.Arguments = HtmlHelper.Unescape(argString);
return true;
@@ -295,7 +312,9 @@ namespace Markdig.Parsers
// Add the language as an attribute by default
if (!string.IsNullOrEmpty(fenced.Info))
{
fenced.GetAttributes().AddClass(InfoPrefix + fenced.Info);
Debug.Assert(_infoPrefixCache is not null || InfoPrefix is null);
string infoWithPrefix = _infoPrefixCache?.Get(fenced.Info!) ?? fenced.Info!;
fenced.GetAttributes().AddClass(infoWithPrefix);
}
// Store the number of matched string into the context
@@ -332,9 +351,13 @@ namespace Markdig.Parsers
var fencedBlock = (IFencedBlock)block;
fencedBlock.ClosingFencedCharCount = closingCount;
fencedBlock.NewLine = processor.Line.NewLine;
fencedBlock.TriviaBeforeClosingFence = processor.UseTrivia(sourcePosition - 1);
fencedBlock.TriviaAfter = new StringSlice(processor.Line.Text, lastFenceCharPosition, endBeforeTrim);
if (processor.TrackTrivia)
{
fencedBlock.NewLine = processor.Line.NewLine;
fencedBlock.TriviaBeforeClosingFence = processor.UseTrivia(sourcePosition - 1);
fencedBlock.TriviaAfter = new StringSlice(processor.Line.Text, lastFenceCharPosition, endBeforeTrim);
}
// Don't keep the last line
return BlockState.BreakDiscard;

View File

@@ -26,13 +26,19 @@ namespace Markdig.Parsers
protected override FencedCodeBlock CreateFencedBlock(BlockProcessor processor)
{
return new FencedCodeBlock(this)
var codeBlock = new FencedCodeBlock(this)
{
IndentCount = processor.Indent,
LinesBefore = processor.UseLinesBefore(),
TriviaBefore = processor.UseTrivia(processor.Start - 1),
NewLine = processor.Line.NewLine,
};
if (processor.TrackTrivia)
{
codeBlock.LinesBefore = processor.UseLinesBefore();
codeBlock.TriviaBefore = processor.UseTrivia(processor.Start - 1);
codeBlock.NewLine = processor.Line.NewLine;
}
return codeBlock;
}
public override BlockState TryContinue(BlockProcessor processor, Block block)

View File

@@ -82,20 +82,25 @@ namespace Markdig.Parsers
var headingBlock = new HeadingBlock(this)
{
HeaderChar = matchingChar,
TriviaAfterAtxHeaderChar = trivia,
Level = leadingCount,
Column = column,
Span = { Start = sourcePosition },
TriviaBefore = processor.UseTrivia(sourcePosition - 1),
LinesBefore = processor.UseLinesBefore(),
NewLine = processor.Line.NewLine,
};
processor.NewBlocks.Push(headingBlock);
if (!processor.TrackTrivia)
if (processor.TrackTrivia)
{
headingBlock.TriviaAfterAtxHeaderChar = trivia;
headingBlock.TriviaBefore = processor.UseTrivia(sourcePosition - 1);
headingBlock.LinesBefore = processor.UseLinesBefore();
headingBlock.NewLine = processor.Line.NewLine;
}
else
{
processor.GoToColumn(column + leadingCount + 1);
}
processor.NewBlocks.Push(headingBlock);
// Gives a chance to parse attributes
TryParseAttributes?.Invoke(processor, ref processor.Line, headingBlock);

View File

@@ -62,10 +62,10 @@ namespace Markdig.Parsers
private BlockState TryParseTagType7(BlockProcessor state, StringSlice line, int startColumn, int startPosition)
{
var builder = StringBuilderCache.Local();
var builder = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
var c = line.CurrentChar;
var result = BlockState.None;
if ((c == '/' && HtmlHelper.TryParseHtmlCloseTag(ref line, builder)) || HtmlHelper.TryParseHtmlTagOpenTag(ref line, builder))
if ((c == '/' && HtmlHelper.TryParseHtmlCloseTag(ref line, ref builder)) || HtmlHelper.TryParseHtmlTagOpenTag(ref line, ref builder))
{
// Must be followed by whitespace only
bool hasOnlySpaces = true;
@@ -90,7 +90,7 @@ namespace Markdig.Parsers
}
}
builder.Length = 0;
builder.Dispose();
return result;
}
@@ -270,16 +270,22 @@ namespace Markdig.Parsers
private BlockState CreateHtmlBlock(BlockProcessor state, HtmlBlockType type, int startColumn, int startPosition)
{
state.NewBlocks.Push(new HtmlBlock(this)
var htmlBlock = new HtmlBlock(this)
{
Column = startColumn,
Type = type,
// By default, setup to the end of line
Span = new SourceSpan(startPosition, startPosition + state.Line.End),
//BeforeWhitespace = state.PopBeforeWhitespace(startPosition - 1),
LinesBefore = state.UseLinesBefore(),
NewLine = state.Line.NewLine,
});
};
if (state.TrackTrivia)
{
htmlBlock.LinesBefore = state.UseLinesBefore();
htmlBlock.NewLine = state.Line.NewLine;
}
state.NewBlocks.Push(htmlBlock);
return BlockState.Continue;
}

View File

@@ -17,7 +17,7 @@ namespace Markdig.Parsers
{
public override bool CanInterrupt(BlockProcessor processor, Block block)
{
return !(block is ParagraphBlock);
return !block.IsParagraphBlock;
}
public override BlockState TryOpen(BlockProcessor processor)
@@ -36,9 +36,14 @@ namespace Markdig.Parsers
{
Column = processor.Column,
Span = new SourceSpan(processor.Start, processor.Line.End),
LinesBefore = processor.UseLinesBefore(),
NewLine = processor.Line.NewLine,
};
if (processor.TrackTrivia)
{
codeBlock.LinesBefore = processor.UseLinesBefore();
codeBlock.NewLine = processor.Line.NewLine;
}
var codeBlockLine = new CodeBlockLine
{
TriviaBefore = processor.UseTrivia(sourceStartPosition - 1)
@@ -68,8 +73,12 @@ namespace Markdig.Parsers
if (line.Slice.IsEmpty)
{
codeBlock.Lines.RemoveAt(i);
processor.LinesBefore ??= new List<StringSlice>();
processor.LinesBefore.Add(line.Slice);
if (processor.TrackTrivia)
{
processor.LinesBefore ??= new List<StringSlice>();
processor.LinesBefore.Add(line.Slice);
}
}
else
{
@@ -92,12 +101,15 @@ namespace Markdig.Parsers
// lines
var cb = (CodeBlock)block;
var codeBlockLine = new CodeBlockLine
{
TriviaBefore = processor.UseTrivia(processor.Start - 1)
};
var codeBlockLine = new CodeBlockLine();
cb.CodeBlockLines.Add(codeBlockLine);
cb.NewLine = processor.Line.NewLine; // ensure block newline is last newline
if (processor.TrackTrivia)
{
codeBlockLine.TriviaBefore = processor.UseTrivia(processor.Start - 1);
cb.NewLine = processor.Line.NewLine; // ensure block newline is last newline
}
}
return BlockState.Continue;

View File

@@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.CompilerServices;
using Markdig.Helpers;
using Markdig.Parsers.Inlines;
using Markdig.Syntax;
@@ -277,7 +278,10 @@ namespace Markdig.Parsers
if (!(leafBlock is HeadingBlock))
{
var newLine = leafBlock.NewLine;
leafBlock.Inline.AppendChild(new LineBreakInline { NewLine = newLine });
if (newLine != NewLine.None)
{
leafBlock.Inline.AppendChild(new LineBreakInline { NewLine = newLine });
}
}
}
@@ -318,9 +322,10 @@ namespace Markdig.Parsers
var container = Block!.Inline!;
for (int depth = 0; ; depth++)
{
if (container.LastChild is ContainerInline nextContainer && !nextContainer.IsClosed)
Inline? lastChild = container.LastChild;
if (lastChild is not null && lastChild.IsContainerInline && !lastChild.IsClosed)
{
container = nextContainer;
container = Unsafe.As<ContainerInline>(lastChild);
}
else
{

View File

@@ -40,7 +40,7 @@ namespace Markdig.Parsers.Inlines
char c = slice.CurrentChar;
var builder = StringBuilderCache.Local();
var builder = new ValueStringBuilder(stackalloc char[ValueStringBuilder.StackallocThreshold]);
// 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.
@@ -98,33 +98,38 @@ namespace Markdig.Parsers.Inlines
bool isMatching = false;
if (closeSticks == openSticks)
{
string content;
ReadOnlySpan<char> contentSpan = builder.AsSpan();
// Remove one space from front and back if the string is not all spaces
if (!allSpace && builder.Length > 2 && builder[0] == ' ' && builder[builder.Length - 1] == ' ')
if (!allSpace && contentSpan.Length > 2 && contentSpan[0] == ' ' && contentSpan[contentSpan.Length - 1] == ' ')
{
content = builder.ToString(1, builder.Length - 2);
}
else
{
content = builder.ToString();
contentSpan = contentSpan.Slice(1, contentSpan.Length - 2);
}
string content = contentSpan.ToString();
int delimiterCount = Math.Min(openSticks, closeSticks);
var spanStart = processor.GetSourcePosition(startPosition, out int line, out int column);
var spanEnd = processor.GetSourcePosition(slice.Start - 1);
processor.Inline = new CodeInline(content)
var codeInline = new CodeInline(content)
{
Delimiter = match,
ContentWithTrivia = new StringSlice(slice.Text, contentStart, contentEnd - 1),
Span = new SourceSpan(spanStart, spanEnd),
Line = line,
Column = column,
DelimiterCount = delimiterCount,
};
if (processor.TrackTrivia)
{
codeInline.ContentWithTrivia = new StringSlice(slice.Text, contentStart, contentEnd - 1);
}
processor.Inline = codeInline;
isMatching = true;
}
builder.Dispose();
return isMatching;
}
}

View File

@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Markdig.Helpers;
using Markdig.Renderers.Html;
using Markdig.Syntax;
@@ -91,11 +92,13 @@ namespace Markdig.Parsers.Inlines
public bool PostProcess(InlineProcessor state, Inline? root, Inline? lastChild, int postInlineProcessorIndex, bool isFinalProcessing)
{
if (!(root is ContainerInline container))
if (root is null || !root.IsContainerInline)
{
return true;
}
ContainerInline container = Unsafe.As<ContainerInline>(root);
List<EmphasisDelimiterInline>? delimiters = null;
if (container is EmphasisDelimiterInline emphasisDelimiter)
{
@@ -103,25 +106,27 @@ namespace Markdig.Parsers.Inlines
delimiters.Add(emphasisDelimiter);
}
// 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.)
var child = container.LastChild;
// Collect all EmphasisDelimiterInline by searching from the root container
var child = container.FirstChild;
while (child != null)
{
// Stop the search on the delimitation child
if (child == lastChild)
{
break;
}
// If we have a delimiter, we search into it as we should have a tree of EmphasisDelimiterInline
if (child is EmphasisDelimiterInline delimiter)
{
if (delimiters is null)
{
delimiters = inlinesCache.Get();
}
delimiters ??= inlinesCache.Get();
delimiters.Add(delimiter);
child = delimiter.FirstChild;
continue;
}
var subContainer = child as ContainerInline;
child = subContainer?.LastChild;
// Follow DelimiterInline (EmphasisDelimiter, TableDelimiter...)
child = child is DelimiterInline delimiterInline ? delimiterInline.FirstChild : child.NextSibling;
}
if (delimiters != null)

View File

@@ -30,7 +30,7 @@ namespace Markdig.Parsers.Inlines
public override bool Match(InlineProcessor processor, ref StringSlice slice)
{
// 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:
if (!(processor.Block is ParagraphBlock))
if (!processor.Block!.IsParagraphBlock)
{
return false;
}

View File

@@ -5,6 +5,7 @@
using Markdig.Helpers;
using Markdig.Syntax;
using Markdig.Syntax.Inlines;
using System.Diagnostics.CodeAnalysis;
namespace Markdig.Parsers.Inlines
{
@@ -78,18 +79,23 @@ namespace Markdig.Parsers.Inlines
// Else we insert a LinkDelimiter
slice.SkipChar();
var labelWithTrivia = new StringSlice(slice.Text, labelWithTriviaSpan.Start, labelWithTriviaSpan.End);
processor.Inline = new LinkDelimiterInline(this)
var linkDelimiter = new LinkDelimiterInline(this)
{
Type = DelimiterType.Open,
Label = label,
LabelWithTrivia = labelWithTrivia,
LabelSpan = processor.GetSourcePositionFromLocalSpan(labelSpan),
IsImage = isImage,
Span = new SourceSpan(startPosition, processor.GetSourcePosition(slice.Start - 1)),
Line = line,
Column = column
};
if (processor.TrackTrivia)
{
linkDelimiter.LabelWithTrivia = new StringSlice(slice.Text, labelWithTriviaSpan.Start, labelWithTriviaSpan.End);
}
processor.Inline = linkDelimiter;
return true;
case ']':
@@ -137,18 +143,13 @@ namespace Markdig.Parsers.Inlines
// Create a default link if the callback was not found
if (link is null)
{
var labelWithTrivia = new StringSlice(text.Text, labelWithriviaSpan.Start, labelWithriviaSpan.End);
// Inline Link
link = new LinkInline()
var linkInline = new LinkInline()
{
Url = HtmlHelper.Unescape(linkRef.Url),
Title = HtmlHelper.Unescape(linkRef.Title),
Label = label,
LabelSpan = labelSpan,
LabelWithTrivia = labelWithTrivia,
LinkRefDefLabel = linkRef.Label,
LinkRefDefLabelWithTrivia = linkRef.LabelWithTrivia,
LocalLabel = localLabel,
UrlSpan = linkRef.UrlSpan,
IsImage = parent.IsImage,
IsShortcut = isShortcut,
@@ -157,6 +158,16 @@ namespace Markdig.Parsers.Inlines
Line = parent.Line,
Column = parent.Column,
};
if (state.TrackTrivia)
{
linkInline.LabelWithTrivia = new StringSlice(text.Text, labelWithriviaSpan.Start, labelWithriviaSpan.End);
linkInline.LinkRefDefLabel = linkRef.Label;
linkInline.LinkRefDefLabelWithTrivia = linkRef.LabelWithTrivia;
linkInline.LocalLabel = localLabel;
}
link = linkInline;
}
if (link is ContainerInline containerLink)
@@ -233,74 +244,18 @@ namespace Markdig.Parsers.Inlines
if (text.CurrentChar == '(')
{
LinkInline? link = null;
if (inlineState.TrackTrivia)
{
if (LinkHelper.TryParseInlineLinkTrivia(
ref text,
out string? url,
out SourceSpan unescapedUrlSpan,
out string? title,
out SourceSpan unescapedTitleSpan,
out char titleEnclosingCharacter,
out SourceSpan linkSpan,
out SourceSpan titleSpan,
out SourceSpan triviaBeforeLink,
out SourceSpan triviaAfterLink,
out SourceSpan triviaAfterTitle,
out bool urlHasPointyBrackets))
{
var wsBeforeLink = new StringSlice(text.Text, triviaBeforeLink.Start, triviaBeforeLink.End);
var wsAfterLink = new StringSlice(text.Text, triviaAfterLink.Start, triviaAfterLink.End);
var wsAfterTitle = new StringSlice(text.Text, triviaAfterTitle.Start, triviaAfterTitle.End);
var unescapedUrl = new StringSlice(text.Text, unescapedUrlSpan.Start, unescapedUrlSpan.End);
var unescapedTitle = new StringSlice(text.Text, unescapedTitleSpan.Start, unescapedTitleSpan.End);
// Inline Link
var link = new LinkInline()
{
TriviaBeforeUrl = wsBeforeLink,
Url = HtmlHelper.Unescape(url),
UnescapedUrl = unescapedUrl,
UrlHasPointyBrackets = urlHasPointyBrackets,
TriviaAfterUrl = wsAfterLink,
Title = HtmlHelper.Unescape(title),
UnescapedTitle = unescapedTitle,
TitleEnclosingCharacter = titleEnclosingCharacter,
TriviaAfterTitle = wsAfterTitle,
IsImage = openParent.IsImage,
LabelSpan = openParent.LabelSpan,
UrlSpan = inlineState.GetSourcePositionFromLocalSpan(linkSpan),
TitleSpan = inlineState.GetSourcePositionFromLocalSpan(titleSpan),
Span = new SourceSpan(openParent.Span.Start, inlineState.GetSourcePosition(text.Start - 1)),
Line = openParent.Line,
Column = openParent.Column,
};
openParent.ReplaceBy(link);
// Notifies processor as we are creating an inline locally
inlineState.Inline = link;
// Process emphasis delimiters
inlineState.PostProcessInlines(0, link, null, false);
// 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.)
if (!openParent.IsImage)
{
MarkParentAsInactive(parentDelimiter);
}
link.IsClosed = true;
return true;
}
link = TryParseInlineLinkTrivia(ref text, inlineState, openParent);
}
else
{
if (LinkHelper.TryParseInlineLink(ref text, out string? url, out string? title, out SourceSpan linkSpan, out SourceSpan titleSpan))
{
// Inline Link
var link = new LinkInline()
link = new LinkInline()
{
Url = HtmlHelper.Unescape(url),
Title = HtmlHelper.Unescape(title),
@@ -312,34 +267,36 @@ namespace Markdig.Parsers.Inlines
Line = openParent.Line,
Column = openParent.Column,
};
openParent.ReplaceBy(link);
// Notifies processor as we are creating an inline locally
inlineState.Inline = link;
// Process emphasis delimiters
inlineState.PostProcessInlines(0, link, null, false);
// 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.)
if (!openParent.IsImage)
{
MarkParentAsInactive(parentDelimiter);
}
link.IsClosed = true;
return true;
}
}
if (link is not null)
{
openParent.ReplaceBy(link);
// Notifies processor as we are creating an inline locally
inlineState.Inline = link;
// Process emphasis delimiters
inlineState.PostProcessInlines(0, link, null, false);
// 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.)
if (!openParent.IsImage)
{
MarkParentAsInactive(parentDelimiter);
}
link.IsClosed = true;
return true;
}
text = savedText;
}
var labelSpan = SourceSpan.Empty;
string? label = null;
SourceSpan labelWithTrivia = SourceSpan.Empty;
bool isLabelSpanLocal = true;
bool isShortcut = false;
@@ -363,9 +320,10 @@ namespace Markdig.Parsers.Inlines
label = openParent.Label;
isShortcut = true;
}
if (label != null || LinkHelper.TryParseLabelTrivia(ref text, true, out label, out labelSpan))
{
labelWithTrivia = new SourceSpan(labelSpan.Start, labelSpan.End);
SourceSpan labelWithTrivia = new SourceSpan(labelSpan.Start, labelSpan.End);
if (isLabelSpanLocal)
{
labelSpan = inlineState.GetSourcePositionFromLocalSpan(labelSpan);
@@ -399,9 +357,55 @@ namespace Markdig.Parsers.Inlines
inlineState.Inline = openParent.ReplaceBy(literal);
return false;
static LinkInline? TryParseInlineLinkTrivia(ref StringSlice text, InlineProcessor inlineState, LinkDelimiterInline openParent)
{
if (LinkHelper.TryParseInlineLinkTrivia(
ref text,
out string? url,
out SourceSpan unescapedUrlSpan,
out string? title,
out SourceSpan unescapedTitleSpan,
out char titleEnclosingCharacter,
out SourceSpan linkSpan,
out SourceSpan titleSpan,
out SourceSpan triviaBeforeLink,
out SourceSpan triviaAfterLink,
out SourceSpan triviaAfterTitle,
out bool urlHasPointyBrackets))
{
var wsBeforeLink = new StringSlice(text.Text, triviaBeforeLink.Start, triviaBeforeLink.End);
var wsAfterLink = new StringSlice(text.Text, triviaAfterLink.Start, triviaAfterLink.End);
var wsAfterTitle = new StringSlice(text.Text, triviaAfterTitle.Start, triviaAfterTitle.End);
var unescapedUrl = new StringSlice(text.Text, unescapedUrlSpan.Start, unescapedUrlSpan.End);
var unescapedTitle = new StringSlice(text.Text, unescapedTitleSpan.Start, unescapedTitleSpan.End);
return new LinkInline()
{
TriviaBeforeUrl = wsBeforeLink,
Url = HtmlHelper.Unescape(url),
UnescapedUrl = unescapedUrl,
UrlHasPointyBrackets = urlHasPointyBrackets,
TriviaAfterUrl = wsAfterLink,
Title = HtmlHelper.Unescape(title),
UnescapedTitle = unescapedTitle,
TitleEnclosingCharacter = titleEnclosingCharacter,
TriviaAfterTitle = wsAfterTitle,
IsImage = openParent.IsImage,
LabelSpan = openParent.LabelSpan,
UrlSpan = inlineState.GetSourcePositionFromLocalSpan(linkSpan),
TitleSpan = inlineState.GetSourcePositionFromLocalSpan(titleSpan),
Span = new SourceSpan(openParent.Span.Start, inlineState.GetSourcePosition(text.Start - 1)),
Line = openParent.Line,
Column = openParent.Column,
};
}
return null;
}
}
private void MarkParentAsInactive(Inline? inline)
private static void MarkParentAsInactive(Inline? inline)
{
while (inline != null)
{

View File

@@ -93,8 +93,12 @@ namespace Markdig.Parsers
{
// TODO: We remove the thematic break, as it will be created later, but this is inefficient, try to find another way
var thematicBreak = processor.NewBlocks.Pop();
var linesBefore = thematicBreak.LinesBefore;
processor.LinesBefore = linesBefore;
if (processor.TrackTrivia)
{
processor.LinesBefore = thematicBreak.LinesBefore;
}
return BlockState.None;
}
}
@@ -259,10 +263,11 @@ namespace Markdig.Parsers
// Starts/continue the list unless:
// - an empty list item follows a paragraph
// - an ordered list is not starting by '1'
if ((block ?? state.LastBlock) is ParagraphBlock previousParagraph)
block ??= state.LastBlock;
if (block is not null && block.IsParagraphBlock)
{
if (state.IsBlankLine ||
state.IsOpen(previousParagraph) && listInfo.BulletType == '1' && listInfo.OrderedStart is not "1")
state.IsOpen(block) && listInfo.BulletType == '1' && listInfo.OrderedStart is not "1")
{
state.GoToColumn(initColumn);
state.TriviaStart = savedTriviaStart; // restore changed TriviaStart state
@@ -276,12 +281,17 @@ namespace Markdig.Parsers
Column = initColumn,
ColumnWidth = columnWidth,
Order = order,
SourceBullet = listInfo.SourceBullet,
TriviaBefore = triviaBefore,
Span = new SourceSpan(sourcePosition, sourceEndPosition),
LinesBefore = state.UseLinesBefore(),
NewLine = state.Line.NewLine,
};
if (state.TrackTrivia)
{
newListItem.TriviaBefore = triviaBefore;
newListItem.LinesBefore = state.UseLinesBefore();
newListItem.NewLine = state.Line.NewLine;
newListItem.SourceBullet = listInfo.SourceBullet;
}
state.NewBlocks.Push(newListItem);
if (currentParent != null)
@@ -313,8 +323,13 @@ namespace Markdig.Parsers
OrderedDelimiter = listInfo.OrderedDelimiter,
DefaultOrderedStart = listInfo.DefaultOrderedStart,
OrderedStart = listInfo.OrderedStart,
LinesBefore = state.UseLinesBefore(),
};
if (state.TrackTrivia)
{
newList.LinesBefore = state.UseLinesBefore();
}
state.NewBlocks.Push(newList);
}
return BlockState.Continue;

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Markdig.Helpers;
using Markdig.Syntax;
@@ -43,8 +44,8 @@ namespace Markdig.Parsers
if (pipeline.PreciseSourceLocation)
{
int roughLineCountEstimate = text.Length / 40;
roughLineCountEstimate = Math.Min(4, Math.Max(512, roughLineCountEstimate));
int roughLineCountEstimate = text.Length / 32;
roughLineCountEstimate = Math.Max(4, Math.Min(512, roughLineCountEstimate));
document.LineStartIndexes = new List<int>(roughLineCountEstimate);
}
@@ -149,8 +150,9 @@ namespace Markdig.Parsers
for (; item.Index < container.Count; item.Index++)
{
var block = container[item.Index];
if (block is LeafBlock leafBlock)
if (block.IsLeafBlock)
{
LeafBlock leafBlock = Unsafe.As<LeafBlock>(block);
leafBlock.OnProcessInlinesBegin(inlineProcessor);
if (leafBlock.ProcessInlines)
{
@@ -167,10 +169,10 @@ namespace Markdig.Parsers
}
leafBlock.OnProcessInlinesEnd(inlineProcessor);
}
else if (block is ContainerBlock newContainer)
else if (block.IsContainerBlock)
{
// If we need to remove it
if (newContainer.RemoveAfterProcessInlines)
if (block.RemoveAfterProcessInlines)
{
container.RemoveAt(item.Index);
}
@@ -185,8 +187,8 @@ namespace Markdig.Parsers
Array.Resize(ref blocks, blockCount * 2);
ThrowHelper.CheckDepthLimit(blocks.Length);
}
blocks[blockCount++] = new ContainerItem(newContainer);
newContainer.OnProcessInlinesBegin(inlineProcessor);
blocks[blockCount++] = new ContainerItem(Unsafe.As<ContainerBlock>(block));
block.OnProcessInlinesBegin(inlineProcessor);
goto process_new_block;
}
}

View File

@@ -23,13 +23,19 @@ namespace Markdig.Parsers
}
// We continue trying to match by default
processor.NewBlocks.Push(new ParagraphBlock(this)
var paragraph = new ParagraphBlock(this)
{
Column = processor.Column,
Span = new SourceSpan(processor.Line.Start, processor.Line.End),
LinesBefore = processor.UseLinesBefore(),
NewLine = processor.Line.NewLine,
});
};
if (processor.TrackTrivia)
{
paragraph.LinesBefore = processor.UseLinesBefore();
paragraph.NewLine = processor.Line.NewLine;
}
processor.NewBlocks.Push(paragraph);
return BlockState.Continue;
}
@@ -128,15 +134,19 @@ namespace Markdig.Parsers
Span = new SourceSpan(paragraph.Span.Start, line.Start),
Level = level,
Lines = paragraph.Lines,
TriviaBefore = state.UseTrivia(sourcePosition - 1), // remove dashes
TriviaAfter = new StringSlice(state.Line.Text, state.Start, line.End),
LinesBefore = paragraph.LinesBefore,
NewLine = state.Line.NewLine,
IsSetext = true,
HeaderCharCount = count,
SetextNewline = paragraph.NewLine,
};
if (!state.TrackTrivia)
if (state.TrackTrivia)
{
heading.LinesBefore = paragraph.LinesBefore;
heading.TriviaBefore = state.UseTrivia(sourcePosition - 1); // remove dashes
heading.TriviaAfter = new StringSlice(state.Line.Text, state.Start, line.End);
heading.NewLine = state.Line.NewLine;
heading.SetextNewline = paragraph.NewLine;
}
else
{
heading.Lines.Trim();
}

View File

@@ -41,9 +41,13 @@ namespace Markdig.Parsers
QuoteChar = quoteChar,
Column = column,
Span = new SourceSpan(sourcePosition, processor.Line.End),
LinesBefore = processor.UseLinesBefore()
};
if (processor.TrackTrivia)
{
quoteBlock.LinesBefore = processor.UseLinesBefore();
}
bool hasSpaceAfterQuoteChar = false;
if (c == ' ')
{
@@ -56,28 +60,34 @@ namespace Markdig.Parsers
processor.NextColumn();
}
var triviaBefore = processor.UseTrivia(sourcePosition - 1);
StringSlice triviaAfter = StringSlice.Empty;
bool wasEmptyLine = false;
if (processor.Line.IsEmptyOrWhitespace())
if (processor.TrackTrivia)
{
processor.TriviaStart = processor.Start;
triviaAfter = processor.UseTrivia(processor.Line.End);
wasEmptyLine = true;
var triviaBefore = processor.UseTrivia(sourcePosition - 1);
StringSlice triviaAfter = StringSlice.Empty;
bool wasEmptyLine = false;
if (processor.Line.IsEmptyOrWhitespace())
{
processor.TriviaStart = processor.Start;
triviaAfter = processor.UseTrivia(processor.Line.End);
wasEmptyLine = true;
}
if (!wasEmptyLine)
{
processor.TriviaStart = processor.Start;
}
quoteBlock.QuoteLines.Add(new QuoteBlockLine
{
TriviaBefore = triviaBefore,
TriviaAfter = triviaAfter,
QuoteChar = true,
HasSpaceAfterQuoteChar = hasSpaceAfterQuoteChar,
NewLine = processor.Line.NewLine,
});
}
quoteBlock.QuoteLines.Add(new QuoteBlockLine
{
TriviaBefore = triviaBefore,
TriviaAfter = triviaAfter,
QuoteChar = true,
HasSpaceAfterQuoteChar = hasSpaceAfterQuoteChar,
NewLine = processor.Line.NewLine,
});
processor.NewBlocks.Push(quoteBlock);
if (!wasEmptyLine)
{
processor.TriviaStart = processor.Start;
}
return BlockState.Continue;
}
@@ -94,7 +104,6 @@ namespace Markdig.Parsers
// 5.1 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.
var c = processor.CurrentChar;
bool hasSpaceAfterQuoteChar = false;
if (c != quote.QuoteChar)
{
if (processor.IsBlankLine)
@@ -103,14 +112,19 @@ namespace Markdig.Parsers
}
else
{
quote.QuoteLines.Add(new QuoteBlockLine
if (processor.TrackTrivia)
{
QuoteChar = false,
NewLine = processor.Line.NewLine,
});
quote.QuoteLines.Add(new QuoteBlockLine
{
QuoteChar = false,
NewLine = processor.Line.NewLine,
});
}
return BlockState.None;
}
}
bool hasSpaceAfterQuoteChar = false;
c = processor.NextChar(); // Skip quote marker char
if (c == ' ')
{
@@ -122,28 +136,33 @@ namespace Markdig.Parsers
{
processor.NextColumn();
}
var TriviaSpaceBefore = processor.UseTrivia(sourcePosition - 1);
StringSlice triviaAfter = StringSlice.Empty;
bool wasEmptyLine = false;
if (processor.Line.IsEmptyOrWhitespace())
{
processor.TriviaStart = processor.Start;
triviaAfter = processor.UseTrivia(processor.Line.End);
wasEmptyLine = true;
}
quote.QuoteLines.Add(new QuoteBlockLine
{
QuoteChar = true,
HasSpaceAfterQuoteChar = hasSpaceAfterQuoteChar,
TriviaBefore = TriviaSpaceBefore,
TriviaAfter = triviaAfter,
NewLine = processor.Line.NewLine,
});
if (!wasEmptyLine)
if (processor.TrackTrivia)
{
processor.TriviaStart = processor.Start;
var triviaSpaceBefore = processor.UseTrivia(sourcePosition - 1);
StringSlice triviaAfter = StringSlice.Empty;
bool wasEmptyLine = false;
if (processor.Line.IsEmptyOrWhitespace())
{
processor.TriviaStart = processor.Start;
triviaAfter = processor.UseTrivia(processor.Line.End);
wasEmptyLine = true;
}
quote.QuoteLines.Add(new QuoteBlockLine
{
QuoteChar = true,
HasSpaceAfterQuoteChar = hasSpaceAfterQuoteChar,
TriviaBefore = triviaSpaceBefore,
TriviaAfter = triviaAfter,
NewLine = processor.Line.NewLine,
});
if (!wasEmptyLine)
{
processor.TriviaStart = processor.Start;
}
}
block.UpdateSpanEnd(processor.Line.End);
return BlockState.Continue;
}

View File

@@ -85,7 +85,7 @@ namespace Markdig.Parsers
}
// Push a new block
processor.NewBlocks.Push(new ThematicBreakBlock(this)
var thematicBreak = new ThematicBreakBlock(this)
{
Column = processor.Column,
Span = new SourceSpan(startPosition, line.End),
@@ -94,10 +94,16 @@ namespace Markdig.Parsers
// TODO: should we separate whitespace before/after?
//BeforeWhitespace = beforeWhitespace,
//AfterWhitespace = processor.PopBeforeWhitespace(processor.CurrentLineStartPosition),
LinesBefore = processor.UseLinesBefore(),
Content = new StringSlice(line.Text, processor.TriviaStart, line.End, line.NewLine), //include whitespace for now
NewLine = processor.Line.NewLine,
});
};
if (processor.TrackTrivia)
{
thematicBreak.LinesBefore = processor.UseLinesBefore();
thematicBreak.NewLine = processor.Line.NewLine;
}
processor.NewBlocks.Push(thematicBreak);
return BlockState.BreakDiscard;
}
}

View File

@@ -5,7 +5,7 @@
namespace System.Diagnostics.CodeAnalysis
{
#if !NETCORE || NETCOREAPP2_1
#if !NETSTANDARD2_1_OR_GREATER && !NETCOREAPP3_1_OR_GREATER
internal sealed class DoesNotReturnAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Parameter, Inherited = false)]
@@ -15,8 +15,12 @@ namespace System.Diagnostics.CodeAnalysis
public bool ReturnValue { get; }
}
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, Inherited = false)]
public sealed class AllowNullAttribute : Attribute { }
#endif
#if !NET5_0_OR_GREATER
internal sealed class MemberNotNullAttribute : Attribute
{
public MemberNotNullAttribute(string member) => Members = new[] { member };
@@ -25,4 +29,5 @@ namespace System.Diagnostics.CodeAnalysis
public string[] Members { get; }
}
#endif
}

View File

@@ -0,0 +1,17 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
namespace System.Runtime.CompilerServices
{
#if NETSTANDARD2_1
internal static class Unsafe
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T As<T>(object o) where T : class
{
return (T)o;
}
}
#endif
}

View File

@@ -15,27 +15,25 @@ namespace Markdig.Renderers.Html
/// <seealso cref="HtmlObjectRenderer{CodeBlock}" />
public class CodeBlockRenderer : HtmlObjectRenderer<CodeBlock>
{
private HashSet<string>? _blocksAsDiv;
/// <summary>
/// Initializes a new instance of the <see cref="CodeBlockRenderer"/> class.
/// </summary>
public CodeBlockRenderer()
{
BlocksAsDiv = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
}
public CodeBlockRenderer() { }
public bool OutputAttributesOnPre { get; set; }
/// <summary>
/// Gets a map of fenced code block infos that should be rendered as div blocks instead of pre/code blocks.
/// </summary>
public HashSet<string> BlocksAsDiv { get; }
public HashSet<string> BlocksAsDiv => _blocksAsDiv ??= new HashSet<string>(StringComparer.OrdinalIgnoreCase);
protected override void Write(HtmlRenderer renderer, CodeBlock obj)
{
renderer.EnsureLine();
var fencedCodeBlock = obj as FencedCodeBlock;
if (fencedCodeBlock?.Info != null && BlocksAsDiv.Contains(fencedCodeBlock.Info))
if (_blocksAsDiv is not null && (obj as FencedCodeBlock)?.Info is string info && _blocksAsDiv.Contains(info))
{
var infoPrefix = (obj.Parser as FencedCodeBlockParser)?.InfoPrefix ??
FencedCodeBlockParser.DefaultInfoPrefix;
@@ -48,7 +46,7 @@ namespace Markdig.Renderers.Html
renderer.Write("<div")
.WriteAttributes(obj.TryGetAttributes(),
cls => cls.StartsWith(infoPrefix, StringComparison.Ordinal) ? cls.Substring(infoPrefix.Length) : cls)
.Write('>');
.WriteRaw('>');
}
renderer.WriteLeafRawLines(obj, true, true, true);
@@ -57,7 +55,6 @@ namespace Markdig.Renderers.Html
{
renderer.WriteLine("</div>");
}
}
else
{
@@ -70,14 +67,14 @@ namespace Markdig.Renderers.Html
renderer.WriteAttributes(obj);
}
renderer.Write("><code");
renderer.WriteRaw("><code");
if (!OutputAttributesOnPre)
{
renderer.WriteAttributes(obj);
}
renderer.Write('>');
renderer.WriteRaw('>');
}
renderer.WriteLeafRawLines(obj, true, true);

View File

@@ -2,7 +2,6 @@
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System.Globalization;
using Markdig.Syntax;
namespace Markdig.Renderers.Html
@@ -25,20 +24,26 @@ namespace Markdig.Renderers.Html
protected override void Write(HtmlRenderer renderer, HeadingBlock obj)
{
int index = obj.Level - 1;
string headingText = ((uint)index < (uint)HeadingTexts.Length)
? HeadingTexts[index]
: "h" + obj.Level.ToString(CultureInfo.InvariantCulture);
string[] headings = HeadingTexts;
string headingText = ((uint)index < (uint)headings.Length)
? headings[index]
: $"h{obj.Level}";
if (renderer.EnableHtmlForBlock)
{
renderer.Write("<").Write(headingText).WriteAttributes(obj).Write('>');
renderer.Write('<');
renderer.WriteRaw(headingText);
renderer.WriteAttributes(obj);
renderer.WriteRaw('>');
}
renderer.WriteLeafInline(obj);
if (renderer.EnableHtmlForBlock)
{
renderer.Write("</").Write(headingText).WriteLine(">");
renderer.Write("</");
renderer.WriteRaw(headingText);
renderer.WriteLine('>');
}
renderer.EnsureLine();

View File

@@ -54,28 +54,26 @@ namespace Markdig.Renderers.Html.Inlines
{
if (renderer.EnableHtmlForInline)
{
renderer.Write("<a href=\"");
if (obj.IsEmail)
{
renderer.Write("mailto:");
}
renderer.Write(obj.IsEmail ? "<a href=\"mailto:" : "<a href=\"");
renderer.WriteEscapeUrl(obj.Url);
renderer.Write('"');
renderer.WriteRaw('"');
renderer.WriteAttributes(obj);
if (!obj.IsEmail && !string.IsNullOrWhiteSpace(Rel))
{
renderer.Write($" rel=\"{Rel}\"");
renderer.WriteRaw(" rel=\"");
renderer.WriteRaw(Rel);
renderer.WriteRaw('"');
}
renderer.Write('>');
renderer.WriteRaw('>');
}
renderer.WriteEscape(obj.Url);
if (renderer.EnableHtmlForInline)
{
renderer.Write("</a>");
renderer.WriteRaw("</a>");
}
}
}

View File

@@ -16,7 +16,9 @@ namespace Markdig.Renderers.Html.Inlines
{
if (renderer.EnableHtmlForInline)
{
renderer.Write("<code").WriteAttributes(obj).Write('>');
renderer.Write("<code");
renderer.WriteAttributes(obj);
renderer.WriteRaw('>');
}
if (renderer.EnableHtmlEscape)
{
@@ -28,7 +30,7 @@ namespace Markdig.Renderers.Html.Inlines
}
if (renderer.EnableHtmlForInline)
{
renderer.Write("</code>");
renderer.WriteRaw("</code>");
}
}
}

View File

@@ -39,12 +39,17 @@ namespace Markdig.Renderers.Html.Inlines
if (renderer.EnableHtmlForInline)
{
tag = GetTag(obj);
renderer.Write("<").Write(tag).WriteAttributes(obj).Write('>');
renderer.Write('<');
renderer.WriteRaw(tag);
renderer.WriteAttributes(obj);
renderer.WriteRaw('>');
}
renderer.WriteChildren(obj);
if (renderer.EnableHtmlForInline)
{
renderer.Write("</").Write(tag).Write('>');
renderer.Write("</");
renderer.WriteRaw(tag);
renderer.WriteRaw('>');
}
}
@@ -53,7 +58,7 @@ namespace Markdig.Renderers.Html.Inlines
/// </summary>
/// <param name="obj">The object.</param>
/// <returns></returns>
public string? GetDefaultTag(EmphasisInline obj)
public static string? GetDefaultTag(EmphasisInline obj)
{
if (obj.DelimiterChar is '*' or '_')
{

View File

@@ -19,6 +19,8 @@ namespace Markdig.Renderers.Html.Inlines
protected override void Write(HtmlRenderer renderer, LineBreakInline obj)
{
if (renderer.IsLastInContainer) return;
if (renderer.EnableHtmlForInline)
{
if (obj.IsHard || RenderAsHardlineBreak)

View File

@@ -25,12 +25,15 @@ namespace Markdig.Renderers.Html.Inlines
}
set
{
string rel = "nofollow";
if (value && !Rel.Contains(rel))
const string rel = "nofollow";
if (value)
{
Rel = string.IsNullOrEmpty(Rel) ? rel : Rel + $" {rel}";
if (string.IsNullOrEmpty(Rel))
Rel = rel;
else if (!Rel!.Contains(rel))
Rel += $" {rel}";
}
else if (!value && Rel.Contains(rel))
else if (!value && Rel is not null)
{
Rel = Rel.Replace(rel, string.Empty);
}
@@ -48,14 +51,14 @@ namespace Markdig.Renderers.Html.Inlines
{
renderer.Write(link.IsImage ? "<img src=\"" : "<a href=\"");
renderer.WriteEscapeUrl(link.GetDynamicUrl != null ? link.GetDynamicUrl() ?? link.Url : link.Url);
renderer.Write('"');
renderer.WriteRaw('"');
renderer.WriteAttributes(link);
}
if (link.IsImage)
{
if (renderer.EnableHtmlForInline)
{
renderer.Write(" alt=\"");
renderer.WriteRaw(" alt=\"");
}
var wasEnableHtmlForInline = renderer.EnableHtmlForInline;
renderer.EnableHtmlForInline = false;
@@ -63,22 +66,22 @@ namespace Markdig.Renderers.Html.Inlines
renderer.EnableHtmlForInline = wasEnableHtmlForInline;
if (renderer.EnableHtmlForInline)
{
renderer.Write('"');
renderer.WriteRaw('"');
}
}
if (renderer.EnableHtmlForInline && !string.IsNullOrEmpty(link.Title))
{
renderer.Write(" title=\"");
renderer.WriteRaw(" title=\"");
renderer.WriteEscape(link.Title);
renderer.Write('"');
renderer.WriteRaw('"');
}
if (link.IsImage)
{
if (renderer.EnableHtmlForInline)
{
renderer.Write(" />");
renderer.WriteRaw(" />");
}
}
else
@@ -87,9 +90,11 @@ namespace Markdig.Renderers.Html.Inlines
{
if (!string.IsNullOrWhiteSpace(Rel))
{
renderer.Write($" rel=\"{Rel}\"");
renderer.WriteRaw(" rel=\"");
renderer.WriteRaw(Rel);
renderer.WriteRaw('"');
}
renderer.Write('>');
renderer.WriteRaw('>');
}
renderer.WriteChildren(link);
if (renderer.EnableHtmlForInline)

View File

@@ -22,12 +22,16 @@ namespace Markdig.Renderers.Html
renderer.Write("<ol");
if (listBlock.BulletType != '1')
{
renderer.Write(" type=\"").Write(listBlock.BulletType).Write('"');
renderer.WriteRaw(" type=\"");
renderer.WriteRaw(listBlock.BulletType);
renderer.WriteRaw('"');
}
if (listBlock.OrderedStart != null && (listBlock.OrderedStart is not "1"))
if (listBlock.OrderedStart is not null && listBlock.OrderedStart != "1")
{
renderer.Write(" start=\"").Write(listBlock.OrderedStart).Write('"');
renderer.Write(" start=\"");
renderer.WriteRaw(listBlock.OrderedStart);
renderer.WriteRaw('"');
}
renderer.WriteAttributes(listBlock);
renderer.WriteLine('>');
@@ -49,7 +53,9 @@ namespace Markdig.Renderers.Html
renderer.EnsureLine();
if (renderer.EnableHtmlForBlock)
{
renderer.Write("<li").WriteAttributes(listItem).Write('>');
renderer.Write("<li");
renderer.WriteAttributes(listItem);
renderer.WriteRaw('>');
}
renderer.WriteChildren(listItem);

View File

@@ -21,12 +21,14 @@ namespace Markdig.Renderers.Html
renderer.EnsureLine();
}
renderer.Write("<p").WriteAttributes(obj).Write(">");
renderer.Write("<p");
renderer.WriteAttributes(obj);
renderer.WriteRaw('>');
}
renderer.WriteLeafInline(obj);
if (!renderer.ImplicitParagraph)
{
if(renderer.EnableHtmlForBlock)
if (renderer.EnableHtmlForBlock)
{
renderer.WriteLine("</p>");
}

Some files were not shown because too many files have changed in this diff Show More