Compare commits

...

56 Commits

Author SHA1 Message Date
Alexandre Mutel
29aa56b4f1 Bump to 0.12.2 2017-06-18 10:58:40 +02:00
Alexandre Mutel
5004ecedb7 Use TestParser.TestSpec instead to mitigate problem with \r 2017-06-18 10:56:44 +02:00
Alexandre Mutel
ba06a796dc Merge branch 'pr/n121_pearsonn' 2017-06-18 10:50:39 +02:00
Nick Pearson
b1d6f34976 Fix issue in GenericAttributesParser causing inline elements to be skipped 2017-06-14 15:20:16 -07:00
Alexandre Mutel
28f4236a57 Bump to 0.12.1 2017-05-29 12:26:17 +02:00
Alexandre Mutel
0739a82735 Merge pull request #119 from meziantou/master
MediaLinkExtension: Remove unexpected closing tag
2017-05-28 19:00:54 +02:00
Meziantou
3ac9f2e788 Fix issue 2017-05-28 12:18:59 +02:00
Meziantou
d9607cc687 Update tests 2017-05-28 12:18:50 +02:00
Alexandre Mutel
f0573ef9e2 Bump to 0.12.0 2017-05-28 08:24:50 +02:00
Alexandre Mutel
017a3bd7e2 Merge branch 'pr/n118_meziantou' 2017-05-28 08:17:46 +02:00
Alexandre Mutel
d6f9a1055c Remove unnecessary test in BlockProcessor (#115) 2017-05-28 08:14:58 +02:00
Alexandre Mutel
2612e9d565 Fix issue in TryParseAutolink in LinkHelper (#115) 2017-05-28 08:02:55 +02:00
Alexandre Mutel
1076d7af10 Fix issue in ScanEntity (#115) 2017-05-28 07:56:58 +02:00
Meziantou
850cecfa6c Fix issue 2017-05-27 16:16:46 +02:00
Meziantou
bfdb03bd78 Update tests 2017-05-27 16:16:33 +02:00
Alexandre Mutel
56b6e329d5 Add missing update to Tests.csproj 2017-05-18 11:31:51 +02:00
Alexandre Mutel
006e384d1a Update links 2017-05-18 11:31:24 +02:00
Alexandre Mutel
9cd9b683a5 Remove specialized renderer for JiraLinks now going through the standard LinkInline 2017-05-18 11:04:42 +02:00
Alexandre Mutel
e01e2c3d2b Add StringBuilder extensions to accept a StringSlice 2017-05-18 11:04:06 +02:00
Alexandre Mutel
97ce0da564 Update JiraLinks, allow ( and ), use StringSlice instead of strings for key/issue, add support for attributes, add tests 2017-05-18 10:33:16 +02:00
Alexandre Mutel
26c5ce59b5 Update Benchmarks to latest DotNetBenchmark. Remove nuget.targets 2017-05-18 09:33:26 +02:00
Alexandre Mutel
d2d94ecf39 Merge branch 'pr/n113_clarkd' 2017-05-18 09:18:50 +02:00
Dave Clarke
0ec82bb81d Fix comment 2017-05-17 11:55:30 +01:00
Dave Clarke
ad9e941cb0 Fix missing space before target attribute
Rename Key -> ProjectKey
2017-05-16 16:48:25 +01:00
Dave Clarke
27dab6ca6d Automatically link JIRA issue references 2017-05-16 12:02:44 +01:00
Alexandre Mutel
762196f03b Bump to 0.11.0 2017-05-08 12:05:15 +02:00
Alexandre Mutel
26a565fa45 Fix/improve parsing of math inline, improving rules for matching, disallow newline between $$/$ for inline parsing (#87) 2017-05-08 11:50:40 +02:00
Alexandre Mutel
4369db1a43 Fix issue with $$ block parsing that should be interpreted as inline parsing (#105) 2017-05-08 11:48:44 +02:00
Alexandre Mutel
d83f1f87cc Add custom arrows to emoji 2017-05-08 09:25:44 +02:00
Alexandre Mutel
14027f4be3 Migrate to VS2017 - dotnet new csproj 2017-05-06 15:41:07 +02:00
Alexandre Mutel
8bcfb53607 Merge pull request #109 from aKzenT/issue-108
Fix for issue #108
2017-04-29 11:11:05 +02:00
Thomas Krause
700bb21e03 Fix for issue #108 2017-04-28 21:47:41 +02:00
Alexandre Mutel
1bc9d9083c Merge pull request #105 from MatthewRichards/DotTerminatedUrls
Treat trailing full stop after a URL as not being part of the URL
2017-04-04 10:02:38 +02:00
Alexandre Mutel
1d7bb021a7 Bump version to 0.10.7 2017-04-01 10:20:18 +02:00
Matthew Richards
3305a74b06 Additional test case 2017-03-30 08:51:05 +01:00
Matthew Richards
6312bc0515 Treat trailing full stop after a URL as not being part of the URL 2017-03-29 16:47:41 +01:00
Alexandre Mutel
b595383281 Merge pull request #103 from Daniel15/replace
Add Replace method to replace an element in an OrderedList
2017-03-20 10:39:01 +01:00
Alexandre Mutel
bf85964543 Merge pull request #102 from Daniel15/lock-dotnet
Lock .NET Core SDK to 1.0.0-preview2
2017-03-20 10:37:16 +01:00
Daniel Lo Nigro
d5b020b784 Add Replace method to replace an element in an OrderedList 2017-03-19 14:39:24 -07:00
Daniel Lo Nigro
8ab0467e78 Lock .NET Core SDK to 1.0.0-preview2 2017-03-19 13:42:26 -07:00
Alexandre Mutel
74fe3be7c7 Bump version to 0.10.6 2017-02-24 07:52:29 +01:00
Alexandre Mutel
b47ae8d9ba Fix emphasis with HTML entities (#97) 2017-02-24 07:49:46 +01:00
Alexandre Mutel
a926e1a326 Bump version to 0.10.5 2017-02-14 17:36:54 +01:00
Alexandre Mutel
6048406f52 Merge branch 'pr/n89_johnsimons' 2017-01-31 13:01:17 +01:00
John Simons
1edf14c742 Remove requirement for space after emoji.
Fixes #88
2017-01-31 12:58:32 +01:00
Alexandre Mutel
d4bb7c0a51 Merge pull request #82 from christophano/bugfix/abbreviation_parser_fix
Fixes the IsValidAbbreviation method in AbbreviationParser
2016-12-19 14:37:32 +01:00
Chris Rodgers
ba4e463517 Adds the test I ought to have included to begin with. 2016-12-19 13:25:56 +00:00
Chris Rodgers
2d0dae4ebb Fixes the IsValidAbbreviation method in AbbreviationParser 2016-12-19 13:05:03 +00:00
Alexandre Mutel
1a9d923c44 Merge pull request #81 from volkanceylan/master
Use Char.ToUpperInvariant instead of Char.ToUpper
2016-12-18 22:20:20 +01:00
volkan.ceylan
013ec0bf80 Due to use of Char.ToUpper, ListExtraItemParser fails in cultures like Turkish where uppercase of 'i' is 'İ'. Char.ToUpperInvariant should be used instead. 2016-12-18 11:47:25 +03:00
Alexandre Mutel
f82e874cb7 Merge pull request #80 from christophano/feature/pipeline_builder_use_method
Adds fluent extension registration method to MarkdownPipelineBuilder.
2016-12-15 11:49:32 +01:00
Chris Rodgers
976fc569fa Moves new Use method to MarkdownExtensions and changes it to extension method. 2016-12-15 10:31:02 +00:00
Chris Rodgers
5aab21f0bf Adds fluent extension registration method to MarkdownPipelineBuilder. 2016-12-15 10:07:54 +00:00
Alexandre Mutel
1df8344576 Bump to 0.10.4 2016-12-12 11:03:48 +01:00
Alexandre Mutel
9eb84cf95e Normalize pipe tables so they contain the same number of columns for all rows 2016-12-11 19:01:49 +01:00
Alexandre Mutel
47d45b5577 Fix issue when parsing autolinks embraced by a pending emphasis (issue #78) 2016-12-11 18:08:51 +01:00
59 changed files with 1634 additions and 351 deletions

41
appveyor.yml Normal file
View File

@@ -0,0 +1,41 @@
version: 10.0.{build}
image: Visual Studio 2017
configuration: Release
install:
- ps: >-
cd src
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]') {
$env:appveyor_nuget_push = 'true'
$env:MARKDIG_VERSION_SUFFIX = ""
}
if($env:appveyor_repo_tag_name -eq 'latest') {
$env:appveyor_nuget_push = 'true'
$env:MARKDIG_VERSION_SUFFIX = "pre$env:MARKDIG_BUILD_NUMBER"
}
}
}
build:
project: src/Markdig.sln
verbosity: minimal
before_package:
- cmd: msbuild /t:pack /p:VersionSuffix="%MARKDIG_VERSION_SUFFIX%" /p:Configuration=Release Markdig/Markdig.csproj
artifacts:
- path: src\Markdig\Bin\Release\*.nupkg
name: Markdig Nugets
deploy:
- provider: NuGet
api_key:
secure: 7cthHh+wYWZjhqxaxR6QObRaRnstvFkQOY7MkxIsC5kpQEBlKZXuinf0IybbYxJt
on:
appveyor_nuget_push: true

View File

@@ -21,42 +21,44 @@ You can **try Markdig online** and compare it to other implementations on [babel
- Even the core Markdown/CommonMark parsing is pluggable, so it allows to disable builtin Markdown/Commonmark parsing (e.g [Disable HTML parsing](https://github.com/lunet-io/markdig/blob/7964bd0160d4c18e4155127a4c863d61ebd8944a/src/Markdig/MarkdownExtensions.cs#L306)) or change behaviour (e.g change matching `#` of a headers with `@`)
- Built-in with **20+ extensions**, including:
- 2 kind of tables:
- **Pipe tables** (inspired from Github tables and [PanDoc - Pipe Tables](http://pandoc.org/README.html#extension-pipe_tables))
- **Grid tables** (inspired from [Pandoc - Grid Tables](http://pandoc.org/README.html#extension-grid_tables))
- **Extra emphasis** (inspired from [Pandoc - Emphasis](http://pandoc.org/README.html#strikeout) and [Markdown-it](https://markdown-it.github.io/))
- [**Pipe tables**](src/Markdig.Tests/Specs/PipeTableSpecs.md) (inspired from Github tables and [PanDoc - Pipe Tables](http://pandoc.org/README.html#extension-pipe_tables))
- [**Grid tables**](src/Markdig.Tests/Specs/GridTableSpecs.md) (inspired from [Pandoc - Grid Tables](http://pandoc.org/README.html#extension-grid_tables))
- [**Extra emphasis**](src/Markdig.Tests/Specs/EmphasisExtraSpecs.md) (inspired from [Pandoc - Emphasis](http://pandoc.org/README.html#strikeout) and [Markdown-it](https://markdown-it.github.io/))
- strike through `~~`,
- Subscript `~`
- Superscript `^`
- Inserted `++`
- Marked `==`
- **Special attributes** or attached HTML attributes (inspired from [PHP Markdown Extra - Special Attributes](https://michelf.ca/projects/php-markdown/extra/#spe-attr))
- **Definition lists** (inspired from [PHP Markdown Extra - Definitions Lists](https://michelf.ca/projects/php-markdown/extra/#def-list))
- **Footnotes** (inspired from [PHP Markdown Extra - Footnotes](https://michelf.ca/projects/php-markdown/extra/#footnotes))
- **Auto-identifiers** for headings (similar to [Pandoc - Auto Identifiers](http://pandoc.org/README.html#extension-auto_identifiers))
- **Auto-links** generates links if a text starts with `http://` or `https://` or `ftp://` or `mailto:` or `www.xxx.yyy`
- **Task Lists** inspired from [Github Task lists](https://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments).
- **Extra bullet lists**, supporting alpha bullet `a.` `b.` and roman bullet (`i`, `ii`...etc.)
- **Media support** for media url (youtube, vimeo, mp4...etc.) (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/embedded-audio-and-video/441))
- **Abbreviations** (inspired from [PHP Markdown Extra - Abbreviations](https://michelf.ca/projects/php-markdown/extra/#abbr))
- **Citation** text by enclosing `""...""` (inspired by this [CommonMark discussion ](https://talk.commonmark.org/t/referencing-creative-works-with-cite/892))
- **Custom containers** similar to fenced code block `:::` for generating a proper `<div>...</div>` instead (inspired by this [CommonMark discussion ](https://talk.commonmark.org/t/custom-container-for-block-and-inline/2051))
- **Figures** (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/image-tag-should-expand-to-figure-when-used-with-title/265/5))
- **Footers** (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/syntax-for-footer/2070))
- **Mathematics**/Latex extension by enclosing `$$` for block and `$` for inline math (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/mathematics-extension/457/31))
- **Soft lines as hard lines**
- **Emoji** support (inspired from [Markdown-it](https://markdown-it.github.io/))
- **SmartyPants** (inspired from [Daring Fireball - SmartyPants](https://daringfireball.net/projects/smartypants/))
- **Bootstrap** class (to output bootstrap class)
- **Diagrams** extension whenever a fenced code block contains a special keyword, it will be converted to a div block with the content as-is (currently, supports only for [`mermaid` diagrams](https://knsv.github.io/mermaid/))
- **YAML frontmatter** to parse without evaluating the frontmatter and to discard it from the HTML output (typically used for previewing without the frontmatter in MarkdownEditor)
- [**Special attributes**](src/Markdig.Tests/Specs/GenericAttributesSpecs.md) or attached HTML attributes (inspired from [PHP Markdown Extra - Special Attributes](https://michelf.ca/projects/php-markdown/extra/#spe-attr))
- [**Definition lists**](src/Markdig.Tests/Specs/DefinitionListSpecs.md) (inspired from [PHP Markdown Extra - Definitions Lists](https://michelf.ca/projects/php-markdown/extra/#def-list))
- [**Footnotes**](src/Markdig.Tests/Specs/FootnotesSpecs.md) (inspired from [PHP Markdown Extra - Footnotes](https://michelf.ca/projects/php-markdown/extra/#footnotes))
- [**Auto-identifiers**](src/Markdig.Tests/Specs/AutoIdentifierSpecs.md) for headings (similar to [Pandoc - Auto Identifiers](http://pandoc.org/README.html#extension-auto_identifiers))
- [**Auto-links**](src/Markdig.Tests/Specs/AutoLinks.md) generates links if a text starts with `http://` or `https://` or `ftp://` or `mailto:` or `www.xxx.yyy`
- [**Task Lists**](src/Markdig.Tests/Specs/TaskListSpecs.md) inspired from [Github Task lists](https://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments).
- [**Extra bullet lists**](src/Markdig.Tests/Specs/ListExtraSpecs.md), supporting alpha bullet `a.` `b.` and roman bullet (`i`, `ii`...etc.)
- [**Media support**](src/Markdig.Tests/Specs/MediaSpecs.md) for media url (youtube, vimeo, mp4...etc.) (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/embedded-audio-and-video/441))
- [**Abbreviations**](src/Markdig.Tests/Specs/AbbreviationSpecs.md) (inspired from [PHP Markdown Extra - Abbreviations](https://michelf.ca/projects/php-markdown/extra/#abbr))
- [**Citation**](src/Markdig.Tests/Specs/FigureFooterAndCiteSpecs.md) text by enclosing `""...""` (inspired by this [CommonMark discussion ](https://talk.commonmark.org/t/referencing-creative-works-with-cite/892))
- [**Custom containers**](src/Markdig.Tests/Specs/CustomContainerSpecs.md) similar to fenced code block `:::` for generating a proper `<div>...</div>` instead (inspired by this [CommonMark discussion ](https://talk.commonmark.org/t/custom-container-for-block-and-inline/2051))
- [**Figures**](src/Markdig.Tests/Specs/FigureFooterAndCiteSpecs.md) (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/image-tag-should-expand-to-figure-when-used-with-title/265/5))
- [**Footers**](src/Markdig.Tests/Specs/FigureFooterAndCiteSpecs.md) (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/syntax-for-footer/2070))
- [**Mathematics**](src/Markdig.Tests/Specs/MathSpecs.md)/Latex extension by enclosing `$$` for block and `$` for inline math (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/mathematics-extension/457/31))
- [**Soft lines as hard lines**](src/Markdig.Tests/Specs/HardlineBreakSpecs.md)
- [**Emoji**](src/Markdig.Tests/Specs/EmojiSpecs.md) support (inspired from [Markdown-it](https://markdown-it.github.io/))
- [**SmartyPants**](src/Markdig.Tests/Specs/SmartyPantsSpecs.md) (inspired from [Daring Fireball - SmartyPants](https://daringfireball.net/projects/smartypants/))
- [**Bootstrap**](src/Markdig.Tests/Specs/BootstrapSpecs.md) class (to output bootstrap class)
- [**Diagrams**](src/Markdig.Tests/Specs/DiagramsSpecs.md) extension whenever a fenced code block contains a special keyword, it will be converted to a div block with the content as-is (currently, supports only for [`mermaid` diagrams](https://knsv.github.io/mermaid/))
- [**YAML frontmatter**](src/Markdig.Tests/Specs/YamlSpecs.md) to parse without evaluating the frontmatter and to discard it from the HTML output (typically used for previewing without the frontmatter in MarkdownEditor)
- [**JIRA links**](src/Markdig.Tests/Specs/JiraLinks.md) to automatically generate links for JIRA project references (Thanks to @clarkd: https://github.com/clarkd/MarkdigJiraLinker)
- Compatible with .NET 3.5, 4.0+ and .NET Core (`netstandard1.1+`)
## Documentation
> The repository is under construction. There will be a dedicated website and proper documentation at some point!
In the meantime, you can have a "behind the scene" article about Markdig in my blog post ["Implementing a Markdown Engine for .NET"](http://xoofx.com/blog/2016/06/13/implementing-a-markdown-processor-for-dotnet/)
While there is not yet a dedicated documentation, you can find from the [specs documentation](src/Markdig.Tests/Specs/readme.md) how to use these extensions.
In the meantime, you can have a "behind the scene" article about Markdig in my blog post ["Implementing a Markdown Engine for .NET"](http://xoofx.com/blog/2016/06/13/implementing-a-markdown-processor-for-dotnet/)
## Download
@@ -73,7 +75,7 @@ var result = Markdown.ToHtml("This is a text with some *emphasis*");
Console.WriteLine(result); // prints: <p>This is a text with some <em>emphasis</em></p>
```
In order to activate most of all advanced extensions (except Emoji, SoftLine as HarLine and SmartyPants)
In order to activate most of all advanced extensions (except Emoji, SoftLine as HardLine, JiraLinks and SmartyPants)
```csharp
// Configure the pipeline with all advanced extensions active
@@ -192,6 +194,7 @@ Thanks also to the project [BenchmarkDotNet](https://github.com/PerfDotNet/Bench
Some decoding part (e.g HTML [EntityHelper.cs](https://github.com/lunet-io/markdig/blob/master/src/Markdig/Helpers/EntityHelper.cs)) have been re-used from [CommonMark.NET](https://github.com/Knagis/CommonMark.NET)
Thanks to the work done by @clarkd on the JIRA Link extension (https://github.com/clarkd/MarkdigJiraLinker), now included with this project!
## Author
Alexandre MUTEL aka [xoofx](http://xoofx.com)

View File

@@ -9,7 +9,7 @@
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Markdig.Benchmarks</RootNamespace>
<AssemblyName>Markdig.Benchmarks</AssemblyName>
<TargetFrameworkVersion>v4.5.1</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(NuGetPackageRoot)' == ''">
<NuGetPackageRoot>$(UserProfile)\.nuget\packages\</NuGetPackageRoot>
</PropertyGroup>
<ImportGroup>
<Import Project="$(NuGetPackageRoot)\Microsoft.Diagnostics.Tracing.TraceEvent\1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets" Condition="Exists('$(NuGetPackageRoot)\Microsoft.Diagnostics.Tracing.TraceEvent\1.0.41\build\Microsoft.Diagnostics.Tracing.TraceEvent.targets')" />
</ImportGroup>
</Project>

View File

@@ -131,7 +131,7 @@ namespace Testamina.Markdig.Benchmarks
var config = ManualConfig.Create(DefaultConfig.Instance);
//var gcDiagnoser = new MemoryDiagnoser();
//config.Add(new Job { Mode = Mode.SingleRun, LaunchCount = 2, WarmupCount = 2, IterationTime = 1024, TargetCount = 10 });
config.Add(new Job { Mode = Mode.Throughput, LaunchCount = 2, WarmupCount = 2, TargetCount = 10 });
//config.Add(new Job { Mode = Mode.Throughput, LaunchCount = 2, WarmupCount = 2, TargetCount = 10 });
//config.Add(gcDiagnoser);
//var config = DefaultConfig.Instance;

View File

@@ -1,3 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1"/></startup></configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/></startup></configuration>

View File

@@ -4,7 +4,7 @@
"win-x64": {}
},
"frameworks": {
"net451": {
"net46": {
"compilationOptions": {
"define": [
"CLASSIC"
@@ -19,9 +19,9 @@
}
},
"dependencies": {
"BenchmarkDotNet": "0.9.6",
"BenchmarkDotNet.Diagnostics.Windows": "0.9.6",
"CommonMark.NET": "0.11.0",
"BenchmarkDotNet": "0.10.6",
"BenchmarkDotNet.Diagnostics.Windows": "0.10.6",
"CommonMark.NET": "0.15.1",
"MarkdownSharp": "1.13.0.0",
"Microsoft.Diagnostics.Runtime": "0.8.31-beta",
"Microsoft.Diagnostics.Tracing.TraceEvent": "1.0.41.0"

View File

@@ -39,10 +39,6 @@
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="Markdig">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\Markdig\Bin\$(Configuration)\net40\Markdig.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
@@ -65,6 +61,7 @@
<Compile Include="TestHtmlHelper.cs" />
<Compile Include="TestLineReader.cs" />
<Compile Include="TestLinkHelper.cs" />
<Compile Include="TestOrderedList.cs" />
<Compile Include="TestPragmaLines.cs" />
<Compile Include="TestSourcePosition.cs" />
<Compile Include="TestStringSliceList.cs" />
@@ -75,6 +72,7 @@
<ItemGroup>
<None Include="App.config" />
<None Include="project.json" />
<None Include="Specs\JiraLinks.md" />
<None Include="Specs\AutoLinks.md" />
<None Include="Specs\AutoIdentifierSpecs.md" />
<None Include="Specs\AbbreviationSpecs.md" />
@@ -90,6 +88,7 @@
<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" />
@@ -108,6 +107,12 @@
<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.

View File

@@ -67,3 +67,13 @@ We should not abbreviate 1.1A or 11A!
.
<p>We should not abbreviate 1.1A or 11A!</p>
````````````````````````````````
Abbreviations should match whole word only, even if the word is the entire content:
```````````````````````````````` example
*[1A]: First
1.1A
.
<p>1.1A</p>
````````````````````````````````

View File

@@ -68,3 +68,11 @@ This is an HTML [http://www.google.com](http://www.google.com) link
.
<p>This is an HTML <a href="http://www.google.com">http://www.google.com</a> link</p>
````````````````````````````````
A link embraced by pending emphasis should let the emphasis takes precedence if characters are placed at the end of the matched link:
```````````````````````````````` example
Check **http://www.a.com** or __http://www.b.com__
.
<p>Check <strong><a href="http://www.a.com">http://www.a.com</a></strong> or <strong><a href="http://www.b.com">http://www.b.com</a></strong></p>
````````````````````````````````

View File

@@ -12,10 +12,28 @@ This is a test with a :) and a :angry: smiley
<p>This is a test with a 😃 and a 😠 smiley</p>
````````````````````````````````
An emoji needs to be preceded by a space and followed by a space:
An emoji needs to be preceded by a space:
```````````````````````````````` example
These are not:) an :)emoji with a:) x:angry:x
These are not:) an emoji with a:) x:angry:x
.
<p>These are not:) an :)emoji with a:) x:angry:x</p>
<p>These are not:) an emoji with a:) x:angry:x</p>
````````````````````````````````
Emoji can be followed by close ponctuation (or any other characters):
```````````````````````````````` example
We all need :), it makes us :muscle:. (and :ok_hand:).
.
<p>We all need 😃, it makes us 💪. (and 👌).</p>
````````````````````````````````
Sentences can end with Emoji:
```````````````````````````````` example
This is a sentance :ok_hand:
and keeps going to the next line :)
.
<p>This is a sentance 👌
and keeps going to the next line 😃</p>
````````````````````````````````

View File

@@ -52,3 +52,16 @@ Marked text can be used to specify that a text has been marked in a document. T
.
<p><mark>Marked text</mark></p>
````````````````````````````````
## Emphasis on Html Entities
```````````````````````````````` example
This is text MyBrand ^&reg;^ and MyTrademark ^&trade;^
This is text MyBrand^&reg;^ and MyTrademark^&trade;^
This is text MyBrand~&reg;~ and MyCopyright^&copy;^
.
<p>This is text MyBrand <sup>®</sup> and MyTrademark <sup>TM</sup>
This is text MyBrand<sup>®</sup> and MyTrademark<sup>TM</sup>
This is text MyBrand<sub>®</sub> and MyCopyright<sup>©</sup></p>
````````````````````````````````

View File

@@ -27,13 +27,13 @@ The following shows that attributes is attached to the current block or the prev
This is a heading{#heading-link2}
-----------------
This is a paragraph with an attached attributes {#myparagraph attached-bool-property}
This is a paragraph with an attached attributes {#myparagraph attached-bool-property attached-bool-property2}
.
<h1 id="heading-link">This is a heading with an an attribute</h1>
<h1 id="heading-link2">This is a heading</h1>
<p><a href="http://google.com" id="a-link" class="myclass" data-lang="fr" data-value="This is a value">This is a link</a></p>
<h2 id="heading-link2">This is a heading</h2>
<p id="myparagraph" attached-bool-property>This is a paragraph with an attached attributes </p>
<p id="myparagraph" attached-bool-property attached-bool-property2>This is a paragraph with an attached attributes </p>
````````````````````````````````
The following shows that attributes can be attached to the next block if they are used inside a single line just preceding the block (and preceded by a blank line or beginning of a block container):

View File

@@ -0,0 +1,77 @@
## Jira Links
The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g.
```
var pipeline = new MarkdownPipelineBuilder()
.UseJiraLinks(new JiraLinkOptions("http://your.company.abc"))
.Build();
```
The rules for detecting a link are:
- The project key must be composed of onre or more capitalised ASCII letter `[A-Z]+`
- A single hypen `-` must separate the project key and issue number.
- The issue number is composed of 1 or more digits `[0, 9]+`
- The reference must be preceeded by either `(` or whitespace or EOF.
- The reference must be followed by either `)` or whitespace or EOF.
The following are valid examples:
```````````````````````````````` example
This is a ABCD-123 issue
.
<p>This is a <a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</a> issue</p>
````````````````````````````````
```````````````````````````````` example
This is a KIRA-1 issue
.
<p>This is a <a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a> issue</p>
````````````````````````````````
```````````````````````````````` example
This is a Z-1 issue
.
<p>This is a <a href="http://your.company.abc/browse/Z-1" target="blank">Z-1</a> issue</p>
````````````````````````````````
These are also valid links with `(` and `)`:
```````````````````````````````` example
This is a (ABCD-123) issue
.
<p>This is a (<a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</a>) issue</p>
````````````````````````````````
```````````````````````````````` example
This is a (KIRA-1) issue
.
<p>This is a (<a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a>) issue</p>
````````````````````````````````
```````````````````````````````` example
This is a (Z-1) issue
.
<p>This is a (<a href="http://your.company.abc/browse/Z-1" target="blank">Z-1</a>) issue</p>
````````````````````````````````
These are not valid links:
```````````````````````````````` example
This is not aJIRA-123 issue
.
<p>This is not aJIRA-123 issue</p>
````````````````````````````````
```````````````````````````````` example
This is not JIRA-123a issue
.
<p>This is not JIRA-123a issue</p>
````````````````````````````````
```````````````````````````````` example
This is not JIRA- issue
.
<p>This is not JIRA- issue</p>
````````````````````````````````

View File

@@ -20,12 +20,47 @@ This is a $$math block$$
<p>This is a <span class="math">math block</span></p>
````````````````````````````````
The opening `$` and closing `$` is following the rules of the emphasis delimiter `_`:
Newlines inside an inline math are not allowed:
```````````````````````````````` example
This is not a $ math block $
This is not a $$math
block$$ and? this is a $$math block$$
.
<p>This is not a $ math block $</p>
<p>This is not a $$math
block$$ and? this is a <span class="math">math block</span></p>
````````````````````````````````
```````````````````````````````` example
This is not a $math
block$ and? this is a $math block$
.
<p>This is not a $math
block$ and? this is a <span class="math">math block</span></p>
````````````````````````````````
An opening `$` can be followed by a space if the closing is also preceded by a space `$`:
```````````````````````````````` example
This is a $ math block $
.
<p>This is a <span class="math">math block</span></p>
````````````````````````````````
```````````````````````````````` example
This is a $ math block $ after
.
<p>This is a <span class="math">math block</span> after</p>
````````````````````````````````
```````````````````````````````` example
This is a $$ math block $$ after
.
<p>This is a <span class="math">math block</span> after</p>
````````````````````````````````
```````````````````````````````` example
This is a not $ math block$ because there is not a whitespace before the closing
.
<p>This is a not $ math block$ because there is not a whitespace before the closing</p>
````````````````````````````````
For the opening `$` it requires a space or a punctuation before (but cannot be used within a word):
@@ -82,6 +117,13 @@ This is *a $math* block$
.
<p>This is *a <span class="math">math* block</span></p>
````````````````````````````````
An opening $$ at the beginning of a line should not be interpreted as a Math block:
```````````````````````````````` example
$$ math $$ starting at a line
.
<p><span class="math">math</span> starting at a line</p>
````````````````````````````````
## Math Block

View File

@@ -10,7 +10,10 @@ Allows to embed audio/video links to popular website:
![Video1](https://www.youtube.com/watch?v=mswPy5bt3TQ)
![Video2](https://vimeo.com/8607834)
![Video3](https://sample.com/video.mp4)
.
<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>
````````````````````````````````

View File

@@ -136,6 +136,7 @@ a | b
<tr>
<th>a</th>
<th>b</th>
<th></th>
</tr>
</thead>
<tbody>
@@ -147,9 +148,12 @@ a | b
<tr>
<td>3</td>
<td>4</td>
<td></td>
</tr>
<tr>
<td>5</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
@@ -548,3 +552,31 @@ Tests trailing spaces after pipes
</tbody>
</table>
````````````````````````````````
** Normalized columns count **
The tables are normalized to the maximum number of columns found in a table
```````````````````````````````` example
a | b
-- | -
0 | 1 | 2
.
<table>
<thead>
<tr>
<th>a</th>
<th>b</th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>1</td>
<td>2</td>
</tr>
</tbody>
</table>
````````````````````````````````

View File

@@ -16633,6 +16633,7 @@ namespace Markdig.Tests
// <tr>
// <th>a</th>
// <th>b</th>
// <th></th>
// </tr>
// </thead>
// <tbody>
@@ -16644,15 +16645,18 @@ namespace Markdig.Tests
// <tr>
// <td>3</td>
// <td>4</td>
// <td></td>
// </tr>
// <tr>
// <td>5</td>
// <td></td>
// <td></td>
// </tr>
// </tbody>
// </table>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 7, "Extensions Pipe Table");
TestParser.TestSpec("a | b \n-- | --\n0 | 1 | 2\n3 | 4\n5 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n<td>2</td>\n</tr>\n<tr>\n<td>3</td>\n<td>4</td>\n</tr>\n<tr>\n<td>5</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
TestParser.TestSpec("a | b \n-- | --\n0 | 1 | 2\n3 | 4\n5 |", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n<td>2</td>\n</tr>\n<tr>\n<td>3</td>\n<td>4</td>\n<td></td>\n</tr>\n<tr>\n<td>5</td>\n<td></td>\n<td></td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
}
}
// **Rule #2**
@@ -17227,6 +17231,45 @@ namespace Markdig.Tests
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 22, "Extensions Pipe Table");
TestParser.TestSpec("| abc | def | \n|---|---|\n| cde| ddd| \n| eee| fff|\n| fff | fffff | \n|gggg | ffff | ", "<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>cde</td>\n<td>ddd</td>\n</tr>\n<tr>\n<td>eee</td>\n<td>fff</td>\n</tr>\n<tr>\n<td>fff</td>\n<td>fffff</td>\n</tr>\n<tr>\n<td>gggg</td>\n<td>ffff</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
}
}
// ** Normalized columns count **
//
// The tables are normalized to the maximum number of columns found in a table
[TestFixture]
public partial class TestExtensionsPipeTable
{
[Test]
public void Example023()
{
// Example 23
// Section: Extensions Pipe Table
//
// The following CommonMark:
// a | b
// -- | -
// 0 | 1 | 2
//
// Should be rendered as:
// <table>
// <thead>
// <tr>
// <th>a</th>
// <th>b</th>
// <th></th>
// </tr>
// </thead>
// <tbody>
// <tr>
// <td>0</td>
// <td>1</td>
// <td>2</td>
// </tr>
// </tbody>
// </table>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 23, "Extensions Pipe Table");
TestParser.TestSpec("a | b\n-- | - \n0 | 1 | 2", "<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>0</td>\n<td>1</td>\n<td>2</td>\n</tr>\n</tbody>\n</table>", "pipetables|advanced");
}
}
// # Extensions
//
@@ -17422,17 +17465,17 @@ namespace Markdig.Tests
// This is a heading{#heading-link2}
// -----------------
//
// This is a paragraph with an attached attributes {#myparagraph attached-bool-property}
// This is a paragraph with an attached attributes {#myparagraph attached-bool-property attached-bool-property2}
//
// Should be rendered as:
// <h1 id="heading-link">This is a heading with an an attribute</h1>
// <h1 id="heading-link2">This is a heading</h1>
// <p><a href="http://google.com" id="a-link" class="myclass" data-lang="fr" data-value="This is a value">This is a link</a></p>
// <h2 id="heading-link2">This is a heading</h2>
// <p id="myparagraph" attached-bool-property>This is a paragraph with an attached attributes </p>
// <p id="myparagraph" attached-bool-property attached-bool-property2>This is a paragraph with an attached attributes </p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 1, "Extensions Generic Attributes");
TestParser.TestSpec("# This is a heading with an an attribute{#heading-link}\n\n# This is a heading # {#heading-link2}\n\n[This is a link](http://google.com){#a-link .myclass data-lang=fr data-value=\"This is a value\"}\n\nThis is a heading{#heading-link2}\n-----------------\n\nThis is a paragraph with an attached attributes {#myparagraph attached-bool-property}", "<h1 id=\"heading-link\">This is a heading with an an attribute</h1>\n<h1 id=\"heading-link2\">This is a heading</h1>\n<p><a href=\"http://google.com\" id=\"a-link\" class=\"myclass\" data-lang=\"fr\" data-value=\"This is a value\">This is a link</a></p>\n<h2 id=\"heading-link2\">This is a heading</h2>\n<p id=\"myparagraph\" attached-bool-property>This is a paragraph with an attached attributes </p>", "attributes|advanced");
TestParser.TestSpec("# This is a heading with an an attribute{#heading-link}\n\n# This is a heading # {#heading-link2}\n\n[This is a link](http://google.com){#a-link .myclass data-lang=fr data-value=\"This is a value\"}\n\nThis is a heading{#heading-link2}\n-----------------\n\nThis is a paragraph with an attached attributes {#myparagraph attached-bool-property attached-bool-property2}", "<h1 id=\"heading-link\">This is a heading with an an attribute</h1>\n<h1 id=\"heading-link2\">This is a heading</h1>\n<p><a href=\"http://google.com\" id=\"a-link\" class=\"myclass\" data-lang=\"fr\" data-value=\"This is a value\">This is a link</a></p>\n<h2 id=\"heading-link2\">This is a heading</h2>\n<p id=\"myparagraph\" attached-bool-property attached-bool-property2>This is a paragraph with an attached attributes </p>", "attributes|advanced");
}
}
// The following shows that attributes can be attached to the next block if they are used inside a single line just preceding the block (and preceded by a blank line or beginning of a block container):
@@ -17573,6 +17616,30 @@ namespace Markdig.Tests
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 5, "Extensions Marked");
TestParser.TestSpec("==Marked text==", "<p><mark>Marked text</mark></p>", "emphasisextras|advanced");
}
}
// ## Emphasis on Html Entities
[TestFixture]
public partial class TestExtensionsEmphasisonHtmlEntities
{
[Test]
public void Example006()
{
// Example 6
// Section: Extensions Emphasis on Html Entities
//
// The following CommonMark:
// This is text MyBrand ^&reg;^ and MyTrademark ^&trade;^
// This is text MyBrand^&reg;^ and MyTrademark^&trade;^
// This is text MyBrand~&reg;~ and MyCopyright^&copy;^
//
// Should be rendered as:
// <p>This is text MyBrand <sup>®</sup> and MyTrademark <sup>TM</sup>
// This is text MyBrand<sup>®</sup> and MyTrademark<sup>TM</sup>
// This is text MyBrand<sub>®</sub> and MyCopyright<sup>©</sup></p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 6, "Extensions Emphasis on Html Entities");
TestParser.TestSpec("This is text MyBrand ^&reg;^ and MyTrademark ^&trade;^\nThis is text MyBrand^&reg;^ and MyTrademark^&trade;^\nThis is text MyBrand~&reg;~ and MyCopyright^&copy;^", "<p>This is text MyBrand <sup>®</sup> and MyTrademark <sup>TM</sup>\nThis is text MyBrand<sup>®</sup> and MyTrademark<sup>TM</sup>\nThis is text MyBrand<sub>®</sub> and MyCopyright<sup>©</sup></p>", "emphasisextras|advanced");
}
}
// # Extensions
//
@@ -18467,7 +18534,7 @@ namespace Markdig.Tests
TestParser.TestSpec("This is a test with a :) and a :angry: smiley", "<p>This is a test with a 😃 and a 😠 smiley</p>", "emojis|advanced+emojis");
}
}
// An emoji needs to be preceded by a space and followed by a space:
// An emoji needs to be preceded by a space:
[TestFixture]
public partial class TestExtensionsEmoji
{
@@ -18478,13 +18545,55 @@ namespace Markdig.Tests
// Section: Extensions Emoji
//
// The following CommonMark:
// These are not:) an :)emoji with a:) x:angry:x
// These are not:) an emoji with a:) x:angry:x
//
// Should be rendered as:
// <p>These are not:) an :)emoji with a:) x:angry:x</p>
// <p>These are not:) an emoji with a:) x:angry:x</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 2, "Extensions 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");
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):
[TestFixture]
public partial class TestExtensionsEmoji
{
[Test]
public void Example003()
{
// Example 3
// Section: Extensions Emoji
//
// The following CommonMark:
// We all need :), it makes us :muscle:. (and :ok_hand:).
//
// Should be rendered as:
// <p>We all need 😃, it makes us 💪. (and 👌).</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 3, "Extensions Emoji");
TestParser.TestSpec("We all need :), it makes us :muscle:. (and :ok_hand:).", "<p>We all need 😃, it makes us 💪. (and 👌).</p>", "emojis|advanced+emojis");
}
}
// Sentences can end with Emoji:
[TestFixture]
public partial class TestExtensionsEmoji
{
[Test]
public void Example004()
{
// Example 4
// Section: Extensions Emoji
//
// The following CommonMark:
// This is a sentance :ok_hand:
// and keeps going to the next line :)
//
// Should be rendered as:
// <p>This is a sentance 👌
// and keeps going to the next line 😃</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 4, "Extensions Emoji");
TestParser.TestSpec("This is a sentance :ok_hand:\nand keeps going to the next line :)", "<p>This is a sentance 👌\nand keeps going to the next line 😃</p>", "emojis|advanced+emojis");
}
}
// # Extensions
@@ -18628,6 +18737,28 @@ namespace Markdig.Tests
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 6, "Extensions Abbreviation");
TestParser.TestSpec("*[1A]: First\n\nWe should not abbreviate 1.1A or 11A!", "<p>We should not abbreviate 1.1A or 11A!</p>", "abbreviations|advanced");
}
}
// Abbreviations should match whole word only, even if the word is the entire content:
[TestFixture]
public partial class TestExtensionsAbbreviation
{
[Test]
public void Example007()
{
// Example 7
// Section: Extensions Abbreviation
//
// The following CommonMark:
// *[1A]: First
//
// 1.1A
//
// Should be rendered as:
// <p>1.1A</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 7, "Extensions Abbreviation");
TestParser.TestSpec("*[1A]: First\n\n1.1A", "<p>1.1A</p>", "abbreviations|advanced");
}
}
// # Extensions
//
@@ -18974,7 +19105,7 @@ namespace Markdig.Tests
TestParser.TestSpec("This is a $$math block$$", "<p>This is a <span class=\"math\">math block</span></p>", "mathematics|advanced");
}
}
// The opening `$` and closing `$` is following the rules of the emphasis delimiter `_`:
// Newlines inside an inline math are not allowed:
[TestFixture]
public partial class TestExtensionsMathInline
{
@@ -18985,16 +19116,17 @@ namespace Markdig.Tests
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is not a $ math block $
// This is not a $$math
// block$$ and? this is a $$math block$$
//
// Should be rendered as:
// <p>This is not a $ math block $</p>
// <p>This is not a $$math
// block$$ and? this is a <span class="math">math block</span></p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 3, "Extensions Math Inline");
TestParser.TestSpec("This is not a $ math block $", "<p>This is not a $ math block $</p>", "mathematics|advanced");
TestParser.TestSpec("This is not a $$math \nblock$$ and? this is a $$math block$$", "<p>This is not a $$math\nblock$$ and? this is a <span class=\"math\">math block</span></p>", "mathematics|advanced");
}
}
// For the opening `$` it requires a space or a punctuation before (but cannot be used within a word):
[TestFixture]
public partial class TestExtensionsMathInline
{
@@ -19005,16 +19137,18 @@ namespace Markdig.Tests
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is not a m$ath block$
// This is not a $math
// block$ and? this is a $math block$
//
// Should be rendered as:
// <p>This is not a m$ath block$</p>
// <p>This is not a $math
// block$ and? this is a <span class="math">math block</span></p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 4, "Extensions Math Inline");
TestParser.TestSpec("This is not a m$ath block$", "<p>This is not a m$ath block$</p>", "mathematics|advanced");
TestParser.TestSpec("This is not a $math \nblock$ and? this is a $math block$", "<p>This is not a $math\nblock$ and? this is a <span class=\"math\">math block</span></p>", "mathematics|advanced");
}
}
// For the closing `$` it requires a space after or a punctuation (but cannot be preceded by a space and cannot be used within a word):
// An opening `$` can be followed by a space if the closing is also preceded by a space `$`:
[TestFixture]
public partial class TestExtensionsMathInline
{
@@ -19025,16 +19159,15 @@ namespace Markdig.Tests
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is not a $math bloc$k
// This is a $ math block $
//
// Should be rendered as:
// <p>This is not a $math bloc$k</p>
// <p>This is a <span class="math">math block</span></p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 5, "Extensions Math Inline");
TestParser.TestSpec("This is not a $math bloc$k", "<p>This is not a $math bloc$k</p>", "mathematics|advanced");
TestParser.TestSpec("This is a $ math block $", "<p>This is a <span class=\"math\">math block</span></p>", "mathematics|advanced");
}
}
// For the closing `$` it requires a space after or a punctuation (but cannot be preceded by a space and cannot be used within a word):
[TestFixture]
public partial class TestExtensionsMathInline
{
@@ -19045,16 +19178,15 @@ namespace Markdig.Tests
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is should not match a 16$ or a $15
// This is a $ math block $ after
//
// Should be rendered as:
// <p>This is should not match a 16$ or a $15</p>
// <p>This is a <span class="math">math block</span> after</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 6, "Extensions Math Inline");
TestParser.TestSpec("This is should not match a 16$ or a $15", "<p>This is should not match a 16$ or a $15</p>", "mathematics|advanced");
TestParser.TestSpec("This is a $ math block $ after", "<p>This is a <span class=\"math\">math block</span> after</p>", "mathematics|advanced");
}
}
// A `$` can be escaped between a math inline block by using the escape `\\`
[TestFixture]
public partial class TestExtensionsMathInline
{
@@ -19065,16 +19197,15 @@ namespace Markdig.Tests
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is a $math \$ block$
// This is a $$ math block $$ after
//
// Should be rendered as:
// <p>This is a <span class="math">math \$ block</span></p>
// <p>This is a <span class="math">math block</span> after</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 7, "Extensions Math Inline");
TestParser.TestSpec("This is a $math \\$ block$", "<p>This is a <span class=\"math\">math \\$ block</span></p>", "mathematics|advanced");
TestParser.TestSpec("This is a $$ math block $$ after", "<p>This is a <span class=\"math\">math block</span> after</p>", "mathematics|advanced");
}
}
// At most, two `$` will be matched for the opening and closing:
[TestFixture]
public partial class TestExtensionsMathInline
{
@@ -19085,16 +19216,16 @@ namespace Markdig.Tests
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is a $$$math block$$$
// This is a not $ math block$ because there is not a whitespace before the closing
//
// Should be rendered as:
// <p>This is a <span class="math">$math block$</span></p>
// <p>This is a not $ math block$ because there is not a whitespace before the closing</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 8, "Extensions Math Inline");
TestParser.TestSpec("This is a $$$math block$$$", "<p>This is a <span class=\"math\">$math block$</span></p>", "mathematics|advanced");
TestParser.TestSpec("This is a not $ math block$ because there is not a whitespace before the closing", "<p>This is a not $ math block$ because there is not a whitespace before the closing</p>", "mathematics|advanced");
}
}
// Regular text can come both before and after the math inline
// For the opening `$` it requires a space or a punctuation before (but cannot be used within a word):
[TestFixture]
public partial class TestExtensionsMathInline
{
@@ -19105,16 +19236,16 @@ namespace Markdig.Tests
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is a $math block$ with text on both sides.
// This is not a m$ath block$
//
// Should be rendered as:
// <p>This is a <span class="math">math block</span> with text on both sides.</p>
// <p>This is not a m$ath block$</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 9, "Extensions Math Inline");
TestParser.TestSpec("This is a $math block$ with text on both sides.", "<p>This is a <span class=\"math\">math block</span> with text on both sides.</p>", "mathematics|advanced");
TestParser.TestSpec("This is not a m$ath block$", "<p>This is not a m$ath block$</p>", "mathematics|advanced");
}
}
// A mathematic block takes precedence over standard emphasis `*` `_`:
// For the closing `$` it requires a space after or a punctuation (but cannot be preceded by a space and cannot be used within a word):
[TestFixture]
public partial class TestExtensionsMathInline
{
@@ -19125,14 +19256,134 @@ namespace Markdig.Tests
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is not a $math bloc$k
//
// Should be rendered as:
// <p>This is not a $math bloc$k</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 10, "Extensions Math Inline");
TestParser.TestSpec("This is not a $math bloc$k", "<p>This is not a $math bloc$k</p>", "mathematics|advanced");
}
}
// For the closing `$` it requires a space after or a punctuation (but cannot be preceded by a space and cannot be used within a word):
[TestFixture]
public partial class TestExtensionsMathInline
{
[Test]
public void Example011()
{
// Example 11
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is should not match a 16$ or a $15
//
// Should be rendered as:
// <p>This is should not match a 16$ or a $15</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 11, "Extensions Math Inline");
TestParser.TestSpec("This is should not match a 16$ or a $15", "<p>This is should not match a 16$ or a $15</p>", "mathematics|advanced");
}
}
// A `$` can be escaped between a math inline block by using the escape `\\`
[TestFixture]
public partial class TestExtensionsMathInline
{
[Test]
public void Example012()
{
// Example 12
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is a $math \$ block$
//
// Should be rendered as:
// <p>This is a <span class="math">math \$ block</span></p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 12, "Extensions Math Inline");
TestParser.TestSpec("This is a $math \\$ block$", "<p>This is a <span class=\"math\">math \\$ block</span></p>", "mathematics|advanced");
}
}
// At most, two `$` will be matched for the opening and closing:
[TestFixture]
public partial class TestExtensionsMathInline
{
[Test]
public void Example013()
{
// Example 13
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is a $$$math block$$$
//
// Should be rendered as:
// <p>This is a <span class="math">$math block$</span></p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 13, "Extensions Math Inline");
TestParser.TestSpec("This is a $$$math block$$$", "<p>This is a <span class=\"math\">$math block$</span></p>", "mathematics|advanced");
}
}
// Regular text can come both before and after the math inline
[TestFixture]
public partial class TestExtensionsMathInline
{
[Test]
public void Example014()
{
// Example 14
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is a $math block$ with text on both sides.
//
// Should be rendered as:
// <p>This is a <span class="math">math block</span> with text on both sides.</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 14, "Extensions Math Inline");
TestParser.TestSpec("This is a $math block$ with text on both sides.", "<p>This is a <span class=\"math\">math block</span> with text on both sides.</p>", "mathematics|advanced");
}
}
// A mathematic block takes precedence over standard emphasis `*` `_`:
[TestFixture]
public partial class TestExtensionsMathInline
{
[Test]
public void Example015()
{
// Example 15
// Section: Extensions Math Inline
//
// The following CommonMark:
// This is *a $math* block$
//
// Should be rendered as:
// <p>This is *a <span class="math">math* block</span></p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 10, "Extensions Math Inline");
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 15, "Extensions Math Inline");
TestParser.TestSpec("This is *a $math* block$", "<p>This is *a <span class=\"math\">math* block</span></p>", "mathematics|advanced");
}
}
// An opening $$ at the beginning of a line should not be interpreted as a Math block:
[TestFixture]
public partial class TestExtensionsMathInline
{
[Test]
public void Example016()
{
// Example 16
// Section: Extensions Math Inline
//
// The following CommonMark:
// $$ math $$ starting at a line
//
// Should be rendered as:
// <p><span class="math">math</span> starting at a line</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 16, "Extensions Math Inline");
TestParser.TestSpec("$$ math $$ starting at a line", "<p><span class=\"math\">math</span> starting at a line</p>", "mathematics|advanced");
}
}
// ## Math Block
//
@@ -19142,9 +19393,9 @@ namespace Markdig.Tests
public partial class TestExtensionsMathBlock
{
[Test]
public void Example011()
public void Example017()
{
// Example 11
// Example 17
// Section: Extensions Math Block
//
// The following CommonMark:
@@ -19162,7 +19413,7 @@ namespace Markdig.Tests
// \end{equation}
// </div>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 11, "Extensions Math Block");
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 17, "Extensions Math Block");
TestParser.TestSpec("$$\n\\begin{equation}\n \\int_0^\\infty \\frac{x^3}{e^x-1}\\,dx = \\frac{\\pi^4}{15}\n \\label{eq:sample}\n\\end{equation}\n$$", "<div class=\"math\">\\begin{equation}\n \\int_0^\\infty \\frac{x^3}{e^x-1}\\,dx = \\frac{\\pi^4}{15}\n \\label{eq:sample}\n\\end{equation}\n</div>", "mathematics|advanced");
}
}
@@ -19294,13 +19545,16 @@ namespace Markdig.Tests
// ![Video1](https://www.youtube.com/watch?v=mswPy5bt3TQ)
//
// ![Video2](https://vimeo.com/8607834)
//
// ![Video3](https://sample.com/video.mp4)
//
// 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>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 1, "Extensions Media links");
TestParser.TestSpec("![Video1](https://www.youtube.com/watch?v=mswPy5bt3TQ)\n\n![Video2](https://vimeo.com/8607834)", "<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>", "medialinks|advanced+medialinks");
TestParser.TestSpec("![Video1](https://www.youtube.com/watch?v=mswPy5bt3TQ)\n\n![Video2](https://vimeo.com/8607834)\n\n![Video3](https://sample.com/video.mp4)", "<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>", "medialinks|advanced+medialinks");
}
}
// # Extensions
@@ -20258,4 +20512,216 @@ namespace Markdig.Tests
TestParser.TestSpec("This is an HTML [http://www.google.com](http://www.google.com) link", "<p>This is an HTML <a href=\"http://www.google.com\">http://www.google.com</a> link</p>", "autolinks|advanced");
}
}
// A link embraced by pending emphasis should let the emphasis takes precedence if characters are placed at the end of the matched link:
[TestFixture]
public partial class TestExtensionsAutoLinks
{
[Test]
public void Example007()
{
// Example 7
// Section: Extensions AutoLinks
//
// The following CommonMark:
// Check **http://www.a.com** or __http://www.b.com__
//
// Should be rendered as:
// <p>Check <strong><a href="http://www.a.com">http://www.a.com</a></strong> or <strong><a href="http://www.b.com">http://www.b.com</a></strong></p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 7, "Extensions AutoLinks");
TestParser.TestSpec("Check **http://www.a.com** or __http://www.b.com__", "<p>Check <strong><a href=\"http://www.a.com\">http://www.a.com</a></strong> or <strong><a href=\"http://www.b.com\">http://www.b.com</a></strong></p>", "autolinks|advanced");
}
}
// ## Jira Links
//
// The JiraLinks extension will automatically add links to JIRA issue items within your markdown, e.g. XX-1234. For this to happen, you must configure the extension when adding to the pipeline, e.g.
//
// ```
// var pipeline = new MarkdownPipelineBuilder()
// .UseJiraLinks(new JiraLinkOptions("http://your.company.abc"))
// .Build();
// ```
//
// The rules for detecting a link are:
//
// - The project key must be composed of onre or more capitalised ASCII letter `[A-Z]+`
// - A single hypen `-` must separate the project key and issue number.
// - The issue number is composed of 1 or more digits `[0, 9]+`
// - The reference must be preceeded by either `(` or whitespace or EOF.
// - The reference must be followed by either `)` or whitespace or EOF.
//
// The following are valid examples:
[TestFixture]
public partial class TestJiraLinks
{
[Test]
public void Example001()
{
// Example 1
// Section: Jira Links
//
// The following CommonMark:
// This is a ABCD-123 issue
//
// Should be rendered as:
// <p>This is a <a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</a> issue</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 1, " Jira Links");
TestParser.TestSpec("This is a ABCD-123 issue", "<p>This is a <a href=\"http://your.company.abc/browse/ABCD-123\" target=\"blank\">ABCD-123</a> issue</p>", "jiralinks");
}
}
[TestFixture]
public partial class TestJiraLinks
{
[Test]
public void Example002()
{
// Example 2
// Section: Jira Links
//
// The following CommonMark:
// This is a KIRA-1 issue
//
// Should be rendered as:
// <p>This is a <a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a> issue</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 2, " Jira Links");
TestParser.TestSpec("This is a KIRA-1 issue", "<p>This is a <a href=\"http://your.company.abc/browse/KIRA-1\" target=\"blank\">KIRA-1</a> issue</p>", "jiralinks");
}
}
[TestFixture]
public partial class TestJiraLinks
{
[Test]
public void Example003()
{
// Example 3
// Section: Jira Links
//
// The following CommonMark:
// This is a Z-1 issue
//
// Should be rendered as:
// <p>This is a <a href="http://your.company.abc/browse/Z-1" target="blank">Z-1</a> issue</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 3, " Jira Links");
TestParser.TestSpec("This is a Z-1 issue", "<p>This is a <a href=\"http://your.company.abc/browse/Z-1\" target=\"blank\">Z-1</a> issue</p>", "jiralinks");
}
}
// These are also valid links with `(` and `)`:
[TestFixture]
public partial class TestJiraLinks
{
[Test]
public void Example004()
{
// Example 4
// Section: Jira Links
//
// The following CommonMark:
// This is a (ABCD-123) issue
//
// Should be rendered as:
// <p>This is a (<a href="http://your.company.abc/browse/ABCD-123" target="blank">ABCD-123</a>) issue</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 4, " Jira Links");
TestParser.TestSpec("This is a (ABCD-123) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/ABCD-123\" target=\"blank\">ABCD-123</a>) issue</p>", "jiralinks");
}
}
[TestFixture]
public partial class TestJiraLinks
{
[Test]
public void Example005()
{
// Example 5
// Section: Jira Links
//
// The following CommonMark:
// This is a (KIRA-1) issue
//
// Should be rendered as:
// <p>This is a (<a href="http://your.company.abc/browse/KIRA-1" target="blank">KIRA-1</a>) issue</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 5, " Jira Links");
TestParser.TestSpec("This is a (KIRA-1) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/KIRA-1\" target=\"blank\">KIRA-1</a>) issue</p>", "jiralinks");
}
}
[TestFixture]
public partial class TestJiraLinks
{
[Test]
public void Example006()
{
// Example 6
// Section: Jira Links
//
// The following CommonMark:
// This is a (Z-1) issue
//
// Should be rendered as:
// <p>This is a (<a href="http://your.company.abc/browse/Z-1" target="blank">Z-1</a>) issue</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 6, " Jira Links");
TestParser.TestSpec("This is a (Z-1) issue", "<p>This is a (<a href=\"http://your.company.abc/browse/Z-1\" target=\"blank\">Z-1</a>) issue</p>", "jiralinks");
}
}
// These are not valid links:
[TestFixture]
public partial class TestJiraLinks
{
[Test]
public void Example007()
{
// Example 7
// Section: Jira Links
//
// The following CommonMark:
// This is not aJIRA-123 issue
//
// Should be rendered as:
// <p>This is not aJIRA-123 issue</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 7, " Jira Links");
TestParser.TestSpec("This is not aJIRA-123 issue", "<p>This is not aJIRA-123 issue</p>", "jiralinks");
}
}
[TestFixture]
public partial class TestJiraLinks
{
[Test]
public void Example008()
{
// Example 8
// Section: Jira Links
//
// The following CommonMark:
// This is not JIRA-123a issue
//
// Should be rendered as:
// <p>This is not JIRA-123a issue</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 8, " Jira Links");
TestParser.TestSpec("This is not JIRA-123a issue", "<p>This is not JIRA-123a issue</p>", "jiralinks");
}
}
[TestFixture]
public partial class TestJiraLinks
{
[Test]
public void Example009()
{
// Example 9
// Section: Jira Links
//
// The following CommonMark:
// This is not JIRA- issue
//
// Should be rendered as:
// <p>This is not JIRA- issue</p>
Console.WriteLine("Example {0}" + Environment.NewLine + "Section: {0}" + Environment.NewLine, 9, " Jira Links");
TestParser.TestSpec("This is not JIRA- issue", "<p>This is not JIRA- issue</p>", "jiralinks");
}
}
}

View File

@@ -61,6 +61,7 @@ SOFTWARE.
new KeyValuePair<string, string>(Host.ResolvePath("NoHtmlSpecs.md"), "nohtml"),
new KeyValuePair<string, string>(Host.ResolvePath("YamlSpecs.md"), "yaml"),
new KeyValuePair<string, string>(Host.ResolvePath("AutoLinks.md"), "autolinks|advanced"),
new KeyValuePair<string, string>(Host.ResolvePath("JiraLinks.md"), "jiralinks"),
};
var emptyLines = false;
var displayEmptyLines = false;

View File

@@ -0,0 +1,36 @@
# Documentation Tests/Specs
You will find from the following links the supported extensions in markdig and their usage:
- 2 kind of tables:
- [**Pipe tables**](PipeTableSpecs.md)
- [**Grid tables**](GridTableSpecs.md)
- [**Extra emphasis**](EmphasisExtraSpecs.md)
- strike through `~~`,
- Subscript `~`
- Superscript `^`
- Inserted `++`
- Marked `==`
- [**Special attributes**](GenericAttributesSpecs.md)
- [**Definition lists**](DefinitionListSpecs.md)
- [**Footnotes**](FootnotesSpecs.md)
- [**Auto-identifiers**](AutoIdentifierSpecs.md)
- [**Auto-links**](AutoLinks.md)
- [**Task Lists**](TaskListSpecs.md)
- [**Extra bullet lists**](ListExtraSpecs.md)
- [**Media support**](MediaSpecs.md)
- [**Abbreviations**](AbbreviationSpecs.md)
- [**Citation**](FigureFooterAndCiteSpecs.md)
- [**Custom containers**](CustomContainerSpecs.md)
- [**Figures**](FigureFooterAndCiteSpecs.md)
- [**Footers**](FigureFooterAndCiteSpecs.md)
- [**Mathematics**](MathSpecs.md)/Latex extension by enclosing `$$` for block and `$` for inline math (inspired from this [CommonMark discussion](https://talk.commonmark.org/t/mathematics-extension/457/31))
- [**Soft lines as hard lines**](HardlineBreakSpecs.md)
- [**Emoji**](EmojiSpecs.md)
- [**SmartyPants**](SmartyPantsSpecs.md)
- [**Bootstrap**](BootstrapSpecs.md)
- [**Diagrams**](DiagramsSpecs.md)
- [**YAML frontmatter**](YamlSpecs.md)
- [**JIRA links**](JiraLinks.md)
> Notice that the links above are not yet the final documentation but are "specification" files used for testing the correctness of markdig for each extension

View File

@@ -1,6 +1,8 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using System.Security;
using NUnit.Framework;
using Markdig.Helpers;
using Markdig.Syntax;
@@ -30,6 +32,18 @@ namespace Markdig.Tests
Assert.AreEqual(')', text.CurrentChar);
}
[Test]
[TestCase("http://google.com.")]
[TestCase("http://google.com. ")]
public void TestUrlTrailingFullStop(string uri)
{
var text = new StringSlice(uri);
string link;
Assert.True(LinkHelper.TryParseUrl(ref text, out link));
Assert.AreEqual("http://google.com", link);
Assert.AreEqual('.', text.CurrentChar);
}
[Test]
public void TestUrlNestedParenthesis()
{

View File

@@ -0,0 +1,43 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using Markdig.Helpers;
using NUnit.Framework;
namespace Markdig.Tests
{
[TestFixture]
public class TestOrderedList
{
[Test]
public void TestReplace()
{
var list = new OrderedList<ITest>
{
new A(),
new B(),
new C(),
};
// Replacing B with D. Order should now be A, D, B.
var result = list.Replace<B>(new D());
Assert.That(result, Is.True);
Assert.That(list.Count, Is.EqualTo(3));
Assert.That(list[0], Is.InstanceOf<A>());
Assert.That(list[1], Is.InstanceOf<D>());
Assert.That(list[2], Is.InstanceOf<C>());
// Replacing B again should fail, as it's no longer in the list.
Assert.That(list.Replace<B>(new D()), Is.False);
}
#region Test fixtures
private interface ITest { }
private class A : ITest { }
private class B : ITest { }
private class C : ITest { }
private class D : ITest { }
#endregion
}
}

View File

@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using Markdig.Extensions.JiraLinks;
namespace Markdig.Tests
{
@@ -71,8 +72,15 @@ namespace Markdig.Tests
{
var builder = new MarkdownPipelineBuilder();
builder.DebugLog = Console.Out;
var pipeline = extensionsText == "self" ? builder.UseSelfPipeline() : builder.Configure(extensionsText);
yield return new KeyValuePair<string, MarkdownPipeline>(extensionsText, pipeline.Build());
if (extensionsText == "jiralinks")
{
builder.UseJiraLinks(new JiraLinkOptions("http://your.company.abc"));
}
else
{
builder = extensionsText == "self" ? builder.UseSelfPipeline() : builder.Configure(extensionsText);
}
yield return new KeyValuePair<string, MarkdownPipeline>(extensionsText, builder.Build());
}
}

View File

@@ -126,6 +126,14 @@ Paragraph
", "<p><code>https://{domain}/callbacks</code></p>\n<h4 id=\"heading\">HEADING</h4>\n<p>Paragraph</p>", "advanced");
}
[Test]
public void TestBugEmphAttribute()
{
// https://github.com/lunet-io/markdig/issues/108
TestParser.TestSpec(@"*test*{name=value}", "<p><em name=\"value\">test</em></p>", "advanced");
}
[Test]
public void TestBugPipeTables()
{
@@ -149,6 +157,37 @@ Paragraph
</table>", "advanced");
}
[Test]
public void TestGridTableWithCustomAttributes() {
var input = @"
{.table}
+---+---+
| a | b |
+===+===+
| 1 | 2 |
+---+---+
";
var expected = @"<table class=""table"">
<col style=""width:50%"">
<col style=""width:50%"">
<thead>
<tr>
<th>a</th>
<th>b</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>2</td>
</tr>
</tbody>
</table>
";
TestParser.TestSpec(input, expected, "advanced");
}
[Test]
public void TestSamePipelineAllExtensions()

View File

@@ -0,0 +1,36 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp1.0</TargetFramework>
<PreserveCompilationContext>true</PreserveCompilationContext>
<AssemblyName>Markdig.WebApp</AssemblyName>
<OutputType>Exe</OutputType>
<PackageId>Markdig.WebApp</PackageId>
<RuntimeFrameworkVersion>1.0.4</RuntimeFrameworkVersion>
<PackageTargetFallback>$(PackageTargetFallback);dotnet5.6;dnxcore50;portable-net45+win8</PackageTargetFallback>
</PropertyGroup>
<ItemGroup>
<None Update="Views">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Markdig\Markdig.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="1.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.0.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.0.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="1.0.2" />
</ItemGroup>
</Project>

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>3cad9801-9976-46be-baca-f6d0d21fdc00</ProjectGuid>
<RootNamespace>Markdig.WebApp</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@@ -1,58 +0,0 @@
{
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.0",
"type": "platform"
},
"Microsoft.ApplicationInsights.AspNetCore": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Logging": "1.0.0",
"Microsoft.Extensions.Logging.Console": "1.0.0",
"Microsoft.Extensions.Logging.Debug": "1.0.0",
"Markdig": "0.7.2"
},
"tools": {
"Microsoft.AspNetCore.Server.IISIntegration.Tools": {
"version": "1.0.0-preview2-final",
"imports": "portable-net45+win8+dnxcore50"
}
},
"frameworks": {
"netcoreapp1.0": {
"imports": [
"dotnet5.6",
"dnxcore50",
"portable-net45+win8"
]
}
},
"buildOptions": {
"emitEntryPoint": true,
"preserveCompilationContext": true
},
"runtimeOptions": {
"gcServer": true
},
"publishOptions": {
"include": [
"wwwroot",
"Views",
"appsettings.json",
"web.config"
]
},
"scripts": {
"postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
}
}

View File

@@ -190,7 +190,7 @@ namespace Markdig.Extensions.Abbreviations
{
// The word matched must be embraced by punctuation or whitespace or \0.
var index = matchIndex - 1;
while (index > content.Start)
while (index >= content.Start)
{
var c = content.PeekCharAbsolute(index);
if (!(c == '\0' || c.IsAsciiPunctuation() || c.IsWhitespace()))
@@ -204,7 +204,7 @@ namespace Markdig.Extensions.Abbreviations
index--;
}
index = matchIndex + match.Length;
while (index < content.End)
while (index <= content.End)
{
var c = content.PeekCharAbsolute(index);
if (!(c == '\0' || c.IsAsciiPunctuation() || c.IsWhitespace()))

View File

@@ -3,6 +3,7 @@
// See the license.txt file in the project root for more information.
using System;
using System.Collections.Generic;
using Markdig.Helpers;
using Markdig.Parsers;
using Markdig.Syntax.Inlines;
@@ -38,8 +39,9 @@ namespace Markdig.Extensions.AutoLinks
return false;
}
List<char> pendingEmphasis;
// Check that an autolink is possible in the current context
if (!IsAutoLinkValidInCurrentContext(processor))
if (!IsAutoLinkValidInCurrentContext(processor, out pendingEmphasis))
{
return false;
}
@@ -84,6 +86,27 @@ namespace Markdig.Extensions.AutoLinks
return false;
}
// If we have any pending emphasis, remove any pending emphasis characters from the end of the link
if (pendingEmphasis != null)
{
for (int i = link.Length - 1; i >= 0; i--)
{
if (pendingEmphasis.Contains(link[i]))
{
slice.Start--;
}
else
{
if (i < link.Length - 1)
{
link = link.Substring(0, i + 1);
}
break;
}
}
}
// Post-check URL
switch (c)
{
@@ -144,8 +167,10 @@ namespace Markdig.Extensions.AutoLinks
return true;
}
private bool IsAutoLinkValidInCurrentContext(InlineProcessor processor)
private bool IsAutoLinkValidInCurrentContext(InlineProcessor processor, out List<char> pendingEmphasis)
{
pendingEmphasis = null;
// Case where there is a pending HtmlInline <a>
var currentInline = processor.Inline;
while (currentInline != null)
@@ -188,6 +213,23 @@ namespace Markdig.Extensions.AutoLinks
countBrackets--;
}
}
else
{
// Record all pending characters for emphasis
var emphasisDelimiter = currentInline as EmphasisDelimiterInline;
if (emphasisDelimiter != null)
{
if (pendingEmphasis == null)
{
// Not optimized for GC, but we don't expect this case much
pendingEmphasis = new List<char>();
}
if (!pendingEmphasis.Contains(emphasisDelimiter.DelimiterChar))
{
pendingEmphasis.Add(emphasisDelimiter.DelimiterChar);
}
}
}
currentInline = currentInline.Parent;
}

View File

@@ -81,12 +81,6 @@ namespace Markdig.Extensions.Emoji
return false;
}
// Following char must be a space
if (!slice.PeekCharExtra(match.Length).IsWhiteSpaceOrZero())
{
return false;
}
// If we have a smiley, we decode it to emoji
string emoji;
if (!SmileyToEmoji.TryGetValue(match, out emoji))
@@ -997,7 +991,16 @@ namespace Markdig.Extensions.Emoji
{":large_orange_diamond:", "🔶"},
{":large_blue_diamond:", "🔷"},
{":small_orange_diamond:", "🔸"},
{":small_blue_diamond:", "🔹"}
{":small_blue_diamond:", "🔹"},
// Custom additions
{ ":custom_arrow_left:", "←"},
{ ":custom_arrow_right:", "→"},
{ ":custom_arrow_left_right:", "↔"},
{ ":custom_arrow_left_strong:", "⇐"},
{ ":custom_arrow_right_strong:", "⇒"},
{ ":custom_arrow_left_right_strong:", "⇔"},
};
SmileyToEmojiDefault = new Dictionary<string, string>()
@@ -1067,6 +1070,15 @@ namespace Markdig.Extensions.Emoji
{":-$", ":unamused:"},
{";)", ":wink:"},
{";-)", ":wink:"},
// Custom arrows
{"<-", ":custom_arrow_left:" },
{"->", ":custom_arrow_rigth:" },
{"<->", ":custom_arrow_left_rigth:" },
{"<=", ":custom_arrow_left_strong:" },
{"=>", ":custom_arrow_rigth_strong:" },
{"<=>", ":custom_arrow_left_rigth_strong:" },
};
}
#endregion

View File

@@ -59,7 +59,7 @@ namespace Markdig.Extensions.GenericAttributes
{
objectToAttach = parent[indexOfParagraph + 1];
// We can remove the paragraph as it is empty
parent.RemoveAt(indexOfParagraph);
paragraph.RemoveAfterProcessInlines = true;
}
}
@@ -171,9 +171,10 @@ namespace Markdig.Extensions.GenericAttributes
// Skip any whitespaces
line.TrimStart();
c = line.CurrentChar;
// Handle boolean properties that are not followed by =
if ((hasSpace && (line.CurrentChar == '.' || line.CurrentChar == '#' || IsStartAttributeName(line.CurrentChar))) || line.CurrentChar == '}')
if ((hasSpace && (c == '.' || c == '#' || IsStartAttributeName(c))) || c == '}')
{
if (properties == null)
{

View File

@@ -0,0 +1,31 @@
// 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.Diagnostics;
using Markdig.Helpers;
using Markdig.Syntax.Inlines;
namespace Markdig.Extensions.JiraLinks
{
/// <summary>
/// Model for a JIRA link item
/// </summary>
[DebuggerDisplay("{ProjectKey}-{Issue}")]
public class JiraLink : LinkInline
{
public JiraLink()
{
IsClosed = true;
}
/// <summary>
/// JIRA Project Key
/// </summary>
public StringSlice ProjectKey { get; set; }
/// <summary>
/// JIRA Issue Number
/// </summary>
public StringSlice Issue { get; set; }
}
}

View File

@@ -0,0 +1,37 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using Markdig.Parsers.Inlines;
using Markdig.Renderers;
namespace Markdig.Extensions.JiraLinks
{
/// <summary>
/// Simple inline parser extension for Markdig to find, and
/// automatically add links to JIRA issue numbers.
/// </summary>
public class JiraLinkExtension : IMarkdownExtension
{
private readonly JiraLinkOptions _options;
public JiraLinkExtension(JiraLinkOptions options)
{
_options = options;
}
public void Setup(MarkdownPipelineBuilder pipeline)
{
if (!pipeline.InlineParsers.Contains<JiraLinkInlineParser>())
{
// Insert the parser before the link inline parser
pipeline.InlineParsers.InsertBefore<LinkInlineParser>(new JiraLinkInlineParser(_options));
}
}
public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer)
{
// Nothing to setup, JiraLinks used a normal LinkInlineRenderer
}
}
}

View File

@@ -0,0 +1,115 @@
// 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.Text;
using Markdig.Helpers;
using Markdig.Parsers;
using Markdig.Renderers.Html;
using Markdig.Syntax.Inlines;
namespace Markdig.Extensions.JiraLinks
{
/// <summary>
/// Finds and replaces JIRA links inline
/// </summary>
public class JiraLinkInlineParser : InlineParser
{
private readonly JiraLinkOptions _options;
private readonly string _baseUrl;
public JiraLinkInlineParser(JiraLinkOptions options)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
_baseUrl = _options.GetUrl();
//look for uppercase chars at the start (for the project key)
OpeningCharacters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray();
}
public override bool Match(InlineProcessor processor, ref StringSlice slice)
{
// Allow preceding whitespace or `(`
var pc = slice.PeekCharExtra(-1);
if (!pc.IsWhiteSpaceOrZero() && pc != '(')
{
return false;
}
var current = slice.CurrentChar;
var startKey = slice.Start;
var endKey = slice.Start;
//read as many uppercase characters as required - project key
while (current.IsAlphaUpper())
{
endKey = slice.Start;
current = slice.NextChar();
}
//require a '-' between key and issue number
if (!current.Equals('-'))
{
return false;
}
current = slice.NextChar(); // skip -
//read as many numbers as required - issue number
if (!current.IsDigit())
{
return false;
}
var startIssue = slice.Start;
var endIssue = slice.Start;
while (current.IsDigit())
{
endIssue = slice.Start;
current = slice.NextChar();
}
if (!current.IsWhiteSpaceOrZero() && current != ')') //can be followed only by a whitespace or `)`
{
return false;
}
int line;
int column;
var jiraLink = new JiraLink() //create the link at the relevant position
{
Span =
{
Start = processor.GetSourcePosition(slice.Start, out line, out column)
},
Line = line,
Column = column,
Issue = new StringSlice(slice.Text, startIssue, endIssue),
ProjectKey = new StringSlice(slice.Text, startKey, endKey),
};
jiraLink.Span.End = jiraLink.Span.Start + (endIssue - startKey);
// Builds the Url
var builder = new StringBuilder();
builder.Append(_baseUrl).Append('/').Append(jiraLink.ProjectKey).Append('-').Append(jiraLink.Issue);
jiraLink.Url = builder.ToString();
// Builds the Label
builder.Length = 0;
builder.Append(jiraLink.ProjectKey).Append('-').Append(jiraLink.Issue);
jiraLink.AppendChild(new LiteralInline(builder.ToString()));
if (_options.OpenInNewWindow)
{
jiraLink.GetAttributes().AddProperty("target", "blank");
}
processor.Inline = jiraLink;
return true;
}
}
}

View File

@@ -0,0 +1,57 @@
// 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.Text;
namespace Markdig.Extensions.JiraLinks
{
/// <summary>
/// Available options for replacing JIRA links
/// </summary>
public class JiraLinkOptions
{
/// <summary>
/// The base Url (e.g. `https://mycompany.atlassian.net`)
/// </summary>
public string BaseUrl { get; set; }
/// <summary>
/// The base path after the base url (default is `/browse`)
/// </summary>
public string BasePath { get; set; }
/// <summary>
/// Should the link open in a new window when clicked
/// </summary>
public bool OpenInNewWindow { get; set; }
public JiraLinkOptions(string baseUrl)
{
OpenInNewWindow = true; //default
BaseUrl = baseUrl;
BasePath = "/browse";
}
/// <summary>
/// Gets the full url composed of the <see cref="BaseUrl"/> and <see cref="BasePath"/> with no trailing `/`
/// </summary>
public virtual string GetUrl()
{
var url = new StringBuilder();
var baseUrl = BaseUrl;
if (baseUrl != null)
{
url.Append(baseUrl.TrimEnd('/'));
}
url.Append("/");
if (BasePath != null)
{
url.Append(BasePath.Trim('/'));
}
return url.ToString();
}
}
}

View File

@@ -62,7 +62,7 @@ namespace Markdig.Extensions.ListExtras
{
// otherwise we expect a regular alpha lettered list with a single character.
var isUpper = c.IsAlphaUpper();
result.OrderedStart = (Char.ToUpper(c) - 64).ToString();
result.OrderedStart = (Char.ToUpperInvariant(c) - 64).ToString();
result.BulletType = isUpper ? 'A' : 'a';
result.DefaultOrderedStart = isUpper ? "A" : "a";
state.NextChar();

View File

@@ -1,15 +1,18 @@
// Copyright (c) Alexandre Mutel. All rights reserved.
// This file is licensed under the BSD-Clause 2 license.
// See the license.txt file in the project root for more information.
using Markdig.Helpers;
using Markdig.Parsers;
using Markdig.Renderers.Html;
using Markdig.Syntax;
namespace Markdig.Extensions.Mathematics
{
/// <summary>
/// The block parser for a <see cref="MathBlock"/>.
/// </summary>
/// <seealso cref="Markdig.Parsers.FencedBlockParserBase{Markdig.Extensions.Mathematics.MathBlock}" />
/// <seealso cref="MathBlock" />
public class MathBlockParser : FencedBlockParserBase<MathBlock>
{
/// <summary>
@@ -22,6 +25,8 @@ namespace Markdig.Extensions.Mathematics
MinimumMatchCount = 2;
MaximumMatchCount = 2;
InfoParser = NoInfoParser;
DefaultClass = "math";
// We don't need a prefix
@@ -39,5 +44,19 @@ namespace Markdig.Extensions.Mathematics
}
return block;
}
private static bool NoInfoParser(BlockProcessor state, ref StringSlice line, IFencedBlock fenced)
{
var c = line.CurrentChar;
for (int i = line.Start; i <= line.End; i++)
{
c = line.Text[i];
if (!c.IsSpaceOrTab())
{
return false;
}
}
return true;
}
}
}

View File

@@ -50,11 +50,18 @@ namespace Markdig.Extensions.Mathematics
c = slice.NextChar();
}
bool canOpen;
bool canClose;
// Check that opening $/$$ is correct, using the same heuristics than for emphasis delimiters
CharHelper.CheckOpenCloseDelimiter(pc, c, false, out canOpen, out canClose);
if (!canOpen)
bool openPrevIsPunctuation;
bool openPrevIsWhiteSpace;
bool openNextIsPunctuation;
bool openNextIsWhiteSpace;
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
if ((!openPrevIsWhiteSpace && !openPrevIsPunctuation) || openNextIsDigit)
{
return false;
}
@@ -62,25 +69,60 @@ namespace Markdig.Extensions.Mathematics
bool isMatching = false;
int closeDollars = 0;
// Eat any leading spaces
while (c.IsSpaceOrTab())
{
c = slice.NextChar();
}
var start = slice.Start;
var end = 0;
pc = match;
var lastWhiteSpace = -1;
while (c != '\0')
{
// Don't allow newline in an inline math expression
if (c == '\r' || c == '\n')
{
return false;
}
// Don't process sticks if we have a '\' as a previous char
if (pc != '\\' )
{
while (c == match)
// Record continous whitespaces at the end
if (c.IsSpaceOrTab())
{
closeDollars++;
c = slice.NextChar();
if (lastWhiteSpace < 0)
{
lastWhiteSpace = slice.Start;
}
}
else
{
bool hasClosingDollars = c == match;
if (hasClosingDollars)
{
while (c == match)
{
closeDollars++;
c = slice.NextChar();
}
}
if (closeDollars >= openDollars)
{
break;
if (closeDollars >= openDollars)
{
break;
}
lastWhiteSpace = -1;
if (hasClosingDollars)
{
pc = match;
continue;
}
}
pc = match;
}
if (closeDollars > 0)
@@ -96,13 +138,30 @@ namespace Markdig.Extensions.Mathematics
if (closeDollars >= openDollars)
{
// Check that closing $/$$ is correct
CharHelper.CheckOpenCloseDelimiter(pc, c, false, out canOpen, out canClose);
if (!canClose || c.IsDigit())
bool closePrevIsPunctuation;
bool closePrevIsWhiteSpace;
bool closeNextIsPunctuation;
bool closeNextIsWhiteSpace;
pc.CheckUnicodeCategory(out closePrevIsWhiteSpace, out closePrevIsPunctuation);
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
// a whitespace as well for the character preceding the closing of $/$$
if ((!closeNextIsPunctuation && !closeNextIsWhiteSpace) || (openNextIsWhiteSpace != closePrevIsWhiteSpace))
{
return false;
}
end = slice.Start - 1;
if (closePrevIsWhiteSpace && lastWhiteSpace > 0)
{
end = lastWhiteSpace + openDollars - 1;
}
else
{
end = slice.Start - 1;
}
// Create a new MathInline
int line;
int column;

View File

@@ -115,7 +115,6 @@ namespace Markdig.Extensions.MediaLinks
renderer.WriteAttributes(htmlAttributes);
renderer.Write($"><source type=\"{mimeType}\" src=\"{linkInline.Url}\"></source></{tagType}>");
renderer.Write("</iframe>");
return true;
}

View File

@@ -458,6 +458,9 @@ namespace Markdig.Extensions.Tables
// Clear cells when we are done
cells.Clear();
// Normalize the table
table.Normalize();
// We don't want to continue procesing delimiters, as we are already processing them here
return false;
}

View File

@@ -69,5 +69,33 @@ namespace Markdig.Extensions.Tables
}
return true;
}
/// <summary>
/// Normalizes the number of columns of this table by taking the maximum columns and appending empty cells.
/// </summary>
public void Normalize()
{
var maxColumn = 0;
for (int i = 0; i < this.Count; i++)
{
var row = this[i] as TableRow;
if (row != null && row.Count > maxColumn)
{
maxColumn = row.Count;
}
}
for (int i = 0; i < this.Count; i++)
{
var row = this[i] as TableRow;
if (row != null)
{
for (int j = row.Count; j < maxColumn; j++)
{
row.Add(new TableCell());
}
}
}
}
}
}

View File

@@ -96,9 +96,9 @@ namespace Markdig.Helpers
int result = 0;
for (int i = 0; i < text.Length; i++)
{
var character = Char.ToUpper(text[i]);
var character = Char.ToUpperInvariant(text[i]);
var candidate = romanMap[character];
if (i + 1 < text.Length && candidate < romanMap[Char.ToUpper(text[i + 1])])
if (i + 1 < text.Length && candidate < romanMap[Char.ToUpperInvariant(text[i + 1])])
{
result -= candidate;
}
@@ -162,6 +162,9 @@ namespace Markdig.Helpers
return IsWhitespace(c) || IsZero(c);
}
// Note that we are not considering the character & as a punctuation in HTML
// as it is used for HTML entities, print unicode, so we assume that when we have a `&`
// it is more likely followed by a valid HTML Entity that represents a non punctuation
public static void CheckUnicodeCategory(this char c, out bool space, out bool punctuation)
{
// Credits: code from CommonMark.NET
@@ -170,7 +173,7 @@ namespace Markdig.Helpers
if (c <= 'ÿ')
{
space = c == '\0' || c == ' ' || (c >= '\t' && c <= '\r') || c == '\u00a0' || c == '\u0085';
punctuation = c == '\0' || (c >= 33 && c <= 47) || (c >= 58 && c <= 64) || (c >= 91 && c <= 96) || (c >= 123 && c <= 126);
punctuation = c == '\0' || (c >= 33 && c <= 47 && c != 38) || (c >= 58 && c <= 64) || (c >= 91 && c <= 96) || (c >= 123 && c <= 126);
}
else
{

View File

@@ -617,7 +617,7 @@ namespace Markdig.Helpers
{
// expect a letter and 1-31 letters or digits
c = s[pos + 1];
if ((c < 'A' || c > 'Z') && (c < 'a' && c > 'z'))
if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')))
return 0;
for (i = pos + 2; i < lastPos; i++)

View File

@@ -31,6 +31,12 @@ namespace Markdig.Helpers
/// <returns>The next character. `\0` is end of the iteration.</returns>
char NextChar();
/// <summary>
/// Peeks at the next character, without incrementing the <see cref="Start"/> position.
/// </summary>
/// <returns>The next character. `\0` is end of the iteration.</returns>
char PeekChar();
/// <summary>
/// Gets a value indicating whether this instance is empty.
/// </summary>

View File

@@ -116,6 +116,7 @@ namespace Markdig.Helpers
// An absolute URI, for these purposes, consists of a scheme followed by a colon (:)
// followed by zero or more characters other than ASCII whitespace and control characters, <, and >.
// If the URI includes these characters, they must be percent-encoded (e.g. %20 for a space).
// A URI that would end with a full stop (.) is treated instead as ending immediately before the full stop.
// a scheme is any sequence of 232 characters
// beginning with an ASCII letter
@@ -258,6 +259,7 @@ namespace Markdig.Helpers
break;
}
builder.Append(c);
pc = c;
}
}
else
@@ -595,7 +597,13 @@ namespace Markdig.Helpers
hasEscape = false;
if (c == '\0' || c.IsSpaceOrTab() || c.IsControl()) // TODO: specs unclear. space is strict or relaxed? (includes tabs?)
if (IsEndOfUri(c))
{
isValid = true;
break;
}
if (c == '.' && IsEndOfUri(text.PeekChar()))
{
isValid = true;
break;
@@ -612,6 +620,11 @@ namespace Markdig.Helpers
return isValid;
}
private static bool IsEndOfUri(char c)
{
return c == '\0' || c.IsSpaceOrTab() || c.IsControl(); // TODO: specs unclear. space is strict or relaxed? (includes tabs?)
}
public static bool TryParseLinkReferenceDefinition<T>(T text, out string label, out string url,
out string title) where T : ICharIterator
{

View File

@@ -101,5 +101,25 @@ namespace Markdig.Helpers
}
return false;
}
/// <summary>
/// Replaces <typeparamref name="TElement"/> with <paramref name="replacement"/>.
/// </summary>
/// <typeparam name="TElement">Element type to find in the list</typeparam>
/// <param name="replacement">Object to replace this element with</param>
/// <returns><c>true</c> if a replacement was made; otherwise <c>false</c>.</returns>
public bool Replace<TElement>(T replacement) where TElement : T
{
for (var i = 0; i < Count; i++)
{
if (this[i] is TElement)
{
RemoveAt(i);
Insert(i, replacement);
return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,23 @@
// 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.Text;
namespace Markdig.Helpers
{
/// <summary>
/// Extensions for StringBuilder with <see cref="StringSlice"/>
/// </summary>
public static class StringBuilderExtensions
{
/// <summary>
/// Appends the specified slice to this <see cref="StringBuilder"/> instance.
/// </summary>
/// <param name="builder">The builder.</param>
/// <param name="slice">The slice.</param>
public static StringBuilder Append(this StringBuilder builder, StringSlice slice)
{
return builder.Append(slice.Text, slice.Start, slice.Length);
}
}
}

View File

@@ -253,6 +253,22 @@ namespace Markdig.Helpers
return CurrentChar;
}
public char PeekChar()
{
if (Start + 1 > End)
{
return '\0';
}
var slice = (StringSlice)lines.Lines[SliceIndex];
if (offset + 1 >= slice.Length)
{
return '\n';
}
return slice[slice.Start + offset + 1];
}
public bool TrimStart()
{
var c = CurrentChar;

View File

@@ -112,6 +112,17 @@ namespace Markdig.Helpers
return index >= Start && index <= End ? Text[index] : (char) 0;
}
/// <summary>
/// Peeks the character immediately after the current <see cref="Start"/> position
/// or returns `\0` if after the <see cref="End"/> position.
/// </summary>
/// <returns>The next character, returns `\0` if none.</returns>
[MethodImpl(MethodImplOptionPortable.AggressiveInlining)]
public char PeekChar()
{
return PeekChar(1);
}
/// <summary>
/// Peeks a character at the specified offset from the current beginning of the string, without taking into account <see cref="Start"/> and <see cref="End"/>
/// </summary>

View File

@@ -0,0 +1,73 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>A fast, powerfull, 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.12.2</VersionPrefix>
<Authors>Alexandre Mutel</Authors>
<TargetFrameworks>net35;net40;portable40-net40+sl5+win8+wp8+wpa81;netstandard1.1</TargetFrameworks>
<AssemblyName>Markdig</AssemblyName>
<PackageId>Markdig</PackageId>
<PackageTags>Markdown CommonMark md html md2html</PackageTags>
<PackageReleaseNotes>
&gt; 0.12.2
- Fix issue with generic attributes used just before a pipe table (issue #121)
&gt; 0.12.1
- Fix issue with media links extension when a URL to video is used, an unexpected closing `&lt;/iframe&gt;` was inserted (issue #119)
&gt; 0.12.0
- Add new extension JiraLink support (thanks to @clarkd)
- Fix issue in html attributes not parsing correctly properties (thanks to @meziantou)
- Fix issues detected by an automatic static code analysis tool
&gt; 0.11.0
- Fix issue with math extension and $$ block parsing not handling correctly beginning of a $$ as a inline math instead (issue #107)
- Fix issue with custom attributes for emphasis
- Add support for new special custom arrows emoji (-&gt; &lt;- &lt;-&gt; &lt;= =&gt; and &lt;==&gt;)
</PackageReleaseNotes>
<PackageIconUrl>https://raw.githubusercontent.com/lunet-io/markdig/master/img/markdig.png</PackageIconUrl>
<PackageProjectUrl>https://github.com/lunet-io/markdig</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/lunet-io/markdig/blob/master/license.txt</PackageLicenseUrl>
<NetStandardImplicitPackageVersion Condition=" '$(TargetFramework)' == 'netstandard1.1' ">1.6.0</NetStandardImplicitPackageVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</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</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' ">
<DefineConstants>$(DefineConstants);NETSTANDARD_11</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'portable40-net40+sl5+win8+wp8+wpa81'">
<TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Profile328</TargetFrameworkProfile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
</Project>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>8A58A7E2-627C-4F41-933F-5AC92ADFAB48</ProjectGuid>
<RootNamespace>Markdig</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild>
<TypeScriptCompileBlocked>True</TypeScriptCompileBlocked>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@@ -1,2 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=syntax_005Cinlines/@EntryIndexedValue">False</s:Boolean></wpf:ResourceDictionary>

View File

@@ -3,6 +3,7 @@
// See the license.txt file in the project root for more information.
using System;
using System.IO;
using System.Reflection;
using Markdig.Extensions.SelfPipeline;
using Markdig.Parsers;
using Markdig.Renderers;
@@ -15,6 +16,12 @@ namespace Markdig
/// </summary>
public static partial class Markdown
{
#if NETSTANDARD_11
public static readonly string Version = typeof(Markdown).GetTypeInfo().Assembly.GetCustomAttribute<AssemblyFileVersionAttribute>().Version;
#else
public static readonly string Version = ((AssemblyFileVersionAttribute) typeof(Markdown).Assembly.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false)[0]).Version;
#endif
/// <summary>
/// Converts a Markdown string to HTML.
/// </summary>

View File

@@ -18,6 +18,7 @@ using Markdig.Extensions.Footers;
using Markdig.Extensions.Footnotes;
using Markdig.Extensions.GenericAttributes;
using Markdig.Extensions.Hardlines;
using Markdig.Extensions.JiraLinks;
using Markdig.Extensions.ListExtras;
using Markdig.Extensions.Mathematics;
using Markdig.Extensions.MediaLinks;
@@ -39,6 +40,17 @@ namespace Markdig
/// </summary>
public static class MarkdownExtensions
{
/// <summary>
/// Adds the specified extension to the extensions collection.
/// </summary>
/// <typeparam name="TExtension">The type of the extension.</typeparam>
/// <returns>The instance of <see cref="MarkdownPipelineBuilder" /></returns>
public static MarkdownPipelineBuilder Use<TExtension>(this MarkdownPipelineBuilder pipeline) where TExtension : class, IMarkdownExtension, new()
{
pipeline.Extensions.AddIfNotAlready<TExtension>();
return pipeline;
}
/// <summary>
/// Uses all extensions except the BootStrap, Emoji, SmartyPants and soft line as hard line breaks extensions.
/// </summary>
@@ -66,8 +78,7 @@ namespace Markdig
.UseAutoLinks()
.UseGenericAttributes(); // Must be last as it is one parser that is modifying other parsers
}
/// <summary>
/// Uses this extension to enable autolinks from text `http://`, `https://`, `ftp://`, `mailto:`, `www.xxx.yyy`
/// </summary>
@@ -416,6 +427,21 @@ namespace Markdig
return pipeline;
}
/// <summary>
/// Automatically link references to JIRA issues
/// </summary>
/// <param name="pipeline">The pipeline</param>
/// <param name="options">Set of required options</param>
/// <returns>The modified pipeline</returns>
public static MarkdownPipelineBuilder UseJiraLinks(this MarkdownPipelineBuilder pipeline, JiraLinkOptions options)
{
if (!pipeline.Extensions.Contains<JiraLinkExtension>())
{
pipeline.Extensions.Add(new JiraLinkExtension(options));
}
return pipeline;
}
/// <summary>
/// This will disable the HTML support in the markdown processor (for constraint/safe parsing).
/// </summary>

View File

@@ -617,12 +617,6 @@ namespace Markdig.Parsers
{
leaf.AppendLine(ref Line, Column, LineIndex, CurrentLineStartPosition);
}
if (NewBlocks.Count > 0)
{
throw new InvalidOperationException(
"The NewBlocks is not empty. This is happening if a LeafBlock is not the last to be pushed");
}
}
// A block is open only if it has a Continue state.

View File

@@ -1,30 +0,0 @@
using System.Resources;
using System.Reflection;
// 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("Markdig")]
[assembly: AssemblyDescription("A fast, powerfull, CommonMark compliant, extensible Markdown processor for .NET")]
#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Markdig")]
[assembly: AssemblyCopyright("Copyright © 2016 - Alexandre MUTEL")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
[assembly: AssemblyVersion(Markdig.Markdown.Version)]
[assembly: AssemblyFileVersion(Markdig.Markdown.Version)]
namespace Markdig
{
public static partial class Markdown
{
public const string Version = "0.10.3";
}
}

View File

@@ -37,7 +37,7 @@ namespace Markdig.Renderers.Html.Inlines
if (renderer.EnableHtmlForInline)
{
tag = GetTag(obj);
renderer.Write("<").Write(tag).Write(">");
renderer.Write("<").Write(tag).WriteAttributes(obj).Write(">");
}
renderer.WriteChildren(obj);
if (renderer.EnableHtmlForInline)

View File

@@ -1,68 +0,0 @@
{
"title": "Markdig",
"version": "0.10.3",
"authors": [ "Alexandre Mutel" ],
"description": "A fast, powerfull, CommonMark compliant, extensible Markdown processor for .NET with 20+ builtin extensions (pipetables, footnotes, definition lists... etc.)",
"copyright": "Alexandre Mutel",
"language": "en-US",
"packOptions": {
"owners": [ "Alexandre Mutel" ],
"licenseUrl": "https://github.com/lunet-io/markdig/blob/master/license.txt",
"projectUrl": "https://github.com/lunet-io/markdig",
"iconUrl": "https://raw.githubusercontent.com/lunet-io/markdig/master/img/markdig.png",
"requireLicenseAcceptance": false,
"releaseNotes": "> 0.10.3\n - Fix issue with pipetables shifting a cell to a new column (issue #73)\n> 0.10.2\n - Fix exception when trying to urlize an url with an unicode character outside the supported range by NormD (issue #75)\n > 0.10.1\n- Update to latest CommonMark specs\n- Fix source span for LinkReferenceDefinition\n> 0.10.0\n- Breaking change of the IMarkdownExtension to allow to receive the MarkdownPipeline for the renderers setup\n",
"tags": [ "Markdown CommonMark md html md2html" ]
},
"configurations": {
"Debug": {
"buildOptions": {
"define": [ "DEBUG", "TRACE" ],
"allowUnsafe": true
}
},
"Release": {
"buildOptions": {
"define": [ "RELEASE", "TRACE" ],
"optimize": true,
"allowUnsafe": true,
"xmlDoc": true,
"nowarn": [ "CS1591" ]
}
}
},
"frameworks": {
"net35": {
"buildOptions": {
"define": [ "SUPPORT_FIXED_STRING" ]
},
"frameworkAssemblies": {
"mscorlib": "",
"System": "",
"System.Core": ""
}
},
"net40": {
"buildOptions": {
"define": [ "SUPPORT_FIXED_STRING" ]
},
"frameworkAssemblies": {
"mscorlib": "",
"System": "",
"System.Core": ""
}
},
".NETPortable,Version=v4.0,Profile=Profile328": {
"frameworkAssemblies": {
"mscorlib": "",
"System": "",
"System.Core": ""
}
},
"netstandard1.1": {
"dependencies": {
"NETStandard.Library": "1.6.0"
}
}
}
}

View File

@@ -1,27 +1,27 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
# Visual Studio 15
VisualStudioVersion = 15.0.26403.7
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Markdig", "Markdig\Markdig.xproj", "{8A58A7E2-627C-4F41-933F-5AC92ADFAB48}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Markdig.Tests", "Markdig.Tests\Markdig.Tests.csproj", "{A0C5CB5F-5568-40AB-B945-D6D2664D51B0}"
ProjectSection(ProjectDependencies) = postProject
{8A58A7E2-627C-4F41-933F-5AC92ADFAB48} = {8A58A7E2-627C-4F41-933F-5AC92ADFAB48}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{061866E2-005C-4D13-A338-EA464BBEC60F}"
ProjectSection(SolutionItems) = preProject
..\license.txt = ..\license.txt
..\readme.md = ..\readme.md
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Markdig", "Markdig\Markdig.csproj", "{8A58A7E2-627C-4F41-933F-5AC92ADFAB48}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Markdig.Tests", "Markdig.Tests\Markdig.Tests.csproj", "{A0C5CB5F-5568-40AB-B945-D6D2664D51B0}"
ProjectSection(ProjectDependencies) = postProject
{8A58A7E2-627C-4F41-933F-5AC92ADFAB48} = {8A58A7E2-627C-4F41-933F-5AC92ADFAB48}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Markdig.Benchmarks", "Markdig.Benchmarks\Markdig.Benchmarks.csproj", "{6A19F040-BC7C-4283-873A-177B5324F1ED}"
ProjectSection(ProjectDependencies) = postProject
{8A58A7E2-627C-4F41-933F-5AC92ADFAB48} = {8A58A7E2-627C-4F41-933F-5AC92ADFAB48}
EndProjectSection
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Markdig.WebApp", "Markdig.WebApp\Markdig.WebApp.xproj", "{3CAD9801-9976-46BE-BACA-F6D0D21FDC00}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Markdig.WebApp", "Markdig.WebApp\Markdig.WebApp.csproj", "{3CAD9801-9976-46BE-BACA-F6D0D21FDC00}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnicodeNormDApp", "UnicodeNormDApp\UnicodeNormDApp.csproj", "{33FFC0B9-0187-44F9-9424-BB5AF5B4FB84}"
EndProject