mirror of
https://github.com/xoofx/markdig.git
synced 2026-02-13 13:54:56 +00:00
Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea13b33f1a | ||
|
|
9b2ec2e2e5 | ||
|
|
d8dffc28b4 | ||
|
|
0735042599 | ||
|
|
d1f99cdb69 | ||
|
|
d0a2ae2b50 | ||
|
|
dd4d1b349f | ||
|
|
e33281b8ae | ||
|
|
50d42560da | ||
|
|
a1e96d717b | ||
|
|
56278657fd | ||
|
|
b7202084d2 | ||
|
|
88052168d0 | ||
|
|
27cb88773a | ||
|
|
fe3d5b0ccf | ||
|
|
86759e44e1 | ||
|
|
dd60990d3d | ||
|
|
a3a9496c6f | ||
|
|
d09013ba14 | ||
|
|
9499660f83 | ||
|
|
df24ab9846 | ||
|
|
40a8cd09b6 | ||
|
|
b556f06d31 | ||
|
|
54e61d3b91 | ||
|
|
221afcc4d3 | ||
|
|
f1fc64af42 | ||
|
|
b39614f10c | ||
|
|
5bda352f7a | ||
|
|
4f08094de0 | ||
|
|
13a733a061 | ||
|
|
d010a4f21e | ||
|
|
a353c59e26 | ||
|
|
01c8aedced | ||
|
|
01d8842ac1 | ||
|
|
69a2261562 | ||
|
|
09905db72a | ||
|
|
754409c8fa | ||
|
|
cd67a3049a | ||
|
|
277aef341a | ||
|
|
9a5ef61bd1 | ||
|
|
ed6c59dd07 | ||
|
|
4deeac538a | ||
|
|
b05161d20e | ||
|
|
d02adf1bf3 | ||
|
|
f767b649e6 | ||
|
|
bdec15d943 | ||
|
|
fe4ac6643a | ||
|
|
eb72bc6d4f | ||
|
|
f484366612 | ||
|
|
bb5e45b939 | ||
|
|
2b41e47170 | ||
|
|
3c16852219 | ||
|
|
744417c7a2 | ||
|
|
4039e11e08 | ||
|
|
3c73a2d05a | ||
|
|
1ef247b093 | ||
|
|
d45d8873f5 | ||
|
|
396a03567c | ||
|
|
6a98e204a5 | ||
|
|
210a6612c7 | ||
|
|
27c35b3b09 | ||
|
|
ac1db841d5 | ||
|
|
09f29615c1 | ||
|
|
05e5a3f2bb | ||
|
|
6d238de69e | ||
|
|
5b88dbb90a | ||
|
|
fbd822cef7 | ||
|
|
0e22a120f1 | ||
|
|
590f3d0b1b | ||
|
|
23766d84fa | ||
|
|
14e9e618a2 | ||
|
|
f523cb243b | ||
|
|
1064818b49 | ||
|
|
befd1ca846 | ||
|
|
65c671d014 | ||
|
|
25bc0b8bf6 | ||
|
|
343a2a17e1 | ||
|
|
5100ed0b68 | ||
|
|
95dd2c148c | ||
|
|
354db6b306 | ||
|
|
50313a36dc | ||
|
|
77d5dcb6dd | ||
|
|
1c88fb65c8 | ||
|
|
db9660d090 | ||
|
|
39ab066e2d | ||
|
|
47f395dad7 | ||
|
|
04e195cdb2 | ||
|
|
3b3872ffe3 | ||
|
|
c7cda0df45 | ||
|
|
7651e75bfa | ||
|
|
ea99cd6115 | ||
|
|
3af4f33b5d | ||
|
|
41e8d5e5fc | ||
|
|
5a73c2bf2b | ||
|
|
f542fd0a88 | ||
|
|
5a6300823c |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
*.nuget.props
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
23
appveyor.yml
23
appveyor.yml
@@ -1,6 +1,7 @@
|
||||
version: 10.0.{build}
|
||||
image: Visual Studio 2017
|
||||
configuration: Release
|
||||
|
||||
install:
|
||||
- ps: >-
|
||||
cd src
|
||||
@@ -8,14 +9,14 @@ install:
|
||||
nuget restore Markdig.sln
|
||||
|
||||
$env:MARKDIG_BUILD_NUMBER = ([int]$env:APPVEYOR_BUILD_NUMBER).ToString("000")
|
||||
|
||||
|
||||
$env:MARKDIG_VERSION_SUFFIX = ""
|
||||
|
||||
$env:appveyor_nuget_push = 'false'
|
||||
|
||||
if(-Not $env:APPVEYOR_PULL_REQUEST_NUMBER) {
|
||||
if($env:appveyor_repo_tag -eq 'True') {
|
||||
if($env:appveyor_repo_tag_name -match '^v[0-9]') {
|
||||
if($env:appveyor_repo_tag_name -match '^[0-9]') {
|
||||
$env:appveyor_nuget_push = 'true'
|
||||
$env:MARKDIG_VERSION_SUFFIX = ""
|
||||
}
|
||||
@@ -25,21 +26,29 @@ install:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
build:
|
||||
project: src/Markdig.sln
|
||||
verbosity: minimal
|
||||
|
||||
after_build:
|
||||
- dotnet run --project SpecFileGen/SpecFileGen.csproj -c Release
|
||||
- cmd: >-
|
||||
dotnet run --project SpecFileGen/SpecFileGen.csproj -c Release
|
||||
|
||||
dotnet test -v n Markdig.Tests
|
||||
|
||||
before_package:
|
||||
- cmd: >-
|
||||
msbuild /t:pack /p:VersionSuffix="%MARKDIG_VERSION_SUFFIX%" /p:Configuration=Release Markdig/Markdig.csproj
|
||||
msbuild /t:pack /p:VersionSuffix="%MARKDIG_VERSION_SUFFIX%" /p:Configuration=Release Markdig/Markdig.csproj
|
||||
|
||||
msbuild /t:Clean Markdig/Markdig.csproj
|
||||
|
||||
msbuild /t:pack /p:VersionSuffix="%MARKDIG_VERSION_SUFFIX%" /p:Configuration=Release;SignAssembly=true Markdig/Markdig.csproj
|
||||
|
||||
msbuild /t:Clean Markdig/Markdig.csproj
|
||||
|
||||
msbuild /t:pack /p:VersionSuffix="%MARKDIG_VERSION_SUFFIX%" /p:Configuration=Release;SignAssembly=true Markdig/Markdig.csproj
|
||||
artifacts:
|
||||
- path: src\Markdig\Bin\Release\*.nupkg
|
||||
name: Markdig Nugets
|
||||
|
||||
deploy:
|
||||
- provider: NuGet
|
||||
api_key:
|
||||
|
||||
13
changelog.md
13
changelog.md
@@ -1,5 +1,14 @@
|
||||
# Changelog
|
||||
|
||||
## 0.17.0 (10 May 2019)
|
||||
- Update to latest CommonMark specs 0.29 ([(PR #327)](https://github.com/lunet-io/markdig/pull/327))
|
||||
- Add `AutoLinkOptions` with `OpenInNewWindow`, `UseHttpsForWWWLinks` ([(PR #327)](https://github.com/lunet-io/markdig/pull/327))
|
||||
- Add `DisableHeadings` extension method to `MarkdownPipelineBuilder` ([(PR #327)](https://github.com/lunet-io/markdig/pull/327))
|
||||
- Drop support for netstandard1.1 and Portable Class Libraries ([(PR #319)](https://github.com/lunet-io/markdig/pull/319))
|
||||
- Allow non-ASCII characters in url domain names ([(PR #319)](https://github.com/lunet-io/markdig/pull/319))
|
||||
- Add better support for youtu.be link ([(PR #336)](https://github.com/lunet-io/markdig/pull/336))
|
||||
- Fix backsticks in Markdown.Normalize ([(PR #334)](https://github.com/lunet-io/markdig/pull/334))
|
||||
|
||||
## 0.16.0 (25 Feb 2019)
|
||||
- Improve performance of emoji-abbreviation parser ([(PR #305)](https://github.com/lunet-io/markdig/pull/305))
|
||||
- Change output for math extension to use a rendering more compatible with existing Math JS libraries ([(PR #311)](https://github.com/lunet-io/markdig/pull/311))
|
||||
@@ -25,7 +34,7 @@
|
||||
- Ensuring line breaks when renderer does not have html enabled ([(PR #270)](https://github.com/lunet-io/markdig/pull/270))
|
||||
|
||||
## 0.15.4 (07 Oct 2018)
|
||||
- Add autolink domain GFM validation ([(PR #239)](https://github.com/lunet-io/markdig/pull/253))
|
||||
- Add autolink domain GFM validation ([(PR #253)](https://github.com/lunet-io/markdig/pull/253))
|
||||
|
||||
## 0.15.3 (15 Sep 2018)
|
||||
- Add support for RTL ([(PR #239)](https://github.com/lunet-io/markdig/pull/239))
|
||||
@@ -132,7 +141,7 @@
|
||||
## 0.8.3
|
||||
- fix NullReferenceException with Gridtables extension when a single `+` is entered on a line
|
||||
## 0.8.2
|
||||
- fix potential cast exception with Abreviation extension and empty literals
|
||||
- fix potential cast exception with Abbreviation extension and empty literals
|
||||
## 0.8.1
|
||||
- new extension to disable URI escaping for non-US-ASCII characters to workaround a bug in Edge/IE
|
||||
- Fix an issue with abbreviations with left/right multiple non-punctuation/space characters
|
||||
|
||||
@@ -14,7 +14,7 @@ You can **try Markdig online** and compare it to other implementations on [babel
|
||||
- **Abstract Syntax Tree** with precise source code location for syntax tree, useful when building a Markdown editor.
|
||||
- Checkout [MarkdownEditor for Visual Studio](https://visualstudiogallery.msdn.microsoft.com/eaab33c3-437b-4918-8354-872dfe5d1bfe) powered by Markdig!
|
||||
- Converter to **HTML**
|
||||
- Passing more than **600+ tests** from the latest [CommonMark specs (0.28)](http://spec.commonmark.org/)
|
||||
- Passing more than **600+ tests** from the latest [CommonMark specs (0.29)](http://spec.commonmark.org/)
|
||||
- Includes all the core elements of CommonMark:
|
||||
- including **GFM fenced code blocks**.
|
||||
- **Extensible** architecture
|
||||
|
||||
@@ -5397,7 +5397,7 @@ foo
|
||||
## Entity and numeric character references
|
||||
|
||||
All valid HTML entity references and numeric character
|
||||
references, except those occuring in code blocks and code spans,
|
||||
references, except those occurring in code blocks and code spans,
|
||||
are recognized as such and treated as equivalent to the
|
||||
corresponding Unicode characters. Conforming CommonMark parsers
|
||||
need not store information about whether a particular character
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
@@ -1,154 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{A0C5CB5F-5568-40AB-B945-D6D2664D51B0}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>Markdig.Tests</RootNamespace>
|
||||
<AssemblyName>Markdig.Tests</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<CopyNuGetImplementations>true</CopyNuGetImplementations>
|
||||
<TargetFrameworkProfile />
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject />
|
||||
<TargetFrameworks>net451;netcoreapp2.1</TargetFrameworks>
|
||||
<OutputType>Library</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
|
||||
<PackageReference Include="NUnit" Version="3.11.0" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Specs\AbbreviationSpecs.cs" />
|
||||
<Compile Include="Specs\AutoIdentifierSpecs.cs" />
|
||||
<Compile Include="Specs\AutoLinks.cs" />
|
||||
<Compile Include="Specs\BootstrapSpecs.cs" />
|
||||
<Compile Include="Specs\CommonMark.cs" />
|
||||
<Compile Include="Specs\CustomContainerSpecs.cs" />
|
||||
<Compile Include="Specs\DefinitionListSpecs.cs" />
|
||||
<Compile Include="Specs\DiagramsSpecs.cs" />
|
||||
<Compile Include="Specs\EmojiSpecs.cs" />
|
||||
<Compile Include="Specs\EmphasisExtraSpecs.cs" />
|
||||
<Compile Include="Specs\FigureFooterAndCiteSpecs.cs" />
|
||||
<Compile Include="Specs\FootnotesSpecs.cs" />
|
||||
<Compile Include="Specs\GenericAttributesSpecs.cs" />
|
||||
<Compile Include="Specs\GlobalizationSpecs.cs" />
|
||||
<Compile Include="Specs\GridTableSpecs.cs" />
|
||||
<Compile Include="Specs\HardlineBreakSpecs.cs" />
|
||||
<Compile Include="Specs\JiraLinks.cs" />
|
||||
<Compile Include="Specs\ListExtraSpecs.cs" />
|
||||
<Compile Include="Specs\MathSpecs.cs" />
|
||||
<Compile Include="Specs\MediaSpecs.cs" />
|
||||
<Compile Include="Specs\NoHtmlSpecs.cs" />
|
||||
<Compile Include="Specs\PipeTableSpecs.cs" />
|
||||
<Compile Include="Specs\SmartyPantsSpecs.cs" />
|
||||
<Compile Include="Specs\TaskListSpecs.cs" />
|
||||
<Compile Include="Specs\YamlSpecs.cs" />
|
||||
<Compile Include="TestEmphasisExtended.cs" />
|
||||
<Compile Include="TestEmphasisPlus.cs" />
|
||||
<Compile Include="TestEmphasisExtraOptions.cs" />
|
||||
<Compile Include="TestDescendantsOrder.cs" />
|
||||
<Compile Include="TestConfigureNewLine.cs" />
|
||||
<Compile Include="TestHtmlAttributes.cs" />
|
||||
<Compile Include="TestHtmlHelper.cs" />
|
||||
<Compile Include="TestLineReader.cs" />
|
||||
<Compile Include="TestLinkHelper.cs" />
|
||||
<Compile Include="TestNormalize.cs" />
|
||||
<Compile Include="TestOrderedList.cs" />
|
||||
<Compile Include="TestPlainText.cs" />
|
||||
<Compile Include="TestPragmaLines.cs" />
|
||||
<Compile Include="TestLinkRewriter.cs" />
|
||||
<Compile Include="TestRelativeUrlReplacement.cs" />
|
||||
<Compile Include="TestSourcePosition.cs" />
|
||||
<Compile Include="TestStringSliceList.cs" />
|
||||
<Compile Include="TestPlayParser.cs" />
|
||||
<Compile Include="TextAssert.cs" />
|
||||
<Compile Include="TestParser.cs" />
|
||||
<ProjectReference Include="..\Markdig\Markdig.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<Content Include="ArgumentOutOfRangeException.md">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="hang.md">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<None Include="project.json" />
|
||||
<None Include="Specs\CommonMark.md" />
|
||||
<None Include="Specs\GlobalizationSpecs.md" />
|
||||
<None Include="Specs\JiraLinks.md" />
|
||||
<None Include="Specs\AutoLinks.md" />
|
||||
<None Include="Specs\AutoIdentifierSpecs.md" />
|
||||
<None Include="Specs\AbbreviationSpecs.md" />
|
||||
<None Include="Specs\FigureFooterAndCiteSpecs.md" />
|
||||
<None Include="Specs\ListExtraSpecs.md" />
|
||||
<None Include="Specs\GenericAttributesSpecs.md" />
|
||||
<None Include="Specs\CustomContainerSpecs.md" />
|
||||
<None Include="Specs\DefinitionListSpecs.md" />
|
||||
<None Include="Specs\EmojiSpecs.md" />
|
||||
<None Include="Specs\FootnotesSpecs.md" />
|
||||
<None Include="Specs\GridTableSpecs.md" />
|
||||
<None Include="Specs\HardlineBreakSpecs.md" />
|
||||
<None Include="Specs\BootstrapSpecs.md" />
|
||||
<None Include="Specs\DiagramsSpecs.md" />
|
||||
<None Include="Specs\NoHtmlSpecs.md" />
|
||||
<None Include="Specs\readme.md" />
|
||||
<None Include="Specs\YamlSpecs.md" />
|
||||
<None Include="Specs\TaskListSpecs.md" />
|
||||
<None Include="Specs\SmartyPantsSpecs.md" />
|
||||
<None Include="Specs\MediaSpecs.md" />
|
||||
<None Include="Specs\MathSpecs.md" />
|
||||
<None Include="Specs\PipeTableSpecs.md" />
|
||||
<None Include="Specs\EmphasisExtraSpecs.md" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{508349B6-6B84-4DF5-91F0-309BEEBAD82D}" />
|
||||
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Markdig\Markdig.csproj">
|
||||
<Project>{8a58a7e2-627c-4f41-933f-5ac92adfab48}</Project>
|
||||
<Name>Markdig</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
|
||||
</Project>
|
||||
183
src/Markdig.Tests/MiscTests.cs
Normal file
183
src/Markdig.Tests/MiscTests.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using Markdig.Extensions.AutoLinks;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
public class MiscTests
|
||||
{
|
||||
[Test]
|
||||
public void TestChangelogPRLinksMatchDescription()
|
||||
{
|
||||
string solutionFolder = Path.GetFullPath(Path.Combine(TestParser.TestsDirectory, "../.."));
|
||||
string changelogPath = Path.Combine(solutionFolder, "changelog.md");
|
||||
string changelog = File.ReadAllText(changelogPath);
|
||||
var matches = Regex.Matches(changelog, @"\(\[\(PR #(\d+)\)\]\(.*?pull\/(\d+)\)\)");
|
||||
Assert.Greater(matches.Count, 0);
|
||||
foreach (Match match in matches)
|
||||
{
|
||||
Assert.True(int.TryParse(match.Groups[1].Value, out int textNr));
|
||||
Assert.True(int.TryParse(match.Groups[2].Value, out int linkNr));
|
||||
Assert.AreEqual(textNr, linkNr);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestFixHang()
|
||||
{
|
||||
var input = File.ReadAllText(Path.Combine(TestParser.TestsDirectory, "hang.md"));
|
||||
_ = Markdown.ToHtml(input);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInvalidHtmlEntity()
|
||||
{
|
||||
var input = "9&ddr;&*&ddr;&de<64><65>__";
|
||||
TestParser.TestSpec(input, "<p>9&ddr;&*&ddr;&de<64><65>__</p>");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInvalidCharacterHandling()
|
||||
{
|
||||
var input = File.ReadAllText(Path.Combine(TestParser.TestsDirectory, "ArgumentOutOfRangeException.md"));
|
||||
_ = Markdown.ToHtml(input);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInvalidCodeEscape()
|
||||
{
|
||||
var input = "```**Header** ";
|
||||
_ = Markdown.ToHtml(input);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmphasisAndHtmlEntity()
|
||||
{
|
||||
var markdownText = "*Unlimited-Fun®*®";
|
||||
TestParser.TestSpec(markdownText, "<p><em>Unlimited-Fun®</em>®</p>");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestThematicInsideCodeBlockInsideList()
|
||||
{
|
||||
var input = @"1. In the :
|
||||
|
||||
```
|
||||
Id DisplayName Description
|
||||
-- ----------- -----------
|
||||
62375ab9-6b52-47ed-826b-58e47e0e304b Group.Unified ...
|
||||
```";
|
||||
TestParser.TestSpec(input, @"<ol>
|
||||
<li><p>In the :</p>
|
||||
<pre><code>Id DisplayName Description
|
||||
-- ----------- -----------
|
||||
62375ab9-6b52-47ed-826b-58e47e0e304b Group.Unified ...
|
||||
</code></pre></li>
|
||||
</ol>");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VisualizeMathExpressions()
|
||||
{
|
||||
string math = @"Math expressions
|
||||
|
||||
$\frac{n!}{k!(n-k)!} = \binom{n}{k}$
|
||||
|
||||
$$\frac{n!}{k!(n-k)!} = \binom{n}{k}$$
|
||||
|
||||
$$
|
||||
\frac{n!}{k!(n-k)!} = \binom{n}{k}
|
||||
$$
|
||||
|
||||
<div class=""math"">
|
||||
\begin{align}
|
||||
\sqrt{37} & = \sqrt{\frac{73^2-1}{12^2}} \\
|
||||
& = \sqrt{\frac{73^2}{12^2}\cdot\frac{73^2-1}{73^2}} \\
|
||||
& = \sqrt{\frac{73^2}{12^2}}\sqrt{\frac{73^2-1}{73^2}} \\
|
||||
& = \frac{73}{12}\sqrt{1 - \frac{1}{73^2}} \\
|
||||
& \approx \frac{73}{12}\left(1 - \frac{1}{2\cdot73^2}\right)
|
||||
\end{align}
|
||||
</div>
|
||||
";
|
||||
Console.WriteLine("Math Expressions:\n");
|
||||
|
||||
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
|
||||
|
||||
|
||||
var html = Markdown.ToHtml(math, pl);
|
||||
Console.WriteLine(html);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InlineMathExpression()
|
||||
{
|
||||
string math = @"Math expressions
|
||||
|
||||
$\frac{n!}{k!(n-k)!} = \binom{n}{k}$
|
||||
";
|
||||
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
|
||||
|
||||
var html = Markdown.ToHtml(math, pl);
|
||||
Console.WriteLine(html);
|
||||
|
||||
Assert.IsTrue(html.Contains("<p><span class=\"math\">\\("), "Leading bracket missing");
|
||||
Assert.IsTrue(html.Contains("\\)</span></p>"), "Trailing bracket missing");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BlockMathExpression()
|
||||
{
|
||||
string math = @"Math expressions
|
||||
|
||||
$$
|
||||
\frac{n!}{k!(n-k)!} = \binom{n}{k}
|
||||
$$
|
||||
";
|
||||
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
|
||||
|
||||
var html = Markdown.ToHtml(math, pl);
|
||||
Console.WriteLine(html);
|
||||
|
||||
Assert.IsTrue(html.Contains("<div class=\"math\">\n\\["), "Leading bracket missing");
|
||||
Assert.IsTrue(html.Contains("\\]</div>"), "Trailing bracket missing");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanDisableParsingHeadings()
|
||||
{
|
||||
var noHeadingsPipeline = new MarkdownPipelineBuilder().DisableHeadings().Build();
|
||||
|
||||
TestParser.TestSpec("Foo\n===", "<h1>Foo</h1>");
|
||||
TestParser.TestSpec("Foo\n===", "<p>Foo\n===</p>", noHeadingsPipeline);
|
||||
|
||||
TestParser.TestSpec("# Heading 1", "<h1>Heading 1</h1>");
|
||||
TestParser.TestSpec("# Heading 1", "<p># Heading 1</p>", noHeadingsPipeline);
|
||||
|
||||
// Does not also disable link reference definitions
|
||||
TestParser.TestSpec("[Foo]\n\n[Foo]: bar", "<p><a href=\"bar\">Foo</a></p>");
|
||||
TestParser.TestSpec("[Foo]\n\n[Foo]: bar", "<p><a href=\"bar\">Foo</a></p>", noHeadingsPipeline);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanOpenAutoLinksInNewWindow()
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder().UseAutoLinks().Build();
|
||||
var newWindowPipeline = new MarkdownPipelineBuilder().UseAutoLinks(new AutoLinkOptions() { OpenInNewWindow = true }).Build();
|
||||
|
||||
TestParser.TestSpec("www.foo.bar", "<p><a href=\"http://www.foo.bar\">www.foo.bar</a></p>", pipeline);
|
||||
TestParser.TestSpec("www.foo.bar", "<p><a href=\"http://www.foo.bar\" target=\"blank\">www.foo.bar</a></p>", newWindowPipeline);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanUseHttpsPrefixForWWWAutoLinks()
|
||||
{
|
||||
var pipeline = new MarkdownPipelineBuilder().UseAutoLinks().Build();
|
||||
var httpsPipeline = new MarkdownPipelineBuilder().UseAutoLinks(new AutoLinkOptions() { UseHttpsForWWWLinks = true }).Build();
|
||||
|
||||
TestParser.TestSpec("www.foo.bar", "<p><a href=\"http://www.foo.bar\">www.foo.bar</a></p>", pipeline);
|
||||
TestParser.TestSpec("www.foo.bar", "<p><a href=\"https://www.foo.bar\">www.foo.bar</a></p>", httpsPipeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
93
src/Markdig.Tests/NormalizeSpecs/Headings.generated.cs
Normal file
93
src/Markdig.Tests/NormalizeSpecs/Headings.generated.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Headings
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Normalize.Headings
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestHeadings
|
||||
{
|
||||
// # Headings
|
||||
[Test]
|
||||
public void Headings_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Headings
|
||||
//
|
||||
// The following Markdown:
|
||||
// # Heading 1
|
||||
//
|
||||
// ## Heading 2
|
||||
//
|
||||
// ### Heading 3
|
||||
//
|
||||
// #### Heading 4
|
||||
//
|
||||
// ##### Heading 5
|
||||
//
|
||||
// ###### Heading 6
|
||||
//
|
||||
// Should be rendered as:
|
||||
// # Heading 1
|
||||
//
|
||||
// ## Heading 2
|
||||
//
|
||||
// ### Heading 3
|
||||
//
|
||||
// #### Heading 4
|
||||
//
|
||||
// ##### Heading 5
|
||||
//
|
||||
// ###### Heading 6
|
||||
|
||||
Console.WriteLine("Example 1\nSection Headings\n");
|
||||
TestNormalize.TestSpec("# Heading 1\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6", "# Heading 1\n\n## Heading 2\n\n### Heading 3\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6", "");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Headings_Example002()
|
||||
{
|
||||
// Example 2
|
||||
// Section: Headings
|
||||
//
|
||||
// The following Markdown:
|
||||
// ###### Heading
|
||||
//
|
||||
// Text after two newlines
|
||||
//
|
||||
// Should be rendered as:
|
||||
// ###### Heading
|
||||
//
|
||||
// Text after two newlines
|
||||
|
||||
Console.WriteLine("Example 2\nSection Headings\n");
|
||||
TestNormalize.TestSpec("###### Heading\n\nText after two newlines", "###### Heading\n\nText after two newlines", "");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Headings_Example003()
|
||||
{
|
||||
// Example 3
|
||||
// Section: Headings
|
||||
//
|
||||
// The following Markdown:
|
||||
// Heading
|
||||
// =======
|
||||
//
|
||||
// Text after two newlines
|
||||
//
|
||||
// Should be rendered as:
|
||||
// # Heading
|
||||
//
|
||||
// Text after two newlines
|
||||
|
||||
Console.WriteLine("Example 3\nSection Headings\n");
|
||||
TestNormalize.TestSpec("Heading\n=======\n\nText after two newlines", "# Heading\n\nText after two newlines", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
48
src/Markdig.Tests/NormalizeSpecs/Headings.md
Normal file
48
src/Markdig.Tests/NormalizeSpecs/Headings.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# Headings
|
||||
|
||||
```````````````````````````````` example
|
||||
# Heading 1
|
||||
|
||||
## Heading 2
|
||||
|
||||
### Heading 3
|
||||
|
||||
#### Heading 4
|
||||
|
||||
##### Heading 5
|
||||
|
||||
###### Heading 6
|
||||
.
|
||||
# Heading 1
|
||||
|
||||
## Heading 2
|
||||
|
||||
### Heading 3
|
||||
|
||||
#### Heading 4
|
||||
|
||||
##### Heading 5
|
||||
|
||||
###### Heading 6
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
###### Heading
|
||||
|
||||
Text after two newlines
|
||||
.
|
||||
###### Heading
|
||||
|
||||
Text after two newlines
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
Heading
|
||||
=======
|
||||
|
||||
Text after two newlines
|
||||
.
|
||||
# Heading
|
||||
|
||||
Text after two newlines
|
||||
````````````````````````````````
|
||||
@@ -0,0 +1,35 @@
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Sample
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.PlainText.Sample
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSamplePlainTextSpec
|
||||
{
|
||||
// # Sample plain text spec
|
||||
//
|
||||
// Emphasis and anchors are stripped. A newline is ensured.
|
||||
[Test]
|
||||
public void SamplePlainTextSpec_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Sample plain text spec
|
||||
//
|
||||
// The following Markdown:
|
||||
// *Hello*, [world](http://example.com)!
|
||||
//
|
||||
// Should be rendered as:
|
||||
// Hello, world!
|
||||
//
|
||||
|
||||
Console.WriteLine("Example 1\nSection Sample plain text spec\n");
|
||||
TestPlainText.TestSpec("*Hello*, [world](http://example.com)!", "Hello, world!\n", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/Markdig.Tests/PlainTextSpecs/SamplePlainText.md
Normal file
10
src/Markdig.Tests/PlainTextSpecs/SamplePlainText.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Sample plain text spec
|
||||
|
||||
Emphasis and anchors are stripped. A newline is ensured.
|
||||
|
||||
```````````````````````````````` example
|
||||
*Hello*, [world](http://example.com)!
|
||||
.
|
||||
Hello, world!
|
||||
|
||||
````````````````````````````````
|
||||
@@ -1,14 +0,0 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main()
|
||||
{
|
||||
new TestPlayParser().TestSimple();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
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
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Textamin.Tests")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Textamin.Tests")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2016")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("a0c5cb5f-5568-40ab-b945-d6d2664d51b0")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 6. 02. 2019 16:15:54
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Abbreviations
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Auto Identifiers
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Auto Links
|
||||
@@ -446,4 +446,113 @@ namespace Markdig.Tests.Specs.AutoLinks
|
||||
TestParser.TestSpec("https://github.com?\n\nhttps://github.com?a\n\nhttps://github.com#a\n\nhttps://github.com:\n\nhttps://github.com:443", "<p><a href=\"https://github.com\">https://github.com</a>?</p>\n<p><a href=\"https://github.com?a\">https://github.com?a</a></p>\n<p><a href=\"https://github.com#a\">https://github.com#a</a></p>\n<p><a href=\"https://github.com\">https://github.com</a>:</p>\n<p><a href=\"https://github.com:443\">https://github.com:443</a></p>", "autolinks|advanced");
|
||||
}
|
||||
}
|
||||
|
||||
[TestFixture]
|
||||
public class TestExtensionsAutoLinksUnicodeSupport
|
||||
{
|
||||
// ### Unicode support
|
||||
//
|
||||
// Links with unicode characters in the path / query / fragment are matched and url encoded
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksUnicodeSupport_Example021()
|
||||
{
|
||||
// Example 21
|
||||
// Section: Extensions / AutoLinks / Unicode support
|
||||
//
|
||||
// The following Markdown:
|
||||
// http://abc.net/☃
|
||||
//
|
||||
// http://abc.net?☃
|
||||
//
|
||||
// http://abc.net#☃
|
||||
//
|
||||
// http://abc.net/foo#☃
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://abc.net/%E2%98%83">http://abc.net/☃</a></p>
|
||||
// <p><a href="http://abc.net?%E2%98%83">http://abc.net?☃</a></p>
|
||||
// <p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
|
||||
// <p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
|
||||
|
||||
Console.WriteLine("Example 21\nSection Extensions / AutoLinks / Unicode support\n");
|
||||
TestParser.TestSpec("http://abc.net/☃\n\nhttp://abc.net?☃\n\nhttp://abc.net#☃\n\nhttp://abc.net/foo#☃", "<p><a href=\"http://abc.net/%E2%98%83\">http://abc.net/☃</a></p>\n<p><a href=\"http://abc.net?%E2%98%83\">http://abc.net?☃</a></p>\n<p><a href=\"http://abc.net#%E2%98%83\">http://abc.net#☃</a></p>\n<p><a href=\"http://abc.net/foo#%E2%98%83\">http://abc.net/foo#☃</a></p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// Unicode characters in the FQDN are matched and IDNA encoded
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksUnicodeSupport_Example022()
|
||||
{
|
||||
// Example 22
|
||||
// Section: Extensions / AutoLinks / Unicode support
|
||||
//
|
||||
// The following Markdown:
|
||||
// http://☃.net?☃
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
|
||||
|
||||
Console.WriteLine("Example 22\nSection Extensions / AutoLinks / Unicode support\n");
|
||||
TestParser.TestSpec("http://☃.net?☃", "<p><a href=\"http://xn--n3h.net?%E2%98%83\">http://☃.net?☃</a></p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// Same goes for regular autolinks
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksUnicodeSupport_Example023()
|
||||
{
|
||||
// Example 23
|
||||
// Section: Extensions / AutoLinks / Unicode support
|
||||
//
|
||||
// The following Markdown:
|
||||
// <http://abc.net/☃>
|
||||
//
|
||||
// <http://abc.net?☃>
|
||||
//
|
||||
// <http://abc.net#☃>
|
||||
//
|
||||
// <http://abc.net/foo#☃>
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://abc.net/%E2%98%83">http://abc.net/☃</a></p>
|
||||
// <p><a href="http://abc.net?%E2%98%83">http://abc.net?☃</a></p>
|
||||
// <p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
|
||||
// <p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
|
||||
|
||||
Console.WriteLine("Example 23\nSection Extensions / AutoLinks / Unicode support\n");
|
||||
TestParser.TestSpec("<http://abc.net/☃>\n\n<http://abc.net?☃>\n\n<http://abc.net#☃>\n\n<http://abc.net/foo#☃>", "<p><a href=\"http://abc.net/%E2%98%83\">http://abc.net/☃</a></p>\n<p><a href=\"http://abc.net?%E2%98%83\">http://abc.net?☃</a></p>\n<p><a href=\"http://abc.net#%E2%98%83\">http://abc.net#☃</a></p>\n<p><a href=\"http://abc.net/foo#%E2%98%83\">http://abc.net/foo#☃</a></p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksUnicodeSupport_Example024()
|
||||
{
|
||||
// Example 24
|
||||
// Section: Extensions / AutoLinks / Unicode support
|
||||
//
|
||||
// The following Markdown:
|
||||
// <http://☃.net?☃>
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
|
||||
|
||||
Console.WriteLine("Example 24\nSection Extensions / AutoLinks / Unicode support\n");
|
||||
TestParser.TestSpec("<http://☃.net?☃>", "<p><a href=\"http://xn--n3h.net?%E2%98%83\">http://☃.net?☃</a></p>", "autolinks|advanced");
|
||||
}
|
||||
|
||||
// It also complies with CommonMark's vision of priority.
|
||||
// This will therefore be seen as an autolink and not as code inline.
|
||||
[Test]
|
||||
public void ExtensionsAutoLinksUnicodeSupport_Example025()
|
||||
{
|
||||
// Example 25
|
||||
// Section: Extensions / AutoLinks / Unicode support
|
||||
//
|
||||
// The following Markdown:
|
||||
// <http://foö.bar.`baz>`
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><a href="http://xn--fo-gka.bar.%60baz">http://foö.bar.`baz</a>`</p>
|
||||
|
||||
Console.WriteLine("Example 25\nSection Extensions / AutoLinks / Unicode support\n");
|
||||
TestParser.TestSpec("<http://foö.bar.`baz>`", "<p><a href=\"http://xn--fo-gka.bar.%60baz\">http://foö.bar.`baz</a>`</p>", "autolinks|advanced");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,4 +239,63 @@ https://github.com:443
|
||||
<p><a href="https://github.com#a">https://github.com#a</a></p>
|
||||
<p><a href="https://github.com">https://github.com</a>:</p>
|
||||
<p><a href="https://github.com:443">https://github.com:443</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
### Unicode support
|
||||
|
||||
Links with unicode characters in the path / query / fragment are matched and url encoded
|
||||
|
||||
```````````````````````````````` example
|
||||
http://abc.net/☃
|
||||
|
||||
http://abc.net?☃
|
||||
|
||||
http://abc.net#☃
|
||||
|
||||
http://abc.net/foo#☃
|
||||
.
|
||||
<p><a href="http://abc.net/%E2%98%83">http://abc.net/☃</a></p>
|
||||
<p><a href="http://abc.net?%E2%98%83">http://abc.net?☃</a></p>
|
||||
<p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
|
||||
<p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
Unicode characters in the FQDN are matched and IDNA encoded
|
||||
|
||||
```````````````````````````````` example
|
||||
http://☃.net?☃
|
||||
.
|
||||
<p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
Same goes for regular autolinks
|
||||
|
||||
```````````````````````````````` example
|
||||
<http://abc.net/☃>
|
||||
|
||||
<http://abc.net?☃>
|
||||
|
||||
<http://abc.net#☃>
|
||||
|
||||
<http://abc.net/foo#☃>
|
||||
.
|
||||
<p><a href="http://abc.net/%E2%98%83">http://abc.net/☃</a></p>
|
||||
<p><a href="http://abc.net?%E2%98%83">http://abc.net?☃</a></p>
|
||||
<p><a href="http://abc.net#%E2%98%83">http://abc.net#☃</a></p>
|
||||
<p><a href="http://abc.net/foo#%E2%98%83">http://abc.net/foo#☃</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
<http://☃.net?☃>
|
||||
.
|
||||
<p><a href="http://xn--n3h.net?%E2%98%83">http://☃.net?☃</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
It also complies with CommonMark's vision of priority.
|
||||
This will therefore be seen as an autolink and not as code inline.
|
||||
|
||||
```````````````````````````````` example
|
||||
<http://foö.bar.`baz>`
|
||||
.
|
||||
<p><a href="http://xn--fo-gka.bar.%60baz">http://foö.bar.`baz</a>`</p>
|
||||
````````````````````````````````
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-15 05:23:49
|
||||
|
||||
// --------------------------------
|
||||
// Bootstrap
|
||||
@@ -14,7 +14,7 @@ namespace Markdig.Tests.Specs.Bootstrap
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// Adds support for outputing bootstrap ready tags:
|
||||
// Adds support for outputting bootstrap ready tags:
|
||||
//
|
||||
// ## Bootstrap
|
||||
//
|
||||
@@ -1,6 +1,6 @@
|
||||
# Extensions
|
||||
|
||||
Adds support for outputing bootstrap ready tags:
|
||||
Adds support for outputting bootstrap ready tags:
|
||||
|
||||
## Bootstrap
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
||||
---
|
||||
title: CommonMark Spec
|
||||
author: John MacFarlane
|
||||
version: 0.28
|
||||
date: '2017-08-01'
|
||||
version: 0.29
|
||||
date: '2019-04-06'
|
||||
license: '[CC-BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/)'
|
||||
...
|
||||
|
||||
@@ -248,7 +248,7 @@ satisfactory replacement for a spec.
|
||||
|
||||
Because there is no unambiguous spec, implementations have diverged
|
||||
considerably. As a result, users are often surprised to find that
|
||||
a document that renders one way on one system (say, a github wiki)
|
||||
a document that renders one way on one system (say, a GitHub wiki)
|
||||
renders differently on another (say, converting to docbook using
|
||||
pandoc). To make matters worse, because nothing in Markdown counts
|
||||
as a "syntax error," the divergence often isn't discovered right away.
|
||||
@@ -328,8 +328,10 @@ that is not a [whitespace character].
|
||||
|
||||
An [ASCII punctuation character](@)
|
||||
is `!`, `"`, `#`, `$`, `%`, `&`, `'`, `(`, `)`,
|
||||
`*`, `+`, `,`, `-`, `.`, `/`, `:`, `;`, `<`, `=`, `>`, `?`, `@`,
|
||||
`[`, `\`, `]`, `^`, `_`, `` ` ``, `{`, `|`, `}`, or `~`.
|
||||
`*`, `+`, `,`, `-`, `.`, `/` (U+0021–2F),
|
||||
`:`, `;`, `<`, `=`, `>`, `?`, `@` (U+003A–0040),
|
||||
`[`, `\`, `]`, `^`, `_`, `` ` `` (U+005B–0060),
|
||||
`{`, `|`, `}`, or `~` (U+007B–007E).
|
||||
|
||||
A [punctuation character](@) is an [ASCII
|
||||
punctuation character] or anything in
|
||||
@@ -514,8 +516,8 @@ one block element does not affect the inline parsing of any other.
|
||||
## Container blocks and leaf blocks
|
||||
|
||||
We can divide blocks into two types:
|
||||
[container block](@)s,
|
||||
which can contain other blocks, and [leaf block](@)s,
|
||||
[container blocks](@),
|
||||
which can contain other blocks, and [leaf blocks](@),
|
||||
which cannot.
|
||||
|
||||
# Leaf blocks
|
||||
@@ -527,7 +529,7 @@ Markdown document.
|
||||
|
||||
A line consisting of 0-3 spaces of indentation, followed by a sequence
|
||||
of three or more matching `-`, `_`, or `*` characters, each followed
|
||||
optionally by any number of spaces, forms a
|
||||
optionally by any number of spaces or tabs, forms a
|
||||
[thematic break](@).
|
||||
|
||||
```````````````````````````````` example
|
||||
@@ -825,7 +827,7 @@ Contents are parsed as inlines:
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
Leading and trailing blanks are ignored in parsing inline content:
|
||||
Leading and trailing [whitespace] is ignored in parsing inline content:
|
||||
|
||||
```````````````````````````````` example
|
||||
# foo
|
||||
@@ -1024,6 +1026,20 @@ baz*
|
||||
baz</em></h1>
|
||||
````````````````````````````````
|
||||
|
||||
The contents are the result of parsing the headings's raw
|
||||
content as inlines. The heading's raw content is formed by
|
||||
concatenating the lines and removing initial and final
|
||||
[whitespace].
|
||||
|
||||
```````````````````````````````` example
|
||||
Foo *bar
|
||||
baz*→
|
||||
====
|
||||
.
|
||||
<h1>Foo <em>bar
|
||||
baz</em></h1>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
The underlining can be any length:
|
||||
|
||||
@@ -1584,8 +1600,8 @@ begins with a code fence, indented no more than three spaces.
|
||||
|
||||
The line with the opening code fence may optionally contain some text
|
||||
following the code fence; this is trimmed of leading and trailing
|
||||
spaces and called the [info string](@).
|
||||
The [info string] may not contain any backtick
|
||||
whitespace and called the [info string](@). If the [info string] comes
|
||||
after a backtick fence, it may not contain any backtick
|
||||
characters. (The reason for this restriction is that otherwise
|
||||
some inline code would be incorrectly interpreted as the
|
||||
beginning of a fenced code block.)
|
||||
@@ -1870,7 +1886,7 @@ Code fences (opening and closing) cannot contain internal spaces:
|
||||
``` ```
|
||||
aaa
|
||||
.
|
||||
<p><code></code>
|
||||
<p><code> </code>
|
||||
aaa</p>
|
||||
````````````````````````````````
|
||||
|
||||
@@ -1922,9 +1938,11 @@ bar
|
||||
|
||||
|
||||
An [info string] can be provided after the opening code fence.
|
||||
Opening and closing spaces will be stripped, and the first word, prefixed
|
||||
with `language-`, is used as the value for the `class` attribute of the
|
||||
`code` element within the enclosing `pre` element.
|
||||
Although this spec doesn't mandate any particular treatment of
|
||||
the info string, the first word is typically used to specify
|
||||
the language of the code block. In HTML output, the language is
|
||||
normally indicated by adding a class to the `code` element consisting
|
||||
of `language-` followed by the language name.
|
||||
|
||||
```````````````````````````````` example
|
||||
```ruby
|
||||
@@ -1973,6 +1991,18 @@ foo</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
[Info strings] for tilde code blocks can contain backticks and tildes:
|
||||
|
||||
```````````````````````````````` example
|
||||
~~~ aa ``` ~~~
|
||||
foo
|
||||
~~~
|
||||
.
|
||||
<pre><code class="language-aa">foo
|
||||
</code></pre>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
Closing code fences cannot have [info strings]:
|
||||
|
||||
```````````````````````````````` example
|
||||
@@ -1991,14 +2021,15 @@ Closing code fences cannot have [info strings]:
|
||||
An [HTML block](@) is a group of lines that is treated
|
||||
as raw HTML (and will not be escaped in HTML output).
|
||||
|
||||
There are seven kinds of [HTML block], which can be defined
|
||||
by their start and end conditions. The block begins with a line that
|
||||
meets a [start condition](@) (after up to three spaces
|
||||
optional indentation). It ends with the first subsequent line that
|
||||
meets a matching [end condition](@), or the last line of
|
||||
the document or other [container block]), if no line is encountered that meets the
|
||||
[end condition]. If the first line meets both the [start condition]
|
||||
and the [end condition], the block will contain just that line.
|
||||
There are seven kinds of [HTML block], which can be defined by their
|
||||
start and end conditions. The block begins with a line that meets a
|
||||
[start condition](@) (after up to three spaces optional indentation).
|
||||
It ends with the first subsequent line that meets a matching [end
|
||||
condition](@), or the last line of the document, or the last line of
|
||||
the [container block](#container-blocks) containing the current HTML
|
||||
block, if no line is encountered that meets the [end condition]. If
|
||||
the first line meets both the [start condition] and the [end
|
||||
condition], the block will contain just that line.
|
||||
|
||||
1. **Start condition:** line begins with the string `<script`,
|
||||
`<pre`, or `<style` (case-insensitive), followed by whitespace,
|
||||
@@ -2029,7 +2060,7 @@ followed by one of the strings (case-insensitive) `address`,
|
||||
`footer`, `form`, `frame`, `frameset`,
|
||||
`h1`, `h2`, `h3`, `h4`, `h5`, `h6`, `head`, `header`, `hr`,
|
||||
`html`, `iframe`, `legend`, `li`, `link`, `main`, `menu`, `menuitem`,
|
||||
`meta`, `nav`, `noframes`, `ol`, `optgroup`, `option`, `p`, `param`,
|
||||
`nav`, `noframes`, `ol`, `optgroup`, `option`, `p`, `param`,
|
||||
`section`, `source`, `summary`, `table`, `tbody`, `td`,
|
||||
`tfoot`, `th`, `thead`, `title`, `tr`, `track`, `ul`, followed
|
||||
by [whitespace], the end of the line, the string `>`, or
|
||||
@@ -2037,16 +2068,17 @@ the string `/>`.\
|
||||
**End condition:** line is followed by a [blank line].
|
||||
|
||||
7. **Start condition:** line begins with a complete [open tag]
|
||||
or [closing tag] (with any [tag name] other than `script`,
|
||||
`style`, or `pre`) followed only by [whitespace]
|
||||
or the end of the line.\
|
||||
(with any [tag name] other than `script`,
|
||||
`style`, or `pre`) or a complete [closing tag],
|
||||
followed only by [whitespace] or the end of the line.\
|
||||
**End condition:** line is followed by a [blank line].
|
||||
|
||||
HTML blocks continue until they are closed by their appropriate
|
||||
[end condition], or the last line of the document or other [container block].
|
||||
This means any HTML **within an HTML block** that might otherwise be recognised
|
||||
as a start condition will be ignored by the parser and passed through as-is,
|
||||
without changing the parser's state.
|
||||
[end condition], or the last line of the document or other [container
|
||||
block](#container-blocks). This means any HTML **within an HTML
|
||||
block** that might otherwise be recognised as a start condition will
|
||||
be ignored by the parser and passed through as-is, without changing
|
||||
the parser's state.
|
||||
|
||||
For instance, `<pre>` within a HTML block started by `<table>` will not affect
|
||||
the parser state; as the HTML block was started in by start condition 6, it
|
||||
@@ -2069,7 +2101,7 @@ _world_.
|
||||
</td></tr></table>
|
||||
````````````````````````````````
|
||||
|
||||
In this case, the HTML block is terminated by the newline — the `**hello**`
|
||||
In this case, the HTML block is terminated by the newline — the `**Hello**`
|
||||
text remains verbatim — and regular parsing resumes, with a paragraph,
|
||||
emphasised `world` and inline and block HTML following.
|
||||
|
||||
@@ -2612,7 +2644,8 @@ bar
|
||||
|
||||
|
||||
However, a following blank line is needed, except at the end of
|
||||
a document, and except for blocks of types 1--5, above:
|
||||
a document, and except for blocks of types 1--5, [above][HTML
|
||||
block]:
|
||||
|
||||
```````````````````````````````` example
|
||||
<div>
|
||||
@@ -2758,8 +2791,8 @@ an indented code block:
|
||||
|
||||
Fortunately, blank lines are usually not necessary and can be
|
||||
deleted. The exception is inside `<pre>` tags, but as described
|
||||
above, raw HTML blocks starting with `<pre>` *can* contain blank
|
||||
lines.
|
||||
[above][HTML blocks], raw HTML blocks starting with `<pre>`
|
||||
*can* contain blank lines.
|
||||
|
||||
## Link reference definitions
|
||||
|
||||
@@ -2811,7 +2844,7 @@ them.
|
||||
|
||||
```````````````````````````````` example
|
||||
[Foo bar]:
|
||||
<my%20url>
|
||||
<my url>
|
||||
'title'
|
||||
|
||||
[Foo bar]
|
||||
@@ -2877,6 +2910,29 @@ The link destination may not be omitted:
|
||||
<p>[foo]</p>
|
||||
````````````````````````````````
|
||||
|
||||
However, an empty link destination may be specified using
|
||||
angle brackets:
|
||||
|
||||
```````````````````````````````` example
|
||||
[foo]: <>
|
||||
|
||||
[foo]
|
||||
.
|
||||
<p><a href="">foo</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
The title must be separated from the link destination by
|
||||
whitespace:
|
||||
|
||||
```````````````````````````````` example
|
||||
[foo]: <bar>(baz)
|
||||
|
||||
[foo]
|
||||
.
|
||||
<p>[foo]: <bar>(baz)</p>
|
||||
<p>[foo]</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
Both title and destination can contain backslash escapes
|
||||
and literal backslashes:
|
||||
@@ -3034,6 +3090,25 @@ and thematic breaks, and it need not be followed by a blank line.
|
||||
</blockquote>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
[foo]: /url
|
||||
bar
|
||||
===
|
||||
[foo]
|
||||
.
|
||||
<h1>bar</h1>
|
||||
<p><a href="/url">foo</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
[foo]: /url
|
||||
===
|
||||
[foo]
|
||||
.
|
||||
<p>===
|
||||
<a href="/url">foo</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
Several [link reference definitions]
|
||||
can occur one after another, without intervening blank lines.
|
||||
@@ -3070,6 +3145,17 @@ are defined:
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
Whether something is a [link reference definition] is
|
||||
independent of whether the link reference it defines is
|
||||
used in the document. Thus, for example, the following
|
||||
document contains just a link reference definition, and
|
||||
no visible content:
|
||||
|
||||
```````````````````````````````` example
|
||||
[foo]: /url
|
||||
.
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
## Paragraphs
|
||||
|
||||
@@ -3207,7 +3293,7 @@ aaa
|
||||
|
||||
# Container blocks
|
||||
|
||||
A [container block] is a block that has other
|
||||
A [container block](#container-blocks) is a block that has other
|
||||
blocks as its contents. There are two basic kinds of container blocks:
|
||||
[block quotes] and [list items].
|
||||
[Lists] are meta-containers for [list items].
|
||||
@@ -3669,9 +3755,8 @@ in some browsers.)
|
||||
The following rules define [list items]:
|
||||
|
||||
1. **Basic case.** If a sequence of lines *Ls* constitute a sequence of
|
||||
blocks *Bs* starting with a [non-whitespace character] and not separated
|
||||
from each other by more than one blank line, and *M* is a list
|
||||
marker of width *W* followed by 1 ≤ *N* ≤ 4 spaces, then the result
|
||||
blocks *Bs* starting with a [non-whitespace character], and *M* is a
|
||||
list marker of width *W* followed by 1 ≤ *N* ≤ 4 spaces, then the result
|
||||
of prepending *M* and the following spaces to the first line of
|
||||
*Ls*, and indenting subsequent lines of *Ls* by *W + N* spaces, is a
|
||||
list item with *Bs* as its contents. The type of the list item
|
||||
@@ -3981,8 +4066,7 @@ A start number may not be negative:
|
||||
|
||||
2. **Item starting with indented code.** If a sequence of lines *Ls*
|
||||
constitute a sequence of blocks *Bs* starting with an indented code
|
||||
block and not separated from each other by more than one blank line,
|
||||
and *M* is a list marker of width *W* followed by
|
||||
block, and *M* is a list marker of width *W* followed by
|
||||
one space, then the result of prepending *M* and the following
|
||||
space to the first line of *Ls*, and indenting subsequent lines of
|
||||
*Ls* by *W + 1* spaces, is a list item with *Bs* as its contents.
|
||||
@@ -4458,9 +4542,10 @@ continued here.</p>
|
||||
6. **That's all.** Nothing that is not counted as a list item by rules
|
||||
#1--5 counts as a [list item](#list-items).
|
||||
|
||||
The rules for sublists follow from the general rules above. A sublist
|
||||
must be indented the same number of spaces a paragraph would need to be
|
||||
in order to be included in the list item.
|
||||
The rules for sublists follow from the general rules
|
||||
[above][List items]. A sublist must be indented the same number
|
||||
of spaces a paragraph would need to be in order to be included
|
||||
in the list item.
|
||||
|
||||
So, in this case we need two spaces indent:
|
||||
|
||||
@@ -5049,11 +5134,9 @@ item:
|
||||
- b
|
||||
- c
|
||||
- d
|
||||
- e
|
||||
- f
|
||||
- g
|
||||
- h
|
||||
- i
|
||||
- e
|
||||
- f
|
||||
- g
|
||||
.
|
||||
<ul>
|
||||
<li>a</li>
|
||||
@@ -5063,12 +5146,54 @@ item:
|
||||
<li>e</li>
|
||||
<li>f</li>
|
||||
<li>g</li>
|
||||
<li>h</li>
|
||||
<li>i</li>
|
||||
</ul>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
```````````````````````````````` example
|
||||
1. a
|
||||
|
||||
2. b
|
||||
|
||||
3. c
|
||||
.
|
||||
<ol>
|
||||
<li>
|
||||
<p>a</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>b</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>c</p>
|
||||
</li>
|
||||
</ol>
|
||||
````````````````````````````````
|
||||
|
||||
Note, however, that list items may not be indented more than
|
||||
three spaces. Here `- e` is treated as a paragraph continuation
|
||||
line, because it is indented more than three spaces:
|
||||
|
||||
```````````````````````````````` example
|
||||
- a
|
||||
- b
|
||||
- c
|
||||
- d
|
||||
- e
|
||||
.
|
||||
<ul>
|
||||
<li>a</li>
|
||||
<li>b</li>
|
||||
<li>c</li>
|
||||
<li>d
|
||||
- e</li>
|
||||
</ul>
|
||||
````````````````````````````````
|
||||
|
||||
And here, `3. c` is treated as in indented code block,
|
||||
because it is indented four spaces and preceded by a
|
||||
blank line.
|
||||
|
||||
```````````````````````````````` example
|
||||
1. a
|
||||
|
||||
@@ -5083,10 +5208,9 @@ item:
|
||||
<li>
|
||||
<p>b</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>c</p>
|
||||
</li>
|
||||
</ol>
|
||||
<pre><code>3. c
|
||||
</code></pre>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
@@ -5378,10 +5502,10 @@ Thus, for example, in
|
||||
<p><code>hi</code>lo`</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
`hi` is parsed as code, leaving the backtick at the end as a literal
|
||||
backtick.
|
||||
|
||||
|
||||
## Backslash escapes
|
||||
|
||||
Any ASCII punctuation character may be backslash-escaped:
|
||||
@@ -5415,6 +5539,7 @@ not have their usual Markdown meanings:
|
||||
\* not a list
|
||||
\# not a heading
|
||||
\[foo]: /url "not a reference"
|
||||
\ö not a character entity
|
||||
.
|
||||
<p>*not emphasized*
|
||||
<br/> not a tag
|
||||
@@ -5423,7 +5548,8 @@ not have their usual Markdown meanings:
|
||||
1. not a list
|
||||
* not a list
|
||||
# not a heading
|
||||
[foo]: /url "not a reference"</p>
|
||||
[foo]: /url "not a reference"
|
||||
&ouml; not a character entity</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
@@ -5521,13 +5647,23 @@ foo
|
||||
|
||||
## Entity and numeric character references
|
||||
|
||||
All valid HTML entity references and numeric character
|
||||
references, except those occuring in code blocks and code spans,
|
||||
are recognized as such and treated as equivalent to the
|
||||
corresponding Unicode characters. Conforming CommonMark parsers
|
||||
need not store information about whether a particular character
|
||||
was represented in the source using a Unicode character or
|
||||
an entity reference.
|
||||
Valid HTML entity references and numeric character references
|
||||
can be used in place of the corresponding Unicode character,
|
||||
with the following exceptions:
|
||||
|
||||
- Entity and character references are not recognized in code
|
||||
blocks and code spans.
|
||||
|
||||
- Entity and character references cannot stand in place of
|
||||
special characters that define structural elements in
|
||||
CommonMark. For example, although `*` can be used
|
||||
in place of a literal `*` character, `*` cannot replace
|
||||
`*` in emphasis delimiters, bullet list markers, or thematic
|
||||
breaks.
|
||||
|
||||
Conforming CommonMark parsers need not store information about
|
||||
whether a particular character was represented in the source
|
||||
using a Unicode character or an entity reference.
|
||||
|
||||
[Entity references](@) consist of `&` + any of the valid
|
||||
HTML5 entity names + `;`. The
|
||||
@@ -5548,22 +5684,22 @@ references and their corresponding code points.
|
||||
|
||||
[Decimal numeric character
|
||||
references](@)
|
||||
consist of `&#` + a string of 1--8 arabic digits + `;`. A
|
||||
consist of `&#` + a string of 1--7 arabic digits + `;`. A
|
||||
numeric character reference is parsed as the corresponding
|
||||
Unicode character. Invalid Unicode code points will be replaced by
|
||||
the REPLACEMENT CHARACTER (`U+FFFD`). For security reasons,
|
||||
the code point `U+0000` will also be replaced by `U+FFFD`.
|
||||
|
||||
```````````````````````````````` example
|
||||
# Ӓ Ϡ � �
|
||||
# Ӓ Ϡ �
|
||||
.
|
||||
<p># Ӓ Ϡ <20> <20></p>
|
||||
<p># Ӓ Ϡ <20></p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
[Hexadecimal numeric character
|
||||
references](@) consist of `&#` +
|
||||
either `X` or `x` + a string of 1-8 hexadecimal digits + `;`.
|
||||
either `X` or `x` + a string of 1-6 hexadecimal digits + `;`.
|
||||
They too are parsed as the corresponding Unicode character (this
|
||||
time specified with a hexadecimal numeral instead of decimal).
|
||||
|
||||
@@ -5578,9 +5714,13 @@ Here are some nonentities:
|
||||
|
||||
```````````````````````````````` example
|
||||
  &x; &#; &#x;
|
||||
�
|
||||
&#abcdef0;
|
||||
&ThisIsNotDefined; &hi?;
|
||||
.
|
||||
<p>&nbsp &x; &#; &#x;
|
||||
&#87654321;
|
||||
&#abcdef0;
|
||||
&ThisIsNotDefined; &hi?;</p>
|
||||
````````````````````````````````
|
||||
|
||||
@@ -5661,6 +5801,51 @@ text in code spans and code blocks:
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
Entity and numeric character references cannot be used
|
||||
in place of symbols indicating structure in CommonMark
|
||||
documents.
|
||||
|
||||
```````````````````````````````` example
|
||||
*foo*
|
||||
*foo*
|
||||
.
|
||||
<p>*foo*
|
||||
<em>foo</em></p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
* foo
|
||||
|
||||
* foo
|
||||
.
|
||||
<p>* foo</p>
|
||||
<ul>
|
||||
<li>foo</li>
|
||||
</ul>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
foo bar
|
||||
.
|
||||
<p>foo
|
||||
|
||||
bar</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
	foo
|
||||
.
|
||||
<p>→foo</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
```````````````````````````````` example
|
||||
[a](url "tit")
|
||||
.
|
||||
<p>[a](url "tit")</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
## Code spans
|
||||
|
||||
A [backtick string](@)
|
||||
@@ -5669,9 +5854,16 @@ preceded nor followed by a backtick.
|
||||
|
||||
A [code span](@) begins with a backtick string and ends with
|
||||
a backtick string of equal length. The contents of the code span are
|
||||
the characters between the two backtick strings, with leading and
|
||||
trailing spaces and [line endings] removed, and
|
||||
[whitespace] collapsed to single spaces.
|
||||
the characters between the two backtick strings, normalized in the
|
||||
following ways:
|
||||
|
||||
- First, [line endings] are converted to [spaces].
|
||||
- If the resulting string both begins *and* ends with a [space]
|
||||
character, but does not consist entirely of [space]
|
||||
characters, a single [space] character is removed from the
|
||||
front and back. This allows you to include code that begins
|
||||
or ends with backtick characters, which must be separated by
|
||||
whitespace from the opening or closing backtick strings.
|
||||
|
||||
This is a simple code span:
|
||||
|
||||
@@ -5683,10 +5875,11 @@ This is a simple code span:
|
||||
|
||||
|
||||
Here two backticks are used, because the code contains a backtick.
|
||||
This example also illustrates stripping of leading and trailing spaces:
|
||||
This example also illustrates stripping of a single leading and
|
||||
trailing space:
|
||||
|
||||
```````````````````````````````` example
|
||||
`` foo ` bar ``
|
||||
`` foo ` bar ``
|
||||
.
|
||||
<p><code>foo ` bar</code></p>
|
||||
````````````````````````````````
|
||||
@@ -5701,57 +5894,78 @@ spaces:
|
||||
<p><code>``</code></p>
|
||||
````````````````````````````````
|
||||
|
||||
Note that only *one* space is stripped:
|
||||
|
||||
```````````````````````````````` example
|
||||
` `` `
|
||||
.
|
||||
<p><code> `` </code></p>
|
||||
````````````````````````````````
|
||||
|
||||
The stripping only happens if the space is on both
|
||||
sides of the string:
|
||||
|
||||
```````````````````````````````` example
|
||||
` a`
|
||||
.
|
||||
<p><code> a</code></p>
|
||||
````````````````````````````````
|
||||
|
||||
Only [spaces], and not [unicode whitespace] in general, are
|
||||
stripped in this way:
|
||||
|
||||
```````````````````````````````` example
|
||||
` b `
|
||||
.
|
||||
<p><code> b </code></p>
|
||||
````````````````````````````````
|
||||
|
||||
No stripping occurs if the code span contains only spaces:
|
||||
|
||||
```````````````````````````````` example
|
||||
` `
|
||||
` `
|
||||
.
|
||||
<p><code> </code>
|
||||
<code> </code></p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
[Line endings] are treated like spaces:
|
||||
|
||||
```````````````````````````````` example
|
||||
``
|
||||
foo
|
||||
bar
|
||||
baz
|
||||
``
|
||||
.
|
||||
<p><code>foo</code></p>
|
||||
<p><code>foo bar baz</code></p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
Interior spaces and [line endings] are collapsed into
|
||||
single spaces, just as they would be by a browser:
|
||||
|
||||
```````````````````````````````` example
|
||||
`foo bar
|
||||
baz`
|
||||
``
|
||||
foo
|
||||
``
|
||||
.
|
||||
<p><code>foo bar baz</code></p>
|
||||
<p><code>foo </code></p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
Not all [Unicode whitespace] (for instance, non-breaking space) is
|
||||
collapsed, however:
|
||||
Interior spaces are not collapsed:
|
||||
|
||||
```````````````````````````````` example
|
||||
`a b`
|
||||
`foo bar
|
||||
baz`
|
||||
.
|
||||
<p><code>a b</code></p>
|
||||
<p><code>foo bar baz</code></p>
|
||||
````````````````````````````````
|
||||
|
||||
Note that browsers will typically collapse consecutive spaces
|
||||
when rendering `<code>` elements, so it is recommended that
|
||||
the following CSS be used:
|
||||
|
||||
Q: Why not just leave the spaces, since browsers will collapse them
|
||||
anyway? A: Because we might be targeting a non-HTML format, and we
|
||||
shouldn't rely on HTML-specific rendering assumptions.
|
||||
|
||||
(Existing implementations differ in their treatment of internal
|
||||
spaces and [line endings]. Some, including `Markdown.pl` and
|
||||
`showdown`, convert an internal [line ending] into a
|
||||
`<br />` tag. But this makes things difficult for those who like to
|
||||
hard-wrap their paragraphs, since a line break in the midst of a code
|
||||
span will cause an unintended line break in the output. Others just
|
||||
leave internal spaces as they are, which is fine if only HTML is being
|
||||
targeted.)
|
||||
|
||||
```````````````````````````````` example
|
||||
`foo `` bar`
|
||||
.
|
||||
<p><code>foo `` bar</code></p>
|
||||
````````````````````````````````
|
||||
code{white-space: pre-wrap;}
|
||||
|
||||
|
||||
Note that backslash escapes do not work in code spans. All backslashes
|
||||
@@ -5768,6 +5982,19 @@ Backslash escapes are never needed, because one can always choose a
|
||||
string of *n* backtick characters as delimiters, where the code does
|
||||
not contain any strings of exactly *n* backtick characters.
|
||||
|
||||
```````````````````````````````` example
|
||||
``foo`bar``
|
||||
.
|
||||
<p><code>foo`bar</code></p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
` foo `` bar `
|
||||
.
|
||||
<p><code>foo `` bar</code></p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
Code span backticks have higher precedence than any other inline
|
||||
constructs except HTML tags and autolinks. Thus, for example, this is
|
||||
not parsed as emphasized text, since the second `*` is part of a code
|
||||
@@ -5905,15 +6132,17 @@ of one or more `_` characters that is not preceded or followed by
|
||||
a non-backslash-escaped `_` character.
|
||||
|
||||
A [left-flanking delimiter run](@) is
|
||||
a [delimiter run] that is (a) not followed by [Unicode whitespace],
|
||||
and (b) not followed by a [punctuation character], or
|
||||
a [delimiter run] that is (1) not followed by [Unicode whitespace],
|
||||
and either (2a) not followed by a [punctuation character], or
|
||||
(2b) followed by a [punctuation character] and
|
||||
preceded by [Unicode whitespace] or a [punctuation character].
|
||||
For purposes of this definition, the beginning and the end of
|
||||
the line count as Unicode whitespace.
|
||||
|
||||
A [right-flanking delimiter run](@) is
|
||||
a [delimiter run] that is (a) not preceded by [Unicode whitespace],
|
||||
and (b) not preceded by a [punctuation character], or
|
||||
a [delimiter run] that is (1) not preceded by [Unicode whitespace],
|
||||
and either (2a) not preceded by a [punctuation character], or
|
||||
(2b) preceded by a [punctuation character] and
|
||||
followed by [Unicode whitespace] or a [punctuation character].
|
||||
For purposes of this definition, the beginning and the end of
|
||||
the line count as Unicode whitespace.
|
||||
@@ -6005,7 +6234,8 @@ The following rules define emphasis and strong emphasis:
|
||||
[delimiter runs]. If one of the delimiters can both
|
||||
open and close emphasis, then the sum of the lengths of the
|
||||
delimiter runs containing the opening and closing delimiters
|
||||
must not be a multiple of 3.
|
||||
must not be a multiple of 3 unless both lengths are
|
||||
multiples of 3.
|
||||
|
||||
10. Strong emphasis begins with a delimiter that
|
||||
[can open strong emphasis] and ends with a delimiter that
|
||||
@@ -6015,7 +6245,8 @@ The following rules define emphasis and strong emphasis:
|
||||
[delimiter runs]. If one of the delimiters can both open
|
||||
and close strong emphasis, then the sum of the lengths of
|
||||
the delimiter runs containing the opening and closing
|
||||
delimiters must not be a multiple of 3.
|
||||
delimiters must not be a multiple of 3 unless both lengths
|
||||
are multiples of 3.
|
||||
|
||||
11. A literal `*` character cannot occur at the beginning or end of
|
||||
`*`-delimited emphasis or `**`-delimited strong emphasis, unless it
|
||||
@@ -6634,7 +6865,19 @@ is precluded by the condition that a delimiter that
|
||||
can both open and close (like the `*` after `foo`)
|
||||
cannot form emphasis if the sum of the lengths of
|
||||
the delimiter runs containing the opening and
|
||||
closing delimiters is a multiple of 3.
|
||||
closing delimiters is a multiple of 3 unless
|
||||
both lengths are multiples of 3.
|
||||
|
||||
|
||||
For the same reason, we don't get two consecutive
|
||||
emphasis sections in this example:
|
||||
|
||||
```````````````````````````````` example
|
||||
*foo**bar*
|
||||
.
|
||||
<p><em>foo**bar</em></p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
The same condition ensures that the following
|
||||
cases are all strong emphasis nested inside
|
||||
@@ -6663,6 +6906,23 @@ omitted:
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
When the lengths of the interior closing and opening
|
||||
delimiter runs are *both* multiples of 3, though,
|
||||
they can match to create emphasis:
|
||||
|
||||
```````````````````````````````` example
|
||||
foo***bar***baz
|
||||
.
|
||||
<p>foo<em><strong>bar</strong></em>baz</p>
|
||||
````````````````````````````````
|
||||
|
||||
```````````````````````````````` example
|
||||
foo******bar*********baz
|
||||
.
|
||||
<p>foo<strong><strong><strong>bar</strong></strong></strong>***baz</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
Indefinite levels of nesting are possible:
|
||||
|
||||
```````````````````````````````` example
|
||||
@@ -7198,15 +7458,16 @@ following rules apply:
|
||||
A [link destination](@) consists of either
|
||||
|
||||
- a sequence of zero or more characters between an opening `<` and a
|
||||
closing `>` that contains no spaces, line breaks, or unescaped
|
||||
closing `>` that contains no line breaks or unescaped
|
||||
`<` or `>` characters, or
|
||||
|
||||
- a nonempty sequence of characters that does not include
|
||||
ASCII space or control characters, and includes parentheses
|
||||
only if (a) they are backslash-escaped or (b) they are part of
|
||||
a balanced pair of unescaped parentheses. (Implementations
|
||||
may impose limits on parentheses nesting to avoid performance
|
||||
issues, but at least three levels of nesting should be supported.)
|
||||
- a nonempty sequence of characters that does not start with
|
||||
`<`, does not include ASCII space or control characters, and
|
||||
includes parentheses only if (a) they are backslash-escaped or
|
||||
(b) they are part of a balanced pair of unescaped parentheses.
|
||||
(Implementations may impose limits on parentheses nesting to
|
||||
avoid performance issues, but at least three levels of nesting
|
||||
should be supported.)
|
||||
|
||||
A [link title](@) consists of either
|
||||
|
||||
@@ -7219,7 +7480,8 @@ A [link title](@) consists of either
|
||||
backslash-escaped, or
|
||||
|
||||
- a sequence of zero or more characters between matching parentheses
|
||||
(`(...)`), including a `)` character only if it is backslash-escaped.
|
||||
(`(...)`), including a `(` or `)` character only if it is
|
||||
backslash-escaped.
|
||||
|
||||
Although [link titles] may span multiple lines, they may not contain
|
||||
a [blank line].
|
||||
@@ -7269,9 +7531,8 @@ Both the title and the destination may be omitted:
|
||||
<p><a href="">link</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
The destination cannot contain spaces or line breaks,
|
||||
even if enclosed in pointy brackets:
|
||||
The destination can only contain spaces if it is
|
||||
enclosed in pointy brackets:
|
||||
|
||||
```````````````````````````````` example
|
||||
[link](/my uri)
|
||||
@@ -7279,13 +7540,14 @@ even if enclosed in pointy brackets:
|
||||
<p>[link](/my uri)</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
```````````````````````````````` example
|
||||
[link](</my uri>)
|
||||
.
|
||||
<p>[link](</my uri>)</p>
|
||||
<p><a href="/my%20uri">link</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
The destination cannot contain line breaks,
|
||||
even if enclosed in pointy brackets:
|
||||
|
||||
```````````````````````````````` example
|
||||
[link](foo
|
||||
@@ -7295,7 +7557,6 @@ bar)
|
||||
bar)</p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
```````````````````````````````` example
|
||||
[link](<foo
|
||||
bar>)
|
||||
@@ -7304,6 +7565,36 @@ bar>)
|
||||
bar>)</p>
|
||||
````````````````````````````````
|
||||
|
||||
The destination can contain `)` if it is enclosed
|
||||
in pointy brackets:
|
||||
|
||||
```````````````````````````````` example
|
||||
[a](<b)c>)
|
||||
.
|
||||
<p><a href="b)c">a</a></p>
|
||||
````````````````````````````````
|
||||
|
||||
Pointy brackets that enclose links must be unescaped:
|
||||
|
||||
```````````````````````````````` example
|
||||
[link](<foo\>)
|
||||
.
|
||||
<p>[link](<foo>)</p>
|
||||
````````````````````````````````
|
||||
|
||||
These are not links, because the opening pointy bracket
|
||||
is not matched properly:
|
||||
|
||||
```````````````````````````````` example
|
||||
[a](<b)c
|
||||
[a](<b)c>
|
||||
[a](<b>c)
|
||||
.
|
||||
<p>[a](<b)c
|
||||
[a](<b)c>
|
||||
[a](<b>c)</p>
|
||||
````````````````````````````````
|
||||
|
||||
Parentheses inside the link destination may be escaped:
|
||||
|
||||
```````````````````````````````` example
|
||||
@@ -8411,7 +8702,7 @@ If you want a link after a literal `!`, backslash-escape the
|
||||
as the link label.
|
||||
|
||||
A [URI autolink](@) consists of `<`, followed by an
|
||||
[absolute URI] not containing `<`, followed by `>`. It is parsed as
|
||||
[absolute URI] followed by `>`. It is parsed as
|
||||
a link to the URI, with the URI as the link's label.
|
||||
|
||||
An [absolute URI](@),
|
||||
@@ -8624,7 +8915,7 @@ a [single-quoted attribute value], or a [double-quoted attribute value].
|
||||
|
||||
An [unquoted attribute value](@)
|
||||
is a nonempty string of characters not
|
||||
including spaces, `"`, `'`, `=`, `<`, `>`, or `` ` ``.
|
||||
including [whitespace], `"`, `'`, `=`, `<`, `>`, or `` ` ``.
|
||||
|
||||
A [single-quoted attribute value](@)
|
||||
consists of `'`, zero or more
|
||||
@@ -8745,9 +9036,13 @@ Illegal [whitespace]:
|
||||
```````````````````````````````` example
|
||||
< a><
|
||||
foo><bar/ >
|
||||
<foo bar=baz
|
||||
bim!bop />
|
||||
.
|
||||
<p>< a><
|
||||
foo><bar/ ></p>
|
||||
foo><bar/ >
|
||||
<foo bar=baz
|
||||
bim!bop /></p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
@@ -8944,10 +9239,10 @@ bar</em></p>
|
||||
Line breaks do not occur inside code spans
|
||||
|
||||
```````````````````````````````` example
|
||||
`code
|
||||
`code
|
||||
span`
|
||||
.
|
||||
<p><code>code span</code></p>
|
||||
<p><code>code span</code></p>
|
||||
````````````````````````````````
|
||||
|
||||
|
||||
@@ -9365,7 +9660,8 @@ just above `stack_bottom` (or the first element if `stack_bottom`
|
||||
is NULL).
|
||||
|
||||
We keep track of the `openers_bottom` for each delimiter
|
||||
type (`*`, `_`). Initialize this to `stack_bottom`.
|
||||
type (`*`, `_`) and each length of the closing delimiter run
|
||||
(modulo 3). Initialize this to `stack_bottom`.
|
||||
|
||||
Then we repeat the following until we run out of potential
|
||||
closers:
|
||||
@@ -9397,7 +9693,7 @@ closers:
|
||||
of the delimiter stack. If the closing node is removed, reset
|
||||
`current_position` to the next element in the stack.
|
||||
|
||||
- If none in found:
|
||||
- If none is found:
|
||||
|
||||
+ Set `openers_bottom` to the element before `current_position`.
|
||||
(We know that there are no openers for this kind of closer up to and
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Custom Containers
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-15 05:06:35
|
||||
|
||||
// --------------------------------
|
||||
// Definition Lists
|
||||
@@ -18,7 +18,7 @@ namespace Markdig.Tests.Specs.DefinitionLists
|
||||
//
|
||||
// ## Definition lists
|
||||
//
|
||||
// A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</dib>` block.
|
||||
// A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</div>` block.
|
||||
[Test]
|
||||
public void ExtensionsDefinitionLists_Example001()
|
||||
{
|
||||
@@ -4,7 +4,7 @@ This section describes the different extensions supported:
|
||||
|
||||
## Definition lists
|
||||
|
||||
A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</dib>` block.
|
||||
A custom container is similar to a fenced code block, but it is using the character `:` to declare a block (with at least 3 characters), and instead of generating a `<pre><code>...</code></pre>` it will generate a `<div>...</div>` block.
|
||||
|
||||
```````````````````````````````` example
|
||||
|
||||
@@ -129,4 +129,4 @@ Definition lists can be nested inside list items
|
||||
<dd>Second Definition</dd>
|
||||
</dl></li>
|
||||
</ol>
|
||||
````````````````````````````````
|
||||
````````````````````````````````
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Diagrams
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-15 05:20:50
|
||||
|
||||
// --------------------------------
|
||||
// Emoji
|
||||
@@ -52,7 +52,7 @@ namespace Markdig.Tests.Specs.Emoji
|
||||
TestParser.TestSpec("These are not:) an emoji with a:) x:angry:x", "<p>These are not:) an emoji with a:) x:angry:x</p>", "emojis|advanced+emojis");
|
||||
}
|
||||
|
||||
// Emoji can be followed by close ponctuation (or any other characters):
|
||||
// Emoji can be followed by close punctuation (or any other characters):
|
||||
[Test]
|
||||
public void ExtensionsEmoji_Example003()
|
||||
{
|
||||
@@ -20,7 +20,7 @@ These are not:) an emoji with a:) x:angry:x
|
||||
<p>These are not:) an emoji with a:) x:angry:x</p>
|
||||
````````````````````````````````
|
||||
|
||||
Emoji can be followed by close ponctuation (or any other characters):
|
||||
Emoji can be followed by close punctuation (or any other characters):
|
||||
|
||||
```````````````````````````````` example
|
||||
We all need :), it makes us :muscle:. (and :ok_hand:).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Emphasis Extra
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:42:25
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Figures, Footers and Cites
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-15 05:33:49
|
||||
|
||||
// --------------------------------
|
||||
// Footnotes
|
||||
@@ -84,7 +84,7 @@ namespace Markdig.Tests.Specs.Footnotes
|
||||
TestParser.TestSpec("Here is a footnote reference,[^1] and another.[^longnote]\n\nThis is another reference to [^1]\n\n[^1]: Here is the footnote.\n\nAnd another reference to [^longnote]\n\n[^longnote]: Here's one with multiple blocks.\n\n Subsequent paragraphs are indented to show that they\nbelong to the previous footnote.\n\n > This is a block quote\n > Inside a footnote\n\n { some.code }\n\n The whole paragraph can be indented, or just the first\n line. In this way, multi-paragraph footnotes work like\n multi-paragraph list items.\n\nThis paragraph won't be part of the note, because it\nisn't indented.", "<p>Here is a footnote reference,<a id=\"fnref:1\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a> and another.<a id=\"fnref:3\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a></p>\n<p>This is another reference to <a id=\"fnref:2\" href=\"#fn:1\" class=\"footnote-ref\"><sup>1</sup></a></p>\n<p>And another reference to <a id=\"fnref:4\" href=\"#fn:2\" class=\"footnote-ref\"><sup>2</sup></a></p>\n<p>This paragraph won't be part of the note, because it\nisn't indented.</p>\n<div class=\"footnotes\">\n<hr />\n<ol>\n<li id=\"fn:1\">\n<p>Here is the footnote.<a href=\"#fnref:1\" class=\"footnote-back-ref\">↩</a><a href=\"#fnref:2\" class=\"footnote-back-ref\">↩</a></p>\n</li>\n<li id=\"fn:2\">\n<p>Here's one with multiple blocks.</p>\n<p>Subsequent paragraphs are indented to show that they\nbelong to the previous footnote.</p>\n<blockquote>\n<p>This is a block quote\nInside a footnote</p>\n</blockquote>\n<pre><code>{ some.code }\n</code></pre>\n<p>The whole paragraph can be indented, or just the first\nline. In this way, multi-paragraph footnotes work like\nmulti-paragraph list items.<a href=\"#fnref:3\" class=\"footnote-back-ref\">↩</a><a href=\"#fnref:4\" class=\"footnote-back-ref\">↩</a></p>\n</li>\n</ol>\n</div>", "footnotes|advanced");
|
||||
}
|
||||
|
||||
// Check with mulitple consecutive footnotes:
|
||||
// Check with multiple consecutive footnotes:
|
||||
[Test]
|
||||
public void ExtensionsFootnotes_Example002()
|
||||
{
|
||||
@@ -61,7 +61,7 @@ multi-paragraph list items.<a href="#fnref:3" class="footnote-back-ref">↩<
|
||||
</div>
|
||||
````````````````````````````````
|
||||
|
||||
Check with mulitple consecutive footnotes:
|
||||
Check with multiple consecutive footnotes:
|
||||
|
||||
```````````````````````````````` example
|
||||
Here is a footnote[^1]. And another one[^2]. And a third one[^3]. And a fourth[^4].
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 15:02:43
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Generic Attributes
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-15 05:25:26
|
||||
|
||||
// --------------------------------
|
||||
// Globalization
|
||||
@@ -173,7 +173,7 @@ namespace Markdig.Tests.Specs.Globalization
|
||||
// Section: Extensions / Globalization
|
||||
//
|
||||
// The following Markdown:
|
||||
// Nuitrion |Apple | Oranges
|
||||
// Nutrition |Apple | Oranges
|
||||
// --|-- | --
|
||||
// Calories|52|47
|
||||
// Sugar|10g|9g
|
||||
@@ -187,7 +187,7 @@ namespace Markdig.Tests.Specs.Globalization
|
||||
// <table>
|
||||
// <thead>
|
||||
// <tr>
|
||||
// <th>Nuitrion</th>
|
||||
// <th>Nutrition</th>
|
||||
// <th>Apple</th>
|
||||
// <th>Oranges</th>
|
||||
// </tr>
|
||||
@@ -228,7 +228,7 @@ namespace Markdig.Tests.Specs.Globalization
|
||||
// </table>
|
||||
|
||||
Console.WriteLine("Example 3\nSection Extensions / Globalization\n");
|
||||
TestParser.TestSpec("Nuitrion |Apple | Oranges\n--|-- | --\nCalories|52|47\nSugar|10g|9g\n\n پێکهاتە |سێو | پڕتەقاڵ\n--|-- | --\nکالۆری|٥٢|٤٧\nشەکر| ١٠گ|٩گ", "<table>\n<thead>\n<tr>\n<th>Nuitrion</th>\n<th>Apple</th>\n<th>Oranges</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Calories</td>\n<td>52</td>\n<td>47</td>\n</tr>\n<tr>\n<td>Sugar</td>\n<td>10g</td>\n<td>9g</td>\n</tr>\n</tbody>\n</table>\n<table dir=\"rtl\" align=\"right\">\n<thead>\n<tr>\n<th>پێکهاتە</th>\n<th>سێو</th>\n<th>پڕتەقاڵ</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>کالۆری</td>\n<td>٥٢</td>\n<td>٤٧</td>\n</tr>\n<tr>\n<td>شەکر</td>\n<td>١٠گ</td>\n<td>٩گ</td>\n</tr>\n</tbody>\n</table>", "globalization+advanced+emojis");
|
||||
TestParser.TestSpec("Nutrition |Apple | Oranges\n--|-- | --\nCalories|52|47\nSugar|10g|9g\n\n پێکهاتە |سێو | پڕتەقاڵ\n--|-- | --\nکالۆری|٥٢|٤٧\nشەکر| ١٠گ|٩گ", "<table>\n<thead>\n<tr>\n<th>Nutrition</th>\n<th>Apple</th>\n<th>Oranges</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Calories</td>\n<td>52</td>\n<td>47</td>\n</tr>\n<tr>\n<td>Sugar</td>\n<td>10g</td>\n<td>9g</td>\n</tr>\n</tbody>\n</table>\n<table dir=\"rtl\" align=\"right\">\n<thead>\n<tr>\n<th>پێکهاتە</th>\n<th>سێو</th>\n<th>پڕتەقاڵ</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>کالۆری</td>\n<td>٥٢</td>\n<td>٤٧</td>\n</tr>\n<tr>\n<td>شەکر</td>\n<td>١٠گ</td>\n<td>٩گ</td>\n</tr>\n</tbody>\n</table>", "globalization+advanced+emojis");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,7 +134,7 @@ Lists:
|
||||
Tables:
|
||||
|
||||
```````````````````````````````` example
|
||||
Nuitrion |Apple | Oranges
|
||||
Nutrition |Apple | Oranges
|
||||
--|-- | --
|
||||
Calories|52|47
|
||||
Sugar|10g|9g
|
||||
@@ -147,7 +147,7 @@ Sugar|10g|9g
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nuitrion</th>
|
||||
<th>Nutrition</th>
|
||||
<th>Apple</th>
|
||||
<th>Oranges</th>
|
||||
</tr>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Grid Tables
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Hardline Breaks
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:22:45
|
||||
// Generated: 2019-04-15 05:30:00
|
||||
|
||||
// --------------------------------
|
||||
// Jira Links
|
||||
@@ -14,7 +14,7 @@ namespace Markdig.Tests.Specs.JiraLinks
|
||||
{
|
||||
// ## Jira Links
|
||||
//
|
||||
// The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g.
|
||||
// The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g.
|
||||
//
|
||||
// ```
|
||||
// var pipeline = new MarkdownPipelineBuilder()
|
||||
@@ -24,10 +24,10 @@ namespace Markdig.Tests.Specs.JiraLinks
|
||||
//
|
||||
// The rules for detecting a link are:
|
||||
//
|
||||
// - The project key must be composed of onre or more capitalised ASCII letter `[A-Z]+`
|
||||
// - A single hypen `-` must separate the project key and issue number.
|
||||
// - The project key must be composed of one or more capitalized ASCII letter `[A-Z]+`
|
||||
// - A single hyphen `-` must separate the project key and issue number.
|
||||
// - The issue number is composed of 1 or more digits `[0, 9]+`
|
||||
// - The reference must be preceeded by either `(` or whitespace or EOF.
|
||||
// - The reference must be preceded by either `(` or whitespace or EOF.
|
||||
// - The reference must be followed by either `)` or whitespace or EOF.
|
||||
//
|
||||
// The following are valid examples:
|
||||
@@ -1,6 +1,6 @@
|
||||
## Jira Links
|
||||
|
||||
The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g.
|
||||
The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g.
|
||||
|
||||
```
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
@@ -10,10 +10,10 @@ var pipeline = new MarkdownPipelineBuilder()
|
||||
|
||||
The rules for detecting a link are:
|
||||
|
||||
- The project key must be composed of onre or more capitalised ASCII letter `[A-Z]+`
|
||||
- A single hypen `-` must separate the project key and issue number.
|
||||
- The project key must be composed of one or more capitalized ASCII letter `[A-Z]+`
|
||||
- A single hyphen `-` must separate the project key and issue number.
|
||||
- The issue number is composed of 1 or more digits `[0, 9]+`
|
||||
- The reference must be preceeded by either `(` or whitespace or EOF.
|
||||
- The reference must be preceded by either `(` or whitespace or EOF.
|
||||
- The reference must be followed by either `)` or whitespace or EOF.
|
||||
|
||||
The following are valid examples:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// List Extras
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 2/22/2019 8:27:26 PM
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Math
|
||||
@@ -1,50 +0,0 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
|
||||
// --------------------------------
|
||||
// Media
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Media
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsMediaLinks
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// Adds support for media links:
|
||||
//
|
||||
// ## Media links
|
||||
//
|
||||
// Allows to embed audio/video links to popular website:
|
||||
[Test]
|
||||
public void ExtensionsMediaLinks_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Media links
|
||||
//
|
||||
// The following Markdown:
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://player.vimeo.com/video/8607834" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><video width="500" height="281" controls=""><source type="video/mp4" src="https://sample.com/video.mp4"></source></video></p>
|
||||
// <p><iframe src="https://music.yandex.ru/iframe/#track/4402274/411845/" width="500" height="281" frameborder="0"></iframe></p>
|
||||
// <p><iframe src="https://ok.ru/videoembed/26870090463" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Media links\n");
|
||||
TestParser.TestSpec("\n\n\n\n\n\n\n\n", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://player.vimeo.com/video/8607834\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"https://sample.com/video.mp4\"></source></video></p>\n<p><iframe src=\"https://music.yandex.ru/iframe/#track/4402274/411845/\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n<p><iframe src=\"https://ok.ru/videoembed/26870090463\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>", "medialinks|advanced+medialinks");
|
||||
}
|
||||
}
|
||||
}
|
||||
65
src/Markdig.Tests/Specs/MediaSpecs.generated.cs
Normal file
65
src/Markdig.Tests/Specs/MediaSpecs.generated.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
// Generated: 2019-04-29 18:40:06
|
||||
|
||||
// --------------------------------
|
||||
// Media
|
||||
// --------------------------------
|
||||
|
||||
using System;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Markdig.Tests.Specs.Media
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestExtensionsMediaLinks
|
||||
{
|
||||
// # Extensions
|
||||
//
|
||||
// Adds support for media links:
|
||||
//
|
||||
// ## Media links
|
||||
//
|
||||
// Allows to embed audio/video links to popular website:
|
||||
[Test]
|
||||
public void ExtensionsMediaLinks_Example001()
|
||||
{
|
||||
// Example 1
|
||||
// Section: Extensions / Media links
|
||||
//
|
||||
// The following Markdown:
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// 
|
||||
//
|
||||
// Should be rendered as:
|
||||
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><iframe src="https://player.vimeo.com/video/8607834" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
// <p><video width="500" height="281" controls=""><source type="video/mp4" src="https://sample.com/video.mp4"></source></video></p>
|
||||
// <p><iframe src="https://music.yandex.ru/iframe/#track/4402274/411845/" width="500" height="281" frameborder="0"></iframe></p>
|
||||
// <p><iframe src="https://ok.ru/videoembed/26870090463" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
|
||||
Console.WriteLine("Example 1\nSection Extensions / Media links\n");
|
||||
TestParser.TestSpec("\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n", "<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><iframe src=\"https://player.vimeo.com/video/8607834\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>\n<p><video width=\"500\" height=\"281\" controls=\"\"><source type=\"video/mp4\" src=\"https://sample.com/video.mp4\"></source></video></p>\n<p><iframe src=\"https://music.yandex.ru/iframe/#track/4402274/411845/\" width=\"500\" height=\"281\" frameborder=\"0\"></iframe></p>\n<p><iframe src=\"https://ok.ru/videoembed/26870090463\" width=\"500\" height=\"281\" frameborder=\"0\" allowfullscreen=\"\"></iframe></p>", "medialinks|advanced+medialinks");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,17 +7,32 @@ Adds support for media links:
|
||||
Allows to embed audio/video links to popular website:
|
||||
|
||||
```````````````````````````````` example
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
.
|
||||
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><iframe src="https://www.youtube.com/embed/mswPy5bt3TQ?start=100&rel=0" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><iframe src="https://www.youtube.com/embed?listType=playlist&list=PLC77007E23FF423C6" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><iframe src="https://player.vimeo.com/video/8607834" width="500" height="281" frameborder="0" allowfullscreen=""></iframe></p>
|
||||
<p><video width="500" height="281" controls=""><source type="video/mp4" src="https://sample.com/video.mp4"></source></video></p>
|
||||
<p><iframe src="https://music.yandex.ru/iframe/#track/4402274/411845/" width="500" height="281" frameborder="0"></iframe></p>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// No Html
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-15 05:54:35
|
||||
|
||||
// --------------------------------
|
||||
// Pipe Tables
|
||||
@@ -21,7 +21,7 @@ namespace Markdig.Tests.Specs.PipeTables
|
||||
// A pipe table is detected when:
|
||||
//
|
||||
// **Rule #1**
|
||||
// - Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backstick \`) or a HTML inline.
|
||||
// - Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backtick \`) or a HTML inline.
|
||||
// - The second row must separate the first header row from sub-sequent rows by containing a **header column separator** for each column separated by a column delimiter. A header column separator is:
|
||||
// - starting by optional spaces
|
||||
// - followed by an optional `:` to specify left align
|
||||
@@ -347,7 +347,7 @@ namespace Markdig.Tests.Specs.PipeTables
|
||||
TestParser.TestSpec("|a|b|\n|-|-|\n|0|1|", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
|
||||
}
|
||||
|
||||
// Or may be ommitted on one side:
|
||||
// Or may be omitted on one side:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example011()
|
||||
{
|
||||
@@ -629,7 +629,7 @@ namespace Markdig.Tests.Specs.PipeTables
|
||||
|
||||
// **Rule #7**
|
||||
//
|
||||
// A backstick/code delimiter has a higher precedence than a column delimiter `|`:
|
||||
// A backtick/code delimiter has a higher precedence than a column delimiter `|`:
|
||||
[Test]
|
||||
public void ExtensionsPipeTable_Example019()
|
||||
{
|
||||
@@ -7,7 +7,7 @@ This section describes the different extensions supported:
|
||||
A pipe table is detected when:
|
||||
|
||||
**Rule #1**
|
||||
- Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backstick \`) or a HTML inline.
|
||||
- Each line of a paragraph block have to contain at least a **column delimiter** `|` that is not embedded by either a code inline (backtick \`) or a HTML inline.
|
||||
- The second row must separate the first header row from sub-sequent rows by containing a **header column separator** for each column separated by a column delimiter. A header column separator is:
|
||||
- starting by optional spaces
|
||||
- followed by an optional `:` to specify left align
|
||||
@@ -243,7 +243,7 @@ A pipe may be present at both the beginning/ending of each line:
|
||||
</table>
|
||||
````````````````````````````````
|
||||
|
||||
Or may be ommitted on one side:
|
||||
Or may be omitted on one side:
|
||||
|
||||
```````````````````````````````` example
|
||||
a|b|
|
||||
@@ -454,7 +454,7 @@ A column delimiter has a higher priority than emphasis delimiter
|
||||
|
||||
**Rule #7**
|
||||
|
||||
A backstick/code delimiter has a higher precedence than a column delimiter `|`:
|
||||
A backtick/code delimiter has a higher precedence than a column delimiter `|`:
|
||||
|
||||
```````````````````````````````` example
|
||||
a | b `
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Smarty Pants
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Task Lists
|
||||
@@ -1,4 +1,4 @@
|
||||
// Generated: 21. 01. 2019 14:26:34
|
||||
// Generated: 2019-04-05 16:06:14
|
||||
|
||||
// --------------------------------
|
||||
// Yaml
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// 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 NUnit.Framework;
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Syntax;
|
||||
|
||||
namespace Markdig.Tests
|
||||
{
|
||||
@@ -15,8 +14,7 @@ namespace Markdig.Tests
|
||||
{
|
||||
var inputTag = "<a>";
|
||||
var text = new StringSlice(inputTag);
|
||||
string outputTag;
|
||||
Assert.True(HtmlHelper.TryParseHtmlTag(text, out outputTag));
|
||||
Assert.True(HtmlHelper.TryParseHtmlTag(text, out string outputTag));
|
||||
Assert.AreEqual(inputTag, outputTag);
|
||||
}
|
||||
|
||||
@@ -25,8 +23,7 @@ namespace Markdig.Tests
|
||||
{
|
||||
var inputTag = "<a href='http://google.com'>";
|
||||
var text = new StringSlice(inputTag);
|
||||
string outputTag;
|
||||
Assert.True(HtmlHelper.TryParseHtmlTag(text, out outputTag));
|
||||
Assert.True(HtmlHelper.TryParseHtmlTag(text, out string outputTag));
|
||||
Assert.AreEqual(inputTag, outputTag);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,5 +409,11 @@ namespace Markdig.Tests
|
||||
{
|
||||
Assert.AreEqual(expectedResult, LinkHelper.Urilize(input, false));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUnicodeInDomainNameOfLinkReferenceDefinition()
|
||||
{
|
||||
TestParser.TestSpec("[Foo]\n\n[Foo]: http://ünicode.com", "<p><a href=\"http://xn--nicode-2ya.com\">Foo</a></p>");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,8 +271,14 @@ asdf
|
||||
[Test]
|
||||
public void CodeInline()
|
||||
{
|
||||
AssertNormalizeNoTrim("This has a ` ` in it");
|
||||
AssertNormalizeNoTrim("This has a `HelloWorld()` in it");
|
||||
AssertNormalizeNoTrim(@"This has a ``Hello`World()`` in it");
|
||||
AssertNormalizeNoTrim(@"This has a ``` Hello`World() ``` in it", @"This has a ``Hello`World()`` in it");
|
||||
AssertNormalizeNoTrim(@"This has a ``Hello`World()` `` in it");
|
||||
AssertNormalizeNoTrim(@"This has a ```` ``Hello```World()` ```` in it");
|
||||
AssertNormalizeNoTrim(@"This has a `` `Hello`World()`` in it");
|
||||
AssertNormalizeNoTrim(@"This has a ``` ``Hello`World()` ``` in it");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -409,8 +415,6 @@ This is a last line";
|
||||
AssertNormalizeNoTrim("[ ] This is not a task list");
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public void JiraLinks()
|
||||
{
|
||||
@@ -453,16 +457,24 @@ This is a last line";
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
public void AssertNormalizeNoTrim(string input, string expected = null, NormalizeOptions options = null)
|
||||
public static void TestSpec(string inputText, string expectedOutputText, string extensions = null)
|
||||
{
|
||||
foreach (var pipeline in TestParser.GetPipeline(extensions))
|
||||
{
|
||||
AssertNormalize(inputText, expectedOutputText, trim: false, pipeline: pipeline.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public static void AssertNormalizeNoTrim(string input, string expected = null, NormalizeOptions options = null)
|
||||
=> AssertNormalize(input, expected, false, options);
|
||||
|
||||
public void AssertNormalize(string input, string expected = null, bool trim = true, NormalizeOptions options = null)
|
||||
public static void AssertNormalize(string input, string expected = null, bool trim = true, NormalizeOptions options = null, MarkdownPipeline pipeline = null)
|
||||
{
|
||||
expected = expected ?? input;
|
||||
input = NormText(input, trim);
|
||||
expected = NormText(expected, trim);
|
||||
|
||||
var pipeline = new MarkdownPipelineBuilder()
|
||||
pipeline = pipeline ?? new MarkdownPipelineBuilder()
|
||||
.UseAutoLinks()
|
||||
.UseJiraLinks(new Extensions.JiraLinks.JiraLinkOptions("https://jira.example.com"))
|
||||
.UseTaskLists()
|
||||
@@ -471,16 +483,7 @@ This is a last line";
|
||||
var result = Markdown.Normalize(input, options, pipeline: pipeline);
|
||||
result = NormText(result, trim);
|
||||
|
||||
Console.WriteLine("```````````````````Source");
|
||||
Console.WriteLine(TestParser.DisplaySpaceAndTabs(input));
|
||||
Console.WriteLine("```````````````````Result");
|
||||
Console.WriteLine(TestParser.DisplaySpaceAndTabs(result));
|
||||
Console.WriteLine("```````````````````Expected");
|
||||
Console.WriteLine(TestParser.DisplaySpaceAndTabs(expected));
|
||||
Console.WriteLine("```````````````````");
|
||||
Console.WriteLine();
|
||||
|
||||
TextAssert.AreEqual(expected, result);
|
||||
TestParser.PrintAssertExpected(input, result, expected);
|
||||
}
|
||||
|
||||
private static string NormText(string text, bool trim)
|
||||
|
||||
@@ -14,60 +14,6 @@ namespace Markdig.Tests
|
||||
{
|
||||
public class TestParser
|
||||
{
|
||||
[Test]
|
||||
public void TestFixHang()
|
||||
{
|
||||
var input = File.ReadAllText(Path.Combine(Path.GetDirectoryName(typeof(TestParser).Assembly.Location), "hang.md"));
|
||||
var html = Markdown.ToHtml(input);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInvalidHtmlEntity()
|
||||
{
|
||||
var input = "9&ddr;&*&ddr;&de<64><65>__";
|
||||
TestSpec(input, "<p>9&ddr;&*&ddr;&de<64><65>__</p>");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInvalidCharacterHandling()
|
||||
{
|
||||
var input = File.ReadAllText(Path.Combine(Path.GetDirectoryName(typeof(TestParser).Assembly.Location), "ArgumentOutOfRangeException.md"));
|
||||
var html = Markdown.ToHtml(input);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestInvalidCodeEscape()
|
||||
{
|
||||
var input = "```**Header** ";
|
||||
var html = Markdown.ToHtml(input);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEmphasisAndHtmlEntity()
|
||||
{
|
||||
var markdownText = "*Unlimited-Fun®*®";
|
||||
TestSpec(markdownText, "<p><em>Unlimited-Fun®</em>®</p>");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestThematicInsideCodeBlockInsideList()
|
||||
{
|
||||
var input = @"1. In the :
|
||||
|
||||
```
|
||||
Id DisplayName Description
|
||||
-- ----------- -----------
|
||||
62375ab9-6b52-47ed-826b-58e47e0e304b Group.Unified ...
|
||||
```";
|
||||
TestSpec(input, @"<ol>
|
||||
<li><p>In the :</p>
|
||||
<pre><code>Id DisplayName Description
|
||||
-- ----------- -----------
|
||||
62375ab9-6b52-47ed-826b-58e47e0e304b Group.Unified ...
|
||||
</code></pre></li>
|
||||
</ol>");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EnsureSpecsAreUpToDate()
|
||||
{
|
||||
@@ -77,7 +23,7 @@ namespace Markdig.Tests
|
||||
|
||||
foreach (var specFilePath in SpecsFilePaths)
|
||||
{
|
||||
string testFilePath = Path.ChangeExtension(specFilePath, ".cs");
|
||||
string testFilePath = Path.ChangeExtension(specFilePath, ".generated.cs");
|
||||
|
||||
Assert.True(File.Exists(testFilePath),
|
||||
"A new specification file has been added. Add the spec to the list in SpecFileGen and regenerate the tests.");
|
||||
@@ -98,104 +44,41 @@ namespace Markdig.Tests
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void VisualizeMathExpressions()
|
||||
{
|
||||
string math = @"Math expressions
|
||||
|
||||
$\frac{n!}{k!(n-k)!} = \binom{n}{k}$
|
||||
|
||||
$$\frac{n!}{k!(n-k)!} = \binom{n}{k}$$
|
||||
|
||||
$$
|
||||
\frac{n!}{k!(n-k)!} = \binom{n}{k}
|
||||
$$
|
||||
|
||||
<div class=""math"">
|
||||
\begin{align}
|
||||
\sqrt{37} & = \sqrt{\frac{73^2-1}{12^2}} \\
|
||||
& = \sqrt{\frac{73^2}{12^2}\cdot\frac{73^2-1}{73^2}} \\
|
||||
& = \sqrt{\frac{73^2}{12^2}}\sqrt{\frac{73^2-1}{73^2}} \\
|
||||
& = \frac{73}{12}\sqrt{1 - \frac{1}{73^2}} \\
|
||||
& \approx \frac{73}{12}\left(1 - \frac{1}{2\cdot73^2}\right)
|
||||
\end{align}
|
||||
</div>
|
||||
";
|
||||
Console.WriteLine("Math Expressions:\n");
|
||||
|
||||
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
|
||||
|
||||
|
||||
var html = Markdown.ToHtml(math, pl);
|
||||
Console.WriteLine(html);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void InlineMathExpression()
|
||||
{
|
||||
string math = @"Math expressions
|
||||
|
||||
$\frac{n!}{k!(n-k)!} = \binom{n}{k}$
|
||||
";
|
||||
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
|
||||
|
||||
var html = Markdown.ToHtml(math, pl);
|
||||
Console.WriteLine(html);
|
||||
|
||||
Assert.IsTrue(html.Contains("<p><span class=\"math\">\\("),"Leading bracket missing");
|
||||
Assert.IsTrue(html.Contains("\\)</span></p>"), "Trailing bracket missing");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BlockMathExpression()
|
||||
{
|
||||
string math = @"Math expressions
|
||||
|
||||
$$
|
||||
\frac{n!}{k!(n-k)!} = \binom{n}{k}
|
||||
$$
|
||||
";
|
||||
var pl = new MarkdownPipelineBuilder().UseMathematics().Build(); // UseEmphasisExtras(EmphasisExtraOptions.Subscript).Build()
|
||||
|
||||
var html = Markdown.ToHtml(math, pl);
|
||||
Console.WriteLine(html);
|
||||
|
||||
Assert.IsTrue(html.Contains("<div class=\"math\">\n\\["), "Leading bracket missing");
|
||||
Assert.IsTrue(html.Contains("\\]</div>"), "Trailing bracket missing");
|
||||
}
|
||||
|
||||
|
||||
public static void TestSpec(string inputText, string expectedOutputText, string extensions = null)
|
||||
public static void TestSpec(string inputText, string expectedOutputText, string extensions = null, bool plainText = false)
|
||||
{
|
||||
foreach (var pipeline in GetPipeline(extensions))
|
||||
{
|
||||
Console.WriteLine($"Pipeline configured with extensions: {pipeline.Key}");
|
||||
TestSpec(inputText, expectedOutputText, pipeline.Value);
|
||||
TestSpec(inputText, expectedOutputText, pipeline.Value, plainText);
|
||||
}
|
||||
}
|
||||
|
||||
public static void TestSpec(string inputText, string expectedOutputText, MarkdownPipeline pipeline)
|
||||
public static void TestSpec(string inputText, string expectedOutputText, MarkdownPipeline pipeline, bool plainText = false)
|
||||
{
|
||||
// Uncomment this line to get more debug information for process inlines.
|
||||
//pipeline.DebugLog = Console.Out;
|
||||
var result = Markdown.ToHtml(inputText, pipeline);
|
||||
var result = plainText ? Markdown.ToPlainText(inputText, pipeline) : Markdown.ToHtml(inputText, pipeline);
|
||||
|
||||
result = Compact(result);
|
||||
expectedOutputText = Compact(expectedOutputText);
|
||||
|
||||
PrintAssertExpected(inputText, result, expectedOutputText);
|
||||
}
|
||||
|
||||
public static void PrintAssertExpected(string source, string result, string expected)
|
||||
{
|
||||
Console.WriteLine("```````````````````Source");
|
||||
Console.WriteLine(DisplaySpaceAndTabs(inputText));
|
||||
Console.WriteLine(DisplaySpaceAndTabs(source));
|
||||
Console.WriteLine("```````````````````Result");
|
||||
Console.WriteLine(DisplaySpaceAndTabs(result));
|
||||
Console.WriteLine("```````````````````Expected");
|
||||
Console.WriteLine(DisplaySpaceAndTabs(expectedOutputText));
|
||||
Console.WriteLine(DisplaySpaceAndTabs(expected));
|
||||
Console.WriteLine("```````````````````");
|
||||
Console.WriteLine();
|
||||
TextAssert.AreEqual(expectedOutputText, result);
|
||||
TextAssert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
private static IEnumerable<KeyValuePair<string, MarkdownPipeline>> GetPipeline(string extensionsGroupText)
|
||||
public 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))
|
||||
@@ -257,6 +140,9 @@ $$
|
||||
|
||||
public static readonly bool IsContinuousIntegration = Environment.GetEnvironmentVariable("CI") != null;
|
||||
|
||||
public static readonly string TestsDirectory =
|
||||
Path.GetFullPath(Path.Combine(Path.GetDirectoryName(typeof(TestParser).Assembly.Location), "../../.."));
|
||||
|
||||
/// <summary>
|
||||
/// Contains absolute paths to specification markdown files (order is the same as in <see cref="SpecsMarkdown"/>)
|
||||
/// </summary>
|
||||
@@ -267,11 +153,11 @@ $$
|
||||
public static readonly string[] SpecsMarkdown;
|
||||
static TestParser()
|
||||
{
|
||||
string assemblyDir = Path.GetDirectoryName(typeof(TestParser).Assembly.Location);
|
||||
string specsDir = Path.GetFullPath(Path.Combine(assemblyDir, "../../Specs"));
|
||||
|
||||
SpecsFilePaths = Directory.GetFiles(specsDir)
|
||||
.Where(file => file.EndsWith(".md", StringComparison.Ordinal) && !file.Contains("readme"))
|
||||
SpecsFilePaths = Directory.GetDirectories(TestsDirectory)
|
||||
.Where(dir => dir.EndsWith("Specs"))
|
||||
.SelectMany(dir => Directory.GetFiles(dir)
|
||||
.Where(file => file.EndsWith(".md", StringComparison.OrdinalIgnoreCase))
|
||||
.Where(file => file.IndexOf("readme", StringComparison.OrdinalIgnoreCase) == -1))
|
||||
.ToArray();
|
||||
|
||||
SpecsMarkdown = new string[SpecsFilePaths.Length];
|
||||
|
||||
@@ -5,15 +5,6 @@ namespace Markdig.Tests
|
||||
[TestFixture]
|
||||
public class TestPlainText
|
||||
{
|
||||
[Test]
|
||||
public void TestPlain()
|
||||
{
|
||||
var markdownText = "*Hello*, [world](http://example.com)!";
|
||||
var expected = "Hello, world!\n";
|
||||
var actual = Markdown.ToPlainText(markdownText);
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(/* markdownText: */ "foo bar", /* expected: */ "foo bar\n")]
|
||||
[TestCase(/* markdownText: */ "foo\nbar", /* expected: */ "foo\nbar\n")]
|
||||
@@ -28,11 +19,25 @@ namespace Markdig.Tests
|
||||
[TestCase(/* markdownText: */ "`foo\nbar`", /* expected: */ "foo bar\n")] // new line within codespan is treated as whitespace (Example317)
|
||||
[TestCase(/* markdownText: */ "```\nfoo bar\n```", /* expected: */ "foo bar\n")]
|
||||
[TestCase(/* markdownText: */ "- foo\n- bar\n- baz", /* expected: */ "foo\nbar\nbaz\n")]
|
||||
[TestCase(/* markdownText: */ "- foo<baz", /* expected: */ "foo<baz\n")]
|
||||
[TestCase(/* markdownText: */ "- foo<baz", /* expected: */ "foo<baz\n")]
|
||||
public void TestPlainEnsureNewLine(string markdownText, string expected)
|
||||
{
|
||||
var actual = Markdown.ToPlainText(markdownText);
|
||||
Assert.AreEqual(expected, actual);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[TestCase(/* markdownText: */ ":::\nfoo\n:::", /* expected: */ "foo\n", /*extensions*/ "customcontainers|advanced")]
|
||||
[TestCase(/* markdownText: */ ":::bar\nfoo\n:::", /* expected: */ "foo\n", /*extensions*/ "customcontainers+attributes|advanced")]
|
||||
public void TestPlainWithExtensions(string markdownText, string expected, string extensions)
|
||||
{
|
||||
TestParser.TestSpec(markdownText, expected, extensions, plainText: true);
|
||||
}
|
||||
|
||||
public static void TestSpec(string markdownText, string expected, string extensions)
|
||||
{
|
||||
TestParser.TestSpec(markdownText, expected, extensions, plainText: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"runtimes": {
|
||||
"win": {}
|
||||
},
|
||||
"frameworks": {
|
||||
"net451": {
|
||||
"compilationOptions": {
|
||||
"define": [
|
||||
"CLASSIC"
|
||||
]
|
||||
},
|
||||
"frameworkAssemblies": {
|
||||
"Microsoft.Build": "4.0.0.0",
|
||||
"Microsoft.Build.Framework": "4.0.0.0",
|
||||
"Microsoft.Build.Utilities.v4.0": "4.0.0.0",
|
||||
"System.Management": "4.0.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"NUnit": "3.2.0",
|
||||
"NUnit3TestAdapter": "3.9.0"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using System;
|
||||
@@ -111,12 +111,12 @@ namespace Markdig.Extensions.AutoIdentifiers
|
||||
doc.SetLinkReferenceDefinition(keyPair.Key, keyPair.Value);
|
||||
}
|
||||
}
|
||||
// Once we are done, we don't need to keep the intermediate dictionary arround
|
||||
// Once we are done, we don't need to keep the intermediate dictionary around
|
||||
doc.RemoveData(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback when there is a reference to found to a heading.
|
||||
/// Callback when there is a reference to found to a heading.
|
||||
/// Note that reference are only working if they are declared after.
|
||||
/// </summary>
|
||||
private Inline CreateLinkInlineForHeading(InlineProcessor inlineState, LinkReferenceDefinition linkRef, Inline child)
|
||||
|
||||
@@ -11,14 +11,14 @@ namespace Markdig.Extensions.AutoLinks
|
||||
/// <summary>
|
||||
/// Extension to automatically create <see cref="LinkInline"/> when a link url http: or mailto: is found.
|
||||
/// </summary>
|
||||
/// <seealso cref="Markdig.IMarkdownExtension" />
|
||||
/// <seealso cref="IMarkdownExtension" />
|
||||
public class AutoLinkExtension : IMarkdownExtension
|
||||
{
|
||||
public readonly string ValidPreviousCharacters;
|
||||
public readonly AutoLinkOptions Options;
|
||||
|
||||
public AutoLinkExtension(string validPreviousCharacters = AutoLinkParser.DefaultValidPreviousCharacters)
|
||||
public AutoLinkExtension(AutoLinkOptions options)
|
||||
{
|
||||
ValidPreviousCharacters = validPreviousCharacters;
|
||||
Options = options ?? new AutoLinkOptions();
|
||||
}
|
||||
|
||||
public void Setup(MarkdownPipelineBuilder pipeline)
|
||||
@@ -26,14 +26,13 @@ namespace Markdig.Extensions.AutoLinks
|
||||
if (!pipeline.InlineParsers.Contains<AutoLinkParser>())
|
||||
{
|
||||
// Insert the parser before any other parsers
|
||||
pipeline.InlineParsers.Insert(0, new AutoLinkParser(ValidPreviousCharacters));
|
||||
pipeline.InlineParsers.Insert(0, new AutoLinkParser(Options));
|
||||
}
|
||||
}
|
||||
|
||||
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
|
||||
{
|
||||
var normalizeRenderer = renderer as NormalizeRenderer;
|
||||
if (normalizeRenderer != null && !normalizeRenderer.ObjectRenderers.Contains<NormalizeAutoLinkRenderer>())
|
||||
if (renderer is NormalizeRenderer normalizeRenderer && !normalizeRenderer.ObjectRenderers.Contains<NormalizeAutoLinkRenderer>())
|
||||
{
|
||||
normalizeRenderer.ObjectRenderers.InsertBefore<LinkInlineRenderer>(new NormalizeAutoLinkRenderer());
|
||||
}
|
||||
|
||||
22
src/Markdig/Extensions/AutoLinks/AutoLinkOptions.cs
Normal file
22
src/Markdig/Extensions/AutoLinks/AutoLinkOptions.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace Markdig.Extensions.AutoLinks
|
||||
{
|
||||
public class AutoLinkOptions
|
||||
{
|
||||
public AutoLinkOptions()
|
||||
{
|
||||
ValidPreviousCharacters = "*_~(";
|
||||
}
|
||||
|
||||
public string ValidPreviousCharacters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should the link open in a new window when clicked (false by default)
|
||||
/// </summary>
|
||||
public bool OpenInNewWindow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should a www link be prefixed with https:// instead of http:// (false by default)
|
||||
/// </summary>
|
||||
public bool UseHttpsForWWWLinks { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Parsers;
|
||||
using Markdig.Renderers.Html;
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
namespace Markdig.Extensions.AutoLinks
|
||||
@@ -19,8 +20,10 @@ namespace Markdig.Extensions.AutoLinks
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AutoLinkParser"/> class.
|
||||
/// </summary>
|
||||
public AutoLinkParser(string validPreviousCharacters = DefaultValidPreviousCharacters)
|
||||
public AutoLinkParser(AutoLinkOptions options)
|
||||
{
|
||||
Options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
|
||||
OpeningCharacters = new char[]
|
||||
{
|
||||
'h', // for http:// and https://
|
||||
@@ -28,19 +31,15 @@ namespace Markdig.Extensions.AutoLinks
|
||||
'm', // for mailto:
|
||||
'w', // for www.
|
||||
};
|
||||
|
||||
ValidPreviousCharacters = validPreviousCharacters;
|
||||
}
|
||||
|
||||
// All such recognized autolinks can only come at the beginning of a line, after whitespace, or any of the delimiting characters *, _, ~, and (.
|
||||
public readonly string ValidPreviousCharacters;
|
||||
public const string DefaultValidPreviousCharacters = "*_~(";
|
||||
public readonly AutoLinkOptions Options;
|
||||
|
||||
public override bool Match(InlineProcessor processor, ref StringSlice slice)
|
||||
{
|
||||
// Previous char must be a whitespace or a punctuation
|
||||
var previousChar = slice.PeekCharExtra(-1);
|
||||
if (!previousChar.IsWhiteSpaceOrZero() && ValidPreviousCharacters.IndexOf(previousChar) == -1)
|
||||
if (!previousChar.IsWhiteSpaceOrZero() && Options.ValidPreviousCharacters.IndexOf(previousChar) == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -153,17 +152,15 @@ namespace Markdig.Extensions.AutoLinks
|
||||
return false;
|
||||
}
|
||||
|
||||
int line;
|
||||
int column;
|
||||
var inline = new LinkInline()
|
||||
{
|
||||
Span =
|
||||
{
|
||||
Start = processor.GetSourcePosition(startPosition, out line, out column),
|
||||
Start = processor.GetSourcePosition(startPosition, out int line, out int column),
|
||||
},
|
||||
Line = line,
|
||||
Column = column,
|
||||
Url = c == 'w' ? "http://" + link : link,
|
||||
Url = c == 'w' ? ((Options.UseHttpsForWWWLinks ? "https://" : "http://") + link) : link,
|
||||
IsClosed = true,
|
||||
IsAutoLink = true,
|
||||
};
|
||||
@@ -182,6 +179,11 @@ namespace Markdig.Extensions.AutoLinks
|
||||
});
|
||||
processor.Inline = inline;
|
||||
|
||||
if (Options.OpenInNewWindow)
|
||||
{
|
||||
inline.GetAttributes().AddPropertyIfNotExist("target", "blank");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,16 @@ namespace Markdig.Extensions.CustomContainers
|
||||
protected override void Write(HtmlRenderer renderer, CustomContainer obj)
|
||||
{
|
||||
renderer.EnsureLine();
|
||||
renderer.Write("<div").WriteAttributes(obj).Write(">");
|
||||
if (renderer.EnableHtmlForBlock)
|
||||
{
|
||||
renderer.Write("<div").WriteAttributes(obj).Write(">");
|
||||
}
|
||||
// We don't escape a CustomContainer
|
||||
renderer.WriteChildren(obj);
|
||||
renderer.WriteLine("</div>");
|
||||
if (renderer.EnableHtmlForBlock)
|
||||
{
|
||||
renderer.WriteLine("</div>");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using Markdig.Parsers;
|
||||
@@ -8,7 +8,7 @@ using Markdig.Syntax;
|
||||
namespace Markdig.Extensions.Footers
|
||||
{
|
||||
/// <summary>
|
||||
/// A block elemeent for a footer.
|
||||
/// A block element for a footer.
|
||||
/// </summary>
|
||||
/// <seealso cref="Markdig.Syntax.ContainerBlock" />
|
||||
public class FooterBlock : ContainerBlock
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// 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;
|
||||
@@ -33,7 +33,7 @@ namespace Markdig.Extensions.GenericAttributes
|
||||
{
|
||||
var inline = processor.Inline;
|
||||
|
||||
// If the curent object to attach is either a literal or delimiter
|
||||
// If the current object to attach is either a literal or delimiter
|
||||
// try to find a suitable parent, otherwise attach the html attributes to the block
|
||||
if (inline is LiteralInline)
|
||||
{
|
||||
@@ -86,7 +86,7 @@ namespace Markdig.Extensions.GenericAttributes
|
||||
/// </summary>
|
||||
/// <param name="slice">The slice to parse.</param>
|
||||
/// <param name="attributes">The output attributes or null if not found or invalid</param>
|
||||
/// <returns><c>true</c> if parsing the HTML attributes was succsesfull</returns>
|
||||
/// <returns><c>true</c> if parsing the HTML attributes was successful</returns>
|
||||
public static bool TryParse(ref StringSlice slice, out HtmlAttributes attributes)
|
||||
{
|
||||
attributes = null;
|
||||
@@ -173,7 +173,7 @@ namespace Markdig.Extensions.GenericAttributes
|
||||
line.TrimStart();
|
||||
c = line.CurrentChar;
|
||||
|
||||
// Handle boolean properties that are not followed by =
|
||||
// Handle boolean properties that are not followed by =
|
||||
if ((hasSpace && (c == '.' || c == '#' || IsStartAttributeName(c))) || c == '}')
|
||||
{
|
||||
if (properties == null)
|
||||
@@ -184,7 +184,7 @@ namespace Markdig.Extensions.GenericAttributes
|
||||
properties.Add(new KeyValuePair<string, string>(name, null));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Else we expect a regular property
|
||||
if (line.CurrentChar != '=')
|
||||
{
|
||||
@@ -264,7 +264,7 @@ namespace Markdig.Extensions.GenericAttributes
|
||||
Properties = properties
|
||||
};
|
||||
|
||||
// Assign back the current processor of the line to
|
||||
// Assign back the current processor of the line to
|
||||
slice = line;
|
||||
}
|
||||
return isValid;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// 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;
|
||||
@@ -92,7 +92,7 @@ namespace Markdig.Extensions.JiraLinks
|
||||
jiraLink.Span.End = jiraLink.Span.Start + (endIssue - startKey);
|
||||
|
||||
// Builds the Url
|
||||
var builder = new StringBuilder();
|
||||
var builder = StringBuilderCache.Local();
|
||||
builder.Append(_baseUrl).Append('/').Append(jiraLink.ProjectKey).Append('-').Append(jiraLink.Issue);
|
||||
jiraLink.Url = builder.ToString();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// 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.
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Markdig.Extensions.Mathematics
|
||||
return block;
|
||||
}
|
||||
|
||||
private static bool NoInfoParser(BlockProcessor state, ref StringSlice line, IFencedBlock fenced)
|
||||
private static bool NoInfoParser(BlockProcessor state, ref StringSlice line, IFencedBlock fenced, char openingCharacter)
|
||||
{
|
||||
var c = line.CurrentChar;
|
||||
for (int i = line.Start; i <= line.End; i++)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using Markdig.Helpers;
|
||||
@@ -57,7 +57,7 @@ namespace Markdig.Extensions.Mathematics
|
||||
bool openNextIsDigit = c.IsDigit();
|
||||
pc.CheckUnicodeCategory(out openPrevIsWhiteSpace, out openPrevIsPunctuation);
|
||||
c.CheckUnicodeCategory(out openNextIsWhiteSpace, out openNextIsPunctuation);
|
||||
|
||||
|
||||
// Check that opening $/$$ is correct, using the different heuristics than for emphasis delimiters
|
||||
// If a $/$$ is not preceded by a whitespace or punctuation, or followed by a digit
|
||||
// this is a not a math block
|
||||
@@ -91,7 +91,7 @@ namespace Markdig.Extensions.Mathematics
|
||||
// Don't process sticks if we have a '\' as a previous char
|
||||
if (pc != '\\' )
|
||||
{
|
||||
// Record continous whitespaces at the end
|
||||
// Record continuous whitespaces at the end
|
||||
if (c.IsSpaceOrTab())
|
||||
{
|
||||
if (lastWhiteSpace < 0)
|
||||
@@ -146,7 +146,7 @@ namespace Markdig.Extensions.Mathematics
|
||||
c.CheckUnicodeCategory(out closeNextIsWhiteSpace, out closeNextIsPunctuation);
|
||||
|
||||
// A closing $/$$ should be followed by at least a punctuation or a whitespace
|
||||
// and if the character after an openning $/$$ was a whitespace, it should be
|
||||
// and if the character after an opening $/$$ was a whitespace, it should be
|
||||
// a whitespace as well for the character preceding the closing of $/$$
|
||||
if ((!closeNextIsPunctuation && !closeNextIsWhiteSpace) || (openNextIsWhiteSpace != closePrevIsWhiteSpace))
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using System;
|
||||
@@ -127,6 +127,7 @@ namespace Markdig.Extensions.MediaLinks
|
||||
private static readonly List<KnownProvider> KnownHosts = new List<KnownProvider>()
|
||||
{
|
||||
new KnownProvider {HostPrefix = "www.youtube.com", Delegate = YouTube},
|
||||
new KnownProvider {HostPrefix = "youtu.be", Delegate = YouTubeShortened},
|
||||
new KnownProvider {HostPrefix = "vimeo.com", Delegate = Vimeo},
|
||||
new KnownProvider {HostPrefix = "music.yandex.ru", Delegate = Yandex, AllowFullScreen = false},
|
||||
new KnownProvider {HostPrefix = "ok.ru", Delegate = Odnoklassniki},
|
||||
@@ -135,7 +136,7 @@ namespace Markdig.Extensions.MediaLinks
|
||||
|
||||
private bool TryRenderIframeFromKnownProviders(Uri uri, HtmlRenderer renderer, LinkInline linkInline)
|
||||
{
|
||||
var foundProvider =
|
||||
var foundProvider =
|
||||
KnownHosts
|
||||
.Where(pair => uri.Host.StartsWith(pair.HostPrefix, StringComparison.OrdinalIgnoreCase)) // when host is match
|
||||
.Select(provider =>
|
||||
@@ -153,7 +154,9 @@ namespace Markdig.Extensions.MediaLinks
|
||||
}
|
||||
|
||||
var htmlAttributes = GetHtmlAttributes(linkInline);
|
||||
renderer.Write($"<iframe src=\"{foundProvider.Result}\"");
|
||||
renderer.Write("<iframe src=\"");
|
||||
renderer.WriteEscapeUrl(foundProvider.Result);
|
||||
renderer.Write("\"");
|
||||
|
||||
if(!string.IsNullOrEmpty(Options.Width))
|
||||
htmlAttributes.AddPropertyIfNotExist("width", Options.Width);
|
||||
@@ -184,10 +187,38 @@ namespace Markdig.Extensions.MediaLinks
|
||||
|
||||
private static string YouTube(Uri uri)
|
||||
{
|
||||
var query = SplitQuery(uri);
|
||||
return query.Length > 0 && query[0].StartsWith("v=")
|
||||
? $"https://www.youtube.com/embed/{query[0].Substring(2)}"
|
||||
: null;
|
||||
string uriPath = uri.AbsolutePath;
|
||||
if (string.Equals(uriPath, "/embed", StringComparison.OrdinalIgnoreCase) || uriPath.StartsWith("/embed/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return uri.ToString();
|
||||
}
|
||||
if (!string.Equals(uriPath, "/watch", StringComparison.OrdinalIgnoreCase) && !uriPath.StartsWith("/watch/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var queryParams = SplitQuery(uri);
|
||||
return BuildYouTubeIframeUrl(
|
||||
queryParams.FirstOrDefault(p => p.StartsWith("v="))?.Substring(2),
|
||||
queryParams.FirstOrDefault(p => p.StartsWith("t="))?.Substring(2)
|
||||
);
|
||||
}
|
||||
|
||||
private static string YouTubeShortened(Uri uri)
|
||||
{
|
||||
return BuildYouTubeIframeUrl(
|
||||
uri.AbsolutePath.Substring(1),
|
||||
SplitQuery(uri).FirstOrDefault(p => p.StartsWith("t="))?.Substring(2)
|
||||
);
|
||||
}
|
||||
|
||||
private static string BuildYouTubeIframeUrl(string videoId, string startTime)
|
||||
{
|
||||
if (string.IsNullOrEmpty(videoId))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
string url = $"https://www.youtube.com/embed/{videoId}";
|
||||
return string.IsNullOrEmpty(startTime) ? url : $"{url}?start={startTime}";
|
||||
}
|
||||
|
||||
private static string Vimeo(Uri uri)
|
||||
@@ -223,4 +254,4 @@ namespace Markdig.Extensions.MediaLinks
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// 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;
|
||||
using Markdig.Helpers;
|
||||
@@ -168,7 +168,7 @@ namespace Markdig.Extensions.SmartyPants
|
||||
};
|
||||
pant.Span.End = pant.Span.Start + slice.Start - startingPosition - 1;
|
||||
|
||||
// We will check in a post-process step for balanaced open/close quotes
|
||||
// We will check in a post-process step for balanced open/close quotes
|
||||
if (postProcess)
|
||||
{
|
||||
var quotePants = GetOrCreateState(processor);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using System;
|
||||
@@ -51,7 +51,7 @@ namespace Markdig.Extensions.Tables
|
||||
|
||||
var c = slice.CurrentChar;
|
||||
|
||||
// If we have not a delimiter on the first line of a paragraph, don't bother to continue
|
||||
// If we have not a delimiter on the first line of a paragraph, don't bother to continue
|
||||
// tracking other delimiters on following lines
|
||||
var tableState = processor.ParserStates[Index] as TableState;
|
||||
bool isFirstLineEmpty = false;
|
||||
@@ -66,7 +66,7 @@ namespace Markdig.Extensions.Tables
|
||||
{
|
||||
|
||||
// A table could be preceded by an empty line or a line containing an inline
|
||||
// that has not been added to the stack, so we consider this as a valid
|
||||
// that has not been added to the stack, so we consider this as a valid
|
||||
// start for a table. Typically, with this, we can have an attributes {...}
|
||||
// starting on the first line of a pipe table, even if the first line
|
||||
// doesn't have a pipe
|
||||
@@ -188,7 +188,7 @@ namespace Markdig.Extensions.Tables
|
||||
tableState.ColumnAndLineDelimiters.Remove(pipeDelimiter);
|
||||
}
|
||||
|
||||
// If we didn't have any delimiter before and after the delimiters we jsut removed, we mark the processor of the current line as no pipe
|
||||
// If we didn't have any delimiter before and after the delimiters we just removed, we mark the processor of the current line as no pipe
|
||||
if (!leftIsDelimiter && !rightIsDelimiter)
|
||||
{
|
||||
tableState.LineHasPipe = false;
|
||||
@@ -237,7 +237,7 @@ namespace Markdig.Extensions.Tables
|
||||
// So the following:
|
||||
// | a | b \n
|
||||
// | d | e \n
|
||||
//
|
||||
//
|
||||
// Will generate a tree of the following node:
|
||||
// |
|
||||
// a
|
||||
@@ -343,7 +343,7 @@ namespace Markdig.Extensions.Tables
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
beginOfCell = cellContentIt;
|
||||
if (endOfCell == null)
|
||||
{
|
||||
@@ -353,7 +353,7 @@ namespace Markdig.Extensions.Tables
|
||||
|
||||
|
||||
// If the current deilimiter is a pipe `|` OR
|
||||
// the beginOfCell/endOfCell are not null and
|
||||
// the beginOfCell/endOfCell are not null and
|
||||
// either they are :
|
||||
// - different
|
||||
// - they contain a single element, but it is not a line break (\n) or an empty/whitespace Literal.
|
||||
@@ -489,7 +489,7 @@ namespace Markdig.Extensions.Tables
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<TableColumnDefinition> FindHeaderRow(List<Inline> delimiters)
|
||||
private List<TableColumnDefinition> FindHeaderRow(List<Inline> delimiters)
|
||||
{
|
||||
bool isValidRow = false;
|
||||
List<TableColumnDefinition> aligns = null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Parsers;
|
||||
@@ -8,7 +8,7 @@ using Markdig.Syntax;
|
||||
namespace Markdig.Extensions.Yaml
|
||||
{
|
||||
/// <summary>
|
||||
/// Block parser for a YAML frontmatter.
|
||||
/// Block parser for a YAML frontmatter.
|
||||
/// </summary>
|
||||
/// <seealso cref="YamlFrontMatterBlock" />
|
||||
public class YamlFrontMatterParser : BlockParser
|
||||
@@ -51,7 +51,7 @@ namespace Markdig.Extensions.Yaml
|
||||
{
|
||||
return BlockState.None;
|
||||
}
|
||||
|
||||
|
||||
int count = 0;
|
||||
var line = processor.Line;
|
||||
char c = line.CurrentChar;
|
||||
@@ -64,7 +64,7 @@ namespace Markdig.Extensions.Yaml
|
||||
}
|
||||
|
||||
// If three dashes (optionally followed by whitespace)
|
||||
// this is a YAML front matter blcok
|
||||
// this is a YAML front matter block
|
||||
if (count == 3 && (c == '\0' || c.IsWhitespace()) && line.TrimEnd())
|
||||
{
|
||||
bool hasFullYamlFrontMatter = false;
|
||||
|
||||
@@ -33,13 +33,12 @@
|
||||
//SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Globalization;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Markdig.Helpers
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class for handling characters.
|
||||
/// </summary>
|
||||
@@ -66,25 +65,25 @@ namespace Markdig.Helpers
|
||||
|
||||
public static void CheckOpenCloseDelimiter(char pc, char c, bool enableWithinWord, out bool canOpen, out bool canClose)
|
||||
{
|
||||
// A left-flanking delimiter run is a delimiter run that is
|
||||
// (a) not followed by Unicode whitespace, and
|
||||
// (b) either not followed by a punctuation character, or preceded by Unicode whitespace
|
||||
// or a punctuation character.
|
||||
// For purposes of this definition, the beginning and the end of the line count as Unicode whitespace.
|
||||
pc.CheckUnicodeCategory(out bool prevIsWhiteSpace, out bool prevIsPunctuation);
|
||||
c.CheckUnicodeCategory(out bool nextIsWhiteSpace, out bool nextIsPunctuation);
|
||||
|
||||
var prevIsExcepted = prevIsPunctuation && punctuationExceptions.Contains(pc);
|
||||
var nextIsExcepted = nextIsPunctuation && punctuationExceptions.Contains(c);
|
||||
|
||||
// A left-flanking delimiter run is a delimiter run that is
|
||||
// (1) not followed by Unicode whitespace, and either
|
||||
// (2a) not followed by a punctuation character or
|
||||
// (2b) followed by a punctuation character and preceded by Unicode whitespace or a punctuation character.
|
||||
// For purposes of this definition, the beginning and the end of the line count as Unicode whitespace.
|
||||
canOpen = !nextIsWhiteSpace &&
|
||||
((!nextIsPunctuation || nextIsExcepted) || prevIsWhiteSpace || prevIsPunctuation);
|
||||
|
||||
|
||||
// A right-flanking delimiter run is a delimiter run that is
|
||||
// (a) not preceded by Unicode whitespace, and
|
||||
// (b) either not preceded by a punctuation character, or followed by Unicode whitespace
|
||||
// or a punctuation character.
|
||||
// A right-flanking delimiter run is a delimiter run that is
|
||||
// (1) not preceded by Unicode whitespace, and either
|
||||
// (1a) not preceded by a punctuation character, or
|
||||
// (2b) preceded by a punctuation character and followed by Unicode whitespace or a punctuation character.
|
||||
// For purposes of this definition, the beginning and the end of the line count as Unicode whitespace.
|
||||
canClose = !prevIsWhiteSpace &&
|
||||
((!prevIsPunctuation || prevIsExcepted) || nextIsWhiteSpace || nextIsPunctuation);
|
||||
@@ -225,6 +224,30 @@ namespace Markdig.Helpers
|
||||
|| category == UnicodeCategory.FinalQuotePunctuation
|
||||
|| category == UnicodeCategory.OtherPunctuation);
|
||||
}
|
||||
}
|
||||
|
||||
// Same as CheckUnicodeCategory
|
||||
internal static bool IsSpaceOrPunctuation(this char c)
|
||||
{
|
||||
if (c <= 'ÿ')
|
||||
{
|
||||
return c == '\0' || c == ' ' || (c >= '\t' && c <= '\r') || c == '\u00a0' || c == '\u0085' ||
|
||||
(c >= 33 && c <= 47 && c != 38) || (c >= 58 && c <= 64) || (c >= 91 && c <= 96) || (c >= 123 && c <= 126);
|
||||
}
|
||||
else
|
||||
{
|
||||
var category = CharUnicodeInfo.GetUnicodeCategory(c);
|
||||
return category == UnicodeCategory.SpaceSeparator
|
||||
|| category == UnicodeCategory.LineSeparator
|
||||
|| category == UnicodeCategory.ParagraphSeparator
|
||||
|| category == UnicodeCategory.ConnectorPunctuation
|
||||
|| category == UnicodeCategory.DashPunctuation
|
||||
|| category == UnicodeCategory.OpenPunctuation
|
||||
|| category == UnicodeCategory.ClosePunctuation
|
||||
|| category == UnicodeCategory.InitialQuotePunctuation
|
||||
|| category == UnicodeCategory.FinalQuotePunctuation
|
||||
|| category == UnicodeCategory.OtherPunctuation;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
|
||||
|
||||
@@ -540,12 +540,6 @@ namespace Markdig.Helpers
|
||||
// Copyright (c) 2014, Kārlis Gaņģis All rights reserved.
|
||||
// See license for details: https://github.com/Knagis/CommonMark.NET/blob/master/LICENSE.md
|
||||
|
||||
/*!re2c
|
||||
[&] ([#] ([Xx][A-Fa-f0-9]{1,8}|[0-9]{1,8}) |[A-Za-z][A-Za-z0-9]{1,31} ) [;]
|
||||
{ return (p - start); }
|
||||
.? { return 0; }
|
||||
*/
|
||||
|
||||
numericEntity = 0;
|
||||
namedEntityStart = 0;
|
||||
namedEntityLength = 0;
|
||||
@@ -565,25 +559,25 @@ namespace Markdig.Helpers
|
||||
if (c == 'x' || c == 'X')
|
||||
{
|
||||
c = slice.NextChar(); // skip #
|
||||
// expect 1-8 hex digits starting from pos+3
|
||||
// expect 1-6 hex digits starting from pos+3
|
||||
while (c != '\0')
|
||||
{
|
||||
c = slice.NextChar();
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
if (++counter == 9) return 0;
|
||||
if (++counter == 7) return 0;
|
||||
numericEntity = numericEntity*16 + (c - '0');
|
||||
continue;
|
||||
}
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
{
|
||||
if (++counter == 9) return 0;
|
||||
if (++counter == 7) return 0;
|
||||
numericEntity = numericEntity*16 + (c - 'A' + 10);
|
||||
continue;
|
||||
}
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
{
|
||||
if (++counter == 9) return 0;
|
||||
if (++counter == 7) return 0;
|
||||
numericEntity = numericEntity*16 + (c - 'a' + 10);
|
||||
continue;
|
||||
}
|
||||
@@ -596,14 +590,14 @@ namespace Markdig.Helpers
|
||||
}
|
||||
else
|
||||
{
|
||||
// expect 1-8 digits starting from pos+2
|
||||
// expect 1-7 digits starting from pos+2
|
||||
while (c != '\0')
|
||||
{
|
||||
c = slice.NextChar();
|
||||
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
if (++counter == 9) return 0;
|
||||
if (++counter == 8) return 0;
|
||||
numericEntity = numericEntity*10 + (c - '0');
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,7 +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.
|
||||
using System;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Markdig.Syntax;
|
||||
|
||||
@@ -302,14 +302,19 @@ namespace Markdig.Helpers
|
||||
}
|
||||
|
||||
// Chars valid for both scheme and email
|
||||
if (c > ' ' && c < 127 && c != '<')
|
||||
{
|
||||
builder.Append(c);
|
||||
if (c <= 127)
|
||||
{
|
||||
if (c > ' ' && c != '>')
|
||||
{
|
||||
builder.Append(c);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
else if (!c.IsSpaceOrPunctuation())
|
||||
{
|
||||
builder.Append(c);
|
||||
}
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,9 +324,7 @@ namespace Markdig.Helpers
|
||||
|
||||
public static bool TryParseInlineLink(StringSlice text, out string link, out string title)
|
||||
{
|
||||
SourceSpan linkSpan;
|
||||
SourceSpan titleSpan;
|
||||
return TryParseInlineLink(ref text, out link, out title, out linkSpan, out titleSpan);
|
||||
return TryParseInlineLink(ref text, out link, out title, out _, out _);
|
||||
}
|
||||
|
||||
public static bool TryParseInlineLink(StringSlice text, out string link, out string title, out SourceSpan linkSpan, out SourceSpan titleSpan)
|
||||
@@ -521,7 +524,7 @@ namespace Markdig.Helpers
|
||||
var c = text.CurrentChar;
|
||||
|
||||
// a sequence of zero or more characters between an opening < and a closing >
|
||||
// that contains no spaces, line breaks, or unescaped < or > characters, or
|
||||
// that contains no line breaks, or unescaped < or > characters, or
|
||||
if (c == '<')
|
||||
{
|
||||
bool hasEscape = false;
|
||||
@@ -551,20 +554,20 @@ namespace Markdig.Helpers
|
||||
continue;
|
||||
}
|
||||
|
||||
hasEscape = false;
|
||||
|
||||
if (c.IsWhitespace()) // TODO: specs unclear. space is strict or relaxed? (includes tabs?)
|
||||
{
|
||||
break;
|
||||
if (c.IsNewLine())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
hasEscape = false;
|
||||
|
||||
buffer.Append(c);
|
||||
|
||||
} while (c != '\0');
|
||||
}
|
||||
else
|
||||
{
|
||||
// a nonempty sequence of characters that does not include ASCII space or control characters,
|
||||
// a nonempty sequence of characters that does not start with <, does not include ASCII space or control characters,
|
||||
// and includes parentheses only if (a) they are backslash-escaped or (b) they are part of a
|
||||
// balanced pair of unescaped parentheses that is not itself inside a balanced pair of unescaped
|
||||
// parentheses.
|
||||
@@ -670,6 +673,9 @@ namespace Markdig.Helpers
|
||||
// A valid domain consists of alphanumeric characters, underscores (_), hyphens (-) and periods (.).
|
||||
// There must be at least one period, and no underscores may be present in the last two segments of the domain.
|
||||
|
||||
// Extended as of https://github.com/lunet-io/markdig/issues/316 to accept non-ascii characters,
|
||||
// as long as they are not in the space or punctuation categories
|
||||
|
||||
int segmentCount = 1;
|
||||
bool segmentHasCharacters = false;
|
||||
int lastUnderscoreSegment = -1;
|
||||
@@ -697,7 +703,7 @@ namespace Markdig.Helpers
|
||||
{
|
||||
lastUnderscoreSegment = segmentCount;
|
||||
}
|
||||
else if (c != '-')
|
||||
else if (c != '-' && c.IsSpaceOrPunctuation())
|
||||
{
|
||||
// An invalid character has been found
|
||||
return false;
|
||||
@@ -752,7 +758,8 @@ namespace Markdig.Helpers
|
||||
text.TrimStart();
|
||||
|
||||
urlSpan.Start = text.Start;
|
||||
if (!TryParseUrl(ref text, out url) || string.IsNullOrEmpty(url))
|
||||
bool isAngleBracketsUrl = text.CurrentChar == '<';
|
||||
if (!TryParseUrl(ref text, out url) || (!isAngleBracketsUrl && string.IsNullOrEmpty(url)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// 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.Collections.Generic;
|
||||
@@ -11,7 +11,7 @@ namespace Markdig.Helpers
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the list item</typeparam>
|
||||
/// <seealso cref="System.Collections.Generic.List{T}" />
|
||||
/// <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>
|
||||
/// <remarks>We use a typed list and don't use extension methods because it would pollute all list implements and the top level namespace.</remarks>
|
||||
public class OrderedList<T> : List<T>
|
||||
{
|
||||
public OrderedList()
|
||||
@@ -45,7 +45,13 @@ namespace Markdig.Helpers
|
||||
return (TElement)this[i];
|
||||
}
|
||||
}
|
||||
return default(TElement);
|
||||
return default;
|
||||
}
|
||||
|
||||
public bool TryFind<TElement>(out TElement element) where TElement : T
|
||||
{
|
||||
element = Find<TElement>();
|
||||
return element != null;
|
||||
}
|
||||
|
||||
public TElement FindExact<TElement>() where TElement : T
|
||||
@@ -57,7 +63,7 @@ namespace Markdig.Helpers
|
||||
return (TElement)this[i];
|
||||
}
|
||||
}
|
||||
return default(TElement);
|
||||
return default;
|
||||
}
|
||||
|
||||
public void AddIfNotAlready<TElement>() where TElement : class, T, new()
|
||||
@@ -128,13 +134,29 @@ namespace Markdig.Helpers
|
||||
/// <typeparam name="TElement">Element type to find in the list</typeparam>
|
||||
/// <param name="newElement">Object to add/replace the found element with</param>
|
||||
/// <returns><c>true</c> if a replacement was made; otherwise <c>false</c>.</returns>
|
||||
public bool ReplaceOrAdd<TElement>(T newElement) where TElement : T
|
||||
{
|
||||
if (Replace<TElement>(newElement))
|
||||
return true;
|
||||
|
||||
Add(newElement);
|
||||
return false;
|
||||
public bool ReplaceOrAdd<TElement>(T newElement) where TElement : T
|
||||
{
|
||||
if (Replace<TElement>(newElement))
|
||||
return true;
|
||||
|
||||
Add(newElement);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the first occurrence of <typeparamref name="TElement"/>
|
||||
/// </summary>
|
||||
public bool TryRemove<TElement>() where TElement : T
|
||||
{
|
||||
for (int i = 0; i < Count; i++)
|
||||
{
|
||||
if (this[i] is TElement)
|
||||
{
|
||||
RemoveAt(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,95 +1,84 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>A fast, powerful, CommonMark compliant, extensible Markdown processor for .NET with 20+ builtin extensions (pipetables, footnotes, definition lists... etc.)</Description>
|
||||
<Copyright>Alexandre Mutel</Copyright>
|
||||
<AssemblyTitle>Markdig</AssemblyTitle>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<VersionPrefix>0.16.0</VersionPrefix>
|
||||
<Authors>Alexandre Mutel</Authors>
|
||||
<TargetFrameworks>net35;net40;portable40-net40+sl5+win8+wp8+wpa81;netstandard1.1;netstandard2.0;uap10.0;netcoreapp2.1</TargetFrameworks>
|
||||
<AssemblyName>Markdig</AssemblyName>
|
||||
<PackageId>Markdig</PackageId>
|
||||
<PackageId Condition="'$(SignAssembly)' == 'true'">Markdig.Signed</PackageId>
|
||||
<PackageTags>Markdown CommonMark md html md2html</PackageTags>
|
||||
<PackageReleaseNotes>https://github.com/lunet-io/markdig/blob/master/changelog.md</PackageReleaseNotes>
|
||||
<PackageLicenseExpression>BSD-2-Clause</PackageLicenseExpression>
|
||||
<PackageIconUrl>https://raw.githubusercontent.com/lunet-io/markdig/master/img/markdig.png</PackageIconUrl>
|
||||
<PackageProjectUrl>https://github.com/lunet-io/markdig</PackageProjectUrl>
|
||||
<NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard1.1' ">1.6.0</NetStandardImplicitPackageVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net35' ">
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net40' ">
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'portable40-net40+sl5+win8+wp8+wpa81' ">
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net35' ">
|
||||
<DefineConstants>$(DefineConstants);SUPPORT_FIXED_STRING;SUPPORT_UNSAFE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net40' ">
|
||||
<DefineConstants>$(DefineConstants);SUPPORT_FIXED_STRING;SUPPORT_UNSAFE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' ">
|
||||
<DefineConstants>$(DefineConstants);NETSTANDARD_11;SUPPORT_UNSAFE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<DefineConstants>$(DefineConstants);SUPPORT_FIXED_STRING;SUPPORT_UNSAFE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">
|
||||
<DefineConstants>$(DefineConstants);SUPPORT_FIXED_STRING;SUPPORT_UNSAFE;NETCORE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'uap10.0' ">
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion Condition="'$(TargetPlatformVersion)' == ''">10.0.10240.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion Condition="'$(TargetPlatformMinVersion)' == ''">10.0.10240.0</TargetPlatformMinVersion>
|
||||
<DefineConstants>$(DefineConstants);NETSTANDARD_11;SUPPORT_UNSAFE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(TargetFramework)' == 'portable40-net40+sl5+win8+wp8+wpa81'">
|
||||
<TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>Profile328</TargetFrameworkProfile>
|
||||
<LanguageTargets>$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets</LanguageTargets>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(SignAssembly)' == 'true' ">
|
||||
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
|
||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Special packages and imports for UWP support -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MSBuild.Sdk.Extras" Version="1.0.9" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'uap10.0' ">
|
||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform " Version="5.2.2" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" />
|
||||
</Project>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>A fast, powerful, CommonMark compliant, extensible Markdown processor for .NET with 20+ builtin extensions (pipetables, footnotes, definition lists... etc.)</Description>
|
||||
<Copyright>Alexandre Mutel</Copyright>
|
||||
<AssemblyTitle>Markdig</AssemblyTitle>
|
||||
<NeutralLanguage>en-US</NeutralLanguage>
|
||||
<VersionPrefix>0.17.0</VersionPrefix>
|
||||
<Authors>Alexandre Mutel</Authors>
|
||||
<TargetFrameworks>net35;net40;netstandard2.0;uap10.0;netcoreapp2.1</TargetFrameworks>
|
||||
<AssemblyName>Markdig</AssemblyName>
|
||||
<PackageId>Markdig</PackageId>
|
||||
<PackageId Condition="'$(SignAssembly)' == 'true'">Markdig.Signed</PackageId>
|
||||
<PackageTags>Markdown CommonMark md html md2html</PackageTags>
|
||||
<PackageReleaseNotes>https://github.com/lunet-io/markdig/blob/master/changelog.md</PackageReleaseNotes>
|
||||
<PackageLicenseExpression>BSD-2-Clause</PackageLicenseExpression>
|
||||
<PackageIconUrl>https://raw.githubusercontent.com/lunet-io/markdig/master/img/markdig.png</PackageIconUrl>
|
||||
<PackageProjectUrl>https://github.com/lunet-io/markdig</PackageProjectUrl>
|
||||
<NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard1.1' ">1.6.0</NetStandardImplicitPackageVersion>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net35' ">
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'net40' ">
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'portable40-net40+sl5+win8+wp8+wpa81' ">
|
||||
<Reference Include="mscorlib" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net35' ">
|
||||
<DefineConstants>$(DefineConstants);SUPPORT_FIXED_STRING;SUPPORT_UNSAFE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'net40' ">
|
||||
<DefineConstants>$(DefineConstants);SUPPORT_FIXED_STRING;SUPPORT_UNSAFE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
|
||||
<DefineConstants>$(DefineConstants);SUPPORT_FIXED_STRING;SUPPORT_UNSAFE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'netcoreapp2.1' ">
|
||||
<DefineConstants>$(DefineConstants);SUPPORT_FIXED_STRING;SUPPORT_UNSAFE;NETCORE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(TargetFramework)' == 'uap10.0' ">
|
||||
<TargetPlatformIdentifier>UAP</TargetPlatformIdentifier>
|
||||
<TargetPlatformVersion Condition="'$(TargetPlatformVersion)' == ''">10.0.17763.0</TargetPlatformVersion>
|
||||
<TargetPlatformMinVersion Condition="'$(TargetPlatformMinVersion)' == ''">10.0.10240.0</TargetPlatformMinVersion>
|
||||
<DefineConstants>$(DefineConstants);NETSTANDARD_11;SUPPORT_UNSAFE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<NoWarn>$(NoWarn);CS1591</NoWarn>
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(SignAssembly)' == 'true' ">
|
||||
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
|
||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Special packages and imports for UWP support -->
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MSBuild.Sdk.Extras" Version="1.0.9" PrivateAssets="all" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition=" '$(TargetFramework)' == 'uap10.0' ">
|
||||
<PackageReference Include="Microsoft.NETCore.UniversalWindowsPlatform " Version="5.2.2" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" />
|
||||
</Project>
|
||||
|
||||
@@ -99,9 +99,9 @@ namespace Markdig
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipelineBuilder UseAutoLinks(this MarkdownPipelineBuilder pipeline, string validPreviousCharacters = AutoLinkParser.DefaultValidPreviousCharacters)
|
||||
public static MarkdownPipelineBuilder UseAutoLinks(this MarkdownPipelineBuilder pipeline, AutoLinkOptions options = null)
|
||||
{
|
||||
pipeline.Extensions.ReplaceOrAdd<AutoLinkExtension>(new AutoLinkExtension(validPreviousCharacters));
|
||||
pipeline.Extensions.ReplaceOrAdd<AutoLinkExtension>(new AutoLinkExtension(options));
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
@@ -616,5 +616,20 @@ namespace Markdig
|
||||
pipeline.Use(new ConfigureNewLineExtension(newLine));
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disables parsing of ATX and Setex headings
|
||||
/// </summary>
|
||||
/// <param name="pipeline">The pipeline.</param>
|
||||
/// <returns>The modified pipeline</returns>
|
||||
public static MarkdownPipelineBuilder DisableHeadings(this MarkdownPipelineBuilder pipeline)
|
||||
{
|
||||
pipeline.BlockParsers.TryRemove<HeadingBlockParser>();
|
||||
if (pipeline.BlockParsers.TryFind<ParagraphBlockParser>(out var parser))
|
||||
{
|
||||
parser.ParseSetexHeadings = false;
|
||||
}
|
||||
return pipeline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// 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.Collections.Generic;
|
||||
@@ -129,7 +129,7 @@ namespace Markdig.Parsers
|
||||
public int Column { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position of the current character in the line being processed.
|
||||
/// Gets the position of the current character in the line being processed.
|
||||
/// </summary>
|
||||
public int Start => Line.Start;
|
||||
|
||||
@@ -144,12 +144,12 @@ namespace Markdig.Parsers
|
||||
public bool IsCodeIndent => Indent >= 4;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the column position before the indent occured.
|
||||
/// Gets the column position before the indent occurred.
|
||||
/// </summary>
|
||||
public int ColumnBeforeIndent { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the character position before the indent occured.
|
||||
/// Gets the character position before the indent occurred.
|
||||
/// </summary>
|
||||
public int StartBeforeIndent { get; private set; }
|
||||
|
||||
@@ -207,7 +207,7 @@ namespace Markdig.Parsers
|
||||
public void NextColumn()
|
||||
{
|
||||
var c = Line.CurrentChar;
|
||||
// If we are accross a tab, we should just add 1 column
|
||||
// If we are across a tab, we should just add 1 column
|
||||
if (c == '\t' && CharHelper.IsAcrossTab(Column))
|
||||
{
|
||||
Column++;
|
||||
@@ -239,7 +239,7 @@ namespace Markdig.Parsers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the indentation from the current position in the line, updating <see cref="StartBeforeIndent"/>,
|
||||
/// Parses the indentation from the current position in the line, updating <see cref="StartBeforeIndent"/>,
|
||||
/// <see cref="ColumnBeforeIndent"/>, <see cref="Start"/> and <see cref="Column"/> accordingly
|
||||
/// taking into account space taken by tabs.
|
||||
/// </summary>
|
||||
@@ -542,7 +542,7 @@ namespace Markdig.Parsers
|
||||
OpenedBlocks[i].IsOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Updates the <see cref="CurrentBlock"/> and <see cref="CurrentContainer"/>.
|
||||
/// </summary>
|
||||
@@ -580,7 +580,7 @@ namespace Markdig.Parsers
|
||||
/// </exception>
|
||||
private void TryContinueBlocks()
|
||||
{
|
||||
// Set all blocks non opened.
|
||||
// Set all blocks non opened.
|
||||
// They will be marked as open in the following loop
|
||||
for (int i = 1; i < OpenedBlocks.Count; i++)
|
||||
{
|
||||
|
||||
@@ -1,231 +1,241 @@
|
||||
// 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.Helpers;
|
||||
using Markdig.Renderers.Html;
|
||||
using Markdig.Syntax;
|
||||
|
||||
namespace Markdig.Parsers
|
||||
{
|
||||
public abstract class FencedBlockParserBase : BlockParser, IAttributesParseable
|
||||
{
|
||||
/// <summary>
|
||||
/// Delegate used to parse the string on the first line after the fenced code block special characters (usually ` or ~)
|
||||
/// </summary>
|
||||
/// <param name="state">The parser processor.</param>
|
||||
/// <param name="line">The being processed line.</param>
|
||||
/// <param name="fenced">The fenced code block.</param>
|
||||
/// <returns><c>true</c> if parsing of the line is successfull; <c>false</c> otherwise</returns>
|
||||
public delegate bool InfoParserDelegate(BlockProcessor state, ref StringSlice line, IFencedBlock fenced);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the information parser.
|
||||
/// </summary>
|
||||
public InfoParserDelegate InfoParser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A delegates that allows to process attached attributes
|
||||
/// </summary>
|
||||
public TryParseAttributesDelegate TryParseAttributes { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base parser for fenced blocks (opened by 3 or more character delimiters on a first line, and closed by at least the same number of delimiters)
|
||||
/// </summary>
|
||||
/// <seealso cref="Markdig.Parsers.BlockParser" />
|
||||
public abstract class FencedBlockParserBase<T> : FencedBlockParserBase where T : Block, IFencedBlock
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FencedBlockParserBase{T}"/> class.
|
||||
/// </summary>
|
||||
protected FencedBlockParserBase()
|
||||
{
|
||||
InfoParser = DefaultInfoParser;
|
||||
MinimumMatchCount = 3;
|
||||
MaximumMatchCount = Int32.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the language prefix (default is "language-")
|
||||
/// </summary>
|
||||
public string InfoPrefix { get; set; }
|
||||
|
||||
public int MinimumMatchCount { get; set; }
|
||||
|
||||
public int MaximumMatchCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The default parser for the information after the fenced code block special characters (usually ` or ~)
|
||||
/// </summary>
|
||||
/// <param name="state">The parser processor.</param>
|
||||
/// <param name="line">The line.</param>
|
||||
/// <param name="fenced">The fenced code block.</param>
|
||||
/// <returns><c>true</c> if parsing of the line is successfull; <c>false</c> otherwise</returns>
|
||||
public static bool DefaultInfoParser(BlockProcessor state, ref StringSlice line,
|
||||
IFencedBlock fenced)
|
||||
{
|
||||
string infoString;
|
||||
string argString = null;
|
||||
|
||||
var c = line.CurrentChar;
|
||||
// An info string cannot contain any backsticks
|
||||
int firstSpace = -1;
|
||||
for (int i = line.Start; i <= line.End; i++)
|
||||
{
|
||||
c = line.Text[i];
|
||||
if (c == '`')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (firstSpace < 0 && c.IsSpaceOrTab())
|
||||
{
|
||||
firstSpace = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstSpace > 0)
|
||||
{
|
||||
infoString = line.Text.Substring(line.Start, firstSpace - line.Start).Trim();
|
||||
|
||||
// Skip any spaces after info string
|
||||
firstSpace++;
|
||||
while (firstSpace <= line.End)
|
||||
{
|
||||
c = line[firstSpace];
|
||||
if (c.IsSpaceOrTab())
|
||||
{
|
||||
firstSpace++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
argString = line.Text.Substring(firstSpace, line.End - firstSpace + 1).Trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
infoString = line.ToString().Trim();
|
||||
}
|
||||
|
||||
fenced.Info = HtmlHelper.Unescape(infoString);
|
||||
fenced.Arguments = HtmlHelper.Unescape(argString);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override BlockState TryOpen(BlockProcessor processor)
|
||||
{
|
||||
// We expect no indentation for a fenced code block.
|
||||
if (processor.IsCodeIndent)
|
||||
{
|
||||
return BlockState.None;
|
||||
}
|
||||
|
||||
var startPosition = processor.Start;
|
||||
|
||||
// Match fenced char
|
||||
int count = 0;
|
||||
var line = processor.Line;
|
||||
char c = line.CurrentChar;
|
||||
var matchChar = c;
|
||||
while (c != '\0')
|
||||
{
|
||||
if (c != matchChar)
|
||||
{
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
c = line.NextChar();
|
||||
}
|
||||
|
||||
// A fenced codeblock requires at least 3 opening chars
|
||||
if (count < MinimumMatchCount || count > MaximumMatchCount)
|
||||
{
|
||||
return BlockState.None;
|
||||
}
|
||||
|
||||
// specs spaces: Is space and tabs? or only spaces? Use space and tab for this case
|
||||
line.TrimStart();
|
||||
|
||||
var fenced = CreateFencedBlock(processor);
|
||||
{
|
||||
fenced.Column = processor.Column;
|
||||
fenced.FencedChar = matchChar;
|
||||
fenced.FencedCharCount = count;
|
||||
fenced.Span.Start = startPosition;
|
||||
fenced.Span.End = line.Start;
|
||||
};
|
||||
|
||||
// Try to parse any attached attributes
|
||||
if (TryParseAttributes != null)
|
||||
{
|
||||
TryParseAttributes(processor, ref line, fenced);
|
||||
}
|
||||
|
||||
// If the info parser was not successfull, early exit
|
||||
if (InfoParser != null && !InfoParser(processor, ref line, fenced))
|
||||
{
|
||||
return BlockState.None;
|
||||
}
|
||||
|
||||
// Add the language as an attribute by default
|
||||
if (!string.IsNullOrEmpty(fenced.Info))
|
||||
{
|
||||
if (string.IsNullOrEmpty(InfoPrefix))
|
||||
{
|
||||
fenced.GetAttributes().AddClass(fenced.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
fenced.GetAttributes().AddClass(InfoPrefix + fenced.Info);
|
||||
}
|
||||
}
|
||||
|
||||
// Store the number of matched string into the context
|
||||
processor.NewBlocks.Push(fenced);
|
||||
|
||||
// Discard the current line as it is already parsed
|
||||
return BlockState.ContinueDiscard;
|
||||
}
|
||||
|
||||
protected abstract T CreateFencedBlock(BlockProcessor processor);
|
||||
|
||||
public override BlockState TryContinue(BlockProcessor processor, Block block)
|
||||
{
|
||||
var fence = (IFencedBlock)block;
|
||||
var count = fence.FencedCharCount;
|
||||
var matchChar = fence.FencedChar;
|
||||
var c = processor.CurrentChar;
|
||||
|
||||
// Match if we have a closing fence
|
||||
var line = processor.Line;
|
||||
while (c == matchChar)
|
||||
{
|
||||
c = line.NextChar();
|
||||
count--;
|
||||
}
|
||||
|
||||
// If we have a closing fence, close it and discard the current line
|
||||
// The line must contain only fence opening character followed only by whitespaces.
|
||||
if (count <=0 && !processor.IsCodeIndent && (c == '\0' || c.IsWhitespace()) && line.TrimEnd())
|
||||
{
|
||||
block.UpdateSpanEnd(line.Start - 1);
|
||||
|
||||
// Don't keep the last line
|
||||
return BlockState.BreakDiscard;
|
||||
}
|
||||
|
||||
// Reset the indentation to the column before the indent
|
||||
processor.GoToColumn(processor.ColumnBeforeIndent);
|
||||
|
||||
return BlockState.Continue;
|
||||
}
|
||||
}
|
||||
// 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.Helpers;
|
||||
using Markdig.Renderers.Html;
|
||||
using Markdig.Syntax;
|
||||
|
||||
namespace Markdig.Parsers
|
||||
{
|
||||
public abstract class FencedBlockParserBase : BlockParser, IAttributesParseable
|
||||
{
|
||||
/// <summary>
|
||||
/// Delegate used to parse the string on the first line after the fenced code block special characters (usually ` or ~)
|
||||
/// </summary>
|
||||
/// <param name="state">The parser processor.</param>
|
||||
/// <param name="line">The being processed line.</param>
|
||||
/// <param name="fenced">The fenced code block.</param>
|
||||
/// <param name="openingCharacter">The opening character for the fenced code block (usually ` or ~)</param>
|
||||
/// <returns><c>true</c> if parsing of the line is successfull; <c>false</c> otherwise</returns>
|
||||
public delegate bool InfoParserDelegate(BlockProcessor state, ref StringSlice line, IFencedBlock fenced, char openingCharacter);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the information parser.
|
||||
/// </summary>
|
||||
public InfoParserDelegate InfoParser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A delegates that allows to process attached attributes
|
||||
/// </summary>
|
||||
public TryParseAttributesDelegate TryParseAttributes { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Base parser for fenced blocks (opened by 3 or more character delimiters on a first line, and closed by at least the same number of delimiters)
|
||||
/// </summary>
|
||||
/// <seealso cref="Markdig.Parsers.BlockParser" />
|
||||
public abstract class FencedBlockParserBase<T> : FencedBlockParserBase where T : Block, IFencedBlock
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FencedBlockParserBase{T}"/> class.
|
||||
/// </summary>
|
||||
protected FencedBlockParserBase()
|
||||
{
|
||||
InfoParser = DefaultInfoParser;
|
||||
MinimumMatchCount = 3;
|
||||
MaximumMatchCount = Int32.MaxValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the language prefix (default is "language-")
|
||||
/// </summary>
|
||||
public string InfoPrefix { get; set; }
|
||||
|
||||
public int MinimumMatchCount { get; set; }
|
||||
|
||||
public int MaximumMatchCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The default parser for the information after the fenced code block special characters (usually ` or ~)
|
||||
/// </summary>
|
||||
/// <param name="state">The parser processor.</param>
|
||||
/// <param name="line">The line.</param>
|
||||
/// <param name="fenced">The fenced code block.</param>
|
||||
/// <returns><c>true</c> if parsing of the line is successfull; <c>false</c> otherwise</returns>
|
||||
public static bool DefaultInfoParser(BlockProcessor state, ref StringSlice line, IFencedBlock fenced, char openingCharacter)
|
||||
{
|
||||
string infoString;
|
||||
string argString = null;
|
||||
|
||||
// An info string cannot contain any backticks (unless it is a tilde block)
|
||||
int firstSpace = -1;
|
||||
if (openingCharacter == '`')
|
||||
{
|
||||
for (int i = line.Start; i <= line.End; i++)
|
||||
{
|
||||
char c = line.Text[i];
|
||||
if (c == '`')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (firstSpace < 0 && c.IsSpaceOrTab())
|
||||
{
|
||||
firstSpace = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = line.Start; i <= line.End; i++)
|
||||
{
|
||||
if (line.Text[i].IsSpaceOrTab())
|
||||
{
|
||||
firstSpace = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (firstSpace > 0)
|
||||
{
|
||||
infoString = line.Text.Substring(line.Start, firstSpace - line.Start).Trim();
|
||||
|
||||
// Skip any spaces after info string
|
||||
firstSpace++;
|
||||
while (firstSpace <= line.End)
|
||||
{
|
||||
char c = line[firstSpace];
|
||||
if (c.IsSpaceOrTab())
|
||||
{
|
||||
firstSpace++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
argString = line.Text.Substring(firstSpace, line.End - firstSpace + 1).Trim();
|
||||
}
|
||||
else
|
||||
{
|
||||
infoString = line.ToString().Trim();
|
||||
}
|
||||
|
||||
fenced.Info = HtmlHelper.Unescape(infoString);
|
||||
fenced.Arguments = HtmlHelper.Unescape(argString);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override BlockState TryOpen(BlockProcessor processor)
|
||||
{
|
||||
// We expect no indentation for a fenced code block.
|
||||
if (processor.IsCodeIndent)
|
||||
{
|
||||
return BlockState.None;
|
||||
}
|
||||
|
||||
var startPosition = processor.Start;
|
||||
|
||||
// Match fenced char
|
||||
int count = 0;
|
||||
var line = processor.Line;
|
||||
char c = line.CurrentChar;
|
||||
var matchChar = c;
|
||||
while (c != '\0')
|
||||
{
|
||||
if (c != matchChar)
|
||||
{
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
c = line.NextChar();
|
||||
}
|
||||
|
||||
// A fenced codeblock requires at least 3 opening chars
|
||||
if (count < MinimumMatchCount || count > MaximumMatchCount)
|
||||
{
|
||||
return BlockState.None;
|
||||
}
|
||||
|
||||
// specs spaces: Is space and tabs? or only spaces? Use space and tab for this case
|
||||
line.TrimStart();
|
||||
|
||||
var fenced = CreateFencedBlock(processor);
|
||||
{
|
||||
fenced.Column = processor.Column;
|
||||
fenced.FencedChar = matchChar;
|
||||
fenced.FencedCharCount = count;
|
||||
fenced.Span.Start = startPosition;
|
||||
fenced.Span.End = line.Start;
|
||||
};
|
||||
|
||||
// Try to parse any attached attributes
|
||||
TryParseAttributes?.Invoke(processor, ref line, fenced);
|
||||
|
||||
// If the info parser was not successfull, early exit
|
||||
if (InfoParser != null && !InfoParser(processor, ref line, fenced, matchChar))
|
||||
{
|
||||
return BlockState.None;
|
||||
}
|
||||
|
||||
// Add the language as an attribute by default
|
||||
if (!string.IsNullOrEmpty(fenced.Info))
|
||||
{
|
||||
if (string.IsNullOrEmpty(InfoPrefix))
|
||||
{
|
||||
fenced.GetAttributes().AddClass(fenced.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
fenced.GetAttributes().AddClass(InfoPrefix + fenced.Info);
|
||||
}
|
||||
}
|
||||
|
||||
// Store the number of matched string into the context
|
||||
processor.NewBlocks.Push(fenced);
|
||||
|
||||
// Discard the current line as it is already parsed
|
||||
return BlockState.ContinueDiscard;
|
||||
}
|
||||
|
||||
protected abstract T CreateFencedBlock(BlockProcessor processor);
|
||||
|
||||
public override BlockState TryContinue(BlockProcessor processor, Block block)
|
||||
{
|
||||
var fence = (IFencedBlock)block;
|
||||
var count = fence.FencedCharCount;
|
||||
var matchChar = fence.FencedChar;
|
||||
var c = processor.CurrentChar;
|
||||
|
||||
// Match if we have a closing fence
|
||||
var line = processor.Line;
|
||||
while (c == matchChar)
|
||||
{
|
||||
c = line.NextChar();
|
||||
count--;
|
||||
}
|
||||
|
||||
// If we have a closing fence, close it and discard the current line
|
||||
// The line must contain only fence opening character followed only by whitespaces.
|
||||
if (count <= 0 && !processor.IsCodeIndent && (c == '\0' || c.IsWhitespace()) && line.TrimEnd())
|
||||
{
|
||||
block.UpdateSpanEnd(line.Start - 1);
|
||||
|
||||
// Don't keep the last line
|
||||
return BlockState.BreakDiscard;
|
||||
}
|
||||
|
||||
// Reset the indentation to the column before the indent
|
||||
processor.GoToColumn(processor.ColumnBeforeIndent);
|
||||
|
||||
return BlockState.Continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -159,7 +159,7 @@ namespace Markdig.Parsers
|
||||
}
|
||||
|
||||
// Cannot start with </script </pre or </style
|
||||
if ((tagIndex == 50 || tagIndex == 51 || tagIndex == 54))
|
||||
if ((tagIndex == 49 || tagIndex == 50 || tagIndex == 53))
|
||||
{
|
||||
if (c == '/' || hasLeadingClose)
|
||||
{
|
||||
@@ -323,30 +323,29 @@ namespace Markdig.Parsers
|
||||
"main", // 39
|
||||
"menu", // 40
|
||||
"menuitem", // 41
|
||||
"meta", // 42
|
||||
"nav", // 43
|
||||
"noframes", // 44
|
||||
"ol", // 45
|
||||
"optgroup", // 46
|
||||
"option", // 47
|
||||
"p", // 48
|
||||
"param", // 49
|
||||
"pre", // 50 <=== special group 1
|
||||
"script", // 51 <=== special group 1
|
||||
"section", // 52
|
||||
"source", // 53
|
||||
"style", // 54 <=== special group 1
|
||||
"summary", // 55
|
||||
"table", // 56
|
||||
"tbody", // 57
|
||||
"td", // 58
|
||||
"tfoot", // 59
|
||||
"th", // 60
|
||||
"thead", // 61
|
||||
"title", // 62
|
||||
"tr", // 63
|
||||
"track", // 64
|
||||
"ul", // 65
|
||||
"nav", // 42
|
||||
"noframes", // 43
|
||||
"ol", // 44
|
||||
"optgroup", // 45
|
||||
"option", // 46
|
||||
"p", // 47
|
||||
"param", // 48
|
||||
"pre", // 49 <=== special group 1
|
||||
"script", // 50 <=== special group 1
|
||||
"section", // 51
|
||||
"source", // 52
|
||||
"style", // 53 <=== special group 1
|
||||
"summary", // 54
|
||||
"table", // 55
|
||||
"tbody", // 56
|
||||
"td", // 57
|
||||
"tfoot", // 58
|
||||
"th", // 59
|
||||
"thead", // 60
|
||||
"title", // 61
|
||||
"tr", // 62
|
||||
"track", // 63
|
||||
"ul", // 64
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using Markdig.Helpers;
|
||||
@@ -8,7 +8,7 @@ using Markdig.Syntax;
|
||||
namespace Markdig.Parsers
|
||||
{
|
||||
/// <summary>
|
||||
/// A delegates that allows to porcess attached attributes at <see cref="BlockParser"/> time.
|
||||
/// A delegates that allows to process attached attributes at <see cref="BlockParser"/> time.
|
||||
/// </summary>
|
||||
/// <param name="processor">The processor.</param>
|
||||
/// <param name="slice">The slice to look for attached attributes.</param>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using Markdig.Syntax.Inlines;
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace Markdig.Parsers
|
||||
/// <param name="lastChild">The last child.</param>
|
||||
/// <param name="postInlineProcessorIndex">Index of this delimiter processor.</param>
|
||||
/// <param name="isFinalProcessing"></param>
|
||||
/// <returns><c>true</c> to continue to the next delimiter processor;
|
||||
/// <c>false</c> to stop the process (in case a processor is perfoming sub-sequent processor itself)</returns>
|
||||
/// <returns><c>true</c> to continue to the next delimiter processor;
|
||||
/// <c>false</c> to stop the process (in case a processor is performing sub-sequent processor itself)</returns>
|
||||
bool PostProcess(InlineProcessor state, Inline root, Inline lastChild, int postInlineProcessorIndex, bool isFinalProcessing);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// 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.Collections.Generic;
|
||||
@@ -52,7 +52,7 @@ namespace Markdig.Parsers
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current block being proessed.
|
||||
/// Gets the current block being processed.
|
||||
/// </summary>
|
||||
public LeafBlock Block { get; private set; }
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace Markdig.Parsers
|
||||
/// <returns>The source position</returns>
|
||||
public int GetSourcePosition(int sliceOffset, out int lineIndex, out int column)
|
||||
{
|
||||
column = 0;
|
||||
column = 0;
|
||||
lineIndex = sliceOffset >= previousSliceOffset ? previousLineIndexForSliceOffset : 0;
|
||||
int position = 0;
|
||||
if (PreciseSourceLocation)
|
||||
@@ -153,7 +153,7 @@ namespace Markdig.Parsers
|
||||
var lineOffset = lineOffsets[lineIndex];
|
||||
if (sliceOffset <= lineOffset.End)
|
||||
{
|
||||
// Use the beginning of the line as a previous slice offset
|
||||
// Use the beginning of the line as a previous slice offset
|
||||
// (since it is on the same line)
|
||||
previousSliceOffset = lineOffsets[lineIndex].Start;
|
||||
var delta = sliceOffset - previousSliceOffset;
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace Markdig.Parsers.Inlines
|
||||
|
||||
public override bool Match(InlineProcessor processor, ref StringSlice slice)
|
||||
{
|
||||
int openSticks = 0;
|
||||
var match = slice.CurrentChar;
|
||||
if (slice.PeekCharExtra(-1) == match)
|
||||
{
|
||||
@@ -32,82 +31,84 @@ namespace Markdig.Parsers.Inlines
|
||||
|
||||
var startPosition = slice.Start;
|
||||
|
||||
int openSticks = 0;
|
||||
int closeSticks = 0;
|
||||
|
||||
// Match the opened sticks
|
||||
var c = slice.CurrentChar;
|
||||
char c = slice.CurrentChar;
|
||||
while (c == match)
|
||||
{
|
||||
openSticks++;
|
||||
c = slice.NextChar();
|
||||
}
|
||||
|
||||
bool isMatching = false;
|
||||
var builder = processor.StringBuilders.Get();
|
||||
|
||||
// A backtick string is a string of one or more backtick characters (`) that is neither preceded nor followed by a backtick.
|
||||
// A code span begins with a backtick string and ends with a backtick string of equal length.
|
||||
// The contents of the code span are the characters between the two backtick strings, normalized in the following ways:
|
||||
|
||||
// 1. line endings are converted to spaces.
|
||||
|
||||
// 2. If the resulting string both begins AND ends with a space character, but does not consist entirely
|
||||
// of space characters, a single space character is removed from the front and back.
|
||||
// This allows you to include code that begins or ends with backtick characters, which must be separated by
|
||||
// whitespace from the opening or closing backtick strings.
|
||||
|
||||
var builder = processor.StringBuilders.Get();
|
||||
int closeSticks = 0;
|
||||
bool allSpace = true;
|
||||
|
||||
// A backtick string is a string of one or more backtick characters (`) that is neither preceded nor followed by a backtick.
|
||||
// A code span begins with a backtick string and ends with a backtick string of equal length.
|
||||
// The contents of the code span are the characters between the two backtick strings, with leading and trailing spaces and line endings removed, and whitespace collapsed to single spaces.
|
||||
var pc = ' ';
|
||||
|
||||
int newLinesFound = 0;
|
||||
while (c != '\0')
|
||||
{
|
||||
// Transform '\n' into a single space
|
||||
if (c == '\n')
|
||||
{
|
||||
newLinesFound++;
|
||||
c = ' ';
|
||||
}
|
||||
|
||||
if (c != match && (c != ' ' || pc != ' '))
|
||||
{
|
||||
builder.Append(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (c == match)
|
||||
if (c == match)
|
||||
{
|
||||
do
|
||||
{
|
||||
closeSticks++;
|
||||
pc = c;
|
||||
c = slice.NextChar();
|
||||
}
|
||||
|
||||
}
|
||||
while (c == match);
|
||||
|
||||
if (openSticks == closeSticks)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (closeSticks > 0)
|
||||
{
|
||||
allSpace = false;
|
||||
builder.Append(match, closeSticks);
|
||||
closeSticks = 0;
|
||||
closeSticks = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pc = c;
|
||||
c = slice.NextChar();
|
||||
else
|
||||
{
|
||||
builder.Append(c);
|
||||
if (c != ' ')
|
||||
{
|
||||
allSpace = false;
|
||||
}
|
||||
c = slice.NextChar();
|
||||
}
|
||||
}
|
||||
|
||||
bool isMatching = false;
|
||||
if (closeSticks == openSticks)
|
||||
{
|
||||
// Remove trailing space
|
||||
if (builder.Length > 0)
|
||||
// Remove one space from front and back if the string is not all spaces
|
||||
if (!allSpace && builder.Length > 2 && builder[0] == ' ' && builder[builder.Length - 1] == ' ')
|
||||
{
|
||||
if (builder[builder.Length - 1].IsWhitespace())
|
||||
{
|
||||
builder.Length--;
|
||||
}
|
||||
builder.Length--;
|
||||
builder.Remove(0, 1); // More expensive, alternative is to have a double-pass algorithm
|
||||
}
|
||||
int line;
|
||||
int column;
|
||||
|
||||
processor.Inline = new CodeInline()
|
||||
{
|
||||
Delimiter = match,
|
||||
Content = builder.ToString(),
|
||||
Span = new SourceSpan(processor.GetSourcePosition(startPosition, out line, out column), processor.GetSourcePosition(slice.Start - 1)),
|
||||
Span = new SourceSpan(processor.GetSourcePosition(startPosition, out int line, out int column), processor.GetSourcePosition(slice.Start - 1)),
|
||||
Line = line,
|
||||
Column = column
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using System;
|
||||
@@ -41,7 +41,7 @@ namespace Markdig.Parsers.Inlines
|
||||
public readonly int MinimumCount;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum number of character this emphasis is expected to have (must be >=1 and >= minumunCount)
|
||||
/// The maximum number of character this emphasis is expected to have (must be >=1 and >= minimumCount)
|
||||
/// </summary>
|
||||
public readonly int MaximumCount;
|
||||
|
||||
|
||||
@@ -244,7 +244,8 @@ namespace Markdig.Parsers.Inlines
|
||||
var isOddMatch = ((closeDelimiter.Type & DelimiterType.Open) != 0 ||
|
||||
(previousOpenDelimiter.Type & DelimiterType.Close) != 0) &&
|
||||
previousOpenDelimiter.DelimiterCount != closeDelimiter.DelimiterCount &&
|
||||
(previousOpenDelimiter.DelimiterCount + closeDelimiter.DelimiterCount) % 3 == 0;
|
||||
(previousOpenDelimiter.DelimiterCount + closeDelimiter.DelimiterCount) % 3 == 0 &&
|
||||
(previousOpenDelimiter.DelimiterCount % 3 != 0 || closeDelimiter.DelimiterCount % 3 != 0);
|
||||
|
||||
if (previousOpenDelimiter.DelimiterChar == closeDelimiter.DelimiterChar &&
|
||||
(previousOpenDelimiter.Type & DelimiterType.Open) != 0 &&
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Syntax;
|
||||
@@ -190,8 +190,8 @@ namespace Markdig.Parsers.Inlines
|
||||
|
||||
if (openParent != null)
|
||||
{
|
||||
// If we do find one, but it’s not active,
|
||||
// we remove the inactive delimiter from the stack,
|
||||
// If we do find one, but it’s not active,
|
||||
// we remove the inactive delimiter from the stack,
|
||||
// and return a literal text node ].
|
||||
if (!openParent.IsActive)
|
||||
{
|
||||
@@ -206,10 +206,10 @@ namespace Markdig.Parsers.Inlines
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we find one and it’s active,
|
||||
// then we parse ahead to see if we have
|
||||
// an inline link/image, reference link/image,
|
||||
// compact reference link/image,
|
||||
// If we find one and it’s active,
|
||||
// then we parse ahead to see if we have
|
||||
// an inline link/image, reference link/image,
|
||||
// compact reference link/image,
|
||||
// or shortcut reference link/image
|
||||
var parentDelimiter = openParent.Parent;
|
||||
var savedText = text;
|
||||
@@ -243,8 +243,8 @@ namespace Markdig.Parsers.Inlines
|
||||
// Process emphasis delimiters
|
||||
inlineState.PostProcessInlines(0, link, null, false);
|
||||
|
||||
// If we have a link (and not an image),
|
||||
// we also set all [ delimiters before the opening delimiter to inactive.
|
||||
// If we have a link (and not an image),
|
||||
// we also set all [ delimiters before the opening delimiter to inactive.
|
||||
// (This will prevent us from getting links within links.)
|
||||
if (!openParent.IsImage)
|
||||
{
|
||||
@@ -309,7 +309,7 @@ namespace Markdig.Parsers.Inlines
|
||||
|
||||
// We have a nested [ ]
|
||||
// firstParent.Remove();
|
||||
// The opening [ will be transformed to a literal followed by all the childrens of the [
|
||||
// The opening [ will be transformed to a literal followed by all the children of the [
|
||||
|
||||
var literal = new LiteralInline()
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
|
||||
using Markdig.Helpers;
|
||||
@@ -38,7 +38,7 @@ namespace Markdig.Parsers.Inlines
|
||||
int column;
|
||||
var startPosition = processor.GetSourcePosition(slice.Start, out line, out column);
|
||||
|
||||
// Sligthly faster to perform our own search for opening characters
|
||||
// Slightly faster to perform our own search for opening characters
|
||||
var nextStart = processor.Parsers.IndexOfOpeningCharacter(text, slice.Start + 1, slice.End);
|
||||
//var nextStart = str.IndexOfAny(processor.SpecialCharacters, slice.Start + 1, slice.Length - 1);
|
||||
int length;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// 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.Collections.Generic;
|
||||
@@ -97,7 +97,7 @@ namespace Markdig.Parsers
|
||||
}
|
||||
}
|
||||
|
||||
// 5.2 List items
|
||||
// 5.2 List items
|
||||
// TODO: Check with specs, it is not clear that list marker or bullet marker must be followed by at least 1 space
|
||||
|
||||
// If we have already a ListItemBlock, we are going to try to append to it
|
||||
@@ -149,23 +149,23 @@ namespace Markdig.Parsers
|
||||
|
||||
// Update list-item source end position
|
||||
listItem.UpdateSpanEnd(state.Line.End);
|
||||
|
||||
|
||||
return BlockState.Continue;
|
||||
}
|
||||
|
||||
list.CountBlankLinesReset = 0;
|
||||
|
||||
int columWidth = listItem.ColumnWidth;
|
||||
if (columWidth < 0)
|
||||
int columnWidth = listItem.ColumnWidth;
|
||||
if (columnWidth < 0)
|
||||
{
|
||||
columWidth = -columWidth;
|
||||
columnWidth = -columnWidth;
|
||||
}
|
||||
|
||||
if (state.Indent >= columWidth)
|
||||
if (state.Indent >= columnWidth)
|
||||
{
|
||||
if (state.Indent > columWidth && state.IsCodeIndent)
|
||||
if (state.Indent > columnWidth && state.IsCodeIndent)
|
||||
{
|
||||
state.GoToColumn(state.ColumnBeforeIndent + columWidth);
|
||||
state.GoToColumn(state.ColumnBeforeIndent + columnWidth);
|
||||
}
|
||||
|
||||
// Update list-item source end position
|
||||
@@ -179,15 +179,15 @@ namespace Markdig.Parsers
|
||||
|
||||
private BlockState TryParseListItem(BlockProcessor state, Block block)
|
||||
{
|
||||
// If we have a code indent and we are not in a ListItem, early exit
|
||||
if (!(block is ListItemBlock) && state.IsCodeIndent)
|
||||
var currentListItem = block as ListItemBlock;
|
||||
var currentParent = block as ListBlock ?? (ListBlock)currentListItem?.Parent;
|
||||
|
||||
// We can early exit if we have a code indent and we are either (1) not in a ListItem, (2) preceded by a blank line, (3) in an unordered list
|
||||
if (state.IsCodeIndent && (currentListItem is null || currentListItem.LastChild is BlankLineBlock || !currentParent.IsOrdered))
|
||||
{
|
||||
return BlockState.None;
|
||||
}
|
||||
|
||||
var currentListItem = block as ListItemBlock;
|
||||
var currentParent = block as ListBlock ?? (ListBlock)currentListItem?.Parent;
|
||||
|
||||
var initColumnBeforeIndent = state.ColumnBeforeIndent;
|
||||
var initColumn = state.Column;
|
||||
var sourcePosition = state.Start;
|
||||
@@ -210,7 +210,7 @@ namespace Markdig.Parsers
|
||||
return BlockState.None;
|
||||
}
|
||||
|
||||
// Gets the current character after a succesfull parsing of the list information
|
||||
// Gets the current character after a successful parsing of the list information
|
||||
c = state.CurrentChar;
|
||||
|
||||
// Item starting with a blank line
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// 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
|
||||
@@ -20,7 +20,7 @@ namespace Markdig.Parsers
|
||||
/// <param name="state">The block processor</param>
|
||||
/// <param name="pendingBulletType">The type of the current bullet type</param>
|
||||
/// <param name="result">The result of parsing</param>
|
||||
/// <returns><c>true</c> if parsing was sucessfull; <c>false</c> otherwise</returns>
|
||||
/// <returns><c>true</c> if parsing was successful; <c>false</c> otherwise</returns>
|
||||
public abstract bool TryParse(BlockProcessor state, char pendingBulletType, out ListInfo result);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Syntax;
|
||||
@@ -12,6 +12,8 @@ namespace Markdig.Parsers
|
||||
/// <seealso cref="BlockParser" />
|
||||
public class ParagraphBlockParser : BlockParser
|
||||
{
|
||||
public bool ParseSetexHeadings { get; set; } = true;
|
||||
|
||||
public override BlockState TryOpen(BlockProcessor processor)
|
||||
{
|
||||
if (processor.IsBlankLine)
|
||||
@@ -35,7 +37,7 @@ namespace Markdig.Parsers
|
||||
return BlockState.BreakDiscard;
|
||||
}
|
||||
|
||||
if (!processor.IsCodeIndent && !(block.Parent is QuoteBlock))
|
||||
if (ParseSetexHeadings && !processor.IsCodeIndent && !(block.Parent is QuoteBlock))
|
||||
{
|
||||
return TryParseSetexHeading(processor, block);
|
||||
}
|
||||
@@ -46,8 +48,7 @@ namespace Markdig.Parsers
|
||||
|
||||
public override bool Close(BlockProcessor processor, Block block)
|
||||
{
|
||||
var paragraph = block as ParagraphBlock;
|
||||
if (paragraph != null)
|
||||
if (block is ParagraphBlock paragraph)
|
||||
{
|
||||
TryMatchLinkReferenceDefinition(ref paragraph.Lines, processor);
|
||||
|
||||
@@ -115,13 +116,13 @@ namespace Markdig.Parsers
|
||||
|
||||
if (headingChar != 0)
|
||||
{
|
||||
// We dicard the paragraph that will be transformed to a heading
|
||||
state.Discard(paragraph);
|
||||
|
||||
// If we matched a LinkReferenceDefinition before matching the heading, and the remaining
|
||||
// If we matched a LinkReferenceDefinition before matching the heading, and the remaining
|
||||
// lines are empty, we can early exit and remove the paragraph
|
||||
if (!(TryMatchLinkReferenceDefinition(ref paragraph.Lines, state) && paragraph.Lines.Count == 0))
|
||||
{
|
||||
// We discard the paragraph that will be transformed to a heading
|
||||
state.Discard(paragraph);
|
||||
|
||||
var level = headingChar == '=' ? 1 : 2;
|
||||
|
||||
var heading = new HeadingBlock(this)
|
||||
@@ -135,8 +136,9 @@ namespace Markdig.Parsers
|
||||
|
||||
// Remove the paragraph as a pending block
|
||||
state.NewBlocks.Push(heading);
|
||||
|
||||
return BlockState.BreakDiscard;
|
||||
}
|
||||
return BlockState.BreakDiscard;
|
||||
}
|
||||
|
||||
block.UpdateSpanEnd(state.Line.End);
|
||||
@@ -153,14 +155,14 @@ namespace Markdig.Parsers
|
||||
// If we have found a LinkReferenceDefinition, we can discard the previous paragraph
|
||||
var iterator = lines.ToCharIterator();
|
||||
if (LinkReferenceDefinition.TryParse(ref iterator, out LinkReferenceDefinition linkReferenceDefinition))
|
||||
{
|
||||
{
|
||||
state.Document.SetLinkReferenceDefinition(linkReferenceDefinition.Label, linkReferenceDefinition);
|
||||
atLeastOneFound = true;
|
||||
|
||||
// Correct the locations of each field
|
||||
linkReferenceDefinition.Line = lines.Lines[0].Line;
|
||||
int startPosition = lines.Lines[0].Slice.Start;
|
||||
|
||||
linkReferenceDefinition.Line = lines.Lines[0].Line;
|
||||
int startPosition = lines.Lines[0].Slice.Start;
|
||||
|
||||
linkReferenceDefinition.Span = linkReferenceDefinition.Span .MoveForward(startPosition);
|
||||
linkReferenceDefinition.LabelSpan = linkReferenceDefinition.LabelSpan .MoveForward(startPosition);
|
||||
linkReferenceDefinition.UrlSpan = linkReferenceDefinition.UrlSpan .MoveForward(startPosition);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// 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;
|
||||
@@ -79,26 +79,20 @@ namespace Markdig.Renderers.Html
|
||||
if (name == null) throw new ArgumentNullException(nameof(name));
|
||||
if (Properties == null)
|
||||
{
|
||||
Properties = new List<KeyValuePair<string, string>>(4) {new KeyValuePair<string, string>(name, value == null ? null : Convert.ToString(value, CultureInfo.InvariantCulture))};
|
||||
Properties = new List<KeyValuePair<string, string>>(4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check that there is not already a property with the same key
|
||||
bool copyProp = true;
|
||||
for (int i = 0; i < Properties.Count; i++)
|
||||
{
|
||||
var againstProp = Properties[i];
|
||||
if (againstProp.Key == name)
|
||||
if (Properties[i].Key == name)
|
||||
{
|
||||
copyProp = false;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (copyProp)
|
||||
{
|
||||
Properties.Add(new KeyValuePair<string, string>(name, value == null ? null : Convert.ToString(value, CultureInfo.InvariantCulture)));
|
||||
}
|
||||
}
|
||||
|
||||
Properties.Add(new KeyValuePair<string, string>(name, value == null ? null : Convert.ToString(value, CultureInfo.InvariantCulture)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -13,7 +13,14 @@ namespace Markdig.Renderers.Html.Inlines
|
||||
{
|
||||
protected override void Write(HtmlRenderer renderer, HtmlEntityInline obj)
|
||||
{
|
||||
renderer.WriteEscape(obj.Transcoded);
|
||||
if (renderer.EnableHtmlForInline)
|
||||
{
|
||||
renderer.WriteEscape(obj.Transcoded);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.Write(obj.Transcoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,14 @@ namespace Markdig.Renderers.Html.Inlines
|
||||
{
|
||||
protected override void Write(HtmlRenderer renderer, LiteralInline obj)
|
||||
{
|
||||
renderer.WriteEscape(ref obj.Content);
|
||||
if (renderer.EnableHtmlForInline)
|
||||
{
|
||||
renderer.WriteEscape(obj.Content);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.Write(obj.Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
// 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;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Text;
|
||||
using Markdig.Helpers;
|
||||
using Markdig.Renderers.Html;
|
||||
using Markdig.Renderers.Html.Inlines;
|
||||
@@ -83,7 +84,7 @@ namespace Markdig.Renderers
|
||||
/// <summary>
|
||||
/// Allows links to be rewritten
|
||||
/// </summary>
|
||||
public Func<string,string> LinkRewriter { get; set; }
|
||||
public Func<string, string> LinkRewriter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Writes the content escaped for HTML.
|
||||
@@ -190,7 +191,9 @@ namespace Markdig.Renderers
|
||||
|
||||
Write(content, previousOffset, end - previousOffset);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly IdnMapping IdnMapping = new IdnMapping();
|
||||
|
||||
/// <summary>
|
||||
/// Writes the URL escaped for HTML.
|
||||
@@ -212,10 +215,57 @@ namespace Markdig.Renderers
|
||||
content = LinkRewriter(content);
|
||||
}
|
||||
|
||||
int previousPosition = 0;
|
||||
int length = content.Length;
|
||||
int previousPosition = 0;
|
||||
|
||||
for (var i = 0; i < length; i++)
|
||||
// ab://c.d = 8 chars
|
||||
int schemeOffset = content.Length < 8 ? -1 : content.IndexOf("://", 2, StringComparison.Ordinal);
|
||||
if (schemeOffset != -1) // This is an absolute URL
|
||||
{
|
||||
schemeOffset += 3; // skip ://
|
||||
Write(content, 0, schemeOffset);
|
||||
|
||||
bool idnaEncodeDomain = false;
|
||||
int endOfDomain = schemeOffset;
|
||||
for (; endOfDomain < content.Length; endOfDomain++)
|
||||
{
|
||||
char c = content[endOfDomain];
|
||||
if (c == '/' || c == '?' || c == '#' || c == ':') // End of domain part
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (c > 127)
|
||||
{
|
||||
idnaEncodeDomain = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (idnaEncodeDomain)
|
||||
{
|
||||
string domainName = IdnMapping.GetAscii(content, schemeOffset, endOfDomain - schemeOffset);
|
||||
|
||||
// Escape the characters (see Commonmark example 327 and think of it with a non-ascii symbol)
|
||||
previousPosition = 0;
|
||||
for (int i = 0; i < domainName.Length; i++)
|
||||
{
|
||||
var escape = HtmlHelper.EscapeUrlCharacter(domainName[i]);
|
||||
if (escape != null)
|
||||
{
|
||||
Write(domainName, previousPosition, i - previousPosition);
|
||||
previousPosition = i + 1;
|
||||
Write(escape);
|
||||
}
|
||||
}
|
||||
Write(domainName, previousPosition, domainName.Length - previousPosition);
|
||||
|
||||
previousPosition = endOfDomain;
|
||||
}
|
||||
else
|
||||
{
|
||||
previousPosition = schemeOffset; // Don't write anything as we might need to escape it
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = previousPosition; i < content.Length; i++)
|
||||
{
|
||||
var c = content[i];
|
||||
|
||||
@@ -242,7 +292,7 @@ namespace Markdig.Renderers
|
||||
else
|
||||
{
|
||||
byte[] bytes;
|
||||
if (c >= '\ud800' && c <= '\udfff' && previousPosition < length)
|
||||
if (c >= '\ud800' && c <= '\udfff' && previousPosition < content.Length)
|
||||
{
|
||||
bytes = Encoding.UTF8.GetBytes(new[] { c, content[previousPosition] });
|
||||
// Skip next char as it is decoded above
|
||||
@@ -261,7 +311,7 @@ namespace Markdig.Renderers
|
||||
}
|
||||
}
|
||||
|
||||
Write(content, previousPosition, length - previousPosition);
|
||||
Write(content, previousPosition, content.Length - previousPosition);
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -359,6 +409,6 @@ namespace Markdig.Renderers
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,11 +13,41 @@ namespace Markdig.Renderers.Normalize.Inlines
|
||||
{
|
||||
protected override void Write(NormalizeRenderer renderer, CodeInline obj)
|
||||
{
|
||||
var delimiter = obj.Content.Contains(obj.Delimiter + "") ? new string(obj.Delimiter, 2) : obj.Delimiter + "";
|
||||
var delimiterCount = 0;
|
||||
for (var i = 0; i < obj.Content.Length; i++)
|
||||
{
|
||||
var index = obj.Content.IndexOf(obj.Delimiter, i);
|
||||
if (index == -1) break;
|
||||
|
||||
renderer.Write(delimiter);
|
||||
renderer.Write(obj.Content);
|
||||
renderer.Write(delimiter);
|
||||
var count = 1;
|
||||
for (i = index + 1; i < obj.Content.Length; i++)
|
||||
{
|
||||
if (obj.Content[i] == obj.Delimiter) count++;
|
||||
else break;
|
||||
}
|
||||
|
||||
if (delimiterCount < count)
|
||||
delimiterCount = count;
|
||||
}
|
||||
var delimiterRun = new string(obj.Delimiter, delimiterCount + 1);
|
||||
renderer.Write(delimiterRun);
|
||||
if (obj.Content.Length != 0)
|
||||
{
|
||||
if (obj.Content[0] == obj.Delimiter)
|
||||
{
|
||||
renderer.Write(' ');
|
||||
}
|
||||
renderer.Write(obj.Content);
|
||||
if (obj.Content[obj.Content.Length - 1] == obj.Delimiter)
|
||||
{
|
||||
renderer.Write(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
renderer.Write(' ');
|
||||
}
|
||||
renderer.Write(delimiterRun);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,15 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using Markdig.Parsers;
|
||||
|
||||
namespace Markdig.Syntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Repressents an indented code block.
|
||||
/// Represents an indented code block.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Related to CommonMark spec: 4.4 Indented code blocks
|
||||
/// Related to CommonMark spec: 4.4 Indented code blocks
|
||||
/// </remarks>
|
||||
public class CodeBlock : LeafBlock
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// 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.
|
||||
|
||||
@@ -98,6 +98,8 @@ namespace Markdig.Syntax
|
||||
children[i].Parent = null;
|
||||
children[i] = null;
|
||||
}
|
||||
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
public bool Contains(Block item)
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using Markdig.Parsers;
|
||||
|
||||
namespace Markdig.Syntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Repressents a fenced code block.
|
||||
/// Represents a fenced code block.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Related to CommonMark spec: 4.5 Fenced code blocks
|
||||
@@ -27,7 +27,7 @@ namespace Markdig.Syntax
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the language parsed after the first line of
|
||||
/// Gets or sets the language parsed after the first line of
|
||||
/// the fenced code block. May be null.
|
||||
/// </summary>
|
||||
public string Info { get; set; }
|
||||
@@ -49,7 +49,7 @@ namespace Markdig.Syntax
|
||||
public char FencedChar { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the indent count when the fenced code block was indented
|
||||
/// Gets or sets the indent count when the fenced code block was indented
|
||||
/// and we need to remove up to indent count chars spaces from the begining of a line.
|
||||
/// </summary>
|
||||
internal int IndentCount { get; set; }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// See the license.txt file in the project root for more information.
|
||||
using System.Diagnostics;
|
||||
using Markdig.Parsers;
|
||||
@@ -7,7 +7,7 @@ using Markdig.Parsers;
|
||||
namespace Markdig.Syntax
|
||||
{
|
||||
/// <summary>
|
||||
/// Repressents a heading.
|
||||
/// Represents a heading.
|
||||
/// </summary>
|
||||
[DebuggerDisplay("{GetType().Name} Line: {Line}, {Lines} Level: {Level}")]
|
||||
public class HeadingBlock : LeafBlock
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright (c) Alexandre Mutel. All rights reserved.
|
||||
// This file is licensed under the BSD-Clause 2 license.
|
||||
// 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.Collections;
|
||||
@@ -94,36 +94,36 @@ namespace Markdig.Syntax.Inlines
|
||||
/// <returns>An enumeration of T</returns>
|
||||
public IEnumerable<T> FindDescendants<T>() where T : Inline
|
||||
{
|
||||
// Fast-path an empty container to avoid allocating a Stack
|
||||
// Fast-path an empty container to avoid allocating a Stack
|
||||
if (LastChild == null) yield break;
|
||||
|
||||
Stack<Inline> stack = new Stack<Inline>();
|
||||
|
||||
var child = LastChild;
|
||||
while (child != null)
|
||||
{
|
||||
stack.Push(child);
|
||||
child = child.PreviousSibling;
|
||||
while (child != null)
|
||||
{
|
||||
stack.Push(child);
|
||||
child = child.PreviousSibling;
|
||||
}
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
child = stack.Pop();
|
||||
|
||||
if (child is T childT)
|
||||
{
|
||||
yield return childT;
|
||||
}
|
||||
|
||||
if (child is ContainerInline containerInline)
|
||||
{
|
||||
child = containerInline.LastChild;
|
||||
while (child != null)
|
||||
{
|
||||
stack.Push(child);
|
||||
child = child.PreviousSibling;
|
||||
}
|
||||
}
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
child = stack.Pop();
|
||||
|
||||
if (child is T childT)
|
||||
{
|
||||
yield return childT;
|
||||
}
|
||||
|
||||
if (child is ContainerInline containerInline)
|
||||
{
|
||||
child = containerInline.LastChild;
|
||||
while (child != null)
|
||||
{
|
||||
stack.Push(child);
|
||||
child = child.PreviousSibling;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,14 +135,14 @@ namespace Markdig.Syntax.Inlines
|
||||
{
|
||||
if (parent == null) throw new ArgumentNullException(nameof(parent));
|
||||
var child = FirstChild;
|
||||
var nextSibliing = parent;
|
||||
var nextSibling = parent;
|
||||
while (child != null)
|
||||
{
|
||||
var next = child.NextSibling;
|
||||
// TODO: optimize this
|
||||
child.Remove();
|
||||
nextSibliing.InsertAfter(child);
|
||||
nextSibliing = child;
|
||||
nextSibling.InsertAfter(child);
|
||||
nextSibling = child;
|
||||
child = next;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user