mirror of
https://github.com/xoofx/markdig.git
synced 2026-02-11 13:54:50 +00:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9da3eef65f | ||
|
|
0b4fe3f02f | ||
|
|
96b39e1856 | ||
|
|
6d90f517cc | ||
|
|
c17630e3b6 | ||
|
|
6eecfe2edc | ||
|
|
9abeb97394 | ||
|
|
fd493865cf | ||
|
|
d43947af45 | ||
|
|
ab04ac3e00 | ||
|
|
547c00eb5a | ||
|
|
795d002ed0 | ||
|
|
987357ef5a | ||
|
|
613a1d97fb | ||
|
|
874170bc1a | ||
|
|
1c1e56aebe | ||
|
|
ed18d3fa25 | ||
|
|
33a6a39c34 | ||
|
|
a1228a1e1c | ||
|
|
d9f1c8c818 | ||
|
|
60350dc9bf | ||
|
|
dbaed0a2bb | ||
|
|
0aa26aeef1 | ||
|
|
09beb2f867 | ||
|
|
fb559af72b | ||
|
|
124b4d6e6e | ||
|
|
4a2d270db1 | ||
|
|
feac9d4125 | ||
|
|
5e77d7b38e | ||
|
|
9f64dcc868 | ||
|
|
7964bd0160 | ||
|
|
191c1e896e | ||
|
|
4bdf1d4d18 | ||
|
|
080dee270d | ||
|
|
7ae36a3794 | ||
|
|
f43d5be0e7 |
@@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<solution>
|
||||
<add key="disableSourceControlIntegration" value="true" />
|
||||
</solution>
|
||||
<packageSources>
|
||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||
<add key="dotnet-core" value="http://myget.org/F/dotnet-core" />
|
||||
</packageSources>
|
||||
</configuration>
|
||||
@@ -1,150 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">$(MSBuildProjectDirectory)\..\</SolutionDir>
|
||||
|
||||
<!-- Enable the restore command to run before builds -->
|
||||
<RestorePackages Condition=" '$(RestorePackages)' == '' ">false</RestorePackages>
|
||||
|
||||
<!-- Property that enables building a package from a project -->
|
||||
<BuildPackage Condition=" '$(BuildPackage)' == '' ">false</BuildPackage>
|
||||
|
||||
<!-- Determines if package restore consent is required to restore packages -->
|
||||
<RequireRestoreConsent Condition=" '$(RequireRestoreConsent)' != 'false' ">true</RequireRestoreConsent>
|
||||
|
||||
<!-- Download NuGet.exe if it does not already exist -->
|
||||
<DownloadNuGetExe Condition=" '$(DownloadNuGetExe)' == '' ">true</DownloadNuGetExe>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(PackageSources)' == '' ">
|
||||
<!-- Package sources used to restore packages. By default will used the registered sources under %APPDATA%\NuGet\NuGet.Config -->
|
||||
<!--
|
||||
<PackageSource Include="https://nuget.org/api/v2/" />
|
||||
<PackageSource Include="https://my-nuget-source/nuget/" />
|
||||
-->
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT'">
|
||||
<!-- Windows specific commands -->
|
||||
<NuGetToolsPath>$([System.IO.Path]::Combine($(SolutionDir), ".nuget"))</NuGetToolsPath>
|
||||
<PackagesConfig>$([System.IO.Path]::Combine($(ProjectDir), "packages.config"))</PackagesConfig>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(OS)' != 'Windows_NT'">
|
||||
<!-- We need to launch nuget.exe with the mono command if we're not on windows -->
|
||||
<NuGetToolsPath>$(SolutionDir).nuget</NuGetToolsPath>
|
||||
<PackagesConfig>packages.config</PackagesConfig>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<!-- NuGet command -->
|
||||
<NuGetExePath Condition=" '$(NuGetExePath)' == '' ">$(NuGetToolsPath)\nuget.exe</NuGetExePath>
|
||||
<PackageSources Condition=" $(PackageSources) == '' ">@(PackageSource)</PackageSources>
|
||||
|
||||
<NuGetCommand Condition=" '$(OS)' == 'Windows_NT'">"$(NuGetExePath)"</NuGetCommand>
|
||||
<NuGetCommand Condition=" '$(OS)' != 'Windows_NT' ">mono --runtime=v4.0.30319 $(NuGetExePath)</NuGetCommand>
|
||||
|
||||
<PackageOutputDir Condition="$(PackageOutputDir) == ''">$(TargetDir.Trim('\\'))</PackageOutputDir>
|
||||
|
||||
<RequireConsentSwitch Condition=" $(RequireRestoreConsent) == 'true' ">-RequireConsent</RequireConsentSwitch>
|
||||
<!-- Commands -->
|
||||
<RestoreCommand>$(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(RequireConsentSwitch) -solutionDir "$(SolutionDir) "</RestoreCommand>
|
||||
<BuildCommand>$(NuGetCommand) pack "$(ProjectPath)" -p Configuration=$(Configuration) -o "$(PackageOutputDir)" -symbols</BuildCommand>
|
||||
|
||||
<!-- We need to ensure packages are restored prior to assembly resolve -->
|
||||
<ResolveReferencesDependsOn Condition="$(RestorePackages) == 'true'">
|
||||
RestorePackages;
|
||||
$(ResolveReferencesDependsOn);
|
||||
</ResolveReferencesDependsOn>
|
||||
|
||||
<!-- Make the build depend on restore packages -->
|
||||
<BuildDependsOn Condition="$(BuildPackage) == 'true'">
|
||||
$(BuildDependsOn);
|
||||
BuildPackage;
|
||||
</BuildDependsOn>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="CheckPrerequisites">
|
||||
<!-- Raise an error if we're unable to locate nuget.exe -->
|
||||
<Error Condition="'$(DownloadNuGetExe)' != 'true' AND !Exists('$(NuGetExePath)')" Text="Unable to locate '$(NuGetExePath)'" />
|
||||
<SetEnvironmentVariable EnvKey="VisualStudioVersion" EnvValue="$(VisualStudioVersion)" Condition=" '$(VisualStudioVersion)' != '' AND '$(OS)' == 'Windows_NT' " />
|
||||
<!--
|
||||
Take advantage of MsBuild's build dependency tracking to make sure that we only ever download nuget.exe once.
|
||||
This effectively acts as a lock that makes sure that the download operation will only happen once and all
|
||||
parallel builds will have to wait for it to complete.
|
||||
-->
|
||||
<MsBuild Targets="_DownloadNuGet" Projects="$(MSBuildThisFileFullPath)" Properties="Configuration=NOT_IMPORTANT" />
|
||||
</Target>
|
||||
|
||||
<Target Name="_DownloadNuGet">
|
||||
<DownloadNuGet OutputFilename="$(NuGetExePath)" Condition=" '$(DownloadNuGetExe)' == 'true' AND !Exists('$(NuGetExePath)')" />
|
||||
</Target>
|
||||
|
||||
<Target Name="RestorePackages" DependsOnTargets="CheckPrerequisites">
|
||||
<Exec Command="$(RestoreCommand)"
|
||||
Condition="'$(OS)' != 'Windows_NT' And Exists('$(PackagesConfig)')" />
|
||||
|
||||
<Exec Command="$(RestoreCommand)"
|
||||
LogStandardErrorAsError="true"
|
||||
Condition="'$(OS)' == 'Windows_NT' And Exists('$(PackagesConfig)')" />
|
||||
</Target>
|
||||
|
||||
<Target Name="BuildPackage" DependsOnTargets="CheckPrerequisites">
|
||||
<Exec Command="$(BuildCommand)"
|
||||
Condition=" '$(OS)' != 'Windows_NT' " />
|
||||
|
||||
<Exec Command="$(BuildCommand)"
|
||||
LogStandardErrorAsError="true"
|
||||
Condition=" '$(OS)' == 'Windows_NT' " />
|
||||
</Target>
|
||||
|
||||
<UsingTask TaskName="DownloadNuGet" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
|
||||
<ParameterGroup>
|
||||
<OutputFilename ParameterType="System.String" Required="true" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Reference Include="System.Core" />
|
||||
<Using Namespace="System" />
|
||||
<Using Namespace="System.IO" />
|
||||
<Using Namespace="System.Net" />
|
||||
<Using Namespace="Microsoft.Build.Framework" />
|
||||
<Using Namespace="Microsoft.Build.Utilities" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
try {
|
||||
OutputFilename = Path.GetFullPath(OutputFilename);
|
||||
|
||||
Log.LogMessage("Downloading latest version of NuGet.exe...");
|
||||
WebClient webClient = new WebClient();
|
||||
webClient.DownloadFile("https://nuget.org/nuget.exe", OutputFilename);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.LogErrorFromException(ex);
|
||||
return false;
|
||||
}
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
|
||||
<UsingTask TaskName="SetEnvironmentVariable" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
|
||||
<ParameterGroup>
|
||||
<EnvKey ParameterType="System.String" Required="true" />
|
||||
<EnvValue ParameterType="System.String" Required="true" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Using Namespace="System" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
try {
|
||||
Environment.SetEnvironmentVariable(EnvKey, EnvValue, System.EnvironmentVariableTarget.Process);
|
||||
}
|
||||
catch {
|
||||
}
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
</Project>
|
||||
145
readme.md
145
readme.md
@@ -1,9 +1,11 @@
|
||||
# Markdig [](https://www.nuget.org/packages/Markdig/)
|
||||
# Markdig [](https://ci.appveyor.com/project/xoofx/markdig) [](https://www.nuget.org/packages/Markdig/)
|
||||
|
||||
Markdig is a fast, powerfull, [CommonMark](http://commonmark.org/) compliant, extensible Markdown processor for .NET.
|
||||
|
||||
> NOTE: The repository is under construction. There will be a dedicated website and proper documentation at some point!
|
||||
|
||||
You can **try Markdig online** and compare it to other implems on [babelmark3](http://babelmark.github.io/)
|
||||
|
||||
## Features
|
||||
|
||||
- **Very fast parser** (no-regexp), very lightweight in terms of GC pressure. See benchmarks
|
||||
@@ -13,32 +15,33 @@ Markdig is a fast, powerfull, [CommonMark](http://commonmark.org/) compliant, ex
|
||||
- Includes all the core elements of CommonMark:
|
||||
- including GFM fenced code blocks.
|
||||
- **Extensible** architecture
|
||||
- Even the core Markdown/CommonMark parsing is pluggable, so it allows to disable builtin Markdown/Commonmark parsing (e.g [Disable HTML parsing](https://github.com/lunet-io/markdig/blob/7964bd0160d4c18e4155127a4c863d61ebd8944a/src/Markdig/MarkdownExtensions.cs#L306)) or change behaviour (e.g change matching `#` of a headers with `@`)
|
||||
- Built-in with **18+ extensions**, including:
|
||||
- **Abbreviations** (inspired from [PHP Markdown Extra - Abbreviations](https://michelf.ca/projects/php-markdown/extra/#abbr))
|
||||
- **Auto-identifiers** for headings (similar to [Pandoc](http://pandoc.org/README.html#extension-auto_identifiers)
|
||||
- **Bootstrap** class (to output bootstrap class)
|
||||
- **Citation** text by enclosing `""...""` (inspired by this [CommonMark discussion ](https://talk.commonmark.org/t/referencing-creative-works-with-cite/892))
|
||||
- **Custom containers** similar to fenced code block `:::` for generating a proper `<div>...</div>` instead (inspired by this [CommonMark discussion ](https://talk.commonmark.org/t/custom-container-for-block-and-inline/2051))
|
||||
- **Definition lists** (inspired from [PHP Markdown Extra - Definitions Lists](https://michelf.ca/projects/php-markdown/extra/#def-list))
|
||||
- **Emoji** support (inspired from [Markdown-it](https://markdown-it.github.io/))
|
||||
- **Extra emphasis** (inspired from [Pandoc](http://pandoc.org/README.html#strikeout) and [Markdown-it](https://markdown-it.github.io/))
|
||||
- 2 kind of tables:
|
||||
- **Pipe tables** (inspired from Github tables and [PanDoc - Pipe Tables](http://pandoc.org/README.html#extension-pipe_tables))
|
||||
- **Grid tables** (inspired from [Pandoc - Grid Tables](http://pandoc.org/README.html#extension-grid_tables))
|
||||
- **Extra emphasis** (inspired from [Pandoc - Emphasis](http://pandoc.org/README.html#strikeout) and [Markdown-it](https://markdown-it.github.io/))
|
||||
- strike through `~~`,
|
||||
- Subscript `~`
|
||||
- Superscript `^`
|
||||
- Inserted `++`
|
||||
- Marked `==`
|
||||
- **Special attributes** or attached HTML attributes (inspired from [PHP Markdown Extra - Special Attributes](https://michelf.ca/projects/php-markdown/extra/#spe-attr))
|
||||
- **Definition lists** (inspired from [PHP Markdown Extra - Definitions Lists](https://michelf.ca/projects/php-markdown/extra/#def-list))
|
||||
- **Footnotes** (inspired from [PHP Markdown Extra - Footnotes](https://michelf.ca/projects/php-markdown/extra/#footnotes))
|
||||
- **Auto-identifiers** for headings (similar to [Pandoc - Auto Identifiers](http://pandoc.org/README.html#extension-auto_identifiers))
|
||||
- **Extra bullet lists**, supporting alpha bullet `a.` `b.` and roman bullet (`i`, `ii`...etc.)
|
||||
- **Media support** for media url (youtube, vimeo, mp4...etc.) (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/embedded-audio-and-video/441))
|
||||
- **Abbreviations** (inspired from [PHP Markdown Extra - Abbreviations](https://michelf.ca/projects/php-markdown/extra/#abbr))
|
||||
- **Citation** text by enclosing `""...""` (inspired by this [CommonMark discussion ](https://talk.commonmark.org/t/referencing-creative-works-with-cite/892))
|
||||
- **Custom containers** similar to fenced code block `:::` for generating a proper `<div>...</div>` instead (inspired by this [CommonMark discussion ](https://talk.commonmark.org/t/custom-container-for-block-and-inline/2051))
|
||||
- **Figures** (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/image-tag-should-expand-to-figure-when-used-with-title/265/5))
|
||||
- **Footers** (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/syntax-for-footer/2070))
|
||||
- **Footnotes** (inspired from [PHP Markdown Extra - Footnotes](https://michelf.ca/projects/php-markdown/extra/#footnotes))
|
||||
- **Special attributes** or attached HTML attributes (inspired from [PHP Markdown Extra - Footnotes](https://michelf.ca/projects/php-markdown/extra/#spe-attr))
|
||||
- **Soft lines as hard lines**
|
||||
- **Extra bullet lists**, supporting alpha bullet `a.` `b.` and roman bullet (`i`, `ii`...etc.)
|
||||
- **Mathematics**/Latex extension by enclosing `$$` for block and `$` for inline math (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/mathematics-extension/457/31))
|
||||
- **Embed player** for media url (youtube, vimeo, mp4...etc.) (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/embedded-audio-and-video/441))
|
||||
- **Soft lines as hard lines**
|
||||
- **Emoji** support (inspired from [Markdown-it](https://markdown-it.github.io/))
|
||||
- **SmartyPants** (inspired from [Daring Fireball - SmartyPants](https://daringfireball.net/projects/smartypants/))
|
||||
- Tables:
|
||||
- **Pipe tables** (inspired from Kramdown/[PanDoc](http://pandoc.org/README.html#pipe_tables))
|
||||
- **Grid tables** (inspired from [Pandoc](http://pandoc.org/README.html#grid_tables))
|
||||
- **Bootstrap** class (to output bootstrap class)
|
||||
- Compatible with .NET 3.5, 4.0+ and .NET Core (`netstandard1.1+`)
|
||||
|
||||
## Download
|
||||
@@ -47,40 +50,110 @@ Markdig is available as a NuGet package: [;
|
||||
var result = Markdown.ToHtml("This is a text with some *emphasis*");
|
||||
Console.WriteLine(result); // prints: <p>This is a text with some <em>emphasis</em></p>
|
||||
```
|
||||
|
||||
In order to activate all extensions (except Emoji)
|
||||
In order to activate most of all advanced extensions (except Emoji, SoftLine as HarLine and SmartyPants)
|
||||
|
||||
```csharp
|
||||
var result = Markdown.ToHtml("This is a text with some **emphasis**", new MarkdownPipeline().UseAllExtensions());
|
||||
// Configure the pipeline with all advanced extensions active
|
||||
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
|
||||
var result = Markdown.ToHtml("This is a text with some *emphasis*", pipeline);
|
||||
```
|
||||
|
||||
You can have a look at the [MarkdownPipeline](https://github.com/lunet-io/markdig/blob/src/Markdig/MarkdownPipeline.cs) file that describes all actionable extensions.
|
||||
You can have a look at the [MarkdownExtensions](https://github.com/lunet-io/markdig/blob/master/src/Markdig/MarkdownExtensions.cs) that describes all actionable extensions (by modifying the MarkdownPipeline)
|
||||
|
||||
## License
|
||||
|
||||
This software is released under the [BSD-Clause 2 license](http://opensource.org/licenses/BSD-2-Clause).
|
||||
This software is released under the [BSD-Clause 2 license](https://github.com/lunet-io/markdig/blob/master/license.txt).
|
||||
|
||||
|
||||
## Benchmarking
|
||||
|
||||
This is an early preview of the benchmarking against various implementations:
|
||||
|
||||
- Markdig: itself
|
||||
- CommonMarkCpp: [cmark](https://github.com/jgm/cmark), Reference C implementation of CommonMark, no support for extensions
|
||||
- [CommonMark.NET](https://github.com/Knagis/CommonMark.NET): CommonMark implementation for .NET, no support for extensions, port of cmark
|
||||
- [CommonMarkNet (devel)](https://github.com/AMDL/CommonMark.NET/tree/pipe-tables): An evolution of CommonMark.NET, supports extensions, not released yet
|
||||
- [MarkdownDeep](https://github.com/toptensoftware/markdowndeep) another .NET implementation
|
||||
- [MarkdownSharp](https://github.com/Kiri-rin/markdownsharp): Open source C# implementation of Markdown processor, as featured on Stack Overflow, regexp based.
|
||||
- [Moonshine](https://github.com/brandonc/moonshine): popular C Markdown processor
|
||||
|
||||
Markdig is roughly x100 times faster than MarkdownSharp and extremelly competitive to other implems (that are not feature wise comparable)
|
||||
|
||||
Performance in x86:
|
||||
|
||||
```
|
||||
// * Summary *
|
||||
|
||||
BenchmarkDotNet-Dev=v0.9.6.0+
|
||||
OS=Microsoft Windows NT 6.2.9200.0
|
||||
Processor=Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz, ProcessorCount=8
|
||||
Frequency=3319351 ticks, Resolution=301.2637 ns, Timer=TSC
|
||||
HostCLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE
|
||||
JitModules=clrjit-v4.6.1080.0
|
||||
|
||||
Type=Program Mode=SingleRun LaunchCount=2
|
||||
WarmupCount=2 TargetCount=10
|
||||
|
||||
Method | Median | StdDev | Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op |
|
||||
--------------------- |---------- |---------- |------- |------ |------- |------------------- |
|
||||
TestMarkdig | 5.4870 ms | 0.0158 ms | 193.00 | 12.00 | 84.00 | 1,425,192.72 |
|
||||
TestCommonMarkCpp | 4.0134 ms | 0.1008 ms | - | - | 180.00 | 454,859.74 |
|
||||
TestCommonMarkNet | 4.6139 ms | 0.0581 ms | 193.00 | 12.00 | 84.00 | 1,406,367.27 |
|
||||
TestCommonMarkNetNew | 5.5327 ms | 0.0461 ms | 193.00 | 96.00 | 84.00 | 1,738,465.42 |
|
||||
TestMarkdownDeep | 7.5910 ms | 0.1006 ms | 205.00 | 96.00 | 84.00 | 1,758,383.79 |
|
||||
TestMoonshine | 5.8843 ms | 0.1758 ms | - | - | 215.00 | 565,000.73 |
|
||||
|
||||
// * Diagnostic Output - MemoryDiagnoser *
|
||||
|
||||
|
||||
// ***** BenchmarkRunner: End *****
|
||||
```
|
||||
|
||||
Performance for x64:
|
||||
|
||||
```
|
||||
// * Summary *
|
||||
|
||||
BenchmarkDotNet-Dev=v0.9.6.0+
|
||||
OS=Microsoft Windows NT 6.2.9200.0
|
||||
Processor=Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz, ProcessorCount=8
|
||||
Frequency=3319351 ticks, Resolution=301.2637 ns, Timer=TSC
|
||||
HostCLR=MS.NET 4.0.30319.42000, Arch=64-bit RELEASE [RyuJIT]
|
||||
JitModules=clrjit-v4.6.1080.0
|
||||
|
||||
Type=Program Mode=SingleRun LaunchCount=2
|
||||
WarmupCount=2 TargetCount=10
|
||||
|
||||
Method | Median | StdDev | Gen 0 | Gen 1 | Gen 2 | Bytes Allocated/Op |
|
||||
--------------------- |---------- |---------- |------- |------- |------ |------------------- |
|
||||
TestMarkdig | 5.9539 ms | 0.0495 ms | 157.00 | 96.00 | 84.00 | 1,767,834.52 |
|
||||
TestCommonMarkNet | 4.3158 ms | 0.0161 ms | 157.00 | 96.00 | 84.00 | 1,747,432.06 |
|
||||
TestCommonMarkNetNew | 5.3421 ms | 0.0435 ms | 229.00 | 168.00 | 84.00 | 2,323,922.97 |
|
||||
TestMarkdownDeep | 7.4750 ms | 0.0281 ms | 318.00 | 186.00 | 84.00 | 2,576,728.69 |
|
||||
|
||||
// * Diagnostic Output - MemoryDiagnoser *
|
||||
|
||||
|
||||
// ***** BenchmarkRunner: End *****
|
||||
```
|
||||
|
||||
## Credits
|
||||
|
||||
Thanks to the fantastic work done by [John Mac Farlane](http://johnmacfarlane.net/) for the CommonMark specs and all the people involved in making Markdown a better standard!
|
||||
|
||||
This project would not have been possible without this huge foundation.
|
||||
|
||||
Thanks also to the project [BenchmarkDotNet](https://github.com/PerfDotNet/BenchmarkDotNet) that makes benchmarking so easy to setup!
|
||||
|
||||
## Author
|
||||
|
||||
Alexandre MUTEL aka [xoofx](http://xoofx.com)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -98,6 +98,14 @@ This is ``a code span''``
|
||||
<p>This is <code>a code span''</code></p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
hello ``there```
|
||||
test
|
||||
.
|
||||
<p>hello “there”`
|
||||
test</p>
|
||||
````````````````````````````````
|
||||
|
||||
An emphasis starting inside left/right quotes will span over the right quote:
|
||||
|
||||
```````````````````````````````` example
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Markdig.Tests
|
||||
// articles, slide shows, letters, and lecture notes.
|
||||
//
|
||||
// What distinguishes Markdown from many other lightweight markup
|
||||
// syntaxes, which are often easier to write, is its readibility.
|
||||
// syntaxes, which are often easier to write, is its readability.
|
||||
// As Gruber writes:
|
||||
//
|
||||
// > The overriding design goal for Markdown's formatting syntax is
|
||||
@@ -17088,7 +17088,7 @@ namespace Markdig.Tests
|
||||
// <p>The following text <del>is deleted</del></p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 1, "Extensions Strikethrough");
|
||||
TestParser.TestSpec("The following text ~~is deleted~~", "<p>The following text <del>is deleted</del></p>", "emphasis_extra");
|
||||
TestParser.TestSpec("The following text ~~is deleted~~", "<p>The following text <del>is deleted</del></p>", "emphasisextra");
|
||||
}
|
||||
}
|
||||
// ## Superscript and Subscript
|
||||
@@ -17110,7 +17110,7 @@ namespace Markdig.Tests
|
||||
// <p>H<sub>2</sub>O is a liquid. 2<sup>10</sup> is 1024</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 2, "Extensions Superscript and Subscript");
|
||||
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>", "emphasis_extra");
|
||||
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>", "emphasisextra");
|
||||
}
|
||||
}
|
||||
// ## Inserted
|
||||
@@ -17132,7 +17132,7 @@ namespace Markdig.Tests
|
||||
// <p><ins>Inserted text</ins></p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 3, "Extensions Inserted");
|
||||
TestParser.TestSpec("++Inserted text++", "<p><ins>Inserted text</ins></p>", "emphasis_extra");
|
||||
TestParser.TestSpec("++Inserted text++", "<p><ins>Inserted text</ins></p>", "emphasisextra");
|
||||
}
|
||||
}
|
||||
// ## Marked
|
||||
@@ -17154,7 +17154,7 @@ namespace Markdig.Tests
|
||||
// <p><mark>Marked text</mark></p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 4, "Extensions Marked");
|
||||
TestParser.TestSpec("==Marked text==", "<p><mark>Marked text</mark></p>", "emphasis_extra");
|
||||
TestParser.TestSpec("==Marked text==", "<p><mark>Marked text</mark></p>", "emphasisextra");
|
||||
}
|
||||
}
|
||||
// # Extensions
|
||||
@@ -17991,7 +17991,7 @@ namespace Markdig.Tests
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 1, "Extensions Ordered list with alpha letter");
|
||||
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>", "list_extra");
|
||||
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>", "listextra");
|
||||
}
|
||||
}
|
||||
// It works also for uppercase alpha:
|
||||
@@ -18017,7 +18017,7 @@ namespace Markdig.Tests
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 2, "Extensions Ordered list with alpha letter");
|
||||
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>", "list_extra");
|
||||
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>", "listextra");
|
||||
}
|
||||
}
|
||||
// Like for numbered list, a list can start with a different letter
|
||||
@@ -18041,7 +18041,7 @@ namespace Markdig.Tests
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 3, "Extensions Ordered list with alpha letter");
|
||||
TestParser.TestSpec("b. First item\nc. Second item", "<ol type=\"a\" start=\"b\">\n<li>First item</li>\n<li>Second item</li>\n</ol>", "list_extra");
|
||||
TestParser.TestSpec("b. First item\nc. Second item", "<ol type=\"a\" start=\"b\">\n<li>First item</li>\n<li>Second item</li>\n</ol>", "listextra");
|
||||
}
|
||||
}
|
||||
// A different type of list will break the existing list:
|
||||
@@ -18069,7 +18069,7 @@ namespace Markdig.Tests
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 4, "Extensions Ordered list with alpha letter");
|
||||
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>", "list_extra");
|
||||
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>", "listextra");
|
||||
}
|
||||
}
|
||||
// ## Ordered list with roman letter
|
||||
@@ -18099,7 +18099,7 @@ namespace Markdig.Tests
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 5, "Extensions Ordered list with roman letter");
|
||||
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>", "list_extra");
|
||||
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>", "listextra");
|
||||
}
|
||||
}
|
||||
// It works also for uppercase alpha:
|
||||
@@ -18127,7 +18127,7 @@ namespace Markdig.Tests
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 6, "Extensions Ordered list with roman letter");
|
||||
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>", "list_extra");
|
||||
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>", "listextra");
|
||||
}
|
||||
}
|
||||
// Like for numbered list, a list can start with a different letter
|
||||
@@ -18151,7 +18151,7 @@ namespace Markdig.Tests
|
||||
// </ol>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 7, "Extensions Ordered list with roman letter");
|
||||
TestParser.TestSpec("ii. First item\niii. Second item", "<ol type=\"i\" start=\"ii\">\n<li>First item</li>\n<li>Second item</li>\n</ol>", "list_extra");
|
||||
TestParser.TestSpec("ii. First item\niii. Second item", "<ol type=\"i\" start=\"ii\">\n<li>First item</li>\n<li>Second item</li>\n</ol>", "listextra");
|
||||
}
|
||||
}
|
||||
// # Extensions
|
||||
@@ -18863,7 +18863,6 @@ namespace Markdig.Tests
|
||||
TestParser.TestSpec("This is ``a code span''`` ", "<p>This is <code>a code span''</code></p>", "smartypants");
|
||||
}
|
||||
}
|
||||
// An emphasis starting inside left/right quotes will span over the right quote:
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
@@ -18874,35 +18873,38 @@ namespace Markdig.Tests
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is "a *text" with an emphasis*
|
||||
// hello ``there```
|
||||
// test
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is “a <em>text” with an emphasis</em></p>
|
||||
// <p>hello “there”`
|
||||
// test</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 15, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is \"a *text\" with an emphasis*", "<p>This is “a <em>text” with an emphasis</em></p>", "smartypants");
|
||||
TestParser.TestSpec("hello ``there```\ntest", "<p>hello “there”`\ntest</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
// ## SmartyPants Separators
|
||||
// An emphasis starting inside left/right quotes will span over the right quote:
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsSeparators
|
||||
public partial class TestExtensionsSmartyPantsQuotes
|
||||
{
|
||||
[Test]
|
||||
public void Example016()
|
||||
{
|
||||
// Example 16
|
||||
// Section: Extensions SmartyPants Separators
|
||||
// Section: Extensions SmartyPants Quotes
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a -- text
|
||||
// This is "a *text" with an emphasis*
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a – text</p>
|
||||
// <p>This is “a <em>text” with an emphasis</em></p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 16, "Extensions SmartyPants Separators");
|
||||
TestParser.TestSpec("This is a -- text", "<p>This is a – text</p>", "smartypants");
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 16, "Extensions SmartyPants Quotes");
|
||||
TestParser.TestSpec("This is \"a *text\" with an emphasis*", "<p>This is “a <em>text” with an emphasis</em></p>", "smartypants");
|
||||
}
|
||||
}
|
||||
// ## SmartyPants Separators
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsSeparators
|
||||
{
|
||||
@@ -18913,13 +18915,13 @@ namespace Markdig.Tests
|
||||
// Section: Extensions SmartyPants Separators
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a --- text
|
||||
// This is a -- text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a — text</p>
|
||||
// <p>This is a – text</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 17, "Extensions SmartyPants Separators");
|
||||
TestParser.TestSpec("This is a --- text", "<p>This is a — text</p>", "smartypants");
|
||||
TestParser.TestSpec("This is a -- text", "<p>This is a – text</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
@@ -18932,12 +18934,31 @@ namespace Markdig.Tests
|
||||
// Section: Extensions SmartyPants Separators
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a --- text
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a — text</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 18, "Extensions SmartyPants Separators");
|
||||
TestParser.TestSpec("This is a --- text", "<p>This is a — text</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
[TestFixture]
|
||||
public partial class TestExtensionsSmartyPantsSeparators
|
||||
{
|
||||
[Test]
|
||||
public void Example019()
|
||||
{
|
||||
// Example 19
|
||||
// Section: Extensions SmartyPants Separators
|
||||
//
|
||||
// The following CommonMark:
|
||||
// This is a en ellipsis...
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p>This is a en ellipsis…</p>
|
||||
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 18, "Extensions SmartyPants Separators");
|
||||
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 19, "Extensions SmartyPants Separators");
|
||||
TestParser.TestSpec("This is a en ellipsis...", "<p>This is a en ellipsis…</p>", "smartypants");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,14 +42,14 @@ SOFTWARE.
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("PipeTableSpecs.md"), "pipetables"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("FootnotesSpecs.md"), "footnotes"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("GenericAttributesSpecs.md"), "attributes"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("EmphasisExtraSpecs.md"), "emphasis_extra"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("EmphasisExtraSpecs.md"), "emphasisextra"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("HardlineBreakSpecs.md"), "hardlinebreak"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("GridTableSpecs.md"), "gridtables"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("CustomContainerSpecs.md"), "customcontainers+attributes"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("DefinitionListSpecs.md"), "definitionlists+attributes"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("EmojiSpecs.md"), "emojis"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("AbbreviationSpecs.md"), "abbreviations"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("ListExtraSpecs.md"), "list_extra"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("ListExtraSpecs.md"), "listextra"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("FigureFooterAndCiteSpecs.md"), "figures+footers+cites"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("MathSpecs.md"), "math"),
|
||||
new KeyValuePair<string, string>(Host.ResolvePath("BootstrapSpecs.md"), "bootstrap+pipetables+figures+attributes"),
|
||||
|
||||
@@ -14,10 +14,10 @@ namespace Markdig.Tests
|
||||
{
|
||||
foreach (var pipeline in GetPipeline(extensions))
|
||||
{
|
||||
Console.WriteLine($"Pipeline configured with extensions: {extensions}");
|
||||
Console.WriteLine($"Pipeline configured with extensions: {pipeline.Key}");
|
||||
// Uncomment this line to get more debug information for process inlines.
|
||||
//pipeline.DebugLog = Console.Out;
|
||||
var result = Markdown.ToHtml(inputText, pipeline);
|
||||
var result = Markdown.ToHtml(inputText, pipeline.Value);
|
||||
|
||||
result = Compact(result);
|
||||
expectedOutputText = Compact(expectedOutputText);
|
||||
@@ -34,86 +34,38 @@ namespace Markdig.Tests
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<MarkdownPipeline> GetPipeline(string extensionsGroupText)
|
||||
private static IEnumerable<KeyValuePair<string, MarkdownPipeline>> GetPipeline(string extensionsGroupText)
|
||||
{
|
||||
// For the standard case, we make sure that both the CommmonMark core and Extra/Advanced are CommonMark compliant!
|
||||
if (string.IsNullOrEmpty(extensionsGroupText))
|
||||
{
|
||||
yield return new MarkdownPipeline();
|
||||
yield return new KeyValuePair<string, MarkdownPipeline>("default", new MarkdownPipelineBuilder().Build());
|
||||
|
||||
yield return new KeyValuePair<string, MarkdownPipeline>("advanced", new MarkdownPipelineBuilder() // Use similar to advanced extension without auto-identifier
|
||||
.UseAbbreviation()
|
||||
//.UseAutoIdentifier()
|
||||
.UseCite()
|
||||
.UseCustomContainer()
|
||||
.UseDefinitionList()
|
||||
.UseEmphasisExtra()
|
||||
.UseFigure()
|
||||
.UseFooter()
|
||||
.UseFootnotes()
|
||||
.UseGridTable()
|
||||
.UseMath()
|
||||
.UseMedia()
|
||||
.UsePipeTable()
|
||||
.UseListExtra()
|
||||
.UseGenericAttributes().Build());
|
||||
|
||||
yield break;
|
||||
}
|
||||
|
||||
var extensionGroups = extensionsGroupText.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var extensionsText in extensionGroups)
|
||||
{
|
||||
var pipeline = new MarkdownPipeline();
|
||||
foreach (var extension in extensionsText.Split(new[] { '+' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
switch (extension.ToLowerInvariant())
|
||||
{
|
||||
case "pipetables":
|
||||
pipeline.UsePipeTable();
|
||||
break;
|
||||
case "emphasis_extra":
|
||||
pipeline.UseEmphasisExtra();
|
||||
break;
|
||||
case "list_extra":
|
||||
pipeline.UseListExtra();
|
||||
break;
|
||||
case "hardlinebreak":
|
||||
pipeline.UseSoftlineBreakAsHardlineBreak();
|
||||
break;
|
||||
case "footnotes":
|
||||
pipeline.UseFootnotes();
|
||||
break;
|
||||
case "footers":
|
||||
pipeline.UseFooter();
|
||||
break;
|
||||
case "cites":
|
||||
pipeline.UseCite();
|
||||
break;
|
||||
case "attributes":
|
||||
pipeline.UseGenericAttributes();
|
||||
break;
|
||||
case "gridtables":
|
||||
pipeline.UseGridTable();
|
||||
break;
|
||||
case "abbreviations":
|
||||
pipeline.UseAbbreviation();
|
||||
break;
|
||||
case "emojis":
|
||||
pipeline.UseEmojiAndSmiley();
|
||||
break;
|
||||
case "definitionlists":
|
||||
pipeline.UseDefinitionList();
|
||||
break;
|
||||
case "customcontainers":
|
||||
pipeline.UseCustomContainer();
|
||||
break;
|
||||
case "figures":
|
||||
pipeline.UseFigure();
|
||||
break;
|
||||
case "math":
|
||||
pipeline.UseMath();
|
||||
break;
|
||||
case "bootstrap":
|
||||
pipeline.UseBootstrap();
|
||||
break;
|
||||
case "medias":
|
||||
pipeline.UseMedia();
|
||||
break;
|
||||
case "smartypants":
|
||||
pipeline.UseSmartyPants();
|
||||
break;
|
||||
case "autoidentifiers":
|
||||
pipeline.UseAutoIdentifier();
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"Unsupported extension: {extension}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
yield return pipeline;
|
||||
var pipeline = new MarkdownPipelineBuilder().Configure(extensionsText);
|
||||
yield return new KeyValuePair<string, MarkdownPipeline>(extensionsText, pipeline.Build());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,39 +22,52 @@ Later in a text we are using HTML and it becomes an abbr tag HTML
|
||||
//");
|
||||
|
||||
//var result = Markdown.ToHtml(text, new MarkdownPipeline().UseFootnotes().UseEmphasisExtra());
|
||||
var result = Markdown.ToHtml(text, new MarkdownPipeline().UseAbbreviation());
|
||||
var result = Markdown.ToHtml(text, new MarkdownPipelineBuilder().UseAbbreviation().Build());
|
||||
//File.WriteAllText("test.html", result, Encoding.UTF8);
|
||||
Console.WriteLine(result);
|
||||
}
|
||||
|
||||
// Test for emoji and smileys
|
||||
// var text = @" This is a test with a :) and a :angry: smiley";
|
||||
[Test]
|
||||
public void TestSamePipelineAllExtensions()
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build();
|
||||
|
||||
// Reuse the same pipeline
|
||||
var result1 = Markdown.ToHtml("This is a \"\"citation\"\"", pipeline);
|
||||
var result2 = Markdown.ToHtml("This is a \"\"citation\"\"", pipeline);
|
||||
|
||||
Assert.AreEqual("<p>This is a <cite>citation</cite></p>", result1.Trim());
|
||||
Assert.AreEqual(result1, result2);
|
||||
}
|
||||
|
||||
// Test for emoji and smileys
|
||||
// var text = @" This is a test with a :) and a :angry: smiley";
|
||||
|
||||
|
||||
// Test for definition lists:
|
||||
//
|
||||
// var text = @"
|
||||
//Term 1
|
||||
//: This is a definition item
|
||||
// With a paragraph
|
||||
// > This is a block quote
|
||||
// Test for definition lists:
|
||||
//
|
||||
// var text = @"
|
||||
//Term 1
|
||||
//: This is a definition item
|
||||
// With a paragraph
|
||||
// > This is a block quote
|
||||
|
||||
// - This is a list
|
||||
// - item2
|
||||
// - This is a list
|
||||
// - item2
|
||||
|
||||
// ```java
|
||||
// Test
|
||||
// ```java
|
||||
// Test
|
||||
|
||||
|
||||
// ```
|
||||
// ```
|
||||
|
||||
// And a lazy line
|
||||
//: This ia another definition item
|
||||
// And a lazy line
|
||||
//: This ia another definition item
|
||||
|
||||
//Term2
|
||||
//Term3 *with some inline*
|
||||
//: This is another definition for term2
|
||||
//";
|
||||
//Term2
|
||||
//Term3 *with some inline*
|
||||
//: This is another definition for term2
|
||||
//";
|
||||
|
||||
|
||||
// Test for grid table
|
||||
|
||||
48
src/Markdig.WebApp/ApiController.cs
Normal file
48
src/Markdig.WebApp/ApiController.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Markdig.WebApp
|
||||
{
|
||||
public class ApiController : Controller
|
||||
{
|
||||
// GET api/to_html?text=xxx&extensions=advanced
|
||||
[Route("api/to_html")]
|
||||
[HttpGet()]
|
||||
public object Get([FromQuery] string text, [FromQuery] string extension)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (text == null)
|
||||
{
|
||||
text = string.Empty;
|
||||
}
|
||||
|
||||
if (text.Length > 1000)
|
||||
{
|
||||
text = text.Substring(0, 1000);
|
||||
}
|
||||
|
||||
var pipeline = new MarkdownPipelineBuilder().Configure(extension).Build();
|
||||
var result = Markdown.ToHtml(text, pipeline);
|
||||
|
||||
return new {name = "markdig", html = result, version = Markdown.Version};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new { name = "markdig", html = "exception: " + GetPrettyMessageFromException(ex), version = Markdown.Version };
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetPrettyMessageFromException(Exception exception)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
while (exception != null)
|
||||
{
|
||||
builder.Append(exception.Message);
|
||||
exception = exception.InnerException;
|
||||
}
|
||||
return builder.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
19
src/Markdig.WebApp/Markdig.WebApp.xproj
Normal file
19
src/Markdig.WebApp/Markdig.WebApp.xproj
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>3cad9801-9976-46be-baca-f6d0d21fdc00</ProjectGuid>
|
||||
<RootNamespace>Markdig.WebApp</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
25
src/Markdig.WebApp/Program.cs
Normal file
25
src/Markdig.WebApp/Program.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
||||
namespace Markdig.WebApp
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>()
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
# Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
|
||||
# Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
[cmdletbinding(SupportsShouldProcess=$true)]
|
||||
param($publishProperties=@{}, $packOutput, $pubProfilePath, $nugetUrl)
|
||||
|
||||
# to learn more about this file visit https://go.microsoft.com/fwlink/?LinkId=524327
|
||||
$publishModuleVersion = '1.1.0'
|
||||
|
||||
function Get-PublishModulePath{
|
||||
[cmdletbinding()]
|
||||
param()
|
||||
process{
|
||||
$keysToCheck = @('hklm:\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\{0}',
|
||||
'hklm:\SOFTWARE\Microsoft\VisualStudio\{0}',
|
||||
'hklm:\SOFTWARE\Wow6432Node\Microsoft\VWDExpress\{0}',
|
||||
'hklm:\SOFTWARE\Microsoft\VWDExpress\{0}'
|
||||
)
|
||||
$versions = @('14.0', '15.0')
|
||||
|
||||
[string]$publishModulePath=$null
|
||||
:outer foreach($keyToCheck in $keysToCheck){
|
||||
foreach($version in $versions){
|
||||
if(Test-Path ($keyToCheck -f $version) ){
|
||||
$vsInstallPath = (Get-itemproperty ($keyToCheck -f $version) -Name InstallDir -ErrorAction SilentlyContinue | select -ExpandProperty InstallDir -ErrorAction SilentlyContinue)
|
||||
|
||||
if($vsInstallPath){
|
||||
$installedPublishModulePath = "{0}Extensions\Microsoft\Web Tools\Publish\Scripts\{1}\" -f $vsInstallPath, $publishModuleVersion
|
||||
if(!(Test-Path $installedPublishModulePath)){
|
||||
$vsInstallPath = $vsInstallPath + 'VWDExpress'
|
||||
$installedPublishModulePath = "{0}Extensions\Microsoft\Web Tools\Publish\Scripts\{1}\" -f $vsInstallPath, $publishModuleVersion
|
||||
}
|
||||
if(Test-Path $installedPublishModulePath){
|
||||
$publishModulePath = $installedPublishModulePath
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$publishModulePath
|
||||
}
|
||||
}
|
||||
|
||||
$publishModulePath = Get-PublishModulePath
|
||||
|
||||
$defaultPublishSettings = New-Object psobject -Property @{
|
||||
LocalInstallDir = $publishModulePath
|
||||
}
|
||||
|
||||
function Enable-PackageDownloader{
|
||||
[cmdletbinding()]
|
||||
param(
|
||||
$toolsDir = "$env:LOCALAPPDATA\Microsoft\Web Tools\Publish\package-downloader-$publishModuleVersion\",
|
||||
$pkgDownloaderDownloadUrl = 'https://go.microsoft.com/fwlink/?LinkId=524325') # package-downloader.psm1
|
||||
process{
|
||||
if(get-module package-downloader){
|
||||
remove-module package-downloader | Out-Null
|
||||
}
|
||||
|
||||
if(!(get-module package-downloader)){
|
||||
if(!(Test-Path $toolsDir)){ New-Item -Path $toolsDir -ItemType Directory -WhatIf:$false }
|
||||
|
||||
$expectedPath = (Join-Path ($toolsDir) 'package-downloader.psm1')
|
||||
if(!(Test-Path $expectedPath)){
|
||||
'Downloading [{0}] to [{1}]' -f $pkgDownloaderDownloadUrl,$expectedPath | Write-Verbose
|
||||
(New-Object System.Net.WebClient).DownloadFile($pkgDownloaderDownloadUrl, $expectedPath)
|
||||
}
|
||||
|
||||
if(!$expectedPath){throw ('Unable to download package-downloader.psm1')}
|
||||
|
||||
'importing module [{0}]' -f $expectedPath | Write-Output
|
||||
Import-Module $expectedPath -DisableNameChecking -Force
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Enable-PublishModule{
|
||||
[cmdletbinding()]
|
||||
param()
|
||||
process{
|
||||
if(get-module publish-module){
|
||||
remove-module publish-module | Out-Null
|
||||
}
|
||||
|
||||
if(!(get-module publish-module)){
|
||||
$localpublishmodulepath = Join-Path $defaultPublishSettings.LocalInstallDir 'publish-module.psm1'
|
||||
if(Test-Path $localpublishmodulepath){
|
||||
'importing module [publish-module="{0}"] from local install dir' -f $localpublishmodulepath | Write-Verbose
|
||||
Import-Module $localpublishmodulepath -DisableNameChecking -Force
|
||||
$true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try{
|
||||
|
||||
if (!(Enable-PublishModule)){
|
||||
Enable-PackageDownloader
|
||||
Enable-NuGetModule -name 'publish-module' -version $publishModuleVersion -nugetUrl $nugetUrl
|
||||
}
|
||||
|
||||
'Calling Publish-AspNet' | Write-Verbose
|
||||
# call Publish-AspNet to perform the publish operation
|
||||
Publish-AspNet -publishProperties $publishProperties -packOutput $packOutput -pubProfilePath $pubProfilePath
|
||||
}
|
||||
catch{
|
||||
"An error occurred during publish.`n{0}" -f $_.Exception.Message | Write-Error
|
||||
}
|
||||
28
src/Markdig.WebApp/Properties/launchSettings.json
Normal file
28
src/Markdig.WebApp/Properties/launchSettings.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:65396/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "api/values",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Markdig.WebApp": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"launchUrl": "http://localhost:5000/api/to_html?text=yes",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
src/Markdig.WebApp/Startup.cs
Normal file
56
src/Markdig.WebApp/Startup.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Markdig.WebApp
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IHostingEnvironment env)
|
||||
{
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(env.ContentRootPath)
|
||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
|
||||
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
|
||||
|
||||
if (env.IsEnvironment("Development"))
|
||||
{
|
||||
// This will push telemetry data through Application Insights pipeline faster, allowing you to view results immediately.
|
||||
builder.AddApplicationInsightsSettings(developerMode: true);
|
||||
}
|
||||
|
||||
builder.AddEnvironmentVariables();
|
||||
Configuration = builder.Build();
|
||||
}
|
||||
|
||||
public IConfigurationRoot Configuration { get; }
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Add framework services.
|
||||
services.AddApplicationInsightsTelemetry(Configuration);
|
||||
|
||||
services.AddMvc();
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
|
||||
loggerFactory.AddDebug();
|
||||
|
||||
app.UseApplicationInsightsRequestTelemetry();
|
||||
|
||||
app.UseApplicationInsightsExceptionTelemetry();
|
||||
|
||||
app.UseMvc();
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/Markdig.WebApp/appsettings.json
Normal file
10
src/Markdig.WebApp/appsettings.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"Logging": {
|
||||
"IncludeScopes": false,
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
}
|
||||
}
|
||||
58
src/Markdig.WebApp/project.json
Normal file
58
src/Markdig.WebApp/project.json
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0-rc2-3002702",
|
||||
"type": "platform"
|
||||
},
|
||||
"Microsoft.ApplicationInsights.AspNetCore": "1.0.0-rc2-final",
|
||||
"Microsoft.AspNetCore.Mvc": "1.0.0-rc2-final",
|
||||
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final",
|
||||
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final",
|
||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc2-final",
|
||||
"Microsoft.Extensions.Configuration.FileExtensions": "1.0.0-rc2-final",
|
||||
"Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-final",
|
||||
"Microsoft.Extensions.Logging": "1.0.0-rc2-final",
|
||||
"Microsoft.Extensions.Logging.Console": "1.0.0-rc2-final",
|
||||
"Microsoft.Extensions.Logging.Debug": "1.0.0-rc2-final",
|
||||
"Markdig": "0.2.1"
|
||||
},
|
||||
|
||||
"tools": {
|
||||
"Microsoft.AspNetCore.Server.IISIntegration.Tools": {
|
||||
"version": "1.0.0-preview1-final",
|
||||
"imports": "portable-net45+win8+dnxcore50"
|
||||
}
|
||||
},
|
||||
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"imports": [
|
||||
"dotnet5.6",
|
||||
"dnxcore50",
|
||||
"portable-net45+win8"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"buildOptions": {
|
||||
"emitEntryPoint": true,
|
||||
"preserveCompilationContext": true
|
||||
},
|
||||
|
||||
"runtimeOptions": {
|
||||
"gcServer": true
|
||||
},
|
||||
|
||||
"publishOptions": {
|
||||
"include": [
|
||||
"wwwroot",
|
||||
"Views",
|
||||
"appsettings.json",
|
||||
"web.config"
|
||||
]
|
||||
},
|
||||
|
||||
"scripts": {
|
||||
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
|
||||
}
|
||||
}
|
||||
14
src/Markdig.WebApp/web.config
Normal file
14
src/Markdig.WebApp/web.config
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
|
||||
<!--
|
||||
Configure your application settings in appsettings.json. Learn more at http://go.microsoft.com/fwlink/?LinkId=786380
|
||||
-->
|
||||
|
||||
<system.webServer>
|
||||
<handlers>
|
||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/>
|
||||
</handlers>
|
||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/>
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
@@ -12,18 +12,18 @@ namespace Markdig.Extensions.Abbreviations
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class AbbreviationExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.BlockParsers.AddIfNotAlready<AbbreviationParser>();
|
||||
}
|
||||
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null)
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null && !htmlRenderer.ObjectRenderers.Contains<HtmlAbbreviationRenderer>())
|
||||
{
|
||||
if (!htmlRenderer.ObjectRenderers.Contains<HtmlAbbreviationRenderer>())
|
||||
{
|
||||
// Must be inserted before CodeBlockRenderer
|
||||
htmlRenderer.ObjectRenderers.Insert(0, new HtmlAbbreviationRenderer());
|
||||
}
|
||||
// Must be inserted before CodeBlockRenderer
|
||||
htmlRenderer.ObjectRenderers.Insert(0, new HtmlAbbreviationRenderer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Markdig.Extensions.AutoIdentifiers
|
||||
};
|
||||
}
|
||||
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
var headingBlockParser = pipeline.BlockParsers.Find<HeadingBlockParser>();
|
||||
if (headingBlockParser != null)
|
||||
@@ -59,6 +59,10 @@ namespace Markdig.Extensions.AutoIdentifiers
|
||||
}
|
||||
}
|
||||
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Process on a new <see cref="HeadingBlock"/>
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// 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.Html;
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
@@ -14,13 +15,17 @@ namespace Markdig.Extensions.Bootstrap
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class BootstrapExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
// Make sure we don't have a delegate twice
|
||||
pipeline.DocumentProcessed -= PipelineOnDocumentProcessed;
|
||||
pipeline.DocumentProcessed += PipelineOnDocumentProcessed;
|
||||
}
|
||||
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
}
|
||||
|
||||
private static void PipelineOnDocumentProcessed(MarkdownDocument document)
|
||||
{
|
||||
foreach(var node in document.Descendants())
|
||||
|
||||
@@ -15,28 +15,25 @@ namespace Markdig.Extensions.Cites
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class CiteExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
var parser = pipeline.InlineParsers.FindExact<EmphasisInlineParser>();
|
||||
if (parser != null)
|
||||
if (parser != null && !parser.HasEmphasisChar('"'))
|
||||
{
|
||||
foreach (var emphasis in parser.EmphasisDescriptors)
|
||||
{
|
||||
if (emphasis.Character == '"')
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
parser.EmphasisDescriptors.Add(new EmphasisDescriptor('"', 2, 2, false));
|
||||
}
|
||||
}
|
||||
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null)
|
||||
{
|
||||
// Extend the rendering here.
|
||||
var emphasisRenderer = htmlRenderer.ObjectRenderers.FindExact<EmphasisInlineRenderer>();
|
||||
var emphasisRenderer = renderer.ObjectRenderers.FindExact<EmphasisInlineRenderer>();
|
||||
if (emphasisRenderer != null)
|
||||
{
|
||||
// TODO: Use an ordered list instead as we don't know if this specific GetTag has been already added
|
||||
var previousTag = emphasisRenderer.GetTag;
|
||||
emphasisRenderer.GetTag = inline => GetTag(inline) ?? previousTag(inline);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Markdig.Extensions.CustomContainers
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class CustomContainerExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (!pipeline.BlockParsers.Contains<CustomContainerParser>())
|
||||
{
|
||||
@@ -23,7 +23,7 @@ namespace Markdig.Extensions.CustomContainers
|
||||
|
||||
// Plug the inline parser for CustomContainerInline
|
||||
var inlineParser = pipeline.InlineParsers.Find<EmphasisInlineParser>();
|
||||
if (inlineParser != null)
|
||||
if (inlineParser != null && !inlineParser.HasEmphasisChar(':'))
|
||||
{
|
||||
inlineParser.EmphasisDescriptors.Add(new EmphasisDescriptor(':', 2, 2, true));
|
||||
var previousCreateEmphasisInline = inlineParser.CreateEmphasisInline;
|
||||
@@ -36,8 +36,11 @@ namespace Markdig.Extensions.CustomContainers
|
||||
return previousCreateEmphasisInline?.Invoke(emphasisChar, strong);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null)
|
||||
{
|
||||
if (!htmlRenderer.ObjectRenderers.Contains<HtmlCustomContainerRenderer>())
|
||||
@@ -51,6 +54,7 @@ namespace Markdig.Extensions.CustomContainers
|
||||
htmlRenderer.ObjectRenderers.Insert(0, new HtmlCustomContainerInlineRenderer());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,15 +11,18 @@ namespace Markdig.Extensions.DefinitionLists
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class DefinitionListExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (!pipeline.BlockParsers.Contains<DefinitionListParser>())
|
||||
{
|
||||
// Insert the parser before any other parsers
|
||||
pipeline.BlockParsers.Insert(0, new DefinitionListParser());
|
||||
}
|
||||
}
|
||||
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null)
|
||||
{
|
||||
if (!htmlRenderer.ObjectRenderers.Contains<HtmlDefinitionListRenderer>())
|
||||
|
||||
@@ -2,6 +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 Markdig.Renderers;
|
||||
|
||||
namespace Markdig.Extensions.Emoji
|
||||
{
|
||||
/// <summary>
|
||||
@@ -10,7 +12,7 @@ namespace Markdig.Extensions.Emoji
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class EmojiExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (!pipeline.InlineParsers.Contains<EmojiParser>())
|
||||
{
|
||||
@@ -18,5 +20,9 @@ namespace Markdig.Extensions.Emoji
|
||||
pipeline.InlineParsers.Insert(0, new EmojiParser());
|
||||
}
|
||||
}
|
||||
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ namespace Markdig.Extensions.EmphasisExtra
|
||||
/// </summary>
|
||||
public EmphasisExtraOptions Options { get; }
|
||||
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
var parser = pipeline.InlineParsers.FindExact<EmphasisInlineParser>();
|
||||
if (parser != null)
|
||||
@@ -83,8 +83,11 @@ namespace Markdig.Extensions.EmphasisExtra
|
||||
parser.EmphasisDescriptors.Add(new EmphasisDescriptor('=', 2, 2, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null)
|
||||
{
|
||||
// Extend the rendering here.
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Markdig.Extensions.Figures
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class FigureExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (!pipeline.BlockParsers.Contains<FigureBlockParser>())
|
||||
{
|
||||
@@ -28,7 +28,11 @@ namespace Markdig.Extensions.Figures
|
||||
pipeline.BlockParsers.Insert(0, new FigureBlockParser());
|
||||
}
|
||||
}
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
}
|
||||
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null)
|
||||
{
|
||||
htmlRenderer.ObjectRenderers.AddIfNotAlready<HtmlFigureRenderer>();
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Markdig.Extensions.Footers
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class FooterExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (!pipeline.BlockParsers.Contains<FooterBlockParser>())
|
||||
{
|
||||
@@ -27,8 +27,11 @@ namespace Markdig.Extensions.Footers
|
||||
pipeline.BlockParsers.Insert(0, new FooterBlockParser());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null)
|
||||
{
|
||||
htmlRenderer.ObjectRenderers.AddIfNotAlready(new HtmlFooterBlockRenderer());
|
||||
|
||||
@@ -11,15 +11,18 @@ namespace Markdig.Extensions.Footnotes
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class FootnoteExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (!pipeline.BlockParsers.Contains<FootnoteParser>())
|
||||
{
|
||||
// Insert the parser before any other parsers
|
||||
pipeline.BlockParsers.Insert(0, new FootnoteParser());
|
||||
}
|
||||
}
|
||||
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null)
|
||||
{
|
||||
htmlRenderer.ObjectRenderers.AddIfNotAlready(new HtmlFootnoteGroupRenderer());
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
using System;
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Parsers;
|
||||
using Markdig.Renderers;
|
||||
using Markdig.Renderers.Html;
|
||||
using Markdig.Syntax;
|
||||
using Markdig.Syntax.Inlines;
|
||||
@@ -18,7 +19,7 @@ namespace Markdig.Extensions.GenericAttributes
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class GenericAttributesExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (!pipeline.InlineParsers.Contains<GenericAttributesParser>())
|
||||
{
|
||||
@@ -36,6 +37,10 @@ namespace Markdig.Extensions.GenericAttributes
|
||||
}
|
||||
}
|
||||
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
}
|
||||
|
||||
private bool TryProcessAttributesForHeading(BlockProcessor processor, ref StringSlice line, IBlock block)
|
||||
{
|
||||
// Try to find if there is any attributes { in the info string on the first line of a FencedCodeBlock
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using Markdig.Parsers.Inlines;
|
||||
using Markdig.Renderers;
|
||||
|
||||
namespace Markdig.Extensions.Hardlines
|
||||
{
|
||||
@@ -12,7 +13,7 @@ namespace Markdig.Extensions.Hardlines
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class SoftlineBreakAsHardlineExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
// Simply modify the LineBreakInlineParser
|
||||
// TODO: We might want more options (like pandoc)
|
||||
@@ -22,5 +23,9 @@ namespace Markdig.Extensions.Hardlines
|
||||
parser.EnableSoftAsHard = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using Markdig.Parsers;
|
||||
using Markdig.Renderers;
|
||||
|
||||
namespace Markdig.Extensions.ListExtra
|
||||
{
|
||||
@@ -12,7 +13,7 @@ namespace Markdig.Extensions.ListExtra
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class ListExtraExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
var parser = pipeline.BlockParsers.Find<ListBlockParser>();
|
||||
if (parser != null)
|
||||
@@ -20,5 +21,9 @@ namespace Markdig.Extensions.ListExtra
|
||||
parser.ItemParsers.AddIfNotAlready<ListExtraItemParser>();
|
||||
}
|
||||
}
|
||||
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ namespace Markdig.Extensions.Mathematics
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class MathExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
// Adds the inline parser
|
||||
if (!pipeline.InlineParsers.Contains<MathInlineParser>())
|
||||
@@ -27,8 +27,11 @@ namespace Markdig.Extensions.Mathematics
|
||||
// Insert before EmphasisInlineParser to take precedence
|
||||
pipeline.BlockParsers.Insert(0, new MathBlockParser());
|
||||
}
|
||||
}
|
||||
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null)
|
||||
{
|
||||
if (!htmlRenderer.ObjectRenderers.Contains<HtmlMathInlineRenderer>())
|
||||
|
||||
@@ -26,9 +26,13 @@ namespace Markdig.Extensions.Medias
|
||||
|
||||
public MediaOptions Options { get; }
|
||||
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
}
|
||||
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null)
|
||||
{
|
||||
var inlineRenderer = htmlRenderer.ObjectRenderers.FindExact<LinkInlineRenderer>();
|
||||
@@ -45,7 +49,8 @@ namespace Markdig.Extensions.Medias
|
||||
if (linkInline.IsImage && linkInline.Url != null)
|
||||
{
|
||||
Uri uri;
|
||||
if (Uri.TryCreate(linkInline.Url, UriKind.RelativeOrAbsolute, out uri))
|
||||
// Only process absolute Uri
|
||||
if (Uri.TryCreate(linkInline.Url, UriKind.RelativeOrAbsolute, out uri) && uri.IsAbsoluteUri)
|
||||
{
|
||||
var htmlAttributes = new HtmlAttributes();
|
||||
var fromAttributes = linkInline.TryGetAttributes();
|
||||
|
||||
@@ -26,15 +26,18 @@ namespace Markdig.Extensions.SmartyPants
|
||||
/// </summary>
|
||||
public SmartyPantOptions Options { get; }
|
||||
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (!pipeline.InlineParsers.Contains<SmaryPantsInlineParser>())
|
||||
{
|
||||
// Insert the parser after the code span parser
|
||||
pipeline.InlineParsers.InsertAfter<CodeInlineParser>(new SmaryPantsInlineParser());
|
||||
}
|
||||
}
|
||||
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null)
|
||||
{
|
||||
if (!htmlRenderer.ObjectRenderers.Contains<HtmlSmartyPantRenderer>())
|
||||
|
||||
@@ -11,14 +11,17 @@ namespace Markdig.Extensions.Tables
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
public class GridTableExtension : IMarkdownExtension
|
||||
{
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (!pipeline.BlockParsers.Contains<GridTableParser>())
|
||||
{
|
||||
pipeline.BlockParsers.Insert(0, new GridTableParser());
|
||||
}
|
||||
}
|
||||
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null && !htmlRenderer.ObjectRenderers.Contains<HtmlTableRenderer>())
|
||||
{
|
||||
htmlRenderer.ObjectRenderers.Add(new HtmlTableRenderer());
|
||||
|
||||
@@ -26,14 +26,17 @@ namespace Markdig.Extensions.Tables
|
||||
/// </summary>
|
||||
public PipeTableOptions Options { get; }
|
||||
|
||||
public void Setup(MarkdownPipeline pipeline)
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
if (!pipeline.InlineParsers.Contains<PipeTableParser>())
|
||||
{
|
||||
pipeline.InlineParsers.InsertBefore<EmphasisInlineParser>(new PipeTableParser(Options));
|
||||
}
|
||||
}
|
||||
|
||||
var htmlRenderer = pipeline.Renderer as HtmlRenderer;
|
||||
public void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
var htmlRenderer = renderer as HtmlRenderer;
|
||||
if (htmlRenderer != null && !htmlRenderer.ObjectRenderers.Contains<HtmlTableRenderer>())
|
||||
{
|
||||
htmlRenderer.ObjectRenderers.Add(new HtmlTableRenderer());
|
||||
|
||||
@@ -14,6 +14,14 @@ namespace Markdig.Helpers
|
||||
/// <remarks>We use a typed list and don't use extension methods because it would pollute all list implemts and the top level namespace.</remarks>
|
||||
public class OrderedList<T> : List<T>
|
||||
{
|
||||
public OrderedList()
|
||||
{
|
||||
}
|
||||
|
||||
public OrderedList(IEnumerable<T> collection) : base(collection)
|
||||
{
|
||||
}
|
||||
|
||||
public bool InsertBefore<TElement>(T element) where TElement : T
|
||||
{
|
||||
if (element == null) throw new ArgumentNullException(nameof(element));
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
// 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;
|
||||
|
||||
namespace Markdig
|
||||
{
|
||||
/// <summary>
|
||||
@@ -12,6 +15,12 @@ namespace Markdig
|
||||
/// Setups this extension for the specified pipeline.
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
void Setup(MarkdownPipeline pipeline);
|
||||
void Setup(MarkdownPipelineBuilder pipeline);
|
||||
|
||||
/// <summary>
|
||||
/// Setups this extension for the specified renderer.
|
||||
/// </summary>
|
||||
/// <param name="renderer">The renderer.</param>
|
||||
void Setup(IMarkdownRenderer renderer);
|
||||
}
|
||||
}
|
||||
@@ -4,16 +4,18 @@
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>8A58A7E2-627C-4F41-933F-5AC92ADFAB48</ProjectGuid>
|
||||
<RootNamespace>Markdig</RootNamespace>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\Bin</OutputPath>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild>
|
||||
<TypeScriptCompileBlocked>True</TypeScriptCompileBlocked>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
@@ -12,7 +12,7 @@ namespace Markdig
|
||||
/// <summary>
|
||||
/// Provides methods for parsing a Markdown string to a syntax tree and converting it to other formats.
|
||||
/// </summary>
|
||||
public static class Markdown
|
||||
public static partial class Markdown
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts a Markdown string to HTML.
|
||||
@@ -54,33 +54,33 @@ namespace Markdig
|
||||
{
|
||||
if (reader == null) throw new ArgumentNullException(nameof(reader));
|
||||
if (writer == null) throw new ArgumentNullException(nameof(writer));
|
||||
pipeline = pipeline ?? new MarkdownPipeline();
|
||||
pipeline = pipeline ?? new MarkdownPipelineBuilder().Build();
|
||||
|
||||
// We override the renderer with our own writer
|
||||
pipeline.Renderer = new HtmlRenderer(writer);
|
||||
var renderer = new HtmlRenderer(writer);
|
||||
pipeline.Setup(renderer);
|
||||
|
||||
var document = Parse(reader, pipeline);
|
||||
pipeline.Renderer.Render(document);
|
||||
renderer.Render(document);
|
||||
writer.Flush();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a Markdown string using a custom <see cref="IMarkdownRenderer"/> specified in the <see cref="MarkdownPipeline.Renderer"/>.
|
||||
/// Converts a Markdown string using a custom <see cref="IMarkdownRenderer"/>.
|
||||
/// </summary>
|
||||
/// <param name="reader">A Markdown text from a <see cref="TextReader"/>.</param>
|
||||
/// <param name="renderer">The renderer to convert Markdown to.</param>
|
||||
/// <param name="pipeline">The pipeline used for the conversion.</param>
|
||||
/// <exception cref="System.ArgumentNullException">if reader or writer variable are null</exception>
|
||||
public static object Convert(TextReader reader, MarkdownPipeline pipeline = null)
|
||||
public static object Convert(TextReader reader, IMarkdownRenderer renderer, MarkdownPipeline pipeline = null)
|
||||
{
|
||||
if (reader == null) throw new ArgumentNullException(nameof(reader));
|
||||
pipeline = pipeline ?? new MarkdownPipeline();
|
||||
if (pipeline.Renderer == null)
|
||||
{
|
||||
throw new InvalidOperationException("The property MarkdownPipeline.Renderer cannot be null");
|
||||
}
|
||||
if (renderer == null) throw new ArgumentNullException(nameof(renderer));
|
||||
pipeline = pipeline ?? new MarkdownPipelineBuilder().Build();
|
||||
|
||||
var document = Parse(reader, pipeline);
|
||||
return pipeline.Renderer.Render(document);
|
||||
pipeline.Setup(renderer);
|
||||
return renderer.Render(document);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -92,7 +92,7 @@ namespace Markdig
|
||||
public static MarkdownDocument Parse(string markdown)
|
||||
{
|
||||
if (markdown == null) throw new ArgumentNullException(nameof(markdown));
|
||||
return Parse(new StringReader(markdown), new MarkdownPipeline());
|
||||
return Parse(new StringReader(markdown));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -105,7 +105,7 @@ namespace Markdig
|
||||
public static MarkdownDocument Parse(TextReader reader, MarkdownPipeline pipeline = null)
|
||||
{
|
||||
if (reader == null) throw new ArgumentNullException(nameof(reader));
|
||||
pipeline = pipeline ?? new MarkdownPipeline();
|
||||
pipeline = pipeline ?? new MarkdownPipelineBuilder().Build();
|
||||
|
||||
return MarkdownParser.Parse(reader, pipeline);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// 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 Markdig.Extensions.Abbreviations;
|
||||
using Markdig.Extensions.AutoIdentifiers;
|
||||
using Markdig.Extensions.Bootstrap;
|
||||
@@ -19,6 +21,8 @@ using Markdig.Extensions.Mathematics;
|
||||
using Markdig.Extensions.Medias;
|
||||
using Markdig.Extensions.SmartyPants;
|
||||
using Markdig.Extensions.Tables;
|
||||
using Markdig.Parsers;
|
||||
using Markdig.Parsers.Inlines;
|
||||
|
||||
namespace Markdig
|
||||
{
|
||||
@@ -28,16 +32,15 @@ namespace Markdig
|
||||
public static class MarkdownExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Uses all extensions except the Emoji.
|
||||
/// Uses all extensions except the BootStrap, Emoji, SmartyPants and soft line as hard line breaks extensions.
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseAllExtensions(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseAdvancedExtensions(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
return pipeline
|
||||
.UseAbbreviation()
|
||||
.UseAutoIdentifier()
|
||||
.UseBootstrap()
|
||||
.UseCite()
|
||||
.UseCustomContainer()
|
||||
.UseDefinitionList()
|
||||
@@ -49,8 +52,7 @@ namespace Markdig
|
||||
.UseMath()
|
||||
.UseMedia()
|
||||
.UsePipeTable()
|
||||
.UseSoftlineBreakAsHardlineBreak()
|
||||
.UseSmartyPants()
|
||||
.UseListExtra()
|
||||
.UseGenericAttributes(); // Must be last as it is one parser that is modifying other parsers
|
||||
}
|
||||
|
||||
@@ -59,7 +61,7 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseCustomContainer(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseCustomContainer(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<CustomContainerExtension>();
|
||||
return pipeline;
|
||||
@@ -73,7 +75,7 @@ namespace Markdig
|
||||
/// <returns>
|
||||
/// The modified pipeline
|
||||
/// </returns>
|
||||
public static MarkdownPipeline UseMedia(this MarkdownPipeline pipeline, MediaOptions options = null)
|
||||
public static MarkdownPipelineBuilder UseMedia(this MarkdownPipelineBuilder pipeline, MediaOptions options = null)
|
||||
{
|
||||
if (!pipeline.Extensions.Contains<MediaExtension>())
|
||||
{
|
||||
@@ -90,7 +92,7 @@ namespace Markdig
|
||||
/// <returns>
|
||||
/// The modified pipeline
|
||||
/// </returns>
|
||||
public static MarkdownPipeline UseAutoIdentifier(this MarkdownPipeline pipeline, AutoIdentifierOptions options = AutoIdentifierOptions.Default)
|
||||
public static MarkdownPipelineBuilder UseAutoIdentifier(this MarkdownPipelineBuilder pipeline, AutoIdentifierOptions options = AutoIdentifierOptions.Default)
|
||||
{
|
||||
if (!pipeline.Extensions.Contains<AutoIdentifierExtension>())
|
||||
{
|
||||
@@ -107,7 +109,7 @@ namespace Markdig
|
||||
/// <returns>
|
||||
/// The modified pipeline
|
||||
/// </returns>
|
||||
public static MarkdownPipeline UseSmartyPants(this MarkdownPipeline pipeline, SmartyPantOptions options = null)
|
||||
public static MarkdownPipelineBuilder UseSmartyPants(this MarkdownPipelineBuilder pipeline, SmartyPantOptions options = null)
|
||||
{
|
||||
if (!pipeline.Extensions.Contains<SmartyPantsExtension>())
|
||||
{
|
||||
@@ -121,7 +123,7 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseBootstrap(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseBootstrap(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<BootstrapExtension>();
|
||||
return pipeline;
|
||||
@@ -132,7 +134,7 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseMath(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseMath(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<MathExtension>();
|
||||
return pipeline;
|
||||
@@ -143,7 +145,7 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseFigure(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseFigure(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<FigureExtension>();
|
||||
return pipeline;
|
||||
@@ -154,7 +156,7 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseAbbreviation(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseAbbreviation(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<AbbreviationExtension>();
|
||||
return pipeline;
|
||||
@@ -165,7 +167,7 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseDefinitionList(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseDefinitionList(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<DefinitionListExtension>();
|
||||
return pipeline;
|
||||
@@ -179,7 +181,7 @@ namespace Markdig
|
||||
/// <returns>
|
||||
/// The modified pipeline
|
||||
/// </returns>
|
||||
public static MarkdownPipeline UsePipeTable(this MarkdownPipeline pipeline, PipeTableOptions options = null)
|
||||
public static MarkdownPipelineBuilder UsePipeTable(this MarkdownPipelineBuilder pipeline, PipeTableOptions options = null)
|
||||
{
|
||||
if (!pipeline.Extensions.Contains<PipeTableExtension>())
|
||||
{
|
||||
@@ -193,7 +195,7 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseGridTable(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseGridTable(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<GridTableExtension>();
|
||||
return pipeline;
|
||||
@@ -205,7 +207,7 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseCite(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseCite(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<CiteExtension>();
|
||||
return pipeline;
|
||||
@@ -216,7 +218,7 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseFooter(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseFooter(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<FooterExtension>();
|
||||
return pipeline;
|
||||
@@ -227,7 +229,7 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseFootnotes(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseFootnotes(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<FootnoteExtension>();
|
||||
return pipeline;
|
||||
@@ -238,7 +240,7 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseSoftlineBreakAsHardlineBreak(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseSoftlineBreakAsHardlineBreak(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<SoftlineBreakAsHardlineExtension>();
|
||||
return pipeline;
|
||||
@@ -252,7 +254,7 @@ namespace Markdig
|
||||
/// <returns>
|
||||
/// The modified pipeline
|
||||
/// </returns>
|
||||
public static MarkdownPipeline UseEmphasisExtra(this MarkdownPipeline pipeline, EmphasisExtraOptions options = EmphasisExtraOptions.Default)
|
||||
public static MarkdownPipelineBuilder UseEmphasisExtra(this MarkdownPipelineBuilder pipeline, EmphasisExtraOptions options = EmphasisExtraOptions.Default)
|
||||
{
|
||||
if (!pipeline.Extensions.Contains<EmphasisExtraExtension>())
|
||||
{
|
||||
@@ -268,7 +270,7 @@ namespace Markdig
|
||||
/// <returns>
|
||||
/// The modified pipeline
|
||||
/// </returns>
|
||||
public static MarkdownPipeline UseListExtra(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseListExtra(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<ListExtraExtension>();
|
||||
return pipeline;
|
||||
@@ -279,7 +281,7 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseGenericAttributes(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseGenericAttributes(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<GenericAttributesExtension>();
|
||||
return pipeline;
|
||||
@@ -290,10 +292,115 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipeline UseEmojiAndSmiley(this MarkdownPipeline pipeline)
|
||||
public static MarkdownPipelineBuilder UseEmojiAndSmiley(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.Extensions.AddIfNotAlready<EmojiExtension>();
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This will disable the HTML support in the markdown processor (for constraint/safe parsing).
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipelineBuilder DisableHtml(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
var parser = pipeline.BlockParsers.Find<HtmlBlockParser>();
|
||||
if (parser != null)
|
||||
{
|
||||
pipeline.BlockParsers.Remove(parser);
|
||||
}
|
||||
|
||||
var inlineParser = pipeline.InlineParsers.Find<AutolineInlineParser>();
|
||||
if (inlineParser != null)
|
||||
{
|
||||
inlineParser.EnableHtmlParsing = false;
|
||||
}
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the pipeline using a string that defines the extensions to activate.
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline (e.g: advanced for <see cref="UseAdvancedExtensions"/>, pipetables+gridtables for <see cref="UsePipeTable"/> and <see cref="UseGridTable"/></param>
|
||||
/// <param name="extensions">The extensions to activate as a string</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipelineBuilder Configure(this MarkdownPipelineBuilder pipeline, string extensions)
|
||||
{
|
||||
if (extensions == null)
|
||||
{
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
foreach (var extension in extensions.Split(new[] { '+' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
switch (extension.ToLowerInvariant())
|
||||
{
|
||||
case "advanced":
|
||||
pipeline.UseAdvancedExtensions();
|
||||
break;
|
||||
case "pipetables":
|
||||
pipeline.UsePipeTable();
|
||||
break;
|
||||
case "emphasisextra":
|
||||
pipeline.UseEmphasisExtra();
|
||||
break;
|
||||
case "listextra":
|
||||
pipeline.UseListExtra();
|
||||
break;
|
||||
case "hardlinebreak":
|
||||
pipeline.UseSoftlineBreakAsHardlineBreak();
|
||||
break;
|
||||
case "footnotes":
|
||||
pipeline.UseFootnotes();
|
||||
break;
|
||||
case "footers":
|
||||
pipeline.UseFooter();
|
||||
break;
|
||||
case "cites":
|
||||
pipeline.UseCite();
|
||||
break;
|
||||
case "attributes":
|
||||
pipeline.UseGenericAttributes();
|
||||
break;
|
||||
case "gridtables":
|
||||
pipeline.UseGridTable();
|
||||
break;
|
||||
case "abbreviations":
|
||||
pipeline.UseAbbreviation();
|
||||
break;
|
||||
case "emojis":
|
||||
pipeline.UseEmojiAndSmiley();
|
||||
break;
|
||||
case "definitionlists":
|
||||
pipeline.UseDefinitionList();
|
||||
break;
|
||||
case "customcontainers":
|
||||
pipeline.UseCustomContainer();
|
||||
break;
|
||||
case "figures":
|
||||
pipeline.UseFigure();
|
||||
break;
|
||||
case "math":
|
||||
pipeline.UseMath();
|
||||
break;
|
||||
case "bootstrap":
|
||||
pipeline.UseBootstrap();
|
||||
break;
|
||||
case "medias":
|
||||
pipeline.UseMedia();
|
||||
break;
|
||||
case "smartypants":
|
||||
pipeline.UseSmartyPants();
|
||||
break;
|
||||
case "autoidentifiers":
|
||||
pipeline.UseAutoIdentifier();
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException($"unknown extension {extension}");
|
||||
}
|
||||
}
|
||||
return pipeline;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,104 +5,51 @@ using System;
|
||||
using System.IO;
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Parsers;
|
||||
using Markdig.Parsers.Inlines;
|
||||
using Markdig.Renderers;
|
||||
|
||||
namespace Markdig
|
||||
{
|
||||
/// <summary>
|
||||
/// This class allows to modify the pipeline to parse and render a Markdown document.
|
||||
/// This class is the Markdown pipeline build from a <see cref="MarkdownPipelineBuilder"/>.
|
||||
/// </summary>
|
||||
public class MarkdownPipeline
|
||||
{
|
||||
// This class is immutable
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MarkdownPipeline" /> class.
|
||||
/// </summary>
|
||||
public MarkdownPipeline()
|
||||
internal MarkdownPipeline(OrderedList<IMarkdownExtension> extensions, BlockParserList blockParsers, InlineParserList inlineParsers, StringBuilderCache cache, TextWriter debugLog, ProcessDocumentDelegate documentProcessed)
|
||||
{
|
||||
if (blockParsers == null) throw new ArgumentNullException(nameof(blockParsers));
|
||||
if (inlineParsers == null) throw new ArgumentNullException(nameof(inlineParsers));
|
||||
// Add all default parsers
|
||||
BlockParsers = new BlockParserList()
|
||||
{
|
||||
new ThematicBreakParser(),
|
||||
new HeadingBlockParser(),
|
||||
new QuoteBlockParser(),
|
||||
new ListBlockParser(),
|
||||
|
||||
new HtmlBlockParser(),
|
||||
new FencedCodeBlockParser(),
|
||||
new IndentedCodeBlockParser(),
|
||||
new ParagraphBlockParser(),
|
||||
};
|
||||
|
||||
InlineParsers = new InlineParserList()
|
||||
{
|
||||
new HtmlEntityParser(),
|
||||
new LinkInlineParser(),
|
||||
new EscapeInlineParser(),
|
||||
new EmphasisInlineParser(),
|
||||
new CodeInlineParser(),
|
||||
new AutolineInlineParser(),
|
||||
new LineBreakInlineParser(),
|
||||
};
|
||||
|
||||
Extensions = new OrderedList<IMarkdownExtension>();
|
||||
|
||||
Renderer = new HtmlRenderer(new StringWriter());
|
||||
|
||||
StringBuilderCache = new StringBuilderCache();
|
||||
Extensions = extensions;
|
||||
BlockParsers = blockParsers;
|
||||
InlineParsers = inlineParsers;
|
||||
StringBuilderCache = cache;
|
||||
DebugLog = debugLog;
|
||||
DocumentProcessed = documentProcessed;
|
||||
}
|
||||
internal OrderedList<IMarkdownExtension> Extensions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the block parsers.
|
||||
/// </summary>
|
||||
public BlockParserList BlockParsers { get; private set; }
|
||||
internal BlockParserList BlockParsers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the inline parsers.
|
||||
/// </summary>
|
||||
public InlineParserList InlineParsers { get; private set; }
|
||||
internal InlineParserList InlineParsers { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the renderer.
|
||||
/// </summary>
|
||||
public IMarkdownRenderer Renderer { get; set; }
|
||||
internal StringBuilderCache StringBuilderCache { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the register extensions.
|
||||
/// </summary>
|
||||
public OrderedList<IMarkdownExtension> Extensions { get; }
|
||||
// TODO: Move the log to a better place
|
||||
internal TextWriter DebugLog { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the string builder cache used by the parsers.
|
||||
/// </summary>
|
||||
public StringBuilderCache StringBuilderCache { get; set; }
|
||||
internal ProcessDocumentDelegate DocumentProcessed;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the debug log.
|
||||
/// </summary>
|
||||
public TextWriter DebugLog { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a document has been processed after the <see cref="MarkdownParser.Parse"/> method.
|
||||
/// </summary>
|
||||
public event ProcessDocumentDelegate DocumentProcessed;
|
||||
|
||||
internal ProcessDocumentDelegate GetDocumentProcessed => DocumentProcessed;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this instance.
|
||||
/// </summary>
|
||||
/// <exception cref="System.InvalidOperationException">An extension cannot be null</exception>
|
||||
public void Initialize()
|
||||
internal void Setup(IMarkdownRenderer renderer)
|
||||
{
|
||||
// Allow extensions to modify existing BlockParsers, InlineParsers and Renderer
|
||||
if (renderer == null) throw new ArgumentNullException(nameof(renderer));
|
||||
foreach (var extension in Extensions)
|
||||
{
|
||||
if (extension == null)
|
||||
{
|
||||
throw new InvalidOperationException("An extension cannot be null");
|
||||
}
|
||||
extension.Setup(this);
|
||||
extension.Setup(renderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
118
src/Markdig/MarkdownPipelineBuilder.cs
Normal file
118
src/Markdig/MarkdownPipelineBuilder.cs
Normal file
@@ -0,0 +1,118 @@
|
||||
// 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.IO;
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Parsers;
|
||||
using Markdig.Parsers.Inlines;
|
||||
using Markdig.Renderers;
|
||||
|
||||
namespace Markdig
|
||||
{
|
||||
/// <summary>
|
||||
/// This class allows to modify the pipeline to parse and render a Markdown document.
|
||||
/// </summary>
|
||||
/// <remarks>NOTE: A pipeline is not thread-safe.</remarks>
|
||||
public class MarkdownPipelineBuilder
|
||||
{
|
||||
private MarkdownPipeline pipeline;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MarkdownPipeline" /> class.
|
||||
/// </summary>
|
||||
public MarkdownPipelineBuilder()
|
||||
{
|
||||
// Add all default parsers
|
||||
BlockParsers = new BlockParserList()
|
||||
{
|
||||
new ThematicBreakParser(),
|
||||
new HeadingBlockParser(),
|
||||
new QuoteBlockParser(),
|
||||
new ListBlockParser(),
|
||||
|
||||
new HtmlBlockParser(),
|
||||
new FencedCodeBlockParser(),
|
||||
new IndentedCodeBlockParser(),
|
||||
new ParagraphBlockParser(),
|
||||
};
|
||||
|
||||
InlineParsers = new InlineParserList()
|
||||
{
|
||||
new HtmlEntityParser(),
|
||||
new LinkInlineParser(),
|
||||
new EscapeInlineParser(),
|
||||
new EmphasisInlineParser(),
|
||||
new CodeInlineParser(),
|
||||
new AutolineInlineParser(),
|
||||
new LineBreakInlineParser(),
|
||||
};
|
||||
|
||||
Extensions = new OrderedList<IMarkdownExtension>();
|
||||
|
||||
StringBuilderCache = new StringBuilderCache();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the block parsers.
|
||||
/// </summary>
|
||||
public BlockParserList BlockParsers { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the inline parsers.
|
||||
/// </summary>
|
||||
public InlineParserList InlineParsers { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the register extensions.
|
||||
/// </summary>
|
||||
public OrderedList<IMarkdownExtension> Extensions { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the string builder cache used by the parsers.
|
||||
/// </summary>
|
||||
public StringBuilderCache StringBuilderCache { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the debug log.
|
||||
/// </summary>
|
||||
public TextWriter DebugLog { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a document has been processed after the <see cref="MarkdownParser.Parse"/> method.
|
||||
/// </summary>
|
||||
public event ProcessDocumentDelegate DocumentProcessed;
|
||||
|
||||
internal ProcessDocumentDelegate GetDocumentProcessed => DocumentProcessed;
|
||||
|
||||
/// <summary>
|
||||
/// Builds a pipeline from this instance. Once the pipeline is build, it cannot be modified.
|
||||
/// </summary>
|
||||
/// <exception cref="System.InvalidOperationException">An extension cannot be null</exception>
|
||||
public MarkdownPipeline Build()
|
||||
{
|
||||
if (pipeline != null)
|
||||
{
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
// TODO: Review the whole initialization process for extensions
|
||||
// - It does not prevent a user to modify the pipeline after it has been used
|
||||
// - a pipeline is not thread safe.
|
||||
// We should find a proper way to make the pipeline safely modifiable/freezable (PipelineBuilder -> Pipeline)
|
||||
|
||||
// Allow extensions to modify existing BlockParsers, InlineParsers and Renderer
|
||||
foreach (var extension in Extensions)
|
||||
{
|
||||
if (extension == null)
|
||||
{
|
||||
throw new InvalidOperationException("An extension cannot be null");
|
||||
}
|
||||
extension.Setup(this);
|
||||
}
|
||||
|
||||
pipeline = new MarkdownPipeline(new OrderedList<IMarkdownExtension>(Extensions), new BlockParserList(BlockParsers), new InlineParserList(InlineParsers), StringBuilderCache, DebugLog, GetDocumentProcessed);
|
||||
return pipeline;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
// 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.Collections.Generic;
|
||||
|
||||
namespace Markdig.Parsers
|
||||
{
|
||||
/// <summary>
|
||||
@@ -9,5 +12,19 @@ namespace Markdig.Parsers
|
||||
/// <seealso cref="Markdig.Parsers.ParserList{Markdig.Parsers.BlockParser, Markdig.Parsers.BlockParserState}" />
|
||||
public class BlockParserList : ParserList<BlockParser, BlockProcessor>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BlockParserList"/> class.
|
||||
/// </summary>
|
||||
public BlockParserList()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BlockParserList"/> class.
|
||||
/// </summary>
|
||||
/// <param name="parsers">The parsers.</param>
|
||||
public BlockParserList(IEnumerable<BlockParser> parsers) : base(parsers)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -260,12 +260,10 @@ namespace Markdig.Parsers
|
||||
public void GoToColumn(int newColumn)
|
||||
{
|
||||
// Optimized path when we are moving above the previous start of indent
|
||||
if (newColumn > ColumnBeforeIndent)
|
||||
if (newColumn >= ColumnBeforeIndent)
|
||||
{
|
||||
Line.Start = StartBeforeIndent;
|
||||
Column = ColumnBeforeIndent;
|
||||
ColumnBeforeIndent = 0;
|
||||
StartBeforeIndent = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace Markdig.Parsers
|
||||
}
|
||||
|
||||
// If we don't have a blank line, we reset to the indent
|
||||
if (processor.Indent >= 4)
|
||||
if (processor.Indent > 4)
|
||||
{
|
||||
processor.GoToCodeIndent();
|
||||
}
|
||||
|
||||
@@ -11,6 +11,14 @@ namespace Markdig.Parsers
|
||||
/// <seealso cref="Markdig.Parsers.ParserList{Markdig.Parsers.InlineParser, Markdig.Parsers.InlineParserState}" />
|
||||
public class InlineParserList : ParserList<InlineParser, InlineProcessor>
|
||||
{
|
||||
public InlineParserList()
|
||||
{
|
||||
}
|
||||
|
||||
public InlineParserList(IEnumerable<InlineParser> parsers) : base(parsers)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registered delimiter processors.
|
||||
/// </summary>
|
||||
|
||||
@@ -18,8 +18,14 @@ namespace Markdig.Parsers.Inlines
|
||||
public AutolineInlineParser()
|
||||
{
|
||||
OpeningCharacters = new[] {'<'};
|
||||
EnableHtmlParsing = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to enable HTML parsing. Default is <c>true</c>
|
||||
/// </summary>
|
||||
public bool EnableHtmlParsing { get; set; }
|
||||
|
||||
public override bool Match(InlineProcessor processor, ref StringSlice slice)
|
||||
{
|
||||
string link;
|
||||
@@ -29,7 +35,7 @@ namespace Markdig.Parsers.Inlines
|
||||
{
|
||||
processor.Inline = new AutolinkInline() {IsEmail = isEmail, Url = link};
|
||||
}
|
||||
else
|
||||
else if (EnableHtmlParsing)
|
||||
{
|
||||
slice = saved;
|
||||
string htmlTag;
|
||||
|
||||
@@ -47,13 +47,13 @@ namespace Markdig.Parsers.Inlines
|
||||
// The contents of the code span are the characters between the two backtick strings, with leading and trailing spaces and line endings removed, and whitespace collapsed to single spaces.
|
||||
var pc = ' ';
|
||||
|
||||
int newLinesFound = 0;
|
||||
while (c != '\0')
|
||||
{
|
||||
// Transform '\n' into a single space
|
||||
if (c == '\n')
|
||||
{
|
||||
processor.LocalLineIndex++;
|
||||
processor.LineIndex++;
|
||||
newLinesFound++;
|
||||
c = ' ';
|
||||
}
|
||||
|
||||
@@ -104,6 +104,9 @@ namespace Markdig.Parsers.Inlines
|
||||
Content = builder.ToString()
|
||||
};
|
||||
isMatching = true;
|
||||
|
||||
processor.LocalLineIndex += newLinesFound;
|
||||
processor.LineIndex += newLinesFound;
|
||||
}
|
||||
|
||||
// Release the builder if not used
|
||||
|
||||
@@ -41,6 +41,23 @@ namespace Markdig.Parsers.Inlines
|
||||
/// </summary>
|
||||
public List<EmphasisDescriptor> EmphasisDescriptors { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this parser is using the specified character as an emphasis delimiter.
|
||||
/// </summary>
|
||||
/// <param name="c">The character to look for.</param>
|
||||
/// <returns><c>true</c> if this parser is using the specified character as an emphasis delimiter; otherwise <c>false</c></returns>
|
||||
public bool HasEmphasisChar(char c)
|
||||
{
|
||||
foreach (var emphasis in EmphasisDescriptors)
|
||||
{
|
||||
if (emphasis.Character == c)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the create emphasis inline delegate (allowing to create a different emphasis inline class)
|
||||
/// </summary>
|
||||
|
||||
@@ -41,7 +41,6 @@ namespace Markdig.Parsers
|
||||
Reader = reader;
|
||||
|
||||
// Initialize the pipeline
|
||||
pipeline.Initialize();
|
||||
var stringBuilderCache = pipeline.StringBuilderCache ?? new StringBuilderCache();
|
||||
|
||||
document = new MarkdownDocument();
|
||||
@@ -59,7 +58,7 @@ namespace Markdig.Parsers
|
||||
DebugLog = pipeline.DebugLog
|
||||
};
|
||||
|
||||
documentProcessed = pipeline.GetDocumentProcessed;
|
||||
documentProcessed = pipeline.DocumentProcessed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -72,7 +71,7 @@ namespace Markdig.Parsers
|
||||
public static MarkdownDocument Parse(TextReader reader, MarkdownPipeline pipeline = null)
|
||||
{
|
||||
if (reader == null) throw new ArgumentNullException(nameof(reader));
|
||||
pipeline = pipeline ?? new MarkdownPipeline();
|
||||
pipeline = pipeline ?? new MarkdownPipelineBuilder().Build();
|
||||
|
||||
// Perform the parsing
|
||||
var markdownParser = new MarkdownParser(reader, pipeline);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// 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 Markdig.Parsers
|
||||
{
|
||||
/// <summary>
|
||||
@@ -8,7 +9,7 @@ namespace Markdig.Parsers
|
||||
/// </summary>
|
||||
/// <typeparam name="TProcessor">Type of the parser processor</typeparam>
|
||||
/// <seealso cref="Markdig.Parsers.IMarkdownParser{TParserState}" />
|
||||
public class ParserBase<TProcessor> : IMarkdownParser<TProcessor>
|
||||
public abstract class ParserBase<TProcessor> : IMarkdownParser<TProcessor>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the opening characters this parser will be triggered if the character is found.
|
||||
|
||||
@@ -23,6 +23,10 @@ namespace Markdig.Parsers
|
||||
{
|
||||
}
|
||||
|
||||
protected ParserList(IEnumerable<T> parsers) : base(parsers)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of global parsers (that don't have any opening characters defined)
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System.Resources;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
@@ -20,8 +18,13 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: NeutralResourcesLanguage("en")]
|
||||
|
||||
[assembly: AssemblyVersion("0.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.0.0")]
|
||||
|
||||
[assembly: InternalsVisibleTo("Scriban.Tests")]
|
||||
[assembly: AssemblyVersion(Markdig.Markdown.Version)]
|
||||
[assembly: AssemblyFileVersion(Markdig.Markdown.Version)]
|
||||
|
||||
namespace Markdig
|
||||
{
|
||||
public static partial class Markdown
|
||||
{
|
||||
public const string Version = "0.3.2";
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,8 @@ namespace Markdig.Renderers
|
||||
{
|
||||
if (writer == null) throw new ArgumentNullException(nameof(writer));
|
||||
this.Writer = writer;
|
||||
// By default we output a newline with '\n' only even on Windows platforms
|
||||
Writer.NewLine = "\n";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"title": "Markdig",
|
||||
"version": "0.1.0",
|
||||
"version": "0.3.2",
|
||||
"authors": [ "Alexandre Mutel" ],
|
||||
"description": "A fast, powerfull, CommonMark compliant, extensible Markdown processor for .NET",
|
||||
"copyright": "Alexandre Mutel",
|
||||
@@ -10,7 +10,8 @@
|
||||
"licenseUrl": "https://github.com/lunet-io/markdig/blob/master/license.txt",
|
||||
"projectUrl": "https://github.com/lunet-io/markdig",
|
||||
"requireLicenseAcceptance": false,
|
||||
"tags": [ "Markdown CommonMark md html" ]
|
||||
"releaseNotes": "Fix exception when Media extension was used with non absolute URI. Make the UseAdvancedExtensions() CommonMark compliant on core specs",
|
||||
"tags": [ "Markdown CommonMark md html md2html" ]
|
||||
},
|
||||
"configurations": {
|
||||
"Debug": {
|
||||
@@ -28,9 +29,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.5.0-rc2-24027"
|
||||
},
|
||||
"frameworks": {
|
||||
"net35": {
|
||||
"buildOptions": {
|
||||
@@ -61,6 +59,7 @@
|
||||
},
|
||||
"netstandard1.1": {
|
||||
"dependencies": {
|
||||
"NETStandard.Library": "1.5.0-rc2-24027",
|
||||
"System.Threading": "4.0.11-rc2-24027",
|
||||
"System.Threading.Tasks": "4.0.11-rc2-24027",
|
||||
"System.Threading.Tasks.Parallel": "4.0.1-rc2-24027"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.24720.0
|
||||
VisualStudioVersion = 14.0.25123.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Markdig", "Markdig\Markdig.xproj", "{8A58A7E2-627C-4F41-933F-5AC92ADFAB48}"
|
||||
EndProject
|
||||
@@ -13,6 +13,7 @@ EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{061866E2-005C-4D13-A338-EA464BBEC60F}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
..\license.txt = ..\license.txt
|
||||
..\readme.md = ..\readme.md
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Markdig.Benchmarks", "Markdig.Benchmarks\Markdig.Benchmarks.csproj", "{6A19F040-BC7C-4283-873A-177B5324F1ED}"
|
||||
@@ -20,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Markdig.Benchmarks", "Markd
|
||||
{8A58A7E2-627C-4F41-933F-5AC92ADFAB48} = {8A58A7E2-627C-4F41-933F-5AC92ADFAB48}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Markdig.WebApp", "Markdig.WebApp\Markdig.WebApp.xproj", "{3CAD9801-9976-46BE-BACA-F6D0D21FDC00}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -38,6 +41,10 @@ Global
|
||||
{6A19F040-BC7C-4283-873A-177B5324F1ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6A19F040-BC7C-4283-873A-177B5324F1ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6A19F040-BC7C-4283-873A-177B5324F1ED}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3CAD9801-9976-46BE-BACA-F6D0D21FDC00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3CAD9801-9976-46BE-BACA-F6D0D21FDC00}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3CAD9801-9976-46BE-BACA-F6D0D21FDC00}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3CAD9801-9976-46BE-BACA-F6D0D21FDC00}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Reference in New Issue
Block a user