diff --git a/appveyor.yml b/appveyor.yml index fa362083..6615be7a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,11 +1,15 @@ version: 10.0.{build} image: Visual Studio 2017 configuration: Release - +environment: + COVERALLS_REPO_TOKEN: + secure: /SEtLgIE6ZrJaWBC1xFZIeESiwfwiXEk9N4pSJ53rFhqBZC2sXJg7ZxZ1DBhnZGu install: - ps: >- cd src + dotnet tool install -g coveralls.net --version 1.0.0 + nuget restore Markdig.sln $env:MARKDIG_BUILD_NUMBER = ([int]$env:APPVEYOR_BUILD_NUMBER).ToString("000") @@ -31,22 +35,35 @@ build: project: src/Markdig.sln verbosity: minimal -after_build: -- cmd: >- - dotnet run --project SpecFileGen/SpecFileGen.csproj -c Release +after_build: > + dotnet SpecFileGen/bin/Release/netcoreapp2.2/SpecFileGen.dll - dotnet test -v n Markdig.Tests +test_script: +- cmd: >- + dotnet test Markdig.Tests -c Release --no-build + + dotnet test Markdig.Tests -c Debug + + dotnet test Markdig.Tests -c Release -f netcoreapp2.1 /p:CollectCoverage=true /p:Include=\"[Markdig]*\" /p:CoverletOutputFormat=opencover /p:CoverletOutput=../../coverage.xml + +after_test: +- ps: >- + if($env:APPVEYOR_REPO_BRANCH -eq "master") { + cd .. + if (Test-Path "./coverage.xml") { + csmacnz.Coveralls --opencover -i "./coverage.xml" --repoToken $env:COVERALLS_REPO_TOKEN --basePath "$env:APPVEYOR_BUILD_FOLDER" --useRelativePath --commitId $env:APPVEYOR_REPO_COMMIT --commitBranch $env:APPVEYOR_REPO_BRANCH --commitAuthor $env:APPVEYOR_REPO_COMMIT_AUTHOR --commitEmail $env:APPVEYOR_REPO_COMMIT_AUTHOR_EMAIL --commitMessage $env:APPVEYOR_REPO_COMMIT_MESSAGE --jobId $env:APPVEYOR_BUILD_NUMBER --serviceName appveyor + } + cd src + } before_package: - cmd: >- msbuild /t:pack /p:VersionSuffix="%MARKDIG_VERSION_SUFFIX%" /p:Configuration=Release Markdig/Markdig.csproj - msbuild /t:Clean Markdig/Markdig.csproj - - msbuild /t:pack /p:VersionSuffix="%MARKDIG_VERSION_SUFFIX%" /p:Configuration=Release;SignAssembly=true Markdig/Markdig.csproj + msbuild /t:pack /p:VersionSuffix="%MARKDIG_VERSION_SUFFIX%" /p:Configuration=Release Markdig.Signed/Markdig.Signed.csproj artifacts: -- path: src\Markdig\Bin\Release\*.nupkg +- path: src\**\*.nupkg name: Markdig Nugets deploy: diff --git a/changelog.md b/changelog.md index d4ab4f57..7d862f4a 100644 --- a/changelog.md +++ b/changelog.md @@ -1,9 +1,11 @@ # Changelog -## WIP -- Fix regression when escaping HTML characters ([(PR #340)](https://github.com/lunet-io/markdig/pull/340)) - Add `IHostProvider` for medialink customization (#337), support protocol-less url (#135) ([(PR #341)](https://github.com/lunet-io/markdig/pull/341)) +## 0.17.1 (04 July 2019) +- Fix regression when escaping HTML characters ([(PR #340)](https://github.com/lunet-io/markdig/pull/340)) +- Update Emoji Dictionary ([(PR #346)](https://github.com/lunet-io/markdig/pull/346)) + ## 0.17.0 (10 May 2019) - Update to latest CommonMark specs 0.29 ([(PR #327)](https://github.com/lunet-io/markdig/pull/327)) - Add `AutoLinkOptions` with `OpenInNewWindow`, `UseHttpsForWWWLinks` ([(PR #327)](https://github.com/lunet-io/markdig/pull/327)) diff --git a/readme.md b/readme.md index db956a21..1609703e 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -# Markdig [![Build status](https://ci.appveyor.com/api/projects/status/hk391x8jcskxt1u8?svg=true)](https://ci.appveyor.com/project/xoofx/markdig) [![NuGet](https://img.shields.io/nuget/v/Markdig.svg)](https://www.nuget.org/packages/Markdig/) [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FRGHXBTP442JL) +# Markdig [![Build status](https://ci.appveyor.com/api/projects/status/hk391x8jcskxt1u8?svg=true)](https://ci.appveyor.com/project/xoofx/markdig) [![Coverage Status](https://coveralls.io/repos/github/lunet-io/markdig/badge.svg?branch=master)](https://coveralls.io/github/lunet-io/markdig?branch=master) [![NuGet](https://img.shields.io/nuget/v/Markdig.svg)](https://www.nuget.org/packages/Markdig/) [![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=FRGHXBTP442JL) diff --git a/src/Markdig.Benchmarks/Markdig.Benchmarks.csproj b/src/Markdig.Benchmarks/Markdig.Benchmarks.csproj index 899ed8a8..8907cb3f 100644 --- a/src/Markdig.Benchmarks/Markdig.Benchmarks.csproj +++ b/src/Markdig.Benchmarks/Markdig.Benchmarks.csproj @@ -1,43 +1,12 @@ - - - + - Debug - AnyCPU - {6A19F040-BC7C-4283-873A-177B5324F1ED} + net471 Exe - Properties - Markdig.Benchmarks - Markdig.Benchmarks - v4.6 - 512 - true - - true - - - x86 - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 true - true - - - x86 - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - true - true + + + lib\CommonMarkNew.dll @@ -45,31 +14,12 @@ newcmark True - - - lib\MoonShine.dll lib\MarkdownDeep.dll - - - - - - - - - - - - - - - - @@ -83,21 +33,16 @@ PreserveNewest - - - - False - ..\Markdig\Bin\$(Configuration)\net40\Markdig.dll - + + + + + + - - - \ No newline at end of file + + + + diff --git a/src/Markdig.Benchmarks/Properties/AssemblyInfo.cs b/src/Markdig.Benchmarks/Properties/AssemblyInfo.cs deleted file mode 100644 index 7e118490..00000000 --- a/src/Markdig.Benchmarks/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Testamina.Markdig.Benchmarks")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Testamina.Markdig.Benchmarks")] -[assembly: AssemblyCopyright("Copyright © 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("6a19f040-bc7c-4283-873a-177b5324f1ed")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/Markdig.Benchmarks/Properties/launchSettings.json b/src/Markdig.Benchmarks/Properties/launchSettings.json deleted file mode 100644 index 759140b1..00000000 --- a/src/Markdig.Benchmarks/Properties/launchSettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "profiles": { - "CLASSIC": { - "executablePath": "Testamina.Markdig.Benchmarks.dll", - "workingDirectory": "..\\..\\artifacts\\bin\\Testamina.Markdig.Benchmarks\\Debug\\net45" - } - } -} \ No newline at end of file diff --git a/src/Markdig.Benchmarks/app.config b/src/Markdig.Benchmarks/app.config deleted file mode 100644 index b45f31e8..00000000 --- a/src/Markdig.Benchmarks/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/Markdig.Benchmarks/project.json b/src/Markdig.Benchmarks/project.json deleted file mode 100644 index 50ba1d7d..00000000 --- a/src/Markdig.Benchmarks/project.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "runtimes": { - "win-x86": {}, - "win-x64": {} - }, - "frameworks": { - "net46": { - "compilationOptions": { - "define": [ - "CLASSIC" - ] - }, - "frameworkAssemblies": { - "Microsoft.Build": "4.0.0.0", - "Microsoft.Build.Framework": "4.0.0.0", - "Microsoft.Build.Utilities.v4.0": "4.0.0.0", - "System.Management": "4.0.0.0" - } - } - }, - "dependencies": { - "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" - } -} \ No newline at end of file diff --git a/src/Markdig.Signed/Markdig.Signed.csproj b/src/Markdig.Signed/Markdig.Signed.csproj new file mode 100644 index 00000000..7b489d7f --- /dev/null +++ b/src/Markdig.Signed/Markdig.Signed.csproj @@ -0,0 +1,13 @@ + + + Markdig.Signed + key.snk + true + + + + %(RecursiveDir)%(Filename)%(Extension) + + + + \ No newline at end of file diff --git a/src/Markdig/key.snk b/src/Markdig.Signed/key.snk similarity index 100% rename from src/Markdig/key.snk rename to src/Markdig.Signed/key.snk diff --git a/src/Markdig.Tests/Markdig.Tests.csproj b/src/Markdig.Tests/Markdig.Tests.csproj index f082320a..bd573f55 100644 --- a/src/Markdig.Tests/Markdig.Tests.csproj +++ b/src/Markdig.Tests/Markdig.Tests.csproj @@ -6,8 +6,12 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - + diff --git a/src/Markdig.Tests/MiscTests.cs b/src/Markdig.Tests/MiscTests.cs index ef4685c4..c96e6e9c 100644 --- a/src/Markdig.Tests/MiscTests.cs +++ b/src/Markdig.Tests/MiscTests.cs @@ -8,6 +8,16 @@ namespace Markdig.Tests { public class MiscTests { + [Test] + public void IsIssue356Corrected() + { + string input = @"https://foo.bar/path/\#m4mv5W0GYKZpGvfA.97"; + string expected = @"

https://foo.bar/path/\#m4mv5W0GYKZpGvfA.97

"; + + TestParser.TestSpec($"<{input}>", expected); + TestParser.TestSpec(input, expected, "autolinks|advanced"); + } + [Test] public void TestAltTextIsCorrectlyEscaped() { diff --git a/src/Markdig.Tests/Specs/GenericAttributesSpecs.generated.cs b/src/Markdig.Tests/Specs/GenericAttributesSpecs.generated.cs index eee04658..17b1a766 100644 --- a/src/Markdig.Tests/Specs/GenericAttributesSpecs.generated.cs +++ b/src/Markdig.Tests/Specs/GenericAttributesSpecs.generated.cs @@ -1,4 +1,4 @@ -// Generated: 2019-04-05 16:06:14 +// Generated: 2019-08-01 13:57:17 // -------------------------------- // Generic Attributes @@ -79,5 +79,28 @@ namespace Markdig.Tests.Specs.GenericAttributes Console.WriteLine("Example 2\nSection Extensions / Generic Attributes\n"); TestParser.TestSpec("{#fenced-id .fenced-class}\n~~~\nThis is a fenced with attached attributes\n~~~ ", "
This is a fenced with attached attributes\n
", "attributes|advanced"); } + + // Attribute values can be one character long + [Test] + public void ExtensionsGenericAttributes_Example003() + { + // Example 3 + // Section: Extensions / Generic Attributes + // + // The following Markdown: + // [Foo](url){data-x=1} + // + // [Foo](url){data-x='1'} + // + // [Foo](url){data-x=11} + // + // Should be rendered as: + //

Foo

+ //

Foo

+ //

Foo

+ + Console.WriteLine("Example 3\nSection Extensions / Generic Attributes\n"); + TestParser.TestSpec("[Foo](url){data-x=1}\n\n[Foo](url){data-x='1'}\n\n[Foo](url){data-x=11}", "

Foo

\n

Foo

\n

Foo

", "attributes|advanced"); + } } } diff --git a/src/Markdig.Tests/Specs/GenericAttributesSpecs.md b/src/Markdig.Tests/Specs/GenericAttributesSpecs.md index 1cb7bd00..a0c46e40 100644 --- a/src/Markdig.Tests/Specs/GenericAttributesSpecs.md +++ b/src/Markdig.Tests/Specs/GenericAttributesSpecs.md @@ -47,3 +47,17 @@ This is a fenced with attached attributes
This is a fenced with attached attributes
 
```````````````````````````````` + +Attribute values can be one character long + +```````````````````````````````` example +[Foo](url){data-x=1} + +[Foo](url){data-x='1'} + +[Foo](url){data-x=11} +. +

Foo

+

Foo

+

Foo

+```````````````````````````````` diff --git a/src/Markdig.Tests/Specs/SmartyPantsSpecs.generated.cs b/src/Markdig.Tests/Specs/SmartyPantsSpecs.generated.cs index 8f63391d..37bb9a6b 100644 --- a/src/Markdig.Tests/Specs/SmartyPantsSpecs.generated.cs +++ b/src/Markdig.Tests/Specs/SmartyPantsSpecs.generated.cs @@ -1,4 +1,4 @@ -// Generated: 2019-04-05 16:06:14 +// Generated: 2019-08-01 12:33:23 // -------------------------------- // Smarty Pants @@ -140,13 +140,13 @@ namespace Markdig.Tests.Specs.SmartyPants // Section: Extensions / SmartyPants Quotes // // The following Markdown: - // This is a 'text <> + // This is 'a "text 'with" a another text' // // Should be rendered as: - //

This is a ‘text <<with’ a another text>>

+ //

This is ‘a “text 'with” a another text’

Console.WriteLine("Example 8\nSection Extensions / SmartyPants Quotes\n"); - TestParser.TestSpec("This is a 'text <>", "

This is a ‘text <<with’ a another text>>

", "pipetables+smartypants|advanced+smartypants"); + TestParser.TestSpec("This is 'a \"text 'with\" a another text'", "

This is ‘a “text 'with” a another text’

", "pipetables+smartypants|advanced+smartypants"); } [Test] @@ -156,20 +156,36 @@ namespace Markdig.Tests.Specs.SmartyPants // Section: Extensions / SmartyPants Quotes // // The following Markdown: + // This is a 'text <> + // + // Should be rendered as: + //

This is a ‘text <<with’ a another text>>

+ + Console.WriteLine("Example 9\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("This is a 'text <>", "

This is a ‘text <<with’ a another text>>

", "pipetables+smartypants|advanced+smartypants"); + } + + [Test] + public void ExtensionsSmartyPantsQuotes_Example010() + { + // Example 10 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: // This is a <> a another text' // // Should be rendered as: //

This is a «text 'with» a another text'

- Console.WriteLine("Example 9\nSection Extensions / SmartyPants Quotes\n"); + Console.WriteLine("Example 10\nSection Extensions / SmartyPants Quotes\n"); TestParser.TestSpec("This is a <> a another text'", "

This is a «text 'with» a another text'

", "pipetables+smartypants|advanced+smartypants"); } // Quotes requires to have the same rules than emphasis `_` regarding left/right frankling rules: [Test] - public void ExtensionsSmartyPantsQuotes_Example010() + public void ExtensionsSmartyPantsQuotes_Example011() { - // Example 10 + // Example 11 // Section: Extensions / SmartyPants Quotes // // The following Markdown: @@ -178,24 +194,8 @@ namespace Markdig.Tests.Specs.SmartyPants // Should be rendered as: //

It's not quotes'

- Console.WriteLine("Example 10\nSection Extensions / SmartyPants Quotes\n"); - TestParser.TestSpec("It's not quotes'", "

It's not quotes'

", "pipetables+smartypants|advanced+smartypants"); - } - - [Test] - public void ExtensionsSmartyPantsQuotes_Example011() - { - // Example 11 - // Section: Extensions / SmartyPants Quotes - // - // The following Markdown: - // They are ' not matching quotes ' - // - // Should be rendered as: - //

They are ' not matching quotes '

- Console.WriteLine("Example 11\nSection Extensions / SmartyPants Quotes\n"); - TestParser.TestSpec("They are ' not matching quotes '", "

They are ' not matching quotes '

", "pipetables+smartypants|advanced+smartypants"); + TestParser.TestSpec("It's not quotes'", "

It's not quotes'

", "pipetables+smartypants|advanced+smartypants"); } [Test] @@ -205,20 +205,36 @@ namespace Markdig.Tests.Specs.SmartyPants // Section: Extensions / SmartyPants Quotes // // The following Markdown: + // They are ' not matching quotes ' + // + // Should be rendered as: + //

They are ' not matching quotes '

+ + Console.WriteLine("Example 12\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("They are ' not matching quotes '", "

They are ' not matching quotes '

", "pipetables+smartypants|advanced+smartypants"); + } + + [Test] + public void ExtensionsSmartyPantsQuotes_Example013() + { + // Example 13 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: // They are' not matching 'quotes // // Should be rendered as: //

They are' not matching 'quotes

- Console.WriteLine("Example 12\nSection Extensions / SmartyPants Quotes\n"); + Console.WriteLine("Example 13\nSection Extensions / SmartyPants Quotes\n"); TestParser.TestSpec("They are' not matching 'quotes", "

They are' not matching 'quotes

", "pipetables+smartypants|advanced+smartypants"); } // An emphasis starting inside left/right quotes will span over the right quote: [Test] - public void ExtensionsSmartyPantsQuotes_Example013() + public void ExtensionsSmartyPantsQuotes_Example014() { - // Example 13 + // Example 14 // Section: Extensions / SmartyPants Quotes // // The following Markdown: @@ -227,9 +243,26 @@ namespace Markdig.Tests.Specs.SmartyPants // Should be rendered as: //

This is “a text” with an emphasis

- Console.WriteLine("Example 13\nSection Extensions / SmartyPants Quotes\n"); + Console.WriteLine("Example 14\nSection Extensions / SmartyPants Quotes\n"); TestParser.TestSpec("This is \"a *text\" with an emphasis*", "

This is “a text” with an emphasis

", "pipetables+smartypants|advanced+smartypants"); } + + // Multiple sets of quotes can be used + [Test] + public void ExtensionsSmartyPantsQuotes_Example015() + { + // Example 15 + // Section: Extensions / SmartyPants Quotes + // + // The following Markdown: + // "aaa" "bbb" "ccc" "ddd" + // + // Should be rendered as: + //

“aaa” “bbb” “ccc” “ddd”

+ + Console.WriteLine("Example 15\nSection Extensions / SmartyPants Quotes\n"); + TestParser.TestSpec("\"aaa\" \"bbb\" \"ccc\" \"ddd\"", "

“aaa” “bbb” “ccc” “ddd”

", "pipetables+smartypants|advanced+smartypants"); + } } [TestFixture] @@ -237,9 +270,9 @@ namespace Markdig.Tests.Specs.SmartyPants { // ## SmartyPants Separators [Test] - public void ExtensionsSmartyPantsSeparators_Example014() + public void ExtensionsSmartyPantsSeparators_Example016() { - // Example 14 + // Example 16 // Section: Extensions / SmartyPants Separators // // The following Markdown: @@ -248,14 +281,14 @@ namespace Markdig.Tests.Specs.SmartyPants // Should be rendered as: //

This is a – text

- Console.WriteLine("Example 14\nSection Extensions / SmartyPants Separators\n"); + Console.WriteLine("Example 16\nSection Extensions / SmartyPants Separators\n"); TestParser.TestSpec("This is a -- text", "

This is a – text

", "pipetables+smartypants|advanced+smartypants"); } [Test] - public void ExtensionsSmartyPantsSeparators_Example015() + public void ExtensionsSmartyPantsSeparators_Example017() { - // Example 15 + // Example 17 // Section: Extensions / SmartyPants Separators // // The following Markdown: @@ -264,14 +297,14 @@ namespace Markdig.Tests.Specs.SmartyPants // Should be rendered as: //

This is a — text

- Console.WriteLine("Example 15\nSection Extensions / SmartyPants Separators\n"); + Console.WriteLine("Example 17\nSection Extensions / SmartyPants Separators\n"); TestParser.TestSpec("This is a --- text", "

This is a — text

", "pipetables+smartypants|advanced+smartypants"); } [Test] - public void ExtensionsSmartyPantsSeparators_Example016() + public void ExtensionsSmartyPantsSeparators_Example018() { - // Example 16 + // Example 18 // Section: Extensions / SmartyPants Separators // // The following Markdown: @@ -280,15 +313,15 @@ namespace Markdig.Tests.Specs.SmartyPants // Should be rendered as: //

This is a en ellipsis…

- Console.WriteLine("Example 16\nSection Extensions / SmartyPants Separators\n"); + Console.WriteLine("Example 18\nSection Extensions / SmartyPants Separators\n"); TestParser.TestSpec("This is a en ellipsis...", "

This is a en ellipsis…

", "pipetables+smartypants|advanced+smartypants"); } // Check that a smartypants are not breaking pipetable parsing: [Test] - public void ExtensionsSmartyPantsSeparators_Example017() + public void ExtensionsSmartyPantsSeparators_Example019() { - // Example 17 + // Example 19 // Section: Extensions / SmartyPants Separators // // The following Markdown: @@ -312,15 +345,15 @@ namespace Markdig.Tests.Specs.SmartyPants // // - Console.WriteLine("Example 17\nSection Extensions / SmartyPants Separators\n"); + Console.WriteLine("Example 19\nSection Extensions / SmartyPants Separators\n"); TestParser.TestSpec("a | b\n-- | --\n0 | 1", "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
01
", "pipetables+smartypants|advanced+smartypants"); } // Check quotes and dash: [Test] - public void ExtensionsSmartyPantsSeparators_Example018() + public void ExtensionsSmartyPantsSeparators_Example020() { - // Example 18 + // Example 20 // Section: Extensions / SmartyPants Separators // // The following Markdown: @@ -329,7 +362,7 @@ namespace Markdig.Tests.Specs.SmartyPants // Should be rendered as: //

A “quote” with a —

- Console.WriteLine("Example 18\nSection Extensions / SmartyPants Separators\n"); + Console.WriteLine("Example 20\nSection Extensions / SmartyPants Separators\n"); TestParser.TestSpec("A \"quote\" with a ---", "

A “quote” with a —

", "pipetables+smartypants|advanced+smartypants"); } } diff --git a/src/Markdig.Tests/Specs/SmartyPantsSpecs.md b/src/Markdig.Tests/Specs/SmartyPantsSpecs.md index b0243f0b..3ed37a42 100644 --- a/src/Markdig.Tests/Specs/SmartyPantsSpecs.md +++ b/src/Markdig.Tests/Specs/SmartyPantsSpecs.md @@ -52,6 +52,12 @@ This is a "text 'with" a another text'

This is a “text 'with” a another text'

```````````````````````````````` +```````````````````````````````` example +This is 'a "text 'with" a another text' +. +

This is ‘a “text 'with” a another text’

+```````````````````````````````` + ```````````````````````````````` example This is a 'text <> . @@ -91,6 +97,14 @@ This is "a *text" with an emphasis*

This is “a text” with an emphasis

```````````````````````````````` +Multiple sets of quotes can be used + +```````````````````````````````` example +"aaa" "bbb" "ccc" "ddd" +. +

“aaa” “bbb” “ccc” “ddd”

+```````````````````````````````` + ## SmartyPants Separators ```````````````````````````````` example diff --git a/src/Markdig.Tests/TestParser.cs b/src/Markdig.Tests/TestParser.cs index 82b185d4..b437503f 100644 --- a/src/Markdig.Tests/TestParser.cs +++ b/src/Markdig.Tests/TestParser.cs @@ -33,9 +33,9 @@ namespace Markdig.Tests // If file creation times aren't preserved by git, add some leeway // If specs have come from git, assume that they were regenerated since CI would fail otherwise - testTime = testTime.AddSeconds(2); + testTime = testTime.AddMinutes(3); - // This might not catch a changed spec every time, but should most of the time. Otherwise CI will catch it + // This might not catch a changed spec every time, but should at least sometimes. Otherwise CI will catch it // This could also trigger, if a user has modified the spec file but reverted the change - can't think of a good workaround Assert.Less(specTime, testTime, diff --git a/src/Markdig/Extensions/Emoji/EmojiParser.cs b/src/Markdig/Extensions/Emoji/EmojiParser.cs index 73666c13..e565fa90 100644 --- a/src/Markdig/Extensions/Emoji/EmojiParser.cs +++ b/src/Markdig/Extensions/Emoji/EmojiParser.cs @@ -3,7 +3,7 @@ // See the license.txt file in the project root for more information. using System; -using System.Collections.Generic; +using System.Collections.Generic; using Markdig.Helpers; using Markdig.Parsers; @@ -47,9 +47,9 @@ namespace Markdig.Extensions.Emoji public override bool Match(InlineProcessor processor, ref StringSlice slice) { // Previous char must be a space - if (!slice.PeekCharExtra(-1).IsWhiteSpaceOrZero()) - { - return false; + if (!slice.PeekCharExtra(-1).IsWhiteSpaceOrZero()) + { + return false; } // Try to match an emoji @@ -75,8 +75,8 @@ namespace Markdig.Extensions.Emoji slice.Start += match.Key.Length; return true; - } - + } + #region Emojis and Smileys static EmojiParser() { @@ -961,6 +961,733 @@ namespace Markdig.Extensions.Emoji { ":custom_arrow_left_strong:", "⇐"}, { ":custom_arrow_right_strong:", "⇒"}, { ":custom_arrow_left_right_strong:", "⇔"}, + {":rofl:","🤣"}, + {":slightly_smiling_face:","🙂"}, + {":upside_down_face:","🙃"}, + {":star_struck:","🤩"}, + {":zany_face:","🤪"}, + {":money_mouth_face:","🤑"}, + {":hugs:","🤗"}, + {":hand_over_mouth:","🤭"}, + {":shushing_face:","🤫"}, + {":thinking:","🤔"}, + {":zipper_mouth_face:","🤐"}, + {":raised_eyebrow:","🤨"}, + {":roll_eyes:","🙄"}, + {":lying_face:","🤥"}, + {":drooling_face:","🤤"}, + {":face_with_thermometer:","🤒"}, + {":face_with_head_bandage:","🤕"}, + {":nauseated_face:","🤢"}, + {":vomiting_face:","🤮"}, + {":sneezing_face:","🤧"}, + {":exploding_head:","🤯"}, + {":cowboy_hat_face:","🤠"}, + {":nerd_face:","🤓"}, + {":monocle_face:","🧐"}, + {":slightly_frowning_face:","🙁"}, + {":frowning_face:","☹️"}, + {":cursing_face:","🤬"}, + {":skull_and_crossbones:","☠️"}, + {":clown_face:","🤡"}, + {":robot:","🤖"}, + {":heavy_heart_exclamation:","❣️"}, + {":orange_heart:","🧡"}, + {":black_heart:","🖤"}, + {":hole:","🕳️"}, + {":eye_speech_bubble:","👁️‍🗨️"}, + {":left_speech_bubble:","🗨️"}, + {":right_anger_bubble:","🗯️"}, + {":raised_back_of_hand:","🤚"}, + {":raised_hand_with_fingers_splayed:","🖐️"}, + {":vulcan_salute:","🖖"}, + {":crossed_fingers:","🤞"}, + {":love_you_gesture:","🤟"}, + {":metal:","🤘"}, + {":call_me_hand:","🤙"}, + {":middle_finger:","🖕"}, + {":fist_raised:","✊"}, + {":fist_oncoming:","👊"}, + {":fist_left:","🤛"}, + {":fist_right:","🤜"}, + {":palms_up_together:","🤲"}, + {":handshake:","🤝"}, + {":writing_hand:","✍️"}, + {":selfie:","🤳"}, + {":brain:","🧠"}, + {":eye:","👁️"}, + {":child:","🧒"}, + {":adult:","🧑"}, + {":blond_haired_person:","👱"}, + {":bearded_person:","🧔"}, + {":blond_haired_man:","👱‍♂️"}, + {":blond_haired_woman:","👱‍♀️"}, + {":older_adult:","🧓"}, + {":frowning_person:","🙍"}, + {":frowning_man:","🙍‍♂️"}, + {":frowning_woman:","🙍‍♀️"}, + {":pouting_face:","🙎"}, + {":pouting_man:","🙎‍♂️"}, + {":pouting_woman:","🙎‍♀️"}, + {":no_good_man:","🙅‍♂️"}, + {":no_good_woman:","🙅‍♀️"}, + {":ok_person:","🙆"}, + {":ok_man:","🙆‍♂️"}, + {":tipping_hand_person:","💁"}, + {":tipping_hand_man:","💁‍♂️"}, + {":tipping_hand_woman:","💁‍♀️"}, + {":raising_hand_man:","🙋‍♂️"}, + {":raising_hand_woman:","🙋‍♀️"}, + {":bowing_man:","🙇‍♂️"}, + {":bowing_woman:","🙇‍♀️"}, + {":facepalm:","🤦"}, + {":man_facepalming:","🤦‍♂️"}, + {":woman_facepalming:","🤦‍♀️"}, + {":shrug:","🤷"}, + {":man_shrugging:","🤷‍♂️"}, + {":woman_shrugging:","🤷‍♀️"}, + {":man_health_worker:","👨‍⚕️"}, + {":woman_health_worker:","👩‍⚕️"}, + {":man_student:","👨‍🎓"}, + {":woman_student:","👩‍🎓"}, + {":man_teacher:","👨‍🏫"}, + {":woman_teacher:","👩‍🏫"}, + {":man_judge:","👨‍⚖️"}, + {":woman_judge:","👩‍⚖️"}, + {":man_farmer:","👨‍🌾"}, + {":woman_farmer:","👩‍🌾"}, + {":man_cook:","👨‍🍳"}, + {":woman_cook:","👩‍🍳"}, + {":man_mechanic:","👨‍🔧"}, + {":woman_mechanic:","👩‍🔧"}, + {":man_factory_worker:","👨‍🏭"}, + {":woman_factory_worker:","👩‍🏭"}, + {":man_office_worker:","👨‍💼"}, + {":woman_office_worker:","👩‍💼"}, + {":man_scientist:","👨‍🔬"}, + {":woman_scientist:","👩‍🔬"}, + {":man_technologist:","👨‍💻"}, + {":woman_technologist:","👩‍💻"}, + {":man_singer:","👨‍🎤"}, + {":woman_singer:","👩‍🎤"}, + {":man_artist:","👨‍🎨"}, + {":woman_artist:","👩‍🎨"}, + {":man_pilot:","👨‍✈️"}, + {":woman_pilot:","👩‍✈️"}, + {":man_astronaut:","👨‍🚀"}, + {":woman_astronaut:","👩‍🚀"}, + {":man_firefighter:","👨‍🚒"}, + {":woman_firefighter:","👩‍🚒"}, + {":police_officer:","👮"}, + {":policeman:","👮‍♂️"}, + {":policewoman:","👮‍♀️"}, + {":detective:","🕵️"}, + {":male_detective:","🕵️‍♂️"}, + {":female_detective:","🕵️‍♀️"}, + {":guard:","💂"}, + {":guardswoman:","💂‍♀️"}, + {":construction_worker_man:","👷‍♂️"}, + {":construction_worker_woman:","👷‍♀️"}, + {":prince:","🤴"}, + {":person_with_turban:","👳"}, + {":woman_with_turban:","👳‍♀️"}, + {":woman_with_headscarf:","🧕"}, + {":man_in_tuxedo:","🤵"}, + {":pregnant_woman:","🤰"}, + {":breast_feeding:","🤱"}, + {":mrs_claus:","🤶"}, + {":mage:","🧙"}, + {":mage_man:","🧙‍♂️"}, + {":mage_woman:","🧙‍♀️"}, + {":fairy:","🧚"}, + {":fairy_man:","🧚‍♂️"}, + {":fairy_woman:","🧚‍♀️"}, + {":vampire:","🧛"}, + {":vampire_man:","🧛‍♂️"}, + {":vampire_woman:","🧛‍♀️"}, + {":merperson:","🧜"}, + {":merman:","🧜‍♂️"}, + {":mermaid:","🧜‍♀️"}, + {":elf:","🧝"}, + {":elf_man:","🧝‍♂️"}, + {":elf_woman:","🧝‍♀️"}, + {":genie:","🧞"}, + {":genie_man:","🧞‍♂️"}, + {":genie_woman:","🧞‍♀️"}, + {":zombie:","🧟"}, + {":zombie_man:","🧟‍♂️"}, + {":zombie_woman:","🧟‍♀️"}, + {":massage_man:","💆‍♂️"}, + {":massage_woman:","💆‍♀️"}, + {":haircut_man:","💇‍♂️"}, + {":haircut_woman:","💇‍♀️"}, + {":walking_man:","🚶‍♂️"}, + {":walking_woman:","🚶‍♀️"}, + {":running_man:","🏃‍♂️"}, + {":running_woman:","🏃‍♀️"}, + {":woman_dancing:","💃"}, + {":man_dancing:","🕺"}, + {":business_suit_levitating:","🕴️"}, + {":dancing_men:","👯‍♂️"}, + {":dancing_women:","👯‍♀️"}, + {":sauna_person:","🧖"}, + {":sauna_man:","🧖‍♂️"}, + {":sauna_woman:","🧖‍♀️"}, + {":climbing:","🧗"}, + {":climbing_man:","🧗‍♂️"}, + {":climbing_woman:","🧗‍♀️"}, + {":person_fencing:","🤺"}, + {":skier:","⛷️"}, + {":golfing:","🏌️"}, + {":golfing_man:","🏌️‍♂️"}, + {":golfing_woman:","🏌️‍♀️"}, + {":surfing_man:","🏄‍♂️"}, + {":surfing_woman:","🏄‍♀️"}, + {":rowing_man:","🚣‍♂️"}, + {":rowing_woman:","🚣‍♀️"}, + {":swimming_man:","🏊‍♂️"}, + {":swimming_woman:","🏊‍♀️"}, + {":bouncing_ball_person:","⛹️"}, + {":bouncing_ball_man:","⛹️‍♂️"}, + {":bouncing_ball_woman:","⛹️‍♀️"}, + {":weight_lifting:","🏋️"}, + {":weight_lifting_man:","🏋️‍♂️"}, + {":weight_lifting_woman:","🏋️‍♀️"}, + {":biking_man:","🚴‍♂️"}, + {":biking_woman:","🚴‍♀️"}, + {":mountain_biking_man:","🚵‍♂️"}, + {":mountain_biking_woman:","🚵‍♀️"}, + {":cartwheeling:","🤸"}, + {":man_cartwheeling:","🤸‍♂️"}, + {":woman_cartwheeling:","🤸‍♀️"}, + {":wrestling:","🤼"}, + {":men_wrestling:","🤼‍♂️"}, + {":women_wrestling:","🤼‍♀️"}, + {":water_polo:","🤽"}, + {":man_playing_water_polo:","🤽‍♂️"}, + {":woman_playing_water_polo:","🤽‍♀️"}, + {":handball_person:","🤾"}, + {":man_playing_handball:","🤾‍♂️"}, + {":woman_playing_handball:","🤾‍♀️"}, + {":juggling_person:","🤹"}, + {":man_juggling:","🤹‍♂️"}, + {":woman_juggling:","🤹‍♀️"}, + {":lotus_position:","🧘"}, + {":lotus_position_man:","🧘‍♂️"}, + {":lotus_position_woman:","🧘‍♀️"}, + {":sleeping_bed:","🛌"}, + {":people_holding_hands:","🧑‍🤝‍🧑"}, + {":couplekiss_man_woman:","👩‍❤️‍💋‍👨"}, + {":couplekiss_man_man:","👨‍❤️‍💋‍👨"}, + {":couplekiss_woman_woman:","👩‍❤️‍💋‍👩"}, + {":couple_with_heart_woman_man:","👩‍❤️‍👨"}, + {":couple_with_heart_man_man:","👨‍❤️‍👨"}, + {":couple_with_heart_woman_woman:","👩‍❤️‍👩"}, + {":family_man_woman_boy:","👨‍👩‍👦"}, + {":family_man_woman_girl:","👨‍👩‍👧"}, + {":family_man_woman_girl_boy:","👨‍👩‍👧‍👦"}, + {":family_man_woman_boy_boy:","👨‍👩‍👦‍👦"}, + {":family_man_woman_girl_girl:","👨‍👩‍👧‍👧"}, + {":family_man_man_boy:","👨‍👨‍👦"}, + {":family_man_man_girl:","👨‍👨‍👧"}, + {":family_man_man_girl_boy:","👨‍👨‍👧‍👦"}, + {":family_man_man_boy_boy:","👨‍👨‍👦‍👦"}, + {":family_man_man_girl_girl:","👨‍👨‍👧‍👧"}, + {":family_woman_woman_boy:","👩‍👩‍👦"}, + {":family_woman_woman_girl:","👩‍👩‍👧"}, + {":family_woman_woman_girl_boy:","👩‍👩‍👧‍👦"}, + {":family_woman_woman_boy_boy:","👩‍👩‍👦‍👦"}, + {":family_woman_woman_girl_girl:","👩‍👩‍👧‍👧"}, + {":family_man_boy:","👨‍👦"}, + {":family_man_boy_boy:","👨‍👦‍👦"}, + {":family_man_girl:","👨‍👧"}, + {":family_man_girl_boy:","👨‍👧‍👦"}, + {":family_man_girl_girl:","👨‍👧‍👧"}, + {":family_woman_boy:","👩‍👦"}, + {":family_woman_boy_boy:","👩‍👦‍👦"}, + {":family_woman_girl:","👩‍👧"}, + {":family_woman_girl_boy:","👩‍👧‍👦"}, + {":family_woman_girl_girl:","👩‍👧‍👧"}, + {":speaking_head:","🗣️"}, + {":gorilla:","🦍"}, + {":fox_face:","🦊"}, + {":lion:","🦁"}, + {":unicorn:","🦄"}, + {":zebra:","🦓"}, + {":deer:","🦌"}, + {":giraffe:","🦒"}, + {":rhinoceros:","🦏"}, + {":chipmunk:","🐿️"}, + {":hedgehog:","🦔"}, + {":bat:","🦇"}, + {":turkey:","🦃"}, + {":dove:","🕊️"}, + {":eagle:","🦅"}, + {":duck:","🦆"}, + {":owl:","🦉"}, + {":lizard:","🦎"}, + {":sauropod:","🦕"}, + {":t-rex:","🦖"}, + {":shark:","🦈"}, + {":butterfly:","🦋"}, + {":cricket:","🦗"}, + {":spider:","🕷️"}, + {":spider_web:","🕸️"}, + {":scorpion:","🦂"}, + {":rosette:","🏵️"}, + {":wilted_flower:","🥀"}, + {":shamrock:","☘️"}, + {":kiwi_fruit:","🥝"}, + {":coconut:","🥥"}, + {":avocado:","🥑"}, + {":potato:","🥔"}, + {":carrot:","🥕"}, + {":hot_pepper:","🌶️"}, + {":cucumber:","🥒"}, + {":broccoli:","🥦"}, + {":peanuts:","🥜"}, + {":croissant:","🥐"}, + {":baguette_bread:","🥖"}, + {":pretzel:","🥨"}, + {":pancakes:","🥞"}, + {":cheese:","🧀"}, + {":cut_of_meat:","🥩"}, + {":bacon:","🥓"}, + {":hotdog:","🌭"}, + {":sandwich:","🥪"}, + {":taco:","🌮"}, + {":burrito:","🌯"}, + {":stuffed_flatbread:","🥙"}, + {":fried_egg:","🍳"}, + {":shallow_pan_of_food:","🥘"}, + {":bowl_with_spoon:","🥣"}, + {":green_salad:","🥗"}, + {":popcorn:","🍿"}, + {":canned_food:","🥫"}, + {":dumpling:","🥟"}, + {":fortune_cookie:","🥠"}, + {":takeout_box:","🥡"}, + {":crab:","🦀"}, + {":shrimp:","🦐"}, + {":squid:","🦑"}, + {":pie:","🥧"}, + {":milk_glass:","🥛"}, + {":champagne:","🍾"}, + {":clinking_glasses:","🥂"}, + {":tumbler_glass:","🥃"}, + {":cup_with_straw:","🥤"}, + {":chopsticks:","🥢"}, + {":plate_with_cutlery:","🍽️"}, + {":spoon:","🥄"}, + {":amphora:","🏺"}, + {":world_map:","🗺️"}, + {":mountain_snow:","🏔️"}, + {":mountain:","⛰️"}, + {":camping:","🏕️"}, + {":beach_umbrella:","🏖️"}, + {":desert:","🏜️"}, + {":desert_island:","🏝️"}, + {":national_park:","🏞️"}, + {":stadium:","🏟️"}, + {":classical_building:","🏛️"}, + {":building_construction:","🏗️"}, + {":houses:","🏘️"}, + {":derelict_house:","🏚️"}, + {":mosque:","🕌"}, + {":synagogue:","🕍"}, + {":shinto_shrine:","⛩️"}, + {":kaaba:","🕋"}, + {":cityscape:","🏙️"}, + {":racing_car:","🏎️"}, + {":motorcycle:","🏍️"}, + {":motor_scooter:","🛵"}, + {":kick_scooter:","🛴"}, + {":motorway:","🛣️"}, + {":railway_track:","🛤️"}, + {":oil_drum:","🛢️"}, + {":stop_sign:","🛑"}, + {":canoe:","🛶"}, + {":passenger_ship:","🛳️"}, + {":ferry:","⛴️"}, + {":motor_boat:","🛥️"}, + {":small_airplane:","🛩️"}, + {":flight_departure:","🛫"}, + {":flight_arrival:","🛬"}, + {":artificial_satellite:","🛰️"}, + {":flying_saucer:","🛸"}, + {":bellhop_bell:","🛎️"}, + {":stopwatch:","⏱️"}, + {":timer_clock:","⏲️"}, + {":mantelpiece_clock:","🕰️"}, + {":thermometer:","🌡️"}, + {":cloud_with_lightning_and_rain:","⛈️"}, + {":sun_behind_small_cloud:","🌤️"}, + {":sun_behind_large_cloud:","🌥️"}, + {":sun_behind_rain_cloud:","🌦️"}, + {":cloud_with_rain:","🌧️"}, + {":cloud_with_snow:","🌨️"}, + {":cloud_with_lightning:","🌩️"}, + {":tornado:","🌪️"}, + {":fog:","🌫️"}, + {":wind_face:","🌬️"}, + {":open_umbrella:","☂️"}, + {":parasol_on_ground:","⛱️"}, + {":snowman_with_snow:","☃️"}, + {":comet:","☄️"}, + {":reminder_ribbon:","🎗️"}, + {":tickets:","🎟️"}, + {":medal_military:","🎖️"}, + {":medal_sports:","🏅"}, + {":1st_place_medal:","🥇"}, + {":2nd_place_medal:","🥈"}, + {":3rd_place_medal:","🥉"}, + {":volleyball:","🏐"}, + {":cricket_game:","🏏"}, + {":field_hockey:","🏑"}, + {":ice_hockey:","🏒"}, + {":ping_pong:","🏓"}, + {":badminton:","🏸"}, + {":boxing_glove:","🥊"}, + {":martial_arts_uniform:","🥋"}, + {":goal_net:","🥅"}, + {":ice_skate:","⛸️"}, + {":sled:","🛷"}, + {":curling_stone:","🥌"}, + {":joystick:","🕹️"}, + {":chess_pawn:","♟️"}, + {":framed_picture:","🖼️"}, + {":dark_sunglasses:","🕶️"}, + {":scarf:","🧣"}, + {":gloves:","🧤"}, + {":coat:","🧥"}, + {":socks:","🧦"}, + {":shopping:","🛍️"}, + {":billed_cap:","🧢"}, + {":rescue_worker_helmet:","⛑️"}, + {":prayer_beads:","📿"}, + {":studio_microphone:","🎙️"}, + {":level_slider:","🎚️"}, + {":control_knobs:","🎛️"}, + {":drum:","🥁"}, + {":desktop_computer:","🖥️"}, + {":printer:","🖨️"}, + {":keyboard:","⌨️"}, + {":computer_mouse:","🖱️"}, + {":trackball:","🖲️"}, + {":film_strip:","🎞️"}, + {":film_projector:","📽️"}, + {":camera_flash:","📸"}, + {":candle:","🕯️"}, + {":newspaper_roll:","🗞️"}, + {":label:","🏷️"}, + {":ballot_box:","🗳️"}, + {":fountain_pen:","🖋️"}, + {":pen:","🖊️"}, + {":paintbrush:","🖌️"}, + {":crayon:","🖍️"}, + {":card_index_dividers:","🗂️"}, + {":spiral_notepad:","🗒️"}, + {":spiral_calendar:","🗓️"}, + {":paperclips:","🖇️"}, + {":card_file_box:","🗃️"}, + {":file_cabinet:","🗄️"}, + {":wastebasket:","🗑️"}, + {":old_key:","🗝️"}, + {":pick:","⛏️"}, + {":hammer_and_pick:","⚒️"}, + {":hammer_and_wrench:","🛠️"}, + {":dagger:","🗡️"}, + {":crossed_swords:","⚔️"}, + {":bow_and_arrow:","🏹"}, + {":shield:","🛡️"}, + {":gear:","⚙️"}, + {":clamp:","🗜️"}, + {":balance_scale:","⚖️"}, + {":chains:","⛓️"}, + {":alembic:","⚗️"}, + {":bed:","🛏️"}, + {":couch_and_lamp:","🛋️"}, + {":shopping_cart:","🛒"}, + {":coffin:","⚰️"}, + {":funeral_urn:","⚱️"}, + {":radioactive:","☢️"}, + {":biohazard:","☣️"}, + {":place_of_worship:","🛐"}, + {":atom_symbol:","⚛️"}, + {":om:","🕉️"}, + {":star_of_david:","✡️"}, + {":wheel_of_dharma:","☸️"}, + {":yin_yang:","☯️"}, + {":latin_cross:","✝️"}, + {":orthodox_cross:","☦️"}, + {":star_and_crescent:","☪️"}, + {":peace_symbol:","☮️"}, + {":menorah:","🕎"}, + {":next_track_button:","⏭️"}, + {":play_or_pause_button:","⏯️"}, + {":previous_track_button:","⏮️"}, + {":pause_button:","⏸️"}, + {":stop_button:","⏹️"}, + {":record_button:","⏺️"}, + {":eject_button:","⏏️"}, + {":female_sign:","♀️"}, + {":male_sign:","♂️"}, + {":medical_symbol:","⚕️"}, + {":infinity:","♾️"}, + {":fleur_de_lis:","⚜️"}, + {":asterisk:","*️⃣"}, + {":black_flag:","🏴"}, + {":white_flag:","🏳️"}, + {":rainbow_flag:","🏳️‍🌈"}, + {":pirate_flag:","🏴‍☠️"}, + {":ascension_island:","🇦🇨"}, + {":andorra:","🇦🇩"}, + {":united_arab_emirates:","🇦🇪"}, + {":afghanistan:","🇦🇫"}, + {":antigua_barbuda:","🇦🇬"}, + {":anguilla:","🇦🇮"}, + {":albania:","🇦🇱"}, + {":armenia:","🇦🇲"}, + {":angola:","🇦🇴"}, + {":antarctica:","🇦🇶"}, + {":argentina:","🇦🇷"}, + {":american_samoa:","🇦🇸"}, + {":austria:","🇦🇹"}, + {":australia:","🇦🇺"}, + {":aruba:","🇦🇼"}, + {":aland_islands:","🇦🇽"}, + {":azerbaijan:","🇦🇿"}, + {":bosnia_herzegovina:","🇧🇦"}, + {":barbados:","🇧🇧"}, + {":bangladesh:","🇧🇩"}, + {":belgium:","🇧🇪"}, + {":burkina_faso:","🇧🇫"}, + {":bulgaria:","🇧🇬"}, + {":bahrain:","🇧🇭"}, + {":burundi:","🇧🇮"}, + {":benin:","🇧🇯"}, + {":st_barthelemy:","🇧🇱"}, + {":bermuda:","🇧🇲"}, + {":brunei:","🇧🇳"}, + {":bolivia:","🇧🇴"}, + {":caribbean_netherlands:","🇧🇶"}, + {":brazil:","🇧🇷"}, + {":bahamas:","🇧🇸"}, + {":bhutan:","🇧🇹"}, + {":bouvet_island:","🇧🇻"}, + {":botswana:","🇧🇼"}, + {":belarus:","🇧🇾"}, + {":belize:","🇧🇿"}, + {":canada:","🇨🇦"}, + {":cocos_islands:","🇨🇨"}, + {":congo_kinshasa:","🇨🇩"}, + {":central_african_republic:","🇨🇫"}, + {":congo_brazzaville:","🇨🇬"}, + {":switzerland:","🇨🇭"}, + {":cote_divoire:","🇨🇮"}, + {":cook_islands:","🇨🇰"}, + {":chile:","🇨🇱"}, + {":cameroon:","🇨🇲"}, + {":colombia:","🇨🇴"}, + {":clipperton_island:","🇨🇵"}, + {":costa_rica:","🇨🇷"}, + {":cuba:","🇨🇺"}, + {":cape_verde:","🇨🇻"}, + {":curacao:","🇨🇼"}, + {":christmas_island:","🇨🇽"}, + {":cyprus:","🇨🇾"}, + {":czech_republic:","🇨🇿"}, + {":diego_garcia:","🇩🇬"}, + {":djibouti:","🇩🇯"}, + {":denmark:","🇩🇰"}, + {":dominica:","🇩🇲"}, + {":dominican_republic:","🇩🇴"}, + {":algeria:","🇩🇿"}, + {":ceuta_melilla:","🇪🇦"}, + {":ecuador:","🇪🇨"}, + {":estonia:","🇪🇪"}, + {":egypt:","🇪🇬"}, + {":western_sahara:","🇪🇭"}, + {":eritrea:","🇪🇷"}, + {":ethiopia:","🇪🇹"}, + {":eu:","🇪🇺"}, + {":finland:","🇫🇮"}, + {":fiji:","🇫🇯"}, + {":falkland_islands:","🇫🇰"}, + {":micronesia:","🇫🇲"}, + {":faroe_islands:","🇫🇴"}, + {":gabon:","🇬🇦"}, + {":grenada:","🇬🇩"}, + {":georgia:","🇬🇪"}, + {":french_guiana:","🇬🇫"}, + {":guernsey:","🇬🇬"}, + {":ghana:","🇬🇭"}, + {":gibraltar:","🇬🇮"}, + {":greenland:","🇬🇱"}, + {":gambia:","🇬🇲"}, + {":guinea:","🇬🇳"}, + {":guadeloupe:","🇬🇵"}, + {":equatorial_guinea:","🇬🇶"}, + {":greece:","🇬🇷"}, + {":south_georgia_south_sandwich_islands:","🇬🇸"}, + {":guatemala:","🇬🇹"}, + {":guam:","🇬🇺"}, + {":guinea_bissau:","🇬🇼"}, + {":guyana:","🇬🇾"}, + {":hong_kong:","🇭🇰"}, + {":heard_mcdonald_islands:","🇭🇲"}, + {":honduras:","🇭🇳"}, + {":croatia:","🇭🇷"}, + {":haiti:","🇭🇹"}, + {":hungary:","🇭🇺"}, + {":canary_islands:","🇮🇨"}, + {":indonesia:","🇮🇩"}, + {":ireland:","🇮🇪"}, + {":israel:","🇮🇱"}, + {":isle_of_man:","🇮🇲"}, + {":india:","🇮🇳"}, + {":british_indian_ocean_territory:","🇮🇴"}, + {":iraq:","🇮🇶"}, + {":iran:","🇮🇷"}, + {":iceland:","🇮🇸"}, + {":jersey:","🇯🇪"}, + {":jamaica:","🇯🇲"}, + {":jordan:","🇯🇴"}, + {":kenya:","🇰🇪"}, + {":kyrgyzstan:","🇰🇬"}, + {":cambodia:","🇰🇭"}, + {":kiribati:","🇰🇮"}, + {":comoros:","🇰🇲"}, + {":st_kitts_nevis:","🇰🇳"}, + {":north_korea:","🇰🇵"}, + {":kuwait:","🇰🇼"}, + {":cayman_islands:","🇰🇾"}, + {":kazakhstan:","🇰🇿"}, + {":laos:","🇱🇦"}, + {":lebanon:","🇱🇧"}, + {":st_lucia:","🇱🇨"}, + {":liechtenstein:","🇱🇮"}, + {":sri_lanka:","🇱🇰"}, + {":liberia:","🇱🇷"}, + {":lesotho:","🇱🇸"}, + {":lithuania:","🇱🇹"}, + {":luxembourg:","🇱🇺"}, + {":latvia:","🇱🇻"}, + {":libya:","🇱🇾"}, + {":morocco:","🇲🇦"}, + {":monaco:","🇲🇨"}, + {":moldova:","🇲🇩"}, + {":montenegro:","🇲🇪"}, + {":st_martin:","🇲🇫"}, + {":madagascar:","🇲🇬"}, + {":marshall_islands:","🇲🇭"}, + {":macedonia:","🇲🇰"}, + {":mali:","🇲🇱"}, + {":myanmar:","🇲🇲"}, + {":mongolia:","🇲🇳"}, + {":macau:","🇲🇴"}, + {":northern_mariana_islands:","🇲🇵"}, + {":martinique:","🇲🇶"}, + {":mauritania:","🇲🇷"}, + {":montserrat:","🇲🇸"}, + {":malta:","🇲🇹"}, + {":mauritius:","🇲🇺"}, + {":maldives:","🇲🇻"}, + {":malawi:","🇲🇼"}, + {":mexico:","🇲🇽"}, + {":malaysia:","🇲🇾"}, + {":mozambique:","🇲🇿"}, + {":namibia:","🇳🇦"}, + {":new_caledonia:","🇳🇨"}, + {":niger:","🇳🇪"}, + {":norfolk_island:","🇳🇫"}, + {":nigeria:","🇳🇬"}, + {":nicaragua:","🇳🇮"}, + {":netherlands:","🇳🇱"}, + {":norway:","🇳🇴"}, + {":nepal:","🇳🇵"}, + {":nauru:","🇳🇷"}, + {":niue:","🇳🇺"}, + {":new_zealand:","🇳🇿"}, + {":oman:","🇴🇲"}, + {":panama:","🇵🇦"}, + {":peru:","🇵🇪"}, + {":french_polynesia:","🇵🇫"}, + {":papua_new_guinea:","🇵🇬"}, + {":philippines:","🇵🇭"}, + {":pakistan:","🇵🇰"}, + {":poland:","🇵🇱"}, + {":st_pierre_miquelon:","🇵🇲"}, + {":pitcairn_islands:","🇵🇳"}, + {":puerto_rico:","🇵🇷"}, + {":palestinian_territories:","🇵🇸"}, + {":portugal:","🇵🇹"}, + {":palau:","🇵🇼"}, + {":paraguay:","🇵🇾"}, + {":qatar:","🇶🇦"}, + {":reunion:","🇷🇪"}, + {":romania:","🇷🇴"}, + {":serbia:","🇷🇸"}, + {":rwanda:","🇷🇼"}, + {":saudi_arabia:","🇸🇦"}, + {":solomon_islands:","🇸🇧"}, + {":seychelles:","🇸🇨"}, + {":sudan:","🇸🇩"}, + {":sweden:","🇸🇪"}, + {":singapore:","🇸🇬"}, + {":st_helena:","🇸🇭"}, + {":slovenia:","🇸🇮"}, + {":svalbard_jan_mayen:","🇸🇯"}, + {":slovakia:","🇸🇰"}, + {":sierra_leone:","🇸🇱"}, + {":san_marino:","🇸🇲"}, + {":senegal:","🇸🇳"}, + {":somalia:","🇸🇴"}, + {":suriname:","🇸🇷"}, + {":south_sudan:","🇸🇸"}, + {":sao_tome_principe:","🇸🇹"}, + {":el_salvador:","🇸🇻"}, + {":sint_maarten:","🇸🇽"}, + {":syria:","🇸🇾"}, + {":swaziland:","🇸🇿"}, + {":tristan_da_cunha:","🇹🇦"}, + {":turks_caicos_islands:","🇹🇨"}, + {":chad:","🇹🇩"}, + {":french_southern_territories:","🇹🇫"}, + {":togo:","🇹🇬"}, + {":thailand:","🇹🇭"}, + {":tajikistan:","🇹🇯"}, + {":tokelau:","🇹🇰"}, + {":timor_leste:","🇹🇱"}, + {":turkmenistan:","🇹🇲"}, + {":tunisia:","🇹🇳"}, + {":tonga:","🇹🇴"}, + {":tr:","🇹🇷"}, + {":trinidad_tobago:","🇹🇹"}, + {":tuvalu:","🇹🇻"}, + {":taiwan:","🇹🇼"}, + {":tanzania:","🇹🇿"}, + {":ukraine:","🇺🇦"}, + {":uganda:","🇺🇬"}, + {":us_outlying_islands:","🇺🇲"}, + {":united_nations:","🇺🇳"}, + {":uruguay:","🇺🇾"}, + {":uzbekistan:","🇺🇿"}, + {":vatican_city:","🇻🇦"}, + {":st_vincent_grenadines:","🇻🇨"}, + {":venezuela:","🇻🇪"}, + {":british_virgin_islands:","🇻🇬"}, + {":us_virgin_islands:","🇻🇮"}, + {":vietnam:","🇻🇳"}, + {":vanuatu:","🇻🇺"}, + {":wallis_futuna:","🇼🇫"}, + {":samoa:","🇼🇸"}, + {":kosovo:","🇽🇰"}, + {":yemen:","🇾🇪"}, + {":mayotte:","🇾🇹"}, + {":south_africa:","🇿🇦"}, + {":zambia:","🇿🇲"}, + {":zimbabwe:","🇿🇼"} }; SmileyToEmojiDefault = new Dictionary() @@ -1039,31 +1766,31 @@ namespace Markdig.Extensions.Emoji {"<=", ":custom_arrow_left_strong:" }, {"=>", ":custom_arrow_right_strong:" }, {"<=>", ":custom_arrow_left_right_strong:" }, - }; - - // Build Emoji and Smiley CompactPrefixTree - EmojiPrefixTreeDefault = new CompactPrefixTree(EmojiToUnicodeDefault); - - int jointCount = EmojiToUnicodeDefault.Count + SmileyToEmojiDefault.Count; - // Count * 2 seems to be a good fit for the data set - EmojiSmileyPrefixTreeDefault = new CompactPrefixTree(jointCount, jointCount * 2, jointCount * 2); - - // This is not the best data set for the prefix tree as it will have to check the first character linearly - // A work-around would require a bunch of substrings / removing the leading ':' from emojis, neither one is pretty - // This way we sacrifice a few microseconds for not introducing breaking changes, emojis aren't all that common anyhow - + }; + + // Build Emoji and Smiley CompactPrefixTree + EmojiPrefixTreeDefault = new CompactPrefixTree(EmojiToUnicodeDefault); + + int jointCount = EmojiToUnicodeDefault.Count + SmileyToEmojiDefault.Count; + // Count * 2 seems to be a good fit for the data set + EmojiSmileyPrefixTreeDefault = new CompactPrefixTree(jointCount, jointCount * 2, jointCount * 2); + + // This is not the best data set for the prefix tree as it will have to check the first character linearly + // A work-around would require a bunch of substrings / removing the leading ':' from emojis, neither one is pretty + // This way we sacrifice a few microseconds for not introducing breaking changes, emojis aren't all that common anyhow + var firstChars = new HashSet { ':' }; - foreach (var emoji in EmojiToUnicodeDefault) + foreach (var emoji in EmojiToUnicodeDefault) EmojiSmileyPrefixTreeDefault.Add(emoji); - foreach (var smiley in SmileyToEmojiDefault) - { - if (!EmojiToUnicodeDefault.TryGetValue(smiley.Value, out string unicode)) - throw new ArgumentException("Invalid smiley target: {0} is not present in the emoji dictionary", smiley.Value); - - firstChars.Add(smiley.Key[0]); - - if (!EmojiSmileyPrefixTreeDefault.TryAdd(smiley.Key, unicode)) - throw new ArgumentException("Smiley {0} is already present in the Emoji dictionary", smiley.Key); + foreach (var smiley in SmileyToEmojiDefault) + { + if (!EmojiToUnicodeDefault.TryGetValue(smiley.Value, out string unicode)) + throw new ArgumentException("Invalid smiley target: {0} is not present in the emoji dictionary", smiley.Value); + + firstChars.Add(smiley.Key[0]); + + if (!EmojiSmileyPrefixTreeDefault.TryAdd(smiley.Key, unicode)) + throw new ArgumentException("Smiley {0} is already present in the Emoji dictionary", smiley.Key); } EmojiOpeningCharactersDefault = new[] { ':' }; diff --git a/src/Markdig/Extensions/GenericAttributes/GenericAttributesExtension.cs b/src/Markdig/Extensions/GenericAttributes/GenericAttributesExtension.cs index eb4821a5..7f65cdb8 100644 --- a/src/Markdig/Extensions/GenericAttributes/GenericAttributesExtension.cs +++ b/src/Markdig/Extensions/GenericAttributes/GenericAttributesExtension.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexandre Mutel. All rights reserved. +// Copyright (c) Alexandre Mutel. All rights reserved. // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. @@ -16,7 +16,7 @@ namespace Markdig.Extensions.GenericAttributes /// Extension that allows to attach HTML attributes to the previous or current . /// This extension should be enabled last after enabling other extensions. /// - /// + /// public class GenericAttributesExtension : IMarkdownExtension { public void Setup(MarkdownPipelineBuilder pipeline) @@ -29,8 +29,7 @@ namespace Markdig.Extensions.GenericAttributes // Plug into all IAttributesParseable foreach (var parser in pipeline.BlockParsers) { - var attributesParseable = parser as IAttributesParseable; - if (attributesParseable != null) + if (parser is IAttributesParseable attributesParseable) { attributesParseable.TryParseAttributes = TryProcessAttributesForHeading; } @@ -53,8 +52,7 @@ namespace Markdig.Extensions.GenericAttributes var copy = line; copy.Start = indexOfAttributes; var startOfAttributes = copy.Start; - HtmlAttributes attributes; - if (GenericAttributesParser.TryParse(ref copy, out attributes)) + if (GenericAttributesParser.TryParse(ref copy, out HtmlAttributes attributes)) { var htmlAttributes = block.GetAttributes(); attributes.CopyTo(htmlAttributes); diff --git a/src/Markdig/Extensions/GenericAttributes/GenericAttributesParser.cs b/src/Markdig/Extensions/GenericAttributes/GenericAttributesParser.cs index 0e58bc27..21255a86 100644 --- a/src/Markdig/Extensions/GenericAttributes/GenericAttributesParser.cs +++ b/src/Markdig/Extensions/GenericAttributes/GenericAttributesParser.cs @@ -14,7 +14,7 @@ namespace Markdig.Extensions.GenericAttributes /// /// An inline parser used to parse a HTML attributes that can be attached to the previous or current . /// - /// + /// public class GenericAttributesParser : InlineParser { /// @@ -27,9 +27,8 @@ namespace Markdig.Extensions.GenericAttributes public override bool Match(InlineProcessor processor, ref StringSlice slice) { - HtmlAttributes attributes; var startPosition = slice.Start; - if (TryParse(ref slice, out attributes)) + if (TryParse(ref slice, out HtmlAttributes attributes)) { var inline = processor.Inline; @@ -50,8 +49,10 @@ namespace Markdig.Extensions.GenericAttributes // If the current block is a Paragraph, but only the HtmlAttributes is used, // Try to attach the attributes to the following block - var paragraph = objectToAttach as ParagraphBlock; - if (paragraph != null && paragraph.Inline.FirstChild == null && processor.Inline == null && slice.IsEmptyOrWhitespace()) + if (objectToAttach is ParagraphBlock paragraph && + paragraph.Inline.FirstChild == null && + processor.Inline == null && + slice.IsEmptyOrWhitespace()) { var parent = paragraph.Parent; var indexOfParagraph = parent.IndexOf(paragraph); @@ -67,9 +68,7 @@ namespace Markdig.Extensions.GenericAttributes attributes.CopyTo(currentHtmlAttributes, true, false); // Update the position of the attributes - int line; - int column; - currentHtmlAttributes.Span.Start = processor.GetSourcePosition(startPosition, out line, out column); + currentHtmlAttributes.Span.Start = processor.GetSourcePosition(startPosition, out int line, out int column); currentHtmlAttributes.Line = line; currentHtmlAttributes.Column = column; currentHtmlAttributes.Span.End = currentHtmlAttributes.Span.Start + slice.Start - startPosition - 1; @@ -223,6 +222,7 @@ namespace Markdig.Extensions.GenericAttributes { // Parse until we match a space or a special html character startValue = line.Start; + bool valid = false; while (true) { if (c == '\0') @@ -234,9 +234,10 @@ namespace Markdig.Extensions.GenericAttributes break; } c = line.NextChar(); + valid = true; } endValue = line.Start - 1; - if (endValue == startValue) + if (!valid) { break; } diff --git a/src/Markdig/Extensions/SmartyPants/HtmlSmartyPantRenderer.cs b/src/Markdig/Extensions/SmartyPants/HtmlSmartyPantRenderer.cs index e1df73ee..172c7a84 100644 --- a/src/Markdig/Extensions/SmartyPants/HtmlSmartyPantRenderer.cs +++ b/src/Markdig/Extensions/SmartyPants/HtmlSmartyPantRenderer.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexandre Mutel. All rights reserved. +// Copyright (c) Alexandre Mutel. All rights reserved. // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. using System; @@ -10,7 +10,7 @@ namespace Markdig.Extensions.SmartyPants /// /// A HTML renderer for a . /// - /// + /// public class HtmlSmartyPantRenderer : HtmlObjectRenderer { private static readonly SmartyPantOptions DefaultOptions = new SmartyPantOptions(); @@ -21,17 +21,15 @@ namespace Markdig.Extensions.SmartyPants /// Initializes a new instance of the class. /// /// The options. - /// + /// public HtmlSmartyPantRenderer(SmartyPantOptions options) { - if (options == null) throw new ArgumentNullException(nameof(options)); - this.options = options; + this.options = options ?? throw new ArgumentNullException(nameof(options)); } protected override void Write(HtmlRenderer renderer, SmartyPant obj) { - string text; - if (!options.Mapping.TryGetValue(obj.Type, out text)) + if (!options.Mapping.TryGetValue(obj.Type, out string text)) { DefaultOptions.Mapping.TryGetValue(obj.Type, out text); } diff --git a/src/Markdig/Extensions/SmartyPants/SmartyPant.cs b/src/Markdig/Extensions/SmartyPants/SmartyPant.cs index 51b55484..e6bd5d2e 100644 --- a/src/Markdig/Extensions/SmartyPants/SmartyPant.cs +++ b/src/Markdig/Extensions/SmartyPants/SmartyPant.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexandre Mutel. All rights reserved. +// Copyright (c) Alexandre Mutel. All rights reserved. // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. using System.Diagnostics; @@ -45,5 +45,15 @@ namespace Markdig.Extensions.SmartyPants } return OpeningCharacter != 0 ? OpeningCharacter.ToString() : string.Empty; } + + public LiteralInline AsLiteralInline() + { + return new LiteralInline(ToString()) + { + Span = Span, + Line = Line, + Column = Column, + }; + } } } \ No newline at end of file diff --git a/src/Markdig/Extensions/SmartyPants/SmartyPantsExtension.cs b/src/Markdig/Extensions/SmartyPants/SmartyPantsExtension.cs index cb97c90a..c9ba64fc 100644 --- a/src/Markdig/Extensions/SmartyPants/SmartyPantsExtension.cs +++ b/src/Markdig/Extensions/SmartyPants/SmartyPantsExtension.cs @@ -1,4 +1,4 @@ -// Copyright (c) Alexandre Mutel. All rights reserved. +// Copyright (c) Alexandre Mutel. All rights reserved. // This file is licensed under the BSD-Clause 2 license. // See the license.txt file in the project root for more information. @@ -37,8 +37,7 @@ namespace Markdig.Extensions.SmartyPants public void Setup(MarkdownPipeline pipeline, IMarkdownRenderer renderer) { - var htmlRenderer = renderer as HtmlRenderer; - if (htmlRenderer != null) + if (renderer is HtmlRenderer htmlRenderer) { if (!htmlRenderer.ObjectRenderers.Contains()) { diff --git a/src/Markdig/Extensions/SmartyPants/SmartyPantsInlineParser.cs b/src/Markdig/Extensions/SmartyPants/SmartyPantsInlineParser.cs index 912c6480..7334a513 100644 --- a/src/Markdig/Extensions/SmartyPants/SmartyPantsInlineParser.cs +++ b/src/Markdig/Extensions/SmartyPants/SmartyPantsInlineParser.cs @@ -95,9 +95,7 @@ namespace Markdig.Extensions.SmartyPants // Skip char c = slice.NextChar(); - bool canOpen; - bool canClose; - CharHelper.CheckOpenCloseDelimiter(pc, c, false, out canOpen, out canClose); + CharHelper.CheckOpenCloseDelimiter(pc, c, false, out bool canOpen, out bool canClose); bool postProcess = false; @@ -156,11 +154,9 @@ namespace Markdig.Extensions.SmartyPants } // Create the SmartyPant inline - int line; - int column; var pant = new SmartyPant() { - Span = {Start = processor.GetSourcePosition(startingPosition, out line, out column)}, + Span = { Start = processor.GetSourcePosition(startingPosition, out int line, out int column) }, Line = line, Column = column, OpeningCharacter = openingChar, @@ -195,96 +191,90 @@ namespace Markdig.Extensions.SmartyPants return quotePants; } + private struct Opener + { + public int Type; + public int Index; + + public Opener(int type, int index) + { + Type = type; + Index = index; + } + } + private void BlockOnProcessInlinesEnd(InlineProcessor processor, Inline inline) { processor.Block.ProcessInlinesEnd -= BlockOnProcessInlinesEnd; var pants = (ListSmartyPants) processor.ParserStates[Index]; - // We only change quote into left or right quotes if we find proper balancing - var previousIndices = new int[3] {-1, -1, -1}; + Stack openers = new Stack(4); for (int i = 0; i < pants.Count; i++) { var quote = pants[i]; + var quoteType = quote.Type; - int currentTypeIndex = -1; - SmartyPantType expectedLeftQuote = 0; - SmartyPantType expectedRightQuote = 0; + int type; + bool isLeft; - if (quote.Type == SmartyPantType.LeftQuote || quote.Type == SmartyPantType.RightQuote) + if (quoteType == SmartyPantType.LeftQuote || quoteType == SmartyPantType.RightQuote) { - currentTypeIndex = 0; - expectedLeftQuote = SmartyPantType.LeftQuote; - expectedRightQuote = SmartyPantType.RightQuote; + type = 0; + isLeft = quoteType == SmartyPantType.LeftQuote; } - else if (quote.Type == SmartyPantType.LeftDoubleQuote || quote.Type == SmartyPantType.RightDoubleQuote) + else if (quoteType == SmartyPantType.LeftDoubleQuote || quoteType == SmartyPantType.RightDoubleQuote) { - currentTypeIndex = 1; - expectedLeftQuote = SmartyPantType.LeftDoubleQuote; - expectedRightQuote = SmartyPantType.RightDoubleQuote; + type = 1; + isLeft = quoteType == SmartyPantType.LeftDoubleQuote; } - else if (quote.Type == SmartyPantType.LeftAngleQuote || quote.Type == SmartyPantType.RightAngleQuote) + else if (quoteType == SmartyPantType.LeftAngleQuote || quoteType == SmartyPantType.RightAngleQuote) { - currentTypeIndex = 2; - expectedLeftQuote = SmartyPantType.LeftAngleQuote; - expectedRightQuote = SmartyPantType.RightAngleQuote; - } - - if (currentTypeIndex < 0) - { - continue; - } - - int previousIndex = previousIndices[currentTypeIndex]; - var previousQuote = previousIndex >= 0 ? pants[previousIndex] : null; - if (previousQuote == null) - { - if (quote.Type == expectedLeftQuote) - { - previousIndices[currentTypeIndex] = i; - } + type = 2; + isLeft = quoteType == SmartyPantType.LeftAngleQuote; } else { - if (quote.Type == expectedRightQuote) - { - // Replace all intermediate unmatched left or right SmartyPants to their literal equivalent - pants.RemoveAt(i); - i--; - for (int j = i; j > previousIndex; j--) - { - var toReplace = pants[j]; - pants.RemoveAt(j); - toReplace.ReplaceBy(new LiteralInline(toReplace.ToString()) - { - Span = toReplace.Span, - Line = toReplace.Line, - Column = toReplace.Column, - }); - i--; - } + quote.ReplaceBy(quote.AsLiteralInline()); + continue; + } - // If we matched, we remove left/right quotes from the list - pants.RemoveAt(previousIndex); - previousIndices[currentTypeIndex] = -1; - } - else + if (isLeft) + { + openers.Push(new Opener(type, i)); + } + else + { + bool found = false; + + while (openers.Count > 0) { - previousIndices[currentTypeIndex] = i; + Opener opener = openers.Pop(); + var previousQuote = pants[opener.Index]; + + if (opener.Type == type) + { + found = true; + break; + } + else + { + previousQuote.ReplaceBy(previousQuote.AsLiteralInline()); + } + } + + if (!found) + { + quote.ReplaceBy(quote.AsLiteralInline()); } } } - // If we have any quotes lefts, replace them by there literal equivalent - foreach (var quote in pants) + foreach (var opener in openers) { - quote.ReplaceBy(new LiteralInline(quote.ToString()) - { - Span = quote.Span, - Line = quote.Line, - Column = quote.Column, - }); + var quote = pants[opener.Index]; + quote.ReplaceBy(quote.AsLiteralInline()); } pants.Clear(); @@ -294,8 +284,7 @@ namespace Markdig.Extensions.SmartyPants bool isFinalProcessing) { // Don't try to process anything if there are no dash - var quotePants = state.ParserStates[Index] as ListSmartyPants; - if (quotePants == null || !quotePants.HasDash) + if (!(state.ParserStates[Index] is ListSmartyPants quotePants) || !quotePants.HasDash) { return true; } @@ -309,10 +298,8 @@ namespace Markdig.Extensions.SmartyPants { var next = child.NextSibling; - if (child is LiteralInline) + if (child is LiteralInline literal) { - var literal = (LiteralInline) child; - var startIndex = 0; var indexOfDash = literal.Content.IndexOf("--", startIndex); diff --git a/src/Markdig/Helpers/CharacterMap.cs b/src/Markdig/Helpers/CharacterMap.cs index b7a42ba0..0eb4107a 100644 --- a/src/Markdig/Helpers/CharacterMap.cs +++ b/src/Markdig/Helpers/CharacterMap.cs @@ -118,20 +118,11 @@ namespace Markdig.Helpers public int IndexOfOpeningCharacter(string text, int start, int end) { var maxChar = isOpeningCharacter.Length; -#if SUPPORT_UNSAFE + unsafe -#endif { -#if SUPPORT_FIXED_STRING - fixed (char* pText = text) -#else - var pText = text; -#endif -#if SUPPORT_UNSAFE + fixed (char* pText = text) fixed (bool* openingChars = isOpeningCharacter) -#else - var openingChars = isOpeningCharacter; -#endif { if (nonAsciiMap == null) { diff --git a/src/Markdig/Helpers/LinkHelper.cs b/src/Markdig/Helpers/LinkHelper.cs index 1180ab2e..7fa1ba22 100644 --- a/src/Markdig/Helpers/LinkHelper.cs +++ b/src/Markdig/Helpers/LinkHelper.cs @@ -597,20 +597,23 @@ namespace Markdig.Helpers } } - if (hasEscape && !c.IsAsciiPunctuation()) + if (!isAutoLink) { - buffer.Append('\\'); - } + if (hasEscape && !c.IsAsciiPunctuation()) + { + buffer.Append('\\'); + } - // If we have an escape - if (c == '\\') - { - hasEscape = true; - c = text.NextChar(); - continue; - } + // If we have an escape + if (c == '\\') + { + hasEscape = true; + c = text.NextChar(); + continue; + } - hasEscape = false; + hasEscape = false; + } if (IsEndOfUri(c, isAutoLink)) { @@ -622,10 +625,7 @@ namespace Markdig.Helpers { if (c == '&') { - int entityNameStart; - int entityNameLength; - int entityValue; - if (HtmlHelper.ScanEntity(text, out entityValue, out entityNameStart, out entityNameLength) > 0) + if (HtmlHelper.ScanEntity(text, out _, out _, out _) > 0) { isValid = true; break; diff --git a/src/Markdig/Markdig.csproj b/src/Markdig/Markdig.csproj index 46162a3b..87e8a68b 100644 --- a/src/Markdig/Markdig.csproj +++ b/src/Markdig/Markdig.csproj @@ -1,84 +1,6 @@  - - A fast, powerful, CommonMark compliant, extensible Markdown processor for .NET with 20+ builtin extensions (pipetables, footnotes, definition lists... etc.) - Alexandre Mutel - Markdig - en-US - 0.17.0 - Alexandre Mutel - net35;net40;netstandard2.0;uap10.0;netcoreapp2.1 - Markdig Markdig - Markdig.Signed - Markdown CommonMark md html md2html - https://github.com/lunet-io/markdig/blob/master/changelog.md - BSD-2-Clause - https://raw.githubusercontent.com/lunet-io/markdig/master/img/markdig.png - https://github.com/lunet-io/markdig - 1.6.0 - true - 7.3 - - - - - - - - - - - - - - - - - - - - - - $(DefineConstants);SUPPORT_FIXED_STRING;SUPPORT_UNSAFE - - - - $(DefineConstants);SUPPORT_FIXED_STRING;SUPPORT_UNSAFE - - - - $(DefineConstants);SUPPORT_FIXED_STRING;SUPPORT_UNSAFE - - - - $(DefineConstants);SUPPORT_FIXED_STRING;SUPPORT_UNSAFE;NETCORE - - - - UAP - 10.0.17763.0 - 10.0.10240.0 - $(DefineConstants);NETSTANDARD_11;SUPPORT_UNSAFE - - - - $(NoWarn);CS1591 - true - - - - key.snk - true - - - - - - - - - - + diff --git a/src/Markdig/Markdig.targets b/src/Markdig/Markdig.targets new file mode 100644 index 00000000..a5c735d6 --- /dev/null +++ b/src/Markdig/Markdig.targets @@ -0,0 +1,43 @@ + + + + A fast, powerful, CommonMark compliant, extensible Markdown processor for .NET with 20+ builtin extensions (pipetables, footnotes, definition lists... etc.) + Alexandre Mutel + en-US + 0.17.1 + Alexandre Mutel + net35;net40;netstandard2.0;uap10.0;netcoreapp2.1 + Markdown CommonMark md html md2html + https://github.com/lunet-io/markdig/blob/master/changelog.md + BSD-2-Clause + https://raw.githubusercontent.com/lunet-io/markdig/master/img/markdig.png + https://github.com/lunet-io/markdig + true + 7.3 + + + + $(DefineConstants);NETCORE + + + + UAP + 10.0.17763.0 + 10.0.10240.0 + $(DefineConstants);UAP + + + + $(NoWarn);CS1591 + true + + + + + + + + + + + diff --git a/src/Markdig/Markdown.cs b/src/Markdig/Markdown.cs index 0dbea434..86a0f1a4 100644 --- a/src/Markdig/Markdown.cs +++ b/src/Markdig/Markdown.cs @@ -17,7 +17,7 @@ namespace Markdig /// public static partial class Markdown { -#if NETSTANDARD_11 +#if UAP public static readonly string Version = typeof(Markdown).GetTypeInfo().Assembly.GetCustomAttribute().Version; #else public static readonly string Version = ((AssemblyFileVersionAttribute) typeof(Markdown).Assembly.GetCustomAttributes(typeof(AssemblyFileVersionAttribute), false)[0]).Version; diff --git a/src/SpecFileGen/Program.cs b/src/SpecFileGen/Program.cs index e3117cf8..7cb0017d 100644 --- a/src/SpecFileGen/Program.cs +++ b/src/SpecFileGen/Program.cs @@ -103,12 +103,12 @@ namespace SpecFileGen continue; } - string source = ParseSpecification(spec, File.ReadAllText(spec.Path)); + string source = ParseSpecification(spec, File.ReadAllText(spec.Path)).Replace("\r\n", "\n", StringComparison.Ordinal); totalTests += spec.TestCount; if (File.Exists(spec.OutputPath)) // If the source hasn't changed, don't bump the generated tag { - string previousSource = File.ReadAllText(spec.OutputPath); + string previousSource = File.ReadAllText(spec.OutputPath).Replace("\r\n", "\n", StringComparison.Ordinal); int start = previousSource.IndexOf('\n', StringComparison.Ordinal) + 1; int previousLength = previousSource.Length - start; if (start != 0 && previousLength == source.Length) diff --git a/src/markdig.sln b/src/markdig.sln index 9feff73a..b5cf2401 100644 --- a/src/markdig.sln +++ b/src/markdig.sln @@ -13,12 +13,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{061866E2 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Markdig", "Markdig\Markdig.csproj", "{8A58A7E2-627C-4F41-933F-5AC92ADFAB48}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Markdig.Signed", "Markdig.Signed\Markdig.Signed.csproj", "{C37C7B94-1219-4ED9-ABAC-C0B4B8FE8750}" +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}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "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 @@ -41,6 +43,10 @@ Global {8A58A7E2-627C-4F41-933F-5AC92ADFAB48}.Debug|Any CPU.Build.0 = Debug|Any CPU {8A58A7E2-627C-4F41-933F-5AC92ADFAB48}.Release|Any CPU.ActiveCfg = Release|Any CPU {8A58A7E2-627C-4F41-933F-5AC92ADFAB48}.Release|Any CPU.Build.0 = Release|Any CPU + {C37C7B94-1219-4ED9-ABAC-C0B4B8FE8750}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C37C7B94-1219-4ED9-ABAC-C0B4B8FE8750}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C37C7B94-1219-4ED9-ABAC-C0B4B8FE8750}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C37C7B94-1219-4ED9-ABAC-C0B4B8FE8750}.Release|Any CPU.Build.0 = Release|Any CPU {A0C5CB5F-5568-40AB-B945-D6D2664D51B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {A0C5CB5F-5568-40AB-B945-D6D2664D51B0}.Debug|Any CPU.Build.0 = Debug|Any CPU {A0C5CB5F-5568-40AB-B945-D6D2664D51B0}.Release|Any CPU.ActiveCfg = Release|Any CPU